Merge branch 'develop' of https://github.com/HBAI-Ltd/Toonflow-app into develop

This commit is contained in:
zhishi 2026-02-06 14:18:36 +08:00
commit 33db2c024c
23 changed files with 443 additions and 1766 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.devtools
# dependencies (bun install) # dependencies (bun install)
node_modules node_modules

View File

@ -1,9 +1,18 @@
{ {
"name": "toonflow-serve", "name": "toonflow-app",
"version": "1.0.5", "version": "1.0.5",
"description": "ToonFlow Serve - Electron Application", "description": "Toonflow 是一款 AI 短剧漫剧工具,能够利用 AI 技术将小说自动转化为剧本,并结合 AI 生成的图片和视频,实现高效的短剧创作。",
"author": "HBAI-Ltd <ltlctools@outlook.com>",
"homepage": "https://github.com/HBAI-Ltd/Toonflow-app#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/HBAI-Ltd/Toonflow-app.git"
},
"bugs": {
"url": "https://github.com/HBAI-Ltd/Toonflow-app/issues",
"email": "ltlctools@outlook.com"
},
"main": "build/main.js", "main": "build/main.js",
"author": "ToonFlow Team",
"packageManager": "yarn@1.0.0", "packageManager": "yarn@1.0.0",
"engines": { "engines": {
"node": ">=1.0.0" "node": ">=1.0.0"
@ -19,18 +28,16 @@
"dist:mac": "yarn build && electron-builder --mac", "dist:mac": "yarn build && electron-builder --mac",
"dist:linux": "yarn build && electron-builder --linux", "dist:linux": "yarn build && electron-builder --linux",
"test": "node build/app.js", "test": "node build/app.js",
"debug:ai": "npx @ai-sdk/devtools",
"license": "bun run scripts/license.ts" "license": "bun run scripts/license.ts"
}, },
"dependencies": { "dependencies": {
"@ai-sdk/anthropic": "^3.0.35", "@ai-sdk/anthropic": "^3.0.35",
"@ai-sdk/deepseek": "^2.0.17", "@ai-sdk/deepseek": "^2.0.17",
"@ai-sdk/devtools": "^0.0.11",
"@ai-sdk/google": "^3.0.20", "@ai-sdk/google": "^3.0.20",
"@ai-sdk/openai": "^3.0.25", "@ai-sdk/openai": "^3.0.25",
"@ai-sdk/openai-compatible": "^2.0.27", "@ai-sdk/openai-compatible": "^2.0.27",
"@aigne/core": "^1.72.0",
"@aigne/openai": "^0.16.16",
"@langchain/core": "^1.1.15",
"@langchain/openai": "^1.2.1",
"@rmp135/sql-ts": "^2.2.0", "@rmp135/sql-ts": "^2.2.0",
"ai": "^6.0.67", "ai": "^6.0.67",
"axios": "^1.13.2", "axios": "^1.13.2",

View File

@ -1,36 +0,0 @@
import { ChatOpenAI, ChatOpenAIFields } from "@langchain/openai";
export const openAI = (config: ChatOpenAIFields = {}) => {
return new ChatOpenAI({
modelName: "gpt-4.1",
temperature: 1,
configuration: {
apiKey: process.env.AI_OPENAI_KEY,
baseURL: process.env.AI_OPENAI_URL,
},
...config,
});
};
export const doubao = (config: ChatOpenAIFields = {}) => {
return new ChatOpenAI({
model: "doubao-seed-1-6-flash-250828",
temperature: 1,
configuration: {
apiKey: process.env.AI_TIKTOK_KEY,
baseURL: process.env.AI_TIKTOK_URL,
},
...config,
});
};
export const deepseek = (config: ChatOpenAIFields = {}) =>
new ChatOpenAI({
model: "DeepSeek-V3.2",
temperature: 1,
configuration: {
apiKey: process.env.AI_DEEPSEEK_KEY,
baseURL: process.env.AI_DEEPSEEK_URL,
},
...config,
});

View File

@ -1,3 +1,4 @@
import "./logger";
import "./err"; import "./err";
import "./env"; import "./env";
import express, { Request, Response, NextFunction } from "express"; import express, { Request, Response, NextFunction } from "express";
@ -32,6 +33,7 @@ export default async function startServe() {
} else { } else {
rootDir = path.join(process.cwd(), "uploads"); rootDir = path.join(process.cwd(), "uploads");
} }
// 确保 uploads 目录存在 // 确保 uploads 目录存在
if (!fs.existsSync(rootDir)) { if (!fs.existsSync(rootDir)) {
fs.mkdirSync(rootDir, { recursive: true }); fs.mkdirSync(rootDir, { recursive: true });

View File

@ -28,4 +28,4 @@ function loadDotenvESM(envPath = ".env.local") {
console.log(`[环境变量]: ${finalPath}`); console.log(`[环境变量]: ${finalPath}`);
} }
if (process.env.NODE_ENV == "dev") loadDotenvESM(".env.local"); if (typeof process.versions?.electron == "undefined") loadDotenvESM(".env.local");

View File

@ -227,6 +227,16 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
table.unique(["id"]); table.unique(["id"]);
}, },
}, },
{
name: "t_aiModelMap",
builder: (table) => {
table.integer("id").notNullable();
table.integer("promptsId"); // 提示词表ID
table.integer("configId"); // 模型列表id
table.primary(["id"]);
table.unique(["id"]);
},
},
{ {
name: "t_prompts", name: "t_prompts",
builder: (table) => { builder: (table) => {

147
src/logger.ts Normal file
View File

@ -0,0 +1,147 @@
import * as fs from "fs";
import * as path from "path";
type LogLevel = "log" | "info" | "warn" | "error" | "debug";
type ConsoleMethod = (...args: unknown[]) => void;
const LOG_DIR = "./logs";
const LOG_FILE = path.join(LOG_DIR, "app.log");
const MAX_SIZE = 10 * 1024 * 1024;
const LEVELS: LogLevel[] = ["log", "info", "warn", "error", "debug"];
class Logger {
private stream: fs.WriteStream | null = null;
private originalConsole: Partial<Record<LogLevel, ConsoleMethod>> = {};
private originalStdoutWrite: typeof process.stdout.write | null = null;
private originalStderrWrite: typeof process.stderr.write | null = null;
private isHijacked = false;
init(): this {
if (!fs.existsSync(LOG_DIR)) fs.mkdirSync(LOG_DIR, { recursive: true });
this.stream = fs.createWriteStream(LOG_FILE, { flags: "a" });
this.hijack();
return this;
}
private formatTime(): string {
const d = new Date();
const p = (n: number, l = 2) => String(n).padStart(l, "0");
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(
d.getMilliseconds(),
3,
)}`;
}
private stringify(arg: unknown): string {
if (arg == null) return String(arg);
if (arg instanceof Error) return `${arg.message}\n${arg.stack || ""}`;
if (typeof arg === "object") {
try {
return JSON.stringify(arg);
} catch {
return String(arg);
}
}
return String(arg);
}
private writing = false;
private write(level: LogLevel, args: unknown[]): void {
const line = `[${this.formatTime()}] [${level.toUpperCase()}] ${args.map((a) => this.stringify(a)).join(" ")}\n`;
if (this.stream && !this.stream.destroyed) this.stream.write(line);
this.checkRotate();
}
private writeRaw(chunk: any): void {
if (this.writing) return;
this.writing = true;
try {
let str = typeof chunk === "string" ? chunk : chunk?.toString?.("utf-8") ?? "";
str = str.replace(/\x1B\[\d*m/g, ""); // 去除 ANSI 颜色码
if (str.trim() && this.stream && !this.stream.destroyed) this.stream.write(str.endsWith("\n") ? str : str + "\n");
} finally {
this.writing = false;
}
}
private checkRotate(): void {
try {
if (!fs.existsSync(LOG_FILE) || fs.statSync(LOG_FILE).size < MAX_SIZE) return;
this.stream?.end();
// 单文件轮转:保留后半部分日志
const content = fs.readFileSync(LOG_FILE, "utf-8");
const half = content.slice(content.length >>> 1);
const firstNewline = half.indexOf("\n");
fs.writeFileSync(LOG_FILE, firstNewline >= 0 ? half.slice(firstNewline + 1) : half);
this.stream = fs.createWriteStream(LOG_FILE, { flags: "a" });
} catch {}
}
private hijack(): void {
if (this.isHijacked) return;
// 劫持 console 方法
for (const level of LEVELS) {
const original = console[level];
if (typeof original !== "function") continue;
this.originalConsole[level] = original.bind(console);
(console as any)[level] = (...args: unknown[]) => {
this.writing = true;
this.write(level, args);
this.originalConsole[level]!(...args);
this.writing = false;
};
}
// 劫持 stdout/stderr捕获 morgan 等直接写 stdout 的输出)
this.originalStdoutWrite = process.stdout.write.bind(process.stdout);
this.originalStderrWrite = process.stderr.write.bind(process.stderr);
process.stdout.write = ((chunk: any, ...rest: any[]) => {
this.writeRaw(chunk);
return this.originalStdoutWrite!(chunk, ...rest);
}) as typeof process.stdout.write;
process.stderr.write = ((chunk: any, ...rest: any[]) => {
this.writeRaw(chunk);
return this.originalStderrWrite!(chunk, ...rest);
}) as typeof process.stderr.write;
this.isHijacked = true;
}
/** 导出日志内容 */
exportLogs(): string {
if (!fs.existsSync(LOG_FILE)) return "";
return fs.readFileSync(LOG_FILE, "utf-8");
}
/** 清空日志 */
clear(): void {
this.stream?.end();
if (fs.existsSync(LOG_FILE)) fs.unlinkSync(LOG_FILE);
this.stream = fs.createWriteStream(LOG_FILE, { flags: "a" });
}
/** 关闭日志 */
close(): void {
if (this.isHijacked) {
for (const level of LEVELS) {
const original = this.originalConsole[level];
if (original) (console as any)[level] = original;
}
this.originalConsole = {};
if (this.originalStdoutWrite) process.stdout.write = this.originalStdoutWrite;
if (this.originalStderrWrite) process.stderr.write = this.originalStderrWrite;
this.originalStdoutWrite = null;
this.originalStderrWrite = null;
this.isHijacked = false;
}
this.stream?.end();
this.stream = null;
}
}
const logger = new Logger().init();
export default logger;

View File

@ -1,4 +1,4 @@
// @routes-hash 4c67f0d89475e1a882416d9f6ab1687d // @routes-hash e51790d6b94bfa5992116635a72e547b
import { Express } from "express"; import { Express } from "express";
import route1 from "./routes/assets/addAssets"; import route1 from "./routes/assets/addAssets";
@ -44,33 +44,34 @@ import route40 from "./routes/prompt/updatePrompt";
import route41 from "./routes/script/generateScriptApi"; import route41 from "./routes/script/generateScriptApi";
import route42 from "./routes/script/generateScriptSave"; import route42 from "./routes/script/generateScriptSave";
import route43 from "./routes/script/geScriptApi"; import route43 from "./routes/script/geScriptApi";
import route44 from "./routes/setting/getSetting"; import route44 from "./routes/setting/getLog";
import route45 from "./routes/setting/updateSetting"; import route45 from "./routes/setting/getSetting";
import route46 from "./routes/storyboard/batchSuperScoreImage"; import route46 from "./routes/setting/updateSetting";
import route47 from "./routes/storyboard/chatStoryboard"; import route47 from "./routes/storyboard/batchSuperScoreImage";
import route48 from "./routes/storyboard/generateShotImage"; import route48 from "./routes/storyboard/chatStoryboard";
import route49 from "./routes/storyboard/generateStoryboardApi"; import route49 from "./routes/storyboard/generateShotImage";
import route50 from "./routes/storyboard/generateVideoPrompt"; import route50 from "./routes/storyboard/generateStoryboardApi";
import route51 from "./routes/storyboard/getStoryboard"; import route51 from "./routes/storyboard/generateVideoPrompt";
import route52 from "./routes/storyboard/keepStoryboard"; import route52 from "./routes/storyboard/getStoryboard";
import route53 from "./routes/storyboard/saveStoryboard"; import route53 from "./routes/storyboard/keepStoryboard";
import route54 from "./routes/storyboard/uploadImage"; import route54 from "./routes/storyboard/saveStoryboard";
import route55 from "./routes/task/getTaskApi"; import route55 from "./routes/storyboard/uploadImage";
import route56 from "./routes/task/taskDetails"; import route56 from "./routes/task/getTaskApi";
import route57 from "./routes/user/getUser"; import route57 from "./routes/task/taskDetails";
import route58 from "./routes/video/addVideo"; import route58 from "./routes/user/getUser";
import route59 from "./routes/video/addVideoConfig"; import route59 from "./routes/video/addVideo";
import route60 from "./routes/video/deleteVideoConfig"; import route60 from "./routes/video/addVideoConfig";
import route61 from "./routes/video/generatePrompt"; import route61 from "./routes/video/deleteVideoConfig";
import route62 from "./routes/video/generateVideo"; import route62 from "./routes/video/generatePrompt";
import route63 from "./routes/video/getManufacturer"; import route63 from "./routes/video/generateVideo";
import route64 from "./routes/video/getVideo"; import route64 from "./routes/video/getManufacturer";
import route65 from "./routes/video/getVideoConfigs"; import route65 from "./routes/video/getVideo";
import route66 from "./routes/video/getVideoModel"; import route66 from "./routes/video/getVideoConfigs";
import route67 from "./routes/video/getVideoStoryboards"; import route67 from "./routes/video/getVideoModel";
import route68 from "./routes/video/reviseVideoStoryboards"; import route68 from "./routes/video/getVideoStoryboards";
import route69 from "./routes/video/saveVideo"; import route69 from "./routes/video/reviseVideoStoryboards";
import route70 from "./routes/video/upDateVideoConfig"; import route70 from "./routes/video/saveVideo";
import route71 from "./routes/video/upDateVideoConfig";
export default async (app: Express) => { export default async (app: Express) => {
app.use("/assets/addAssets", route1); app.use("/assets/addAssets", route1);
@ -116,31 +117,32 @@ export default async (app: Express) => {
app.use("/script/generateScriptApi", route41); app.use("/script/generateScriptApi", route41);
app.use("/script/generateScriptSave", route42); app.use("/script/generateScriptSave", route42);
app.use("/script/geScriptApi", route43); app.use("/script/geScriptApi", route43);
app.use("/setting/getSetting", route44); app.use("/setting/getLog", route44);
app.use("/setting/updateSetting", route45); app.use("/setting/getSetting", route45);
app.use("/storyboard/batchSuperScoreImage", route46); app.use("/setting/updateSetting", route46);
app.use("/storyboard/chatStoryboard", route47); app.use("/storyboard/batchSuperScoreImage", route47);
app.use("/storyboard/generateShotImage", route48); app.use("/storyboard/chatStoryboard", route48);
app.use("/storyboard/generateStoryboardApi", route49); app.use("/storyboard/generateShotImage", route49);
app.use("/storyboard/generateVideoPrompt", route50); app.use("/storyboard/generateStoryboardApi", route50);
app.use("/storyboard/getStoryboard", route51); app.use("/storyboard/generateVideoPrompt", route51);
app.use("/storyboard/keepStoryboard", route52); app.use("/storyboard/getStoryboard", route52);
app.use("/storyboard/saveStoryboard", route53); app.use("/storyboard/keepStoryboard", route53);
app.use("/storyboard/uploadImage", route54); app.use("/storyboard/saveStoryboard", route54);
app.use("/task/getTaskApi", route55); app.use("/storyboard/uploadImage", route55);
app.use("/task/taskDetails", route56); app.use("/task/getTaskApi", route56);
app.use("/user/getUser", route57); app.use("/task/taskDetails", route57);
app.use("/video/addVideo", route58); app.use("/user/getUser", route58);
app.use("/video/addVideoConfig", route59); app.use("/video/addVideo", route59);
app.use("/video/deleteVideoConfig", route60); app.use("/video/addVideoConfig", route60);
app.use("/video/generatePrompt", route61); app.use("/video/deleteVideoConfig", route61);
app.use("/video/generateVideo", route62); app.use("/video/generatePrompt", route62);
app.use("/video/getManufacturer", route63); app.use("/video/generateVideo", route63);
app.use("/video/getVideo", route64); app.use("/video/getManufacturer", route64);
app.use("/video/getVideoConfigs", route65); app.use("/video/getVideo", route65);
app.use("/video/getVideoModel", route66); app.use("/video/getVideoConfigs", route66);
app.use("/video/getVideoStoryboards", route67); app.use("/video/getVideoModel", route67);
app.use("/video/reviseVideoStoryboards", route68); app.use("/video/getVideoStoryboards", route68);
app.use("/video/saveVideo", route69); app.use("/video/reviseVideoStoryboards", route69);
app.use("/video/upDateVideoConfig", route70); app.use("/video/saveVideo", route70);
app.use("/video/upDateVideoConfig", route71);
} }

View File

@ -3,12 +3,9 @@ import { success, error } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware"; import { validateFields } from "@/middleware/middleware";
import u from "@/utils"; import u from "@/utils";
import { z } from "zod"; import { z } from "zod";
import { generateText, Output, tool, stepCountIs } from "ai"; import { tool } from "ai";
const router = express.Router(); const router = express.Router();
import { createOpenAI } from "@ai-sdk/openai";
import { createDeepSeek } from "@ai-sdk/deepseek";
// 检查语言模型 // 检查语言模型
export default router.post( export default router.post(
"/", "/",
@ -48,7 +45,6 @@ export default router.post(
baseURL, baseURL,
}, },
); );
console.log("%c Line:52 🍐 reply", "background:#ffdd4d", reply);
res.status(200).send(success(reply)); res.status(200).send(success(reply));
} catch (err) { } catch (err) {
const msg = u.error(err).message; const msg = u.error(err).message;

View File

@ -1,9 +1,6 @@
import express from "express"; import express from "express";
import { success, error } from "@/lib/responseFormat"; import { success, error } from "@/lib/responseFormat";
import u from "@/utils"; import u from "@/utils";
import { createAgent } from "langchain";
import { openAI } from "@/agents/models";
import { OpenAIChatModel, type OpenAIChatModelOptions } from "@aigne/openai";
import { validateFields } from "@/middleware/middleware"; import { validateFields } from "@/middleware/middleware";
import { z } from "zod"; import { z } from "zod";
const router = express.Router(); const router = express.Router();

View File

@ -0,0 +1,33 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
export default router.post(
"/",
validateFields({
type: z.string(),
name: z.string(),
model: z.string(),
baseUrl: z.string(),
apiKey: z.string(),
manufacturer: z.string(),
}),
async (req, res) => {
const { type, name, model, baseUrl, apiKey, manufacturer } = req.body;
await u.db("t_config").insert({
type,
name,
model,
baseUrl,
apiKey,
manufacturer,
createTime: Date.now(),
userId: 1,
});
res.status(200).send(success("新增成功"));
},
);

View File

@ -0,0 +1,30 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
export default router.post(
"/",
validateFields({
id: z.number().optional(),
promptsId: z.number(),
configId: z.number(),
}),
async (req, res) => {
const { id, promptsId, configId } = req.body;
if (id) {
await u.db("t_aiModelMap").where("id", id).update({
promptsId,
configId,
});
} else {
await u.db("t_aiModelMap").insert({
promptsId,
configId,
});
}
res.status(200).send(success("配置成功"));
},
);

View File

@ -0,0 +1,19 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
export default router.post(
"/",
validateFields({
id: z.number(),
}),
async (req, res) => {
const { id } = req.body;
await u.db("t_config").where("id", id).delete();
await u.db("t_aiModelMap").where("configId", id).delete();
res.status(200).send(success("删除成功"));
},
);

View File

@ -0,0 +1,13 @@
import express from "express";
import u from "@/utils";
import { success } from "@/lib/responseFormat";
const router = express.Router();
export default router.post("/", async (req, res) => {
const configData = await u
.db("t_prompts")
.leftJoin("t_aiModelMap", "t_prompts.id", "t_aiModelMap.promptsId")
.leftJoin("t_config", "t_config.id", "t_aiModelMap.configId")
.select("t_prompts.id as promptsId", "t_prompts.code", "t_prompts.name", "t_config.model", "t_aiModelMap.id");
res.status(200).send(success(configData));
});

View File

@ -0,0 +1,17 @@
import logger from "@/logger";
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success, error } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
export default router.post("/", async (req, res) => {
const { id } = (req as any).user;
if (id !== 1) return res.status(400).send(error("无权限查看仅管理员USERID=1可见"));
const logs = logger.exportLogs();
res.status(200).send(success(logs));
});

View File

@ -1,29 +1,11 @@
import express from "express"; import express from "express";
import u from "@/utils"; import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat"; import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router(); const router = express.Router();
export default router.post( export default router.post("/", async (req, res) => {
"/", const userId = 1;
validateFields({ const configData = await u.db("t_config").where("userId", userId).select("*");
userId: z.number(),
}),
async (req, res) => {
const { userId } = req.body;
const settingData = await u.db("t_setting").select("*"); res.status(200).send(success(configData));
});
const configData = await u.db("t_config").where("userId", userId).select("*");
const parsedData = settingData.map((item) => ({
...item,
imageModel: configData.find((i) => i.type == "image"),
languageModel: configData.find((i) => i.type == "text"),
videoModel: configData.filter((i) => i.type == "video").filter(Boolean),
}));
res.status(200).send(success(parsedData));
},
);

View File

@ -1,79 +0,0 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
// 修改全局配置
export default router.post(
"/",
validateFields({
userId: z.number(),
imageModel: z.object().optional(),
videoModel: z.array(z.object()).optional(),
languageModel: z.object().optional(),
name: z.string().optional(),
password: z.string().optional(),
}),
async (req, res) => {
const { userId, imageModel, videoModel, languageModel, name, password } = req.body;
await u
.db("t_setting")
.where("userId", userId)
.update({
imageModel: JSON.stringify(imageModel),
languageModel: JSON.stringify(languageModel),
});
if (videoModel) {
await u.db("t_config").where("type", "video").delete();
for (const item of videoModel) {
await u.db("t_config").insert({
type: "video",
name: item.model,
model: item.model,
apiKey: item.apiKey,
baseUrl: item.baseUrl,
createTime: Date.now(),
userId,
manufacturer: item.manufacturer,
});
}
}
if (languageModel) {
await u.db("t_config").where("type", "text").delete();
await u.db("t_config").insert({
type: "text",
name: languageModel.model,
model: languageModel.model,
apiKey: languageModel.apiKey,
baseUrl: languageModel.baseUrl,
createTime: Date.now(),
userId,
manufacturer: languageModel.manufacturer,
});
}
if (imageModel) {
await u.db("t_config").where("type", "image").delete();
await u.db("t_config").insert({
type: "image",
name: imageModel.model,
model: imageModel.model,
apiKey: imageModel.apiKey,
baseUrl: imageModel.baseUrl,
createTime: Date.now(),
userId,
manufacturer: imageModel.manufacturer,
});
}
await u.db("t_user").where("id", userId).update({
name,
password,
});
res.status(200).send(success({ message: "修改全局配置成功" }));
},
);

View File

@ -0,0 +1,32 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
export default router.post(
"/",
validateFields({
id: z.number(),
type: z.string(),
name: z.string(),
model: z.string(),
baseUrl: z.string(),
apiKey: z.string(),
manufacturer: z.string(),
}),
async (req, res) => {
const { id, type, name, model, baseUrl, apiKey, manufacturer } = req.body;
await u.db("t_config").where("id", id).update({
type,
name,
model,
baseUrl,
apiKey,
manufacturer,
});
res.status(200).send(success("编辑成功"));
},
);

View File

@ -1,6 +1,11 @@
// @db-hash b6b4d8cdc25a2f4d60f1c239cd7e7060 // @db-hash e1460b0ace03f6aaed458653a32b6ffb
//该文件由脚本自动生成,请勿手动修改 //该文件由脚本自动生成,请勿手动修改
export interface t_aiModelMap {
'configId'?: number | null;
'id'?: number;
'promptsId'?: number | null;
}
export interface t_assets { export interface t_assets {
'duration'?: string | null; 'duration'?: string | null;
'episode'?: string | null; 'episode'?: string | null;
@ -30,7 +35,6 @@ export interface t_config {
'baseUrl'?: string | null; 'baseUrl'?: string | null;
'createTime'?: number | null; 'createTime'?: number | null;
'id'?: number; 'id'?: number;
'index'?: number | null;
'manufacturer'?: string | null; 'manufacturer'?: string | null;
'model'?: string | null; 'model'?: string | null;
'name'?: string | null; 'name'?: string | null;
@ -148,6 +152,7 @@ export interface t_videoConfig {
} }
export interface DB { export interface DB {
"t_aiModelMap": t_aiModelMap;
"t_assets": t_assets; "t_assets": t_assets;
"t_chatHistory": t_chatHistory; "t_chatHistory": t_chatHistory;
"t_config": t_config; "t_config": t_config;

View File

@ -1,9 +1,5 @@
import axios from "axios"; import axios from "axios";
import u from "@/utils";
import FormData from "form-data";
import axiosRetry from "axios-retry"; import axiosRetry from "axios-retry";
import { OpenAIChatModel, type OpenAIChatModelOptions } from "@aigne/openai";
import sharp from "sharp";
import { pollTask } from "@/utils/ai/utils"; import { pollTask } from "@/utils/ai/utils";
axiosRetry(axios, { retries: 3, retryDelay: () => 200 }); axiosRetry(axios, { retries: 3, retryDelay: () => 200 });

View File

@ -1,8 +1,6 @@
import axios from "axios"; import axios from "axios";
import u from "@/utils";
import FormData from "form-data"; import FormData from "form-data";
import axiosRetry from "axios-retry"; import axiosRetry from "axios-retry";
import { OpenAIChatModel, type OpenAIChatModelOptions } from "@aigne/openai";
import sharp from "sharp"; import sharp from "sharp";
import { pollTask } from "@/utils/ai/utils"; import { pollTask } from "@/utils/ai/utils";

View File

@ -1,5 +1,7 @@
import u from "@/utils"; import u from "@/utils";
import { generateText, streamText, Output, stepCountIs, ModelMessage, LanguageModel, Tool, GenerateTextResult } from "ai"; import { generateText, streamText, Output, stepCountIs, ModelMessage, LanguageModel, Tool, GenerateTextResult } from "ai";
import { wrapLanguageModel } from "ai";
import { devToolsMiddleware } from "@ai-sdk/devtools";
import { parse } from "best-effort-json-parser"; import { parse } from "best-effort-json-parser";
import modelList from "./modelList"; import modelList from "./modelList";
import { z } from "zod"; import { z } from "zod";
@ -43,11 +45,17 @@ const buildOptions = async (input: AIInput<any>, config: AIConfig) => {
}, },
}; };
const output = input.output ? (outputBuilders[owned.responseFormat]?.(input.output) ?? null) : null; const output = input.output ? outputBuilders[owned.responseFormat]?.(input.output) ?? null : null;
return { return {
config: { config: {
model: modelInstance(model!) as LanguageModel, model:
process.env.NODE_ENV === "dev"
? wrapLanguageModel({
model: modelInstance(model!) as any,
middleware: devToolsMiddleware(),
})
: (modelInstance(model!) as LanguageModel),
...(input.system && { system: input.system }), ...(input.system && { system: input.system }),
...(input.prompt ? { prompt: input.prompt } : { messages: input.messages! }), ...(input.prompt ? { prompt: input.prompt } : { messages: input.messages! }),
...(input.tools && owned.tool && { tools: input.tools }), ...(input.tools && owned.tool && { tools: input.tools }),

1591
yarn.lock

File diff suppressed because it is too large Load Diff