Merge branch 'develop' of https://github.com/HBAI-Ltd/Toonflow-app into develop
This commit is contained in:
commit
33db2c024c
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
.devtools
|
||||||
# dependencies (bun install)
|
# dependencies (bun install)
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
|
|||||||
21
package.json
21
package.json
@ -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",
|
||||||
|
|||||||
@ -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,
|
|
||||||
});
|
|
||||||
@ -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 });
|
||||||
|
|||||||
@ -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");
|
||||||
|
|||||||
@ -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
147
src/logger.ts
Normal 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;
|
||||||
112
src/router.ts
112
src/router.ts
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
33
src/routes/setting/addModel.ts
Normal file
33
src/routes/setting/addModel.ts
Normal 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("新增成功"));
|
||||||
|
},
|
||||||
|
);
|
||||||
30
src/routes/setting/configurationModel.ts
Normal file
30
src/routes/setting/configurationModel.ts
Normal 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("配置成功"));
|
||||||
|
},
|
||||||
|
);
|
||||||
19
src/routes/setting/delModel.ts
Normal file
19
src/routes/setting/delModel.ts
Normal 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("删除成功"));
|
||||||
|
},
|
||||||
|
);
|
||||||
13
src/routes/setting/getAiModelMap.ts
Normal file
13
src/routes/setting/getAiModelMap.ts
Normal 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));
|
||||||
|
});
|
||||||
17
src/routes/setting/getLog.ts
Normal file
17
src/routes/setting/getLog.ts
Normal 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));
|
||||||
|
});
|
||||||
@ -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));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|||||||
@ -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: "修改全局配置成功" }));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
32
src/routes/setting/updeteModel.ts
Normal file
32
src/routes/setting/updeteModel.ts
Normal 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("编辑成功"));
|
||||||
|
},
|
||||||
|
);
|
||||||
9
src/types/database.d.ts
vendored
9
src/types/database.d.ts
vendored
@ -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;
|
||||||
|
|||||||
@ -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 });
|
||||||
|
|||||||
@ -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";
|
||||||
|
|
||||||
|
|||||||
@ -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 }),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user