Merge branch 'develop'
This commit is contained in:
commit
d9198e2148
15
.github/workflows/release.yml
vendored
15
.github/workflows/release.yml
vendored
@ -17,8 +17,17 @@ env:
|
||||
jobs:
|
||||
# ==================== Windows 构建 ====================
|
||||
build-Windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: x64
|
||||
name: x64
|
||||
- arch: arm64
|
||||
name: ARM64
|
||||
|
||||
runs-on: windows-latest
|
||||
name: 构建 Windows
|
||||
name: 构建 Windows (${{ matrix.name }})
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
@ -33,14 +42,14 @@ jobs:
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: 打包 Windows 安装程序
|
||||
run: yarn dist:win
|
||||
run: yarn dist:win --${{ matrix.arch }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: 上传构建产物
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows
|
||||
name: windows-${{ matrix.arch }}
|
||||
path: dist/*.exe
|
||||
retention-days: 7
|
||||
|
||||
|
||||
@ -114,10 +114,10 @@ Toonflow 是面向短剧生产的 AI 工作台,围绕“策划 → 编剧 →
|
||||
|
||||
## 📺 视频教程
|
||||
|
||||
https://www.bilibili.com/video/BV1na6wB6Ea2
|
||||
[](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
https://www.bilibili.com/video/BV1oXD7BqEqJ
|
||||
[](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
|
||||
**Toonflow 8 分钟快速上手 AI 视频**
|
||||
**Toonflow 12 分钟快速上手 AI 视频**
|
||||
👉 [点击观看](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
|
||||
📱 手机微信扫码观看
|
||||
|
||||
2
data/vendor/toonflow.ts
vendored
2
data/vendor/toonflow.ts
vendored
@ -327,7 +327,7 @@ const videoRequest = async (config: VideoConfig, model: VideoModel): Promise<str
|
||||
const lowerName = model.modelName.toLowerCase();
|
||||
|
||||
// 当前激活的单一 VideoMode(取第一个非数组模式,或数组模式)
|
||||
const activeMode = config.mode[0];
|
||||
const activeMode = config.mode;
|
||||
const imageRefs = (config.referenceList ?? []).filter((r) => r.type === "image").map((r) => r.base64);
|
||||
const videoRefs = (config.referenceList ?? []).filter((r) => r.type === "video").map((r) => r.base64);
|
||||
const audioRefs = (config.referenceList ?? []).filter((r) => r.type === "audio").map((r) => r.base64);
|
||||
|
||||
23
data/vendor/volcengine.ts
vendored
23
data/vendor/volcengine.ts
vendored
@ -133,11 +133,10 @@ declare const exports: {
|
||||
|
||||
const vendor: VendorConfig = {
|
||||
id: "volcengine",
|
||||
version: "2.1",
|
||||
version: "2.3",
|
||||
author: "leeqi",
|
||||
name: "火山引擎(豆包)",
|
||||
description:
|
||||
"火山引擎豆包大模型,支持文本、图片生成、视频生成等能力。\n\n需要在[火山引擎控制台](https://console.volcengine.com/ark)获取API密钥。",
|
||||
description: "火山引擎豆包大模型,支持文本、图片生成、视频生成等能力。\n\n需要在[火山引擎控制台](https://console.volcengine.com/ark)获取API密钥。",
|
||||
icon: "",
|
||||
inputs: [
|
||||
{ key: "apiKey", label: "API密钥", type: "password", required: true, placeholder: "火山引擎API Key" },
|
||||
@ -301,10 +300,10 @@ const textRequest = (model: TextModel, think: boolean, thinkLevel: 0 | 1 | 2 | 3
|
||||
3: "high",
|
||||
};
|
||||
|
||||
return createOpenAI({
|
||||
return createOpenAICompatible({
|
||||
name: "volcengine",
|
||||
baseURL: getBaseUrl(),
|
||||
apiKey,
|
||||
compatibility: "compatible",
|
||||
fetch: async (url: string, options?: RequestInit) => {
|
||||
const rawBody = JSON.parse((options?.body as string) ?? "{}");
|
||||
const modifiedBody = {
|
||||
@ -319,7 +318,7 @@ const textRequest = (model: TextModel, think: boolean, thinkLevel: 0 | 1 | 2 | 3
|
||||
body: JSON.stringify(modifiedBody),
|
||||
});
|
||||
},
|
||||
}).chat(model.modelName);
|
||||
}).chatModel(model.modelName);
|
||||
};
|
||||
|
||||
const imageRequest = async (config: ImageConfig, model: ImageModel): Promise<string> => {
|
||||
@ -455,10 +454,8 @@ const videoRequest = async (config: VideoConfig, model: VideoModel): Promise<str
|
||||
content.push({ type: "text", text: config.prompt });
|
||||
}
|
||||
|
||||
const activeMode = config.mode && config.mode.length > 0 ? config.mode[0] : "text";
|
||||
|
||||
if (typeof activeMode === "string") {
|
||||
switch (activeMode) {
|
||||
if (typeof config.mode === "string") {
|
||||
switch (config.mode) {
|
||||
case "singleImage": {
|
||||
const firstImage = config.referenceList?.find((r) => r.type === "image");
|
||||
if (firstImage) {
|
||||
@ -526,13 +523,13 @@ const videoRequest = async (config: VideoConfig, model: VideoModel): Promise<str
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (Array.isArray(activeMode)) {
|
||||
} else if (Array.isArray(config.mode)) {
|
||||
// 多模态参考模式:按类型分别提取并添加
|
||||
const imageRefs = config.referenceList?.filter((r) => r.type === "image") ?? [];
|
||||
const videoRefs = config.referenceList?.filter((r) => r.type === "video") ?? [];
|
||||
const audioRefs = config.referenceList?.filter((r) => r.type === "audio") ?? [];
|
||||
|
||||
for (const refDef of activeMode) {
|
||||
for (const refDef of config.mode) {
|
||||
if (typeof refDef === "string") {
|
||||
if (refDef.startsWith("imageReference:")) {
|
||||
const maxCount = parseInt(refDef.split(":")[1], 10);
|
||||
@ -618,7 +615,7 @@ const videoRequest = async (config: VideoConfig, model: VideoModel): Promise<str
|
||||
}
|
||||
},
|
||||
10000,
|
||||
600000,
|
||||
600000 * 3,
|
||||
);
|
||||
|
||||
if (result.error) {
|
||||
|
||||
@ -1 +1 @@
|
||||
1.1.3
|
||||
1.1.5
|
||||
2308
data/web/index.html
2308
data/web/index.html
File diff suppressed because one or more lines are too long
@ -107,11 +107,11 @@ With Toonflow, you can complete the entire workflow from text to final video wit
|
||||
|
||||
## 📺 Video Tutorial
|
||||
|
||||
[https://www.bilibili.com/video/BV1na6wB6Ea2](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[https://www.bilibili.com/video/BV1oXD7BqEqJ](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
[](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
|
||||
**Toonflow: 8-Minute AI Video Quick Start**
|
||||
👉 [Click to Watch](https://www.bilibili.com/video/BV1na6wB6Ea2/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
👉 [Click to Watch](https://www.bilibili.com/video/BV1oXD7BqEqJ/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
|
||||
📱 Scan the QR code to watch on mobile
|
||||
|
||||
|
||||
@ -101,11 +101,11 @@ Toonflow は、AI技術を活用して小説を自動的に脚本へ変換し、
|
||||
|
||||
## 📺 動画チュートリアル
|
||||
|
||||
[https://www.bilibili.com/video/BV1na6wB6Ea2](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[https://www.bilibili.com/video/BV1oXD7BqEqJ](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
[](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
|
||||
**Toonflow 8分でわかるクイックスタート AI動画作成**
|
||||
👉 [クリックして視聴](https://www.bilibili.com/video/BV1na6wB6Ea2/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
**Toonflow 12分でわかるクイックスタート AI動画作成**
|
||||
👉 [クリックして視聴](https://www.bilibili.com/video/BV1oXD7BqEqJ/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
|
||||
📱 QRコードをスキャンして視聴
|
||||
|
||||
|
||||
@ -105,11 +105,11 @@ Toonflow — это мощный ИИ-инструмент для создани
|
||||
|
||||
## 📺 Видеоуроки
|
||||
|
||||
[https://www.bilibili.com/video/BV1na6wB6Ea2](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[https://www.bilibili.com/video/BV1oXD7BqEqJ](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
[](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
|
||||
**Toonflow: Быстрый старт в AI-видео за 8 минут**
|
||||
👉 [Нажмите для просмотра](https://www.bilibili.com/video/BV1na6wB6Ea2/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
**Toonflow: Быстрый старт в AI-видео за 12 минут**
|
||||
👉 [Нажмите для просмотра](https://www.bilibili.com/video/BV1oXD7BqEqJ/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
|
||||
📱 Отсканируйте QR-код для просмотра видео на телефоне
|
||||
|
||||
|
||||
@ -102,11 +102,11 @@ Toonflow เป็นเครื่องมือ AI สำหรับสร
|
||||
|
||||
## 📺 วิดีโอสอนการใช้งาน
|
||||
|
||||
[https://www.bilibili.com/video/BV1na6wB6Ea2](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[https://www.bilibili.com/video/BV1oXD7BqEqJ](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
[](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
|
||||
**เริ่มต้นสร้างวิดีโอ AI กับ Toonflow ใน 8 นาที**
|
||||
👉 [คลิกเพื่อรับชม](https://www.bilibili.com/video/BV1na6wB6Ea2/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
**เริ่มต้นสร้างวิดีโอ AI กับ Toonflow ใน 12 นาที**
|
||||
👉 [คลิกเพื่อรับชม](https://www.bilibili.com/video/BV1oXD7BqEqJ/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
|
||||
📱 **สแกน QR Code เพื่อรับชมวิดีโอบนมือถือ**
|
||||
|
||||
|
||||
@ -97,11 +97,11 @@ Toonflow là công cụ AI chuyên tạo phim ngắn và truyện tranh, có kh
|
||||
|
||||
## 📺 Hướng dẫn bằng Video
|
||||
|
||||
[https://www.bilibili.com/video/BV1na6wB6Ea2](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[https://www.bilibili.com/video/BV1oXD7BqEqJ](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
[](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
|
||||
**Toonflow - 8 phút làm quen nhanh với Video AI**
|
||||
👉 [Nhấn để xem](https://www.bilibili.com/video/BV1na6wB6Ea2/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
**Toonflow - 12 phút làm quen nhanh với Video AI**
|
||||
👉 [Nhấn để xem](https://www.bilibili.com/video/BV1oXD7BqEqJ/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
|
||||
📱 **Quét mã QR để xem video trên điện thoại**
|
||||
<img src="./videoQR.png" alt="Quét mã QR để xem video" width="150"/>
|
||||
|
||||
@ -104,11 +104,11 @@ Toonflow 是一款 AI 短劇與漫畫創作工具,能夠利用 AI 技術將小
|
||||
|
||||
## 📺 影片教學
|
||||
|
||||
[https://www.bilibili.com/video/BV1na6wB6Ea2](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[](https://www.bilibili.com/video/BV1na6wB6Ea2)
|
||||
[https://www.bilibili.com/video/BV1oXD7BqEqJ](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
[](https://www.bilibili.com/video/BV1oXD7BqEqJ)
|
||||
|
||||
**Toonflow 8 分鐘快速上手 AI 影片**
|
||||
👉 [點擊觀看](https://www.bilibili.com/video/BV1na6wB6Ea2/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
**Toonflow 12 分鐘快速上手 AI 影片**
|
||||
👉 [點擊觀看](https://www.bilibili.com/video/BV1oXD7BqEqJ/?share_source=copy_web&vd_source=5b718c25439a901a34c7bc0c1d35b38e)
|
||||
|
||||
📱 使用手機掃描 QR Code 觀看
|
||||
|
||||
|
||||
BIN
docs/videoCover.jpg
Normal file
BIN
docs/videoCover.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 101 KiB |
@ -37,9 +37,6 @@ extraResources:
|
||||
win:
|
||||
target:
|
||||
- target: nsis
|
||||
arch:
|
||||
- x64
|
||||
- arm64
|
||||
icon: ./scripts/logo.ico
|
||||
|
||||
nsis:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "toonflow",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5",
|
||||
"description": "Toonflow 是一款 AI 短剧漫剧工具,能够利用 AI 技术将小说自动转化为剧本,并结合 AI 生成的图片和视频,实现高效的短剧创作。",
|
||||
"author": "HBAI-Ltd <ltlctools@outlook.com>",
|
||||
"license": "Apache-2.0",
|
||||
@ -47,7 +47,7 @@
|
||||
"ai": "^6.0.67",
|
||||
"axios": "^1.13.2",
|
||||
"axios-retry": "^4.5.0",
|
||||
"better-sqlite3": "^12.8.0",
|
||||
"better-sqlite3": "^12.9.0",
|
||||
"compressing": "^2.1.0",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^17.2.3",
|
||||
|
||||
@ -17,6 +17,11 @@ export interface AgentContext {
|
||||
abortSignal?: AbortSignal;
|
||||
resTool: ResTool;
|
||||
msg: ReturnType<ResTool["newMessage"]>;
|
||||
messages?: { role: "user" | "assistant" | "system"; content: string }[];
|
||||
thinkConfig: {
|
||||
think: boolean;
|
||||
thinlLevel: 0 | 1 | 2 | 3;
|
||||
};
|
||||
}
|
||||
|
||||
function buildMemPrompt(mem: Awaited<ReturnType<Memory["get"]>>): string {
|
||||
@ -35,7 +40,7 @@ function buildMemPrompt(mem: Awaited<ReturnType<Memory["get"]>>): string {
|
||||
return `## Memory\n以下是你对用户的记忆,可作为参考但不要主动提及:\n${memoryContext}`;
|
||||
}
|
||||
|
||||
export async function decisionAI(ctx: AgentContext) {
|
||||
export async function runDecisionAI(ctx: AgentContext) {
|
||||
const { isolationKey, text, abortSignal } = ctx;
|
||||
const memory = new Memory("productionAgent", isolationKey);
|
||||
await memory.add("user", text);
|
||||
@ -45,17 +50,24 @@ export async function decisionAI(ctx: AgentContext) {
|
||||
|
||||
const projectInfo = await u.db("o_project").where("id", ctx.resTool.data.projectId).first();
|
||||
if (!projectInfo) throw new Error(`项目不存在,ID: ${ctx.resTool.data.projectId}`);
|
||||
const [_, imageModelName] = projectInfo.imageModel!.split(":");
|
||||
const [id, videoModelName] = projectInfo.videoModel!.split(":");
|
||||
const [_, imageModelName] = projectInfo.imageModel!.split(/:(.+)/);
|
||||
const [id, videoModelName] = projectInfo.videoModel!.split(/:(.+)/);
|
||||
const models = await u.vendor.getModelList(id);
|
||||
if (!models.length) throw new Error(`项目使用的模型不存在,ID: ${projectInfo.videoModel}`);
|
||||
const findData = models.find((i: any) => i.modelName == videoModelName);
|
||||
const isRef = findData.mode.every((i: any) => Array.isArray(i));
|
||||
let videoMode = "";
|
||||
try {
|
||||
videoMode = JSON.parse(projectInfo.mode ?? "");
|
||||
} catch (e) {
|
||||
videoMode = projectInfo.mode ?? "";
|
||||
}
|
||||
const isRef = Array.isArray(videoMode) ? true : false;
|
||||
// const findData = models.find((i: any) => i.modelName == videoModelName);
|
||||
// const isRef = findData.mode.every((i: any) => Array.isArray(i));
|
||||
const modelInfo = `项目使用的模型如下:\n图像模型:${imageModelName}\n视频模型:${videoModelName}\n多参:${isRef ? "是" : "否"}`;
|
||||
|
||||
const mem = buildMemPrompt(await memory.get(text));
|
||||
|
||||
const { textStream } = await u.Ai.Text("productionAgent").stream({
|
||||
const { fullStream } = await u.Ai.Text("productionAgent:decisionAgent", ctx.thinkConfig.think, ctx.thinkConfig.thinlLevel).stream({
|
||||
messages: [
|
||||
{ role: "system", content: prompt },
|
||||
{ role: "assistant", content: mem + "\n" + modelInfo },
|
||||
@ -72,13 +84,20 @@ export async function decisionAI(ctx: AgentContext) {
|
||||
},
|
||||
});
|
||||
|
||||
return textStream;
|
||||
let currentMsg = ctx.msg;
|
||||
await consumeFullStream(fullStream, currentMsg, () => {
|
||||
if (ctx.msg === currentMsg) return currentMsg;
|
||||
currentMsg.complete();
|
||||
currentMsg = ctx.msg;
|
||||
return currentMsg;
|
||||
});
|
||||
}
|
||||
|
||||
async function createSubAgent(parentCtx: AgentContext) {
|
||||
const { resTool, abortSignal } = parentCtx;
|
||||
const memory = new Memory("productionAgent", parentCtx.isolationKey);
|
||||
async function runAgent({
|
||||
key,
|
||||
prompt,
|
||||
system,
|
||||
name,
|
||||
@ -86,6 +105,7 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
tools: extraTools,
|
||||
messages,
|
||||
}: {
|
||||
key: `${string}:${string}`;
|
||||
prompt: string;
|
||||
system: string;
|
||||
name: string;
|
||||
@ -95,29 +115,15 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
}) {
|
||||
parentCtx.msg.complete();
|
||||
const subMsg = resTool.newMessage("assistant", name);
|
||||
const text = subMsg.text();
|
||||
let fullResponse = "";
|
||||
|
||||
const { textStream } = await u.Ai.Text("productionAgent").stream({
|
||||
const { fullStream } = await u.Ai.Text(key, parentCtx.thinkConfig.think, parentCtx.thinkConfig.thinlLevel).stream({
|
||||
system,
|
||||
messages: messages ?? [{ role: "user", content: prompt }],
|
||||
abortSignal,
|
||||
tools: { ...extraTools, ...useTools({ resTool, msg: subMsg }) },
|
||||
});
|
||||
|
||||
try {
|
||||
for await (const chunk of textStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
text.append(chunk);
|
||||
fullResponse += chunk;
|
||||
}
|
||||
text.complete();
|
||||
subMsg.complete();
|
||||
} catch (err: any) {
|
||||
text.complete();
|
||||
subMsg.stop();
|
||||
throw err;
|
||||
}
|
||||
const fullResponse = await consumeFullStream(fullStream, subMsg);
|
||||
|
||||
if (fullResponse.trim()) {
|
||||
await memory.add(memoryKey, removeAllXmlTags(fullResponse), {
|
||||
@ -138,8 +144,8 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
if (!projectInfo) throw new Error(`项目不存在,ID: ${resTool.data.projectId}`);
|
||||
const artSkills = await createArtSkills(projectInfo?.artStyle!, projectInfo?.directorManual!);
|
||||
|
||||
const [_, imageModelName] = projectInfo.imageModel!.split(":");
|
||||
const [id, videoModelName] = projectInfo.videoModel!.split(":");
|
||||
const [_, imageModelName] = projectInfo.imageModel!.split(/:(.+)/);
|
||||
const [id, videoModelName] = projectInfo.videoModel!.split(/:(.+)/);
|
||||
const models = await u.vendor.getModelList(id);
|
||||
if (!models.length) throw new Error(`项目使用的模型不存在,ID: ${projectInfo.videoModel}`);
|
||||
const findData = models.find((i: any) => i.modelName == videoModelName);
|
||||
@ -184,6 +190,7 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
const skill = path.join(u.getPath("skills"), "production_execution_derive_assets.md");
|
||||
const systemPrompt = await fs.promises.readFile(skill, "utf-8");
|
||||
return runAgent({
|
||||
key: "productionAgent:deriveAssetsAgent",
|
||||
prompt,
|
||||
system: systemPrompt,
|
||||
name: "执行导演",
|
||||
@ -205,6 +212,7 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
const skill = path.join(u.getPath("skills"), "production_execution_generate_assets.md");
|
||||
const systemPrompt = await fs.promises.readFile(skill, "utf-8");
|
||||
return runAgent({
|
||||
key: "productionAgent:generateAssetsAgent",
|
||||
prompt,
|
||||
system: systemPrompt,
|
||||
name: "执行导演",
|
||||
@ -229,6 +237,7 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
const addPrompt = "\n你必须使用如下XML格式写入工作区:\n```\n<scriptPlan>内容</scriptPlan>\n```";
|
||||
|
||||
return runAgent({
|
||||
key: "productionAgent:directorPlanAgent",
|
||||
prompt,
|
||||
system: systemPrompt + addPrompt,
|
||||
name: "执行导演",
|
||||
@ -250,6 +259,7 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
const skill = path.join(u.getPath("skills"), "production_execution_storyboard_gen.md");
|
||||
const systemPrompt = await fs.promises.readFile(skill, "utf-8");
|
||||
return runAgent({
|
||||
key: "productionAgent:storyboardGenAgent",
|
||||
prompt,
|
||||
system: systemPrompt,
|
||||
name: "执行导演",
|
||||
@ -287,6 +297,7 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
"\n你必须使用如下XML格式写入工作区:\n```\n<storyboardItem videoDesc='视频描述' prompt=提示词内容 track='分组' duration='视频推荐时间' associateAssetsIds='[该分镜所需的资产ID列表]'></storyboardItem>\n```";
|
||||
|
||||
return runAgent({
|
||||
key: "productionAgent:storyboardPanelAgent",
|
||||
prompt,
|
||||
system: systemPrompt + addPrompt,
|
||||
name: "执行导演",
|
||||
@ -311,6 +322,7 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
const addPrompt = "\n你必须使用如下XML格式写入工作区:\n```\n<storyboardTable>内容</storyboardTable>\n```";
|
||||
|
||||
return runAgent({
|
||||
key: "productionAgent:storyboardTableAgent",
|
||||
prompt,
|
||||
system: systemPrompt + addPrompt,
|
||||
name: "执行导演",
|
||||
@ -331,6 +343,7 @@ async function createSubAgent(parentCtx: AgentContext) {
|
||||
const skill = path.join(u.getPath("skills"), "production_agent_supervision.md");
|
||||
const systemPrompt = await fs.promises.readFile(skill, "utf-8");
|
||||
return runAgent({
|
||||
key: "productionAgent:supervisionAgent",
|
||||
prompt,
|
||||
system: systemPrompt,
|
||||
name: "监制",
|
||||
@ -370,7 +383,57 @@ ${buildSkillPrompt(mainSkills)}`,
|
||||
};
|
||||
return res;
|
||||
}
|
||||
async function consumeFullStream(
|
||||
fullStream: AsyncIterable<any>,
|
||||
initialMsg: ReturnType<ResTool["newMessage"]>,
|
||||
syncMsg?: () => ReturnType<ResTool["newMessage"]>,
|
||||
): Promise<string> {
|
||||
let msg = initialMsg;
|
||||
let text = msg.text();
|
||||
let thinking: ReturnType<typeof msg.thinking> | null = null;
|
||||
let thinkTime = 0;
|
||||
let fullResponse = "";
|
||||
|
||||
try {
|
||||
for await (const chunk of fullStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
if (syncMsg) {
|
||||
const newMsg = syncMsg();
|
||||
if (newMsg !== msg) {
|
||||
msg = newMsg;
|
||||
text = msg.text();
|
||||
}
|
||||
}
|
||||
if (chunk.type === "reasoning-start") {
|
||||
thinkTime = Date.now();
|
||||
thinking = msg.thinking("思考中...");
|
||||
} else if (chunk.type === "reasoning-delta") {
|
||||
thinking?.append(chunk.text);
|
||||
} else if (chunk.type === "reasoning-end") {
|
||||
thinkTime = Date.now() - thinkTime;
|
||||
thinking?.updateTitle(`思考完毕(${(thinkTime / 1000).toFixed(1)} 秒)`);
|
||||
thinking?.complete();
|
||||
thinking = null;
|
||||
} else if (chunk.type === "text-delta") {
|
||||
text.append(chunk.text);
|
||||
fullResponse += chunk.text;
|
||||
} else if (chunk.type === "error") {
|
||||
throw chunk.error;
|
||||
}
|
||||
}
|
||||
text.complete();
|
||||
msg.complete();
|
||||
} catch (err: any) {
|
||||
thinking?.complete();
|
||||
const errMsg = err?.message ?? String(err);
|
||||
text.append(errMsg);
|
||||
text.error();
|
||||
msg.error();
|
||||
throw err;
|
||||
}
|
||||
|
||||
return fullResponse;
|
||||
}
|
||||
function removeAllXmlTags(text: string): string {
|
||||
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?>([\s\S]*?)<\/\1>/g, "");
|
||||
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?\/>/g, "");
|
||||
|
||||
@ -16,6 +16,10 @@ export interface AgentContext {
|
||||
abortSignal?: AbortSignal;
|
||||
resTool: ResTool;
|
||||
msg: ReturnType<ResTool["newMessage"]>;
|
||||
thinkConfig: {
|
||||
think: boolean;
|
||||
thinlLevel: 0 | 1 | 2 | 3;
|
||||
};
|
||||
}
|
||||
|
||||
function buildMemPrompt(mem: Awaited<ReturnType<Memory["get"]>>): string {
|
||||
@ -34,7 +38,7 @@ function buildMemPrompt(mem: Awaited<ReturnType<Memory["get"]>>): string {
|
||||
return `## Memory\n以下是你对用户的记忆,可作为参考但不要主动提及:\n${memoryContext}`;
|
||||
}
|
||||
|
||||
export async function decisionAI(ctx: AgentContext) {
|
||||
export async function runDecisionAI(ctx: AgentContext) {
|
||||
const { isolationKey, text, userMessageTime, abortSignal, resTool } = ctx;
|
||||
|
||||
const memory = new Memory("scriptAgent", isolationKey);
|
||||
@ -59,7 +63,7 @@ export async function decisionAI(ctx: AgentContext) {
|
||||
`章节数量:${novelData.length}章`,
|
||||
].join("\n");
|
||||
|
||||
const { textStream } = await u.Ai.Text("scriptAgent").stream({
|
||||
const { fullStream } = await u.Ai.Text("scriptAgent:decisionAgent", ctx.thinkConfig.think, ctx.thinkConfig.thinlLevel).stream({
|
||||
messages: [
|
||||
{ role: "system", content: prompt },
|
||||
{ role: "assistant", content: projectInfo + "\n" + mem },
|
||||
@ -76,7 +80,13 @@ export async function decisionAI(ctx: AgentContext) {
|
||||
},
|
||||
});
|
||||
|
||||
return textStream;
|
||||
let currentMsg = ctx.msg;
|
||||
await consumeFullStream(fullStream, currentMsg, () => {
|
||||
if (ctx.msg === currentMsg) return currentMsg;
|
||||
currentMsg.complete();
|
||||
currentMsg = ctx.msg;
|
||||
return currentMsg;
|
||||
});
|
||||
}
|
||||
|
||||
function createSubAgent(parentCtx: AgentContext) {
|
||||
@ -84,6 +94,7 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
const memory = new Memory("scriptAgent", parentCtx.isolationKey);
|
||||
|
||||
async function runAgent({
|
||||
key,
|
||||
prompt,
|
||||
system,
|
||||
name,
|
||||
@ -91,6 +102,7 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
tools: extraTools,
|
||||
messages,
|
||||
}: {
|
||||
key: `${string}:${string}`;
|
||||
prompt: string;
|
||||
system: string;
|
||||
name: string;
|
||||
@ -100,29 +112,15 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
}) {
|
||||
parentCtx.msg.complete();
|
||||
const subMsg = resTool.newMessage("assistant", name);
|
||||
const text = subMsg.text();
|
||||
let fullResponse = "";
|
||||
|
||||
const { textStream } = await u.Ai.Text("scriptAgent").stream({
|
||||
const { fullStream } = await u.Ai.Text(key, parentCtx.thinkConfig.think, parentCtx.thinkConfig.thinlLevel).stream({
|
||||
system,
|
||||
messages: messages ?? [{ role: "user", content: prompt }],
|
||||
abortSignal,
|
||||
tools: { ...extraTools, ...useTools({ resTool, msg: subMsg }) },
|
||||
});
|
||||
|
||||
try {
|
||||
for await (const chunk of textStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
text.append(chunk);
|
||||
fullResponse += chunk;
|
||||
}
|
||||
text.complete();
|
||||
subMsg.complete();
|
||||
} catch (err: any) {
|
||||
text.complete();
|
||||
subMsg.stop();
|
||||
throw err;
|
||||
}
|
||||
const fullResponse = await consumeFullStream(fullStream, subMsg);
|
||||
|
||||
if (fullResponse.trim()) {
|
||||
await memory.add(memoryKey, removeAllXmlTags(fullResponse), {
|
||||
@ -149,6 +147,7 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
const formatPrompt = "\n你必须使用如下XML格式写入工作区:\n<storySkeleton>故事骨架内容</storySkeleton>";
|
||||
|
||||
return runAgent({
|
||||
key: "scriptAgent:storySkeletonAgent",
|
||||
prompt,
|
||||
system: systemPrompt + formatPrompt,
|
||||
name: "编剧",
|
||||
@ -168,6 +167,7 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
const formatPrompt = "\n你必须使用如下XML格式写入工作区:\n<adaptationStrategy>改编策略内容</adaptationStrategy>";
|
||||
|
||||
return runAgent({
|
||||
key: "scriptAgent:adaptationStrategyAgent",
|
||||
prompt,
|
||||
system: systemPrompt + formatPrompt,
|
||||
name: "编剧",
|
||||
@ -194,6 +194,7 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
const formatPrompt = `\n你必须使用如下XML格式写入工作区:\nXML不得添加任何额外标签<scriptItem name="剧本名称">剧本内容</scriptItem><scriptItem name="剧本名称">剧本内容</scriptItem><scriptItem name="剧本名称">剧本内容</scriptItem>`;
|
||||
|
||||
return runAgent({
|
||||
key: "scriptAgent:scriptAgent",
|
||||
prompt,
|
||||
system: systemPrompt + formatPrompt,
|
||||
messages: [
|
||||
@ -214,6 +215,7 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
const systemPrompt = await fs.promises.readFile(skill, "utf-8");
|
||||
|
||||
return runAgent({
|
||||
key: "scriptAgent:supervisionAgent",
|
||||
prompt,
|
||||
system: systemPrompt,
|
||||
name: "编辑",
|
||||
@ -230,6 +232,58 @@ function createSubAgent(parentCtx: AgentContext) {
|
||||
};
|
||||
}
|
||||
|
||||
async function consumeFullStream(
|
||||
fullStream: AsyncIterable<any>,
|
||||
initialMsg: ReturnType<ResTool["newMessage"]>,
|
||||
syncMsg?: () => ReturnType<ResTool["newMessage"]>,
|
||||
): Promise<string> {
|
||||
let msg = initialMsg;
|
||||
let text = msg.text();
|
||||
let thinking: ReturnType<typeof msg.thinking> | null = null;
|
||||
let thinkTime = 0;
|
||||
let fullResponse = "";
|
||||
|
||||
try {
|
||||
for await (const chunk of fullStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
if (syncMsg) {
|
||||
const newMsg = syncMsg();
|
||||
if (newMsg !== msg) {
|
||||
msg = newMsg;
|
||||
text = msg.text();
|
||||
}
|
||||
}
|
||||
if (chunk.type === "reasoning-start") {
|
||||
thinkTime = Date.now();
|
||||
thinking = msg.thinking("思考中...");
|
||||
} else if (chunk.type === "reasoning-delta") {
|
||||
thinking?.append(chunk.text);
|
||||
} else if (chunk.type === "reasoning-end") {
|
||||
thinkTime = Date.now() - thinkTime;
|
||||
thinking?.updateTitle(`思考完毕(${(thinkTime / 1000).toFixed(1)} 秒)`);
|
||||
thinking?.complete();
|
||||
thinking = null;
|
||||
} else if (chunk.type === "text-delta") {
|
||||
text.append(chunk.text);
|
||||
fullResponse += chunk.text;
|
||||
} else if (chunk.type === "error") {
|
||||
throw chunk.error;
|
||||
}
|
||||
}
|
||||
text.complete();
|
||||
msg.complete();
|
||||
} catch (err: any) {
|
||||
thinking?.complete();
|
||||
const errMsg = err?.message ?? String(err);
|
||||
text.append(errMsg);
|
||||
text.error();
|
||||
msg.error();
|
||||
throw err;
|
||||
}
|
||||
|
||||
return fullResponse;
|
||||
}
|
||||
|
||||
function removeAllXmlTags(text: string): string {
|
||||
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?>([\s\S]*?)<\/\1>/g, "");
|
||||
text = text.replace(/<([a-zA-Z][\w-]*)(\s+[^>]*)?\/>/g, "");
|
||||
|
||||
28
src/app.ts
28
src/app.ts
@ -8,15 +8,43 @@ import expressWs from "express-ws";
|
||||
import logger from "morgan";
|
||||
import cors from "cors";
|
||||
import buildRoute from "@/core";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import u from "@/utils";
|
||||
import jwt from "jsonwebtoken";
|
||||
import socketInit from "@/socket/index";
|
||||
import { isEletron } from "@/utils/getPath";
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
|
||||
async function checkPermissions() {
|
||||
if (!isEletron()) return true;
|
||||
const userDataPath = u.getPath();
|
||||
try {
|
||||
fs.mkdirSync(userDataPath, { recursive: true });
|
||||
const testFile = path.join(userDataPath, ".access_test");
|
||||
fs.writeFileSync(testFile, "test");
|
||||
fs.unlinkSync(testFile);
|
||||
} catch (e) {
|
||||
const { dialog, app } = require("electron");
|
||||
const { response } = await dialog.showMessageBox({
|
||||
type: "warning",
|
||||
title: "权限不足",
|
||||
message: "应用无法访问数据目录",
|
||||
detail: `无法读写以下目录:\n${userDataPath}\n\n请联系管理员授予权限,或以管理员身份运行本程序。`,
|
||||
buttons: ["确认退出"],
|
||||
defaultId: 0,
|
||||
});
|
||||
if (response === 0) {
|
||||
app.quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default async function startServe(randomPort: Boolean = false) {
|
||||
await checkPermissions();
|
||||
|
||||
await u.writeVersion();
|
||||
const io = new Server(server, { cors: { origin: "*" } });
|
||||
socketInit(io);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -71,6 +71,8 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
table.text("vendorId");
|
||||
table.string("desc");
|
||||
table.string("name");
|
||||
table.integer("temperature");
|
||||
table.integer("maxOutputTokens");
|
||||
table.boolean("disabled").defaultTo(false);
|
||||
table.primary(["id"]);
|
||||
table.unique(["id"]);
|
||||
@ -113,6 +115,150 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
desc: "根据剧本内容生成角色配音,支持多种声音风格和情绪",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "scriptAgent:decisionAgent",
|
||||
name: "剧本Agent:决策层",
|
||||
desc: "决策层",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "scriptAgent:supervisionAgent",
|
||||
name: "剧本Agent:监督层",
|
||||
desc: "监督层",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "scriptAgent:storySkeletonAgent",
|
||||
name: "剧本Agent:故事骨架",
|
||||
desc: "故事骨架生成",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "scriptAgent:adaptationStrategyAgent",
|
||||
name: "剧本Agent:改编策略",
|
||||
desc: "改编策略生成",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "scriptAgent:scriptAgent",
|
||||
name: "剧本Agent:剧本生成",
|
||||
desc: "剧本生成",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "productionAgent:decisionAgent",
|
||||
name: "生产Agent:决策层",
|
||||
desc: "决策层",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "productionAgent:supervisionAgent",
|
||||
name: "生产Agent:监督层",
|
||||
desc: "监督层",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "productionAgent:deriveAssetsAgent",
|
||||
name: "生产Agent:衍生资产",
|
||||
desc: "衍生资产",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "productionAgent:generateAssetsAgent",
|
||||
name: "生产Agent:生成资产",
|
||||
desc: "生成资产",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "productionAgent:directorPlanAgent",
|
||||
name: "生产Agent:导演规划",
|
||||
desc: "导演规划",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "productionAgent:storyboardGenAgent",
|
||||
name: "生产Agent:分镜生成",
|
||||
desc: "分镜生成",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "productionAgent:storyboardPanelAgent",
|
||||
name: "生产Agent:分镜面板",
|
||||
desc: "分镜面板生成",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
model: "",
|
||||
modelName: "",
|
||||
vendorId: null,
|
||||
key: "productionAgent:storyboardTableAgent",
|
||||
name: "生产Agent:分镜表格",
|
||||
desc: "分镜表格生成",
|
||||
temperature: 1,
|
||||
maxOutputTokens: 0,
|
||||
disabled: false,
|
||||
},
|
||||
|
||||
]);
|
||||
},
|
||||
},
|
||||
@ -220,6 +366,19 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
]);
|
||||
},
|
||||
},
|
||||
//模型绑定提示词表
|
||||
{
|
||||
name: "o_modelPrompt",
|
||||
builder: (table) => {
|
||||
table.integer("id").notNullable();
|
||||
table.string("vendorId");
|
||||
table.string("model");
|
||||
table.text("prompt");
|
||||
table.primary(["id"]);
|
||||
table.unique(["id"]);
|
||||
},
|
||||
initData: async (knex) => { },
|
||||
},
|
||||
//小说原文表
|
||||
{
|
||||
name: "o_novel",
|
||||
@ -261,29 +420,6 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
table.unique(["id"]);
|
||||
},
|
||||
},
|
||||
//大纲表
|
||||
{
|
||||
name: "o_outline",
|
||||
builder: (table) => {
|
||||
table.integer("id").notNullable();
|
||||
table.integer("episode");
|
||||
table.text("data");
|
||||
table.integer("projectId");
|
||||
table.primary(["id"]);
|
||||
table.unique(["id"]);
|
||||
},
|
||||
},
|
||||
//大纲-原文表
|
||||
{
|
||||
name: "o_outlineNovel",
|
||||
builder: (table) => {
|
||||
table.integer("id").notNullable();
|
||||
table.integer("outlineId").unsigned().references("id").inTable("o_outline");
|
||||
table.integer("novelId").unsigned().references("id").inTable("o_novel");
|
||||
table.primary(["id"]);
|
||||
table.unique(["id"]);
|
||||
},
|
||||
},
|
||||
//剧本
|
||||
{
|
||||
name: "o_script",
|
||||
@ -424,38 +560,38 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
await knex("o_vendorConfig").insert([
|
||||
{
|
||||
id: "toonflow",
|
||||
inputValues: "",
|
||||
models: [],
|
||||
inputValues: "{}",
|
||||
models: "[]",
|
||||
enable: 0,
|
||||
},
|
||||
{
|
||||
id: "volcengine",
|
||||
inputValues: "",
|
||||
models: [],
|
||||
inputValues: "{}",
|
||||
models: "[]",
|
||||
enable: 0,
|
||||
},
|
||||
{
|
||||
id: "minimax",
|
||||
inputValues: "",
|
||||
models: [],
|
||||
inputValues: "{}",
|
||||
models: "[]",
|
||||
enable: 0,
|
||||
},
|
||||
{
|
||||
id: "openai",
|
||||
inputValues: "",
|
||||
models: [],
|
||||
inputValues: "{}",
|
||||
models: "[]",
|
||||
enable: 0,
|
||||
},
|
||||
{
|
||||
id: "klingai",
|
||||
inputValues: "",
|
||||
models: [],
|
||||
inputValues: "{}",
|
||||
models: "[]",
|
||||
enable: 0,
|
||||
},
|
||||
{
|
||||
id: "vidu",
|
||||
inputValues: "",
|
||||
models: [],
|
||||
inputValues: "{}",
|
||||
models: "[]",
|
||||
enable: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
10
src/lib/vendor.json
Normal file
10
src/lib/vendor.json
Normal file
File diff suppressed because one or more lines are too long
446
src/router.ts
446
src/router.ts
@ -1,4 +1,4 @@
|
||||
// @routes-hash 62534cff632db5d31442f1bca1932925
|
||||
// @routes-hash 341ae5b09b9564f4ea847d0edead3c77
|
||||
import { Express } from "express";
|
||||
|
||||
import route1 from "./routes/agents/clearMemory";
|
||||
@ -34,116 +34,126 @@ import route30 from "./routes/general/generalStatistics";
|
||||
import route31 from "./routes/general/getSingleProject";
|
||||
import route32 from "./routes/general/updateProject";
|
||||
import route33 from "./routes/login/login";
|
||||
import route34 from "./routes/migrate/migrateData";
|
||||
import route35 from "./routes/modelSelect/getModelDetail";
|
||||
import route36 from "./routes/modelSelect/getModelList";
|
||||
import route37 from "./routes/novel/addNovel";
|
||||
import route38 from "./routes/novel/batchDeleteNovel";
|
||||
import route39 from "./routes/novel/delNovel";
|
||||
import route40 from "./routes/novel/event/batchDeleteEvent";
|
||||
import route41 from "./routes/novel/event/deletEvent";
|
||||
import route42 from "./routes/novel/event/generateEvents";
|
||||
import route43 from "./routes/novel/event/getEvent";
|
||||
import route44 from "./routes/novel/getNovel";
|
||||
import route45 from "./routes/novel/getNovelData";
|
||||
import route46 from "./routes/novel/getNovelEventState";
|
||||
import route47 from "./routes/novel/getNovelIndex";
|
||||
import route48 from "./routes/novel/updateNovel";
|
||||
import route49 from "./routes/other/deleteAllData";
|
||||
import route50 from "./routes/other/getVersion";
|
||||
import route51 from "./routes/production/assets/batchGenerateAssetsImage";
|
||||
import route52 from "./routes/production/assets/deleteAssetsDireve";
|
||||
import route53 from "./routes/production/assets/getAssetsData";
|
||||
import route54 from "./routes/production/assets/pollingImage";
|
||||
import route55 from "./routes/production/assets/updateAssetsUrl";
|
||||
import route56 from "./routes/production/editImage/generateFlowImage";
|
||||
import route57 from "./routes/production/editImage/getImageDefaultModle";
|
||||
import route58 from "./routes/production/editImage/getImageFlow";
|
||||
import route59 from "./routes/production/editImage/saveImageFlow";
|
||||
import route60 from "./routes/production/editImage/updateImageFlow";
|
||||
import route61 from "./routes/production/editImage/uploadImage";
|
||||
import route62 from "./routes/production/getFlowData";
|
||||
import route63 from "./routes/production/getStoryboardData";
|
||||
import route64 from "./routes/production/saveFlowData";
|
||||
import route65 from "./routes/production/storyboard/addStoryboard";
|
||||
import route66 from "./routes/production/storyboard/batchAddStoryboardInfo";
|
||||
import route67 from "./routes/production/storyboard/batchGenerateImage";
|
||||
import route68 from "./routes/production/storyboard/downPreviewImage";
|
||||
import route69 from "./routes/production/storyboard/editStoryboardInfo";
|
||||
import route70 from "./routes/production/storyboard/getStoryboardData";
|
||||
import route71 from "./routes/production/storyboard/pollingImage";
|
||||
import route72 from "./routes/production/storyboard/previewImage";
|
||||
import route73 from "./routes/production/storyboard/removeFrame";
|
||||
import route74 from "./routes/production/storyboard/updateStoryboardUrl";
|
||||
import route75 from "./routes/production/workbench/addTrack";
|
||||
import route34 from "./routes/modelSelect/getModelDetail";
|
||||
import route35 from "./routes/modelSelect/getModelList";
|
||||
import route36 from "./routes/novel/addNovel";
|
||||
import route37 from "./routes/novel/batchDeleteNovel";
|
||||
import route38 from "./routes/novel/delNovel";
|
||||
import route39 from "./routes/novel/event/batchDeleteEvent";
|
||||
import route40 from "./routes/novel/event/deletEvent";
|
||||
import route41 from "./routes/novel/event/generateEvents";
|
||||
import route42 from "./routes/novel/event/getEvent";
|
||||
import route43 from "./routes/novel/getNovel";
|
||||
import route44 from "./routes/novel/getNovelData";
|
||||
import route45 from "./routes/novel/getNovelEventState";
|
||||
import route46 from "./routes/novel/getNovelIndex";
|
||||
import route47 from "./routes/novel/updateNovel";
|
||||
import route48 from "./routes/other/deleteAllData";
|
||||
import route49 from "./routes/other/getVersion";
|
||||
import route50 from "./routes/production/assets/batchGenerateAssetsImage";
|
||||
import route51 from "./routes/production/assets/deleteAssetsDireve";
|
||||
import route52 from "./routes/production/assets/getAssetsData";
|
||||
import route53 from "./routes/production/assets/pollingImage";
|
||||
import route54 from "./routes/production/assets/updateAssetsUrl";
|
||||
import route55 from "./routes/production/editImage/generateFlowImage";
|
||||
import route56 from "./routes/production/editImage/getImageDefaultModle";
|
||||
import route57 from "./routes/production/editImage/getImageFlow";
|
||||
import route58 from "./routes/production/editImage/saveImageFlow";
|
||||
import route59 from "./routes/production/editImage/updateImageFlow";
|
||||
import route60 from "./routes/production/editImage/uploadImage";
|
||||
import route61 from "./routes/production/getFlowData";
|
||||
import route62 from "./routes/production/getStoryboardData";
|
||||
import route63 from "./routes/production/saveFlowData";
|
||||
import route64 from "./routes/production/storyboard/addStoryboard";
|
||||
import route65 from "./routes/production/storyboard/batchAddStoryboardInfo";
|
||||
import route66 from "./routes/production/storyboard/batchGenerateImage";
|
||||
import route67 from "./routes/production/storyboard/downPreviewImage";
|
||||
import route68 from "./routes/production/storyboard/editStoryboardInfo";
|
||||
import route69 from "./routes/production/storyboard/getStoryboardData";
|
||||
import route70 from "./routes/production/storyboard/pollingImage";
|
||||
import route71 from "./routes/production/storyboard/previewImage";
|
||||
import route72 from "./routes/production/storyboard/removeFrame";
|
||||
import route73 from "./routes/production/storyboard/updateStoryboardUrl";
|
||||
import route74 from "./routes/production/workbench/addTrack";
|
||||
import route75 from "./routes/production/workbench/checkVideoStateList";
|
||||
import route76 from "./routes/production/workbench/deleteTrack";
|
||||
import route77 from "./routes/production/workbench/delVideo";
|
||||
import route78 from "./routes/production/workbench/generateVideo";
|
||||
import route79 from "./routes/production/workbench/generateVideoPrompt";
|
||||
import route80 from "./routes/production/workbench/getGenerateData";
|
||||
import route81 from "./routes/production/workbench/getVideoList";
|
||||
import route82 from "./routes/production/workbench/selectVideo";
|
||||
import route83 from "./routes/production/workbench/updateVideoPrompt";
|
||||
import route84 from "./routes/project/addDirectorManual";
|
||||
import route85 from "./routes/project/addProject";
|
||||
import route86 from "./routes/project/addVisualManual";
|
||||
import route87 from "./routes/project/deleteDirectorManual";
|
||||
import route88 from "./routes/project/deleteVisualManual";
|
||||
import route89 from "./routes/project/delProject";
|
||||
import route90 from "./routes/project/editDirectorlManual";
|
||||
import route91 from "./routes/project/editProject";
|
||||
import route92 from "./routes/project/editVisualManual";
|
||||
import route93 from "./routes/project/getProject";
|
||||
import route94 from "./routes/project/getVisualManual";
|
||||
import route95 from "./routes/project/queryDirectorManual";
|
||||
import route96 from "./routes/project/visualManual";
|
||||
import route97 from "./routes/script/addScript";
|
||||
import route98 from "./routes/script/batchAddScript";
|
||||
import route99 from "./routes/script/delScript";
|
||||
import route100 from "./routes/script/exportScript";
|
||||
import route101 from "./routes/script/extractAssets";
|
||||
import route102 from "./routes/script/getScrptApi";
|
||||
import route103 from "./routes/script/pollScriptAssets";
|
||||
import route104 from "./routes/script/updateScript";
|
||||
import route105 from "./routes/scriptAgent/getPlanData";
|
||||
import route106 from "./routes/scriptAgent/setPlanData";
|
||||
import route107 from "./routes/scriptAgent/updateData";
|
||||
import route108 from "./routes/setting/about/checkUpdate";
|
||||
import route109 from "./routes/setting/about/downloadApp";
|
||||
import route110 from "./routes/setting/agentDeploy/agentSetKey";
|
||||
import route111 from "./routes/setting/agentDeploy/deployAgentModel";
|
||||
import route112 from "./routes/setting/agentDeploy/getAgentDeploy";
|
||||
import route113 from "./routes/setting/dbConfig/clearData";
|
||||
import route114 from "./routes/setting/dev/getSwitchAiDevTool";
|
||||
import route115 from "./routes/setting/dev/updateSwitchAiDevTool";
|
||||
import route116 from "./routes/setting/fileManagement/openFolder";
|
||||
import route117 from "./routes/setting/getTextModel";
|
||||
import route118 from "./routes/setting/loginConfig/getUser";
|
||||
import route119 from "./routes/setting/loginConfig/updateUserPwd";
|
||||
import route120 from "./routes/setting/memoryConfig/delAllMemory";
|
||||
import route121 from "./routes/setting/memoryConfig/getMemory";
|
||||
import route122 from "./routes/setting/memoryConfig/sureMemory";
|
||||
import route123 from "./routes/setting/promptManage/getPrompt";
|
||||
import route124 from "./routes/setting/promptManage/updatePrompt";
|
||||
import route125 from "./routes/setting/skillManagement/getSkillContent";
|
||||
import route126 from "./routes/setting/skillManagement/getSkillList";
|
||||
import route127 from "./routes/setting/skillManagement/saveSkillContent";
|
||||
import route128 from "./routes/setting/vendorConfig/addVendor";
|
||||
import route129 from "./routes/setting/vendorConfig/addVendorModel";
|
||||
import route130 from "./routes/setting/vendorConfig/deleteVendor";
|
||||
import route131 from "./routes/setting/vendorConfig/delVendorModel";
|
||||
import route132 from "./routes/setting/vendorConfig/enableVendor";
|
||||
import route133 from "./routes/setting/vendorConfig/getCodeByLink";
|
||||
import route134 from "./routes/setting/vendorConfig/getVendorList";
|
||||
import route135 from "./routes/setting/vendorConfig/modelTest";
|
||||
import route136 from "./routes/setting/vendorConfig/updateCode";
|
||||
import route137 from "./routes/setting/vendorConfig/updateVendorInputs";
|
||||
import route138 from "./routes/setting/vendorConfig/upVendorModel";
|
||||
import route139 from "./routes/task/getProject";
|
||||
import route140 from "./routes/task/getTaskApi";
|
||||
import route141 from "./routes/task/getTaskCategories";
|
||||
import route142 from "./routes/task/taskDetails";
|
||||
import route143 from "./routes/test/test";
|
||||
import route80 from "./routes/production/workbench/getFileUrl";
|
||||
import route81 from "./routes/production/workbench/getGenerateData";
|
||||
import route82 from "./routes/production/workbench/getVideoList";
|
||||
import route83 from "./routes/production/workbench/selectVideo";
|
||||
import route84 from "./routes/production/workbench/updateVideoDuration";
|
||||
import route85 from "./routes/production/workbench/updateVideoPrompt";
|
||||
import route86 from "./routes/project/addDirectorManual";
|
||||
import route87 from "./routes/project/addProject";
|
||||
import route88 from "./routes/project/addVisualManual";
|
||||
import route89 from "./routes/project/deleteDirectorManual";
|
||||
import route90 from "./routes/project/deleteVisualManual";
|
||||
import route91 from "./routes/project/delProject";
|
||||
import route92 from "./routes/project/editDirectorlManual";
|
||||
import route93 from "./routes/project/editProject";
|
||||
import route94 from "./routes/project/editVisualManual";
|
||||
import route95 from "./routes/project/getModelDetails";
|
||||
import route96 from "./routes/project/getProject";
|
||||
import route97 from "./routes/project/getVisualManual";
|
||||
import route98 from "./routes/project/queryDirectorManual";
|
||||
import route99 from "./routes/project/visualManual";
|
||||
import route100 from "./routes/script/addScript";
|
||||
import route101 from "./routes/script/batchAddScript";
|
||||
import route102 from "./routes/script/delScript";
|
||||
import route103 from "./routes/script/exportScript";
|
||||
import route104 from "./routes/script/extractAssets";
|
||||
import route105 from "./routes/script/getAiRegex";
|
||||
import route106 from "./routes/script/getScrptApi";
|
||||
import route107 from "./routes/script/pollScriptAssets";
|
||||
import route108 from "./routes/script/updateScript";
|
||||
import route109 from "./routes/scriptAgent/getPlanData";
|
||||
import route110 from "./routes/scriptAgent/setPlanData";
|
||||
import route111 from "./routes/scriptAgent/updateData";
|
||||
import route112 from "./routes/setting/about/checkUpdate";
|
||||
import route113 from "./routes/setting/about/downloadApp";
|
||||
import route114 from "./routes/setting/agentDeploy/agentSetKey";
|
||||
import route115 from "./routes/setting/agentDeploy/deployAgentModel";
|
||||
import route116 from "./routes/setting/agentDeploy/getAgentDeploy";
|
||||
import route117 from "./routes/setting/dbConfig/clearData";
|
||||
import route118 from "./routes/setting/dbConfig/clearTable";
|
||||
import route119 from "./routes/setting/dbConfig/dbInfo";
|
||||
import route120 from "./routes/setting/dbConfig/exportData";
|
||||
import route121 from "./routes/setting/dbConfig/importData";
|
||||
import route122 from "./routes/setting/dev/getSwitchAiDevTool";
|
||||
import route123 from "./routes/setting/dev/updateSwitchAiDevTool";
|
||||
import route124 from "./routes/setting/fileManagement/openFolder";
|
||||
import route125 from "./routes/setting/getTextModel";
|
||||
import route126 from "./routes/setting/loginConfig/getUser";
|
||||
import route127 from "./routes/setting/loginConfig/updateUserPwd";
|
||||
import route128 from "./routes/setting/memoryConfig/delAllMemory";
|
||||
import route129 from "./routes/setting/memoryConfig/getMemory";
|
||||
import route130 from "./routes/setting/memoryConfig/sureMemory";
|
||||
import route131 from "./routes/setting/modelMap/bindingPrompt";
|
||||
import route132 from "./routes/setting/modelMap/getImageAndVideoModel";
|
||||
import route133 from "./routes/setting/promptManage/getPrompt";
|
||||
import route134 from "./routes/setting/promptManage/updatePrompt";
|
||||
import route135 from "./routes/setting/skillManagement/getSkillContent";
|
||||
import route136 from "./routes/setting/skillManagement/getSkillList";
|
||||
import route137 from "./routes/setting/skillManagement/saveSkillContent";
|
||||
import route138 from "./routes/setting/vendorConfig/addVendor";
|
||||
import route139 from "./routes/setting/vendorConfig/addVendorModel";
|
||||
import route140 from "./routes/setting/vendorConfig/deleteVendor";
|
||||
import route141 from "./routes/setting/vendorConfig/delVendorModel";
|
||||
import route142 from "./routes/setting/vendorConfig/enableVendor";
|
||||
import route143 from "./routes/setting/vendorConfig/getCodeByLink";
|
||||
import route144 from "./routes/setting/vendorConfig/getVendorList";
|
||||
import route145 from "./routes/setting/vendorConfig/modelTest";
|
||||
import route146 from "./routes/setting/vendorConfig/updateCode";
|
||||
import route147 from "./routes/setting/vendorConfig/updateVendorInputs";
|
||||
import route148 from "./routes/setting/vendorConfig/upVendorModel";
|
||||
import route149 from "./routes/task/getProject";
|
||||
import route150 from "./routes/task/getTaskApi";
|
||||
import route151 from "./routes/task/getTaskCategories";
|
||||
import route152 from "./routes/task/taskDetails";
|
||||
import route153 from "./routes/test/test";
|
||||
|
||||
export default async (app: Express) => {
|
||||
app.use("/api/agents/clearMemory", route1);
|
||||
@ -179,114 +189,124 @@ export default async (app: Express) => {
|
||||
app.use("/api/general/getSingleProject", route31);
|
||||
app.use("/api/general/updateProject", route32);
|
||||
app.use("/api/login/login", route33);
|
||||
app.use("/api/migrate/migrateData", route34);
|
||||
app.use("/api/modelSelect/getModelDetail", route35);
|
||||
app.use("/api/modelSelect/getModelList", route36);
|
||||
app.use("/api/novel/addNovel", route37);
|
||||
app.use("/api/novel/batchDeleteNovel", route38);
|
||||
app.use("/api/novel/delNovel", route39);
|
||||
app.use("/api/novel/event/batchDeleteEvent", route40);
|
||||
app.use("/api/novel/event/deletEvent", route41);
|
||||
app.use("/api/novel/event/generateEvents", route42);
|
||||
app.use("/api/novel/event/getEvent", route43);
|
||||
app.use("/api/novel/getNovel", route44);
|
||||
app.use("/api/novel/getNovelData", route45);
|
||||
app.use("/api/novel/getNovelEventState", route46);
|
||||
app.use("/api/novel/getNovelIndex", route47);
|
||||
app.use("/api/novel/updateNovel", route48);
|
||||
app.use("/api/other/deleteAllData", route49);
|
||||
app.use("/api/other/getVersion", route50);
|
||||
app.use("/api/production/assets/batchGenerateAssetsImage", route51);
|
||||
app.use("/api/production/assets/deleteAssetsDireve", route52);
|
||||
app.use("/api/production/assets/getAssetsData", route53);
|
||||
app.use("/api/production/assets/pollingImage", route54);
|
||||
app.use("/api/production/assets/updateAssetsUrl", route55);
|
||||
app.use("/api/production/editImage/generateFlowImage", route56);
|
||||
app.use("/api/production/editImage/getImageDefaultModle", route57);
|
||||
app.use("/api/production/editImage/getImageFlow", route58);
|
||||
app.use("/api/production/editImage/saveImageFlow", route59);
|
||||
app.use("/api/production/editImage/updateImageFlow", route60);
|
||||
app.use("/api/production/editImage/uploadImage", route61);
|
||||
app.use("/api/production/getFlowData", route62);
|
||||
app.use("/api/production/getStoryboardData", route63);
|
||||
app.use("/api/production/saveFlowData", route64);
|
||||
app.use("/api/production/storyboard/addStoryboard", route65);
|
||||
app.use("/api/production/storyboard/batchAddStoryboardInfo", route66);
|
||||
app.use("/api/production/storyboard/batchGenerateImage", route67);
|
||||
app.use("/api/production/storyboard/downPreviewImage", route68);
|
||||
app.use("/api/production/storyboard/editStoryboardInfo", route69);
|
||||
app.use("/api/production/storyboard/getStoryboardData", route70);
|
||||
app.use("/api/production/storyboard/pollingImage", route71);
|
||||
app.use("/api/production/storyboard/previewImage", route72);
|
||||
app.use("/api/production/storyboard/removeFrame", route73);
|
||||
app.use("/api/production/storyboard/updateStoryboardUrl", route74);
|
||||
app.use("/api/production/workbench/addTrack", route75);
|
||||
app.use("/api/modelSelect/getModelDetail", route34);
|
||||
app.use("/api/modelSelect/getModelList", route35);
|
||||
app.use("/api/novel/addNovel", route36);
|
||||
app.use("/api/novel/batchDeleteNovel", route37);
|
||||
app.use("/api/novel/delNovel", route38);
|
||||
app.use("/api/novel/event/batchDeleteEvent", route39);
|
||||
app.use("/api/novel/event/deletEvent", route40);
|
||||
app.use("/api/novel/event/generateEvents", route41);
|
||||
app.use("/api/novel/event/getEvent", route42);
|
||||
app.use("/api/novel/getNovel", route43);
|
||||
app.use("/api/novel/getNovelData", route44);
|
||||
app.use("/api/novel/getNovelEventState", route45);
|
||||
app.use("/api/novel/getNovelIndex", route46);
|
||||
app.use("/api/novel/updateNovel", route47);
|
||||
app.use("/api/other/deleteAllData", route48);
|
||||
app.use("/api/other/getVersion", route49);
|
||||
app.use("/api/production/assets/batchGenerateAssetsImage", route50);
|
||||
app.use("/api/production/assets/deleteAssetsDireve", route51);
|
||||
app.use("/api/production/assets/getAssetsData", route52);
|
||||
app.use("/api/production/assets/pollingImage", route53);
|
||||
app.use("/api/production/assets/updateAssetsUrl", route54);
|
||||
app.use("/api/production/editImage/generateFlowImage", route55);
|
||||
app.use("/api/production/editImage/getImageDefaultModle", route56);
|
||||
app.use("/api/production/editImage/getImageFlow", route57);
|
||||
app.use("/api/production/editImage/saveImageFlow", route58);
|
||||
app.use("/api/production/editImage/updateImageFlow", route59);
|
||||
app.use("/api/production/editImage/uploadImage", route60);
|
||||
app.use("/api/production/getFlowData", route61);
|
||||
app.use("/api/production/getStoryboardData", route62);
|
||||
app.use("/api/production/saveFlowData", route63);
|
||||
app.use("/api/production/storyboard/addStoryboard", route64);
|
||||
app.use("/api/production/storyboard/batchAddStoryboardInfo", route65);
|
||||
app.use("/api/production/storyboard/batchGenerateImage", route66);
|
||||
app.use("/api/production/storyboard/downPreviewImage", route67);
|
||||
app.use("/api/production/storyboard/editStoryboardInfo", route68);
|
||||
app.use("/api/production/storyboard/getStoryboardData", route69);
|
||||
app.use("/api/production/storyboard/pollingImage", route70);
|
||||
app.use("/api/production/storyboard/previewImage", route71);
|
||||
app.use("/api/production/storyboard/removeFrame", route72);
|
||||
app.use("/api/production/storyboard/updateStoryboardUrl", route73);
|
||||
app.use("/api/production/workbench/addTrack", route74);
|
||||
app.use("/api/production/workbench/checkVideoStateList", route75);
|
||||
app.use("/api/production/workbench/deleteTrack", route76);
|
||||
app.use("/api/production/workbench/delVideo", route77);
|
||||
app.use("/api/production/workbench/generateVideo", route78);
|
||||
app.use("/api/production/workbench/generateVideoPrompt", route79);
|
||||
app.use("/api/production/workbench/getGenerateData", route80);
|
||||
app.use("/api/production/workbench/getVideoList", route81);
|
||||
app.use("/api/production/workbench/selectVideo", route82);
|
||||
app.use("/api/production/workbench/updateVideoPrompt", route83);
|
||||
app.use("/api/project/addDirectorManual", route84);
|
||||
app.use("/api/project/addProject", route85);
|
||||
app.use("/api/project/addVisualManual", route86);
|
||||
app.use("/api/project/deleteDirectorManual", route87);
|
||||
app.use("/api/project/deleteVisualManual", route88);
|
||||
app.use("/api/project/delProject", route89);
|
||||
app.use("/api/project/editDirectorlManual", route90);
|
||||
app.use("/api/project/editProject", route91);
|
||||
app.use("/api/project/editVisualManual", route92);
|
||||
app.use("/api/project/getProject", route93);
|
||||
app.use("/api/project/getVisualManual", route94);
|
||||
app.use("/api/project/queryDirectorManual", route95);
|
||||
app.use("/api/project/visualManual", route96);
|
||||
app.use("/api/script/addScript", route97);
|
||||
app.use("/api/script/batchAddScript", route98);
|
||||
app.use("/api/script/delScript", route99);
|
||||
app.use("/api/script/exportScript", route100);
|
||||
app.use("/api/script/extractAssets", route101);
|
||||
app.use("/api/script/getScrptApi", route102);
|
||||
app.use("/api/script/pollScriptAssets", route103);
|
||||
app.use("/api/script/updateScript", route104);
|
||||
app.use("/api/scriptAgent/getPlanData", route105);
|
||||
app.use("/api/scriptAgent/setPlanData", route106);
|
||||
app.use("/api/scriptAgent/updateData", route107);
|
||||
app.use("/api/setting/about/checkUpdate", route108);
|
||||
app.use("/api/setting/about/downloadApp", route109);
|
||||
app.use("/api/setting/agentDeploy/agentSetKey", route110);
|
||||
app.use("/api/setting/agentDeploy/deployAgentModel", route111);
|
||||
app.use("/api/setting/agentDeploy/getAgentDeploy", route112);
|
||||
app.use("/api/setting/dbConfig/clearData", route113);
|
||||
app.use("/api/setting/dev/getSwitchAiDevTool", route114);
|
||||
app.use("/api/setting/dev/updateSwitchAiDevTool", route115);
|
||||
app.use("/api/setting/fileManagement/openFolder", route116);
|
||||
app.use("/api/setting/getTextModel", route117);
|
||||
app.use("/api/setting/loginConfig/getUser", route118);
|
||||
app.use("/api/setting/loginConfig/updateUserPwd", route119);
|
||||
app.use("/api/setting/memoryConfig/delAllMemory", route120);
|
||||
app.use("/api/setting/memoryConfig/getMemory", route121);
|
||||
app.use("/api/setting/memoryConfig/sureMemory", route122);
|
||||
app.use("/api/setting/promptManage/getPrompt", route123);
|
||||
app.use("/api/setting/promptManage/updatePrompt", route124);
|
||||
app.use("/api/setting/skillManagement/getSkillContent", route125);
|
||||
app.use("/api/setting/skillManagement/getSkillList", route126);
|
||||
app.use("/api/setting/skillManagement/saveSkillContent", route127);
|
||||
app.use("/api/setting/vendorConfig/addVendor", route128);
|
||||
app.use("/api/setting/vendorConfig/addVendorModel", route129);
|
||||
app.use("/api/setting/vendorConfig/deleteVendor", route130);
|
||||
app.use("/api/setting/vendorConfig/delVendorModel", route131);
|
||||
app.use("/api/setting/vendorConfig/enableVendor", route132);
|
||||
app.use("/api/setting/vendorConfig/getCodeByLink", route133);
|
||||
app.use("/api/setting/vendorConfig/getVendorList", route134);
|
||||
app.use("/api/setting/vendorConfig/modelTest", route135);
|
||||
app.use("/api/setting/vendorConfig/updateCode", route136);
|
||||
app.use("/api/setting/vendorConfig/updateVendorInputs", route137);
|
||||
app.use("/api/setting/vendorConfig/upVendorModel", route138);
|
||||
app.use("/api/task/getProject", route139);
|
||||
app.use("/api/task/getTaskApi", route140);
|
||||
app.use("/api/task/getTaskCategories", route141);
|
||||
app.use("/api/task/taskDetails", route142);
|
||||
app.use("/api/test/test", route143);
|
||||
app.use("/api/production/workbench/getFileUrl", route80);
|
||||
app.use("/api/production/workbench/getGenerateData", route81);
|
||||
app.use("/api/production/workbench/getVideoList", route82);
|
||||
app.use("/api/production/workbench/selectVideo", route83);
|
||||
app.use("/api/production/workbench/updateVideoDuration", route84);
|
||||
app.use("/api/production/workbench/updateVideoPrompt", route85);
|
||||
app.use("/api/project/addDirectorManual", route86);
|
||||
app.use("/api/project/addProject", route87);
|
||||
app.use("/api/project/addVisualManual", route88);
|
||||
app.use("/api/project/deleteDirectorManual", route89);
|
||||
app.use("/api/project/deleteVisualManual", route90);
|
||||
app.use("/api/project/delProject", route91);
|
||||
app.use("/api/project/editDirectorlManual", route92);
|
||||
app.use("/api/project/editProject", route93);
|
||||
app.use("/api/project/editVisualManual", route94);
|
||||
app.use("/api/project/getModelDetails", route95);
|
||||
app.use("/api/project/getProject", route96);
|
||||
app.use("/api/project/getVisualManual", route97);
|
||||
app.use("/api/project/queryDirectorManual", route98);
|
||||
app.use("/api/project/visualManual", route99);
|
||||
app.use("/api/script/addScript", route100);
|
||||
app.use("/api/script/batchAddScript", route101);
|
||||
app.use("/api/script/delScript", route102);
|
||||
app.use("/api/script/exportScript", route103);
|
||||
app.use("/api/script/extractAssets", route104);
|
||||
app.use("/api/script/getAiRegex", route105);
|
||||
app.use("/api/script/getScrptApi", route106);
|
||||
app.use("/api/script/pollScriptAssets", route107);
|
||||
app.use("/api/script/updateScript", route108);
|
||||
app.use("/api/scriptAgent/getPlanData", route109);
|
||||
app.use("/api/scriptAgent/setPlanData", route110);
|
||||
app.use("/api/scriptAgent/updateData", route111);
|
||||
app.use("/api/setting/about/checkUpdate", route112);
|
||||
app.use("/api/setting/about/downloadApp", route113);
|
||||
app.use("/api/setting/agentDeploy/agentSetKey", route114);
|
||||
app.use("/api/setting/agentDeploy/deployAgentModel", route115);
|
||||
app.use("/api/setting/agentDeploy/getAgentDeploy", route116);
|
||||
app.use("/api/setting/dbConfig/clearData", route117);
|
||||
app.use("/api/setting/dbConfig/clearTable", route118);
|
||||
app.use("/api/setting/dbConfig/dbInfo", route119);
|
||||
app.use("/api/setting/dbConfig/exportData", route120);
|
||||
app.use("/api/setting/dbConfig/importData", route121);
|
||||
app.use("/api/setting/dev/getSwitchAiDevTool", route122);
|
||||
app.use("/api/setting/dev/updateSwitchAiDevTool", route123);
|
||||
app.use("/api/setting/fileManagement/openFolder", route124);
|
||||
app.use("/api/setting/getTextModel", route125);
|
||||
app.use("/api/setting/loginConfig/getUser", route126);
|
||||
app.use("/api/setting/loginConfig/updateUserPwd", route127);
|
||||
app.use("/api/setting/memoryConfig/delAllMemory", route128);
|
||||
app.use("/api/setting/memoryConfig/getMemory", route129);
|
||||
app.use("/api/setting/memoryConfig/sureMemory", route130);
|
||||
app.use("/api/setting/modelMap/bindingPrompt", route131);
|
||||
app.use("/api/setting/modelMap/getImageAndVideoModel", route132);
|
||||
app.use("/api/setting/promptManage/getPrompt", route133);
|
||||
app.use("/api/setting/promptManage/updatePrompt", route134);
|
||||
app.use("/api/setting/skillManagement/getSkillContent", route135);
|
||||
app.use("/api/setting/skillManagement/getSkillList", route136);
|
||||
app.use("/api/setting/skillManagement/saveSkillContent", route137);
|
||||
app.use("/api/setting/vendorConfig/addVendor", route138);
|
||||
app.use("/api/setting/vendorConfig/addVendorModel", route139);
|
||||
app.use("/api/setting/vendorConfig/deleteVendor", route140);
|
||||
app.use("/api/setting/vendorConfig/delVendorModel", route141);
|
||||
app.use("/api/setting/vendorConfig/enableVendor", route142);
|
||||
app.use("/api/setting/vendorConfig/getCodeByLink", route143);
|
||||
app.use("/api/setting/vendorConfig/getVendorList", route144);
|
||||
app.use("/api/setting/vendorConfig/modelTest", route145);
|
||||
app.use("/api/setting/vendorConfig/updateCode", route146);
|
||||
app.use("/api/setting/vendorConfig/updateVendorInputs", route147);
|
||||
app.use("/api/setting/vendorConfig/upVendorModel", route148);
|
||||
app.use("/api/task/getProject", route149);
|
||||
app.use("/api/task/getTaskApi", route150);
|
||||
app.use("/api/task/getTaskCategories", route151);
|
||||
app.use("/api/task/taskDetails", route152);
|
||||
app.use("/api/test/test", route153);
|
||||
}
|
||||
|
||||
@ -141,7 +141,7 @@ export default router.post("/", validateFields(requestSchema), async (req, res)
|
||||
state: "已完成",
|
||||
filePath: imagePath,
|
||||
type: item.type,
|
||||
model: model.split(":")[1],
|
||||
model: model.split(/:(.+)/)[1],
|
||||
resolution,
|
||||
});
|
||||
|
||||
|
||||
@ -27,22 +27,6 @@ interface NovelChapter {
|
||||
|
||||
type ItemType = "characters" | "props" | "scenes";
|
||||
|
||||
interface ResultItem {
|
||||
type: ItemType;
|
||||
name: string;
|
||||
chapterRange: number[];
|
||||
}
|
||||
function findItemByName(items: ResultItem[], name: string, type?: ItemType): ResultItem | undefined {
|
||||
return items.find((item) => (!type || item.type === type) && item.name === name);
|
||||
}
|
||||
function mergeNovelText(novelData: NovelChapter[]): string {
|
||||
if (!Array.isArray(novelData)) return "";
|
||||
return novelData
|
||||
.map((chap) => {
|
||||
return `${chap.chapter.trim()}\n\n${chap.chapterData.trim().replace(/\r?\n/g, "\n")}\n`;
|
||||
})
|
||||
.join("\n");
|
||||
}
|
||||
//润色提示词
|
||||
export default router.post(
|
||||
"/",
|
||||
@ -66,23 +50,6 @@ export default router.post(
|
||||
if (!project) return res.status(500).send(success({ message: "项目为空" }));
|
||||
|
||||
// 预加载公共数据
|
||||
const allOutlineDataList: { data: string }[] = await u.db("o_outline").where("projectId", projectId).select("data");
|
||||
const itemMap: Record<string, ResultItem> = {};
|
||||
if (allOutlineDataList.length > 0)
|
||||
allOutlineDataList.forEach((row) => {
|
||||
const data: OutlineData = JSON.parse(row?.data || "{}");
|
||||
(["characters", "props", "scenes"] as ItemType[]).forEach((type) => {
|
||||
(data[type] || []).forEach((item) => {
|
||||
const key = `${type}-${item.name}`;
|
||||
if (!itemMap[key]) {
|
||||
itemMap[key] = { type, name: item.name, chapterRange: [...(data.chapterRange || [])] };
|
||||
} else {
|
||||
itemMap[key].chapterRange = Array.from(new Set([...itemMap[key].chapterRange, ...(data.chapterRange || [])]));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
const result: ResultItem[] = Object.values(itemMap);
|
||||
const assetsIds = items.map((item: { assetsId: number }) => item.assetsId);
|
||||
//查询所有资产,用于判断每个资产是否是衍生资产
|
||||
const assetsDataList = await u.db("o_assets").whereIn("id", assetsIds).select("id", "assetsId");
|
||||
@ -132,7 +99,6 @@ export default router.post(
|
||||
await u.db("o_assets").where("id", item.assetsId).update({ promptState: "生成失败", promptErrorReason: "视觉手册未定义" });
|
||||
return;
|
||||
}
|
||||
findItemByName(result, item.name, config.itemType);
|
||||
const systemPrompt = visualManual;
|
||||
try {
|
||||
const { _output } = (await u.Ai.Text("universalAi").invoke({
|
||||
|
||||
@ -123,7 +123,7 @@ export default router.post("/", validateFields(requestSchema), async (req, res)
|
||||
state: "已完成",
|
||||
filePath: imagePath,
|
||||
type,
|
||||
model: model.split(":")[1],
|
||||
model: model.split(/:(.+)/)[1],
|
||||
resolution,
|
||||
});
|
||||
|
||||
|
||||
@ -4,36 +4,10 @@ import * as zod from "zod";
|
||||
import { error, success } from "@/lib/responseFormat";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
const router = express.Router();
|
||||
interface OutlineItem {
|
||||
description: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface OutlineData {
|
||||
chapterRange: number[];
|
||||
characters?: OutlineItem[];
|
||||
props?: OutlineItem[];
|
||||
scenes?: OutlineItem[];
|
||||
}
|
||||
|
||||
interface NovelChapter {
|
||||
id: number;
|
||||
reel: string;
|
||||
chapter: string;
|
||||
chapterData: string;
|
||||
projectId: number;
|
||||
}
|
||||
|
||||
type ItemType = "characters" | "props" | "scenes";
|
||||
|
||||
interface ResultItem {
|
||||
type: ItemType;
|
||||
name: string;
|
||||
chapterRange: number[];
|
||||
}
|
||||
function findItemByName(items: ResultItem[], name: string, type?: ItemType): ResultItem | undefined {
|
||||
return items.find((item) => (!type || item.type === type) && item.name === name);
|
||||
}
|
||||
//润色提示词
|
||||
export default router.post(
|
||||
"/",
|
||||
@ -51,31 +25,8 @@ export default router.post(
|
||||
//如果没有找到对应的项目,返回错误
|
||||
if (!project) return res.status(500).send(success({ message: "项目为空" }));
|
||||
|
||||
const allOutlineDataList: { data: string }[] = await u.db("o_outline").where("projectId", projectId).select("data");
|
||||
await u.db("o_assets").where("id", assetsId).update({ promptState: "生成中" });
|
||||
|
||||
const itemMap: Record<string, ResultItem> = {};
|
||||
|
||||
if (allOutlineDataList.length > 0)
|
||||
allOutlineDataList.forEach((row) => {
|
||||
const data: OutlineData = JSON.parse(row?.data || "{}");
|
||||
(["characters", "props", "scenes"] as ItemType[]).forEach((type) => {
|
||||
(data[type] || []).forEach((item) => {
|
||||
const key = `${type}-${item.name}`;
|
||||
if (!itemMap[key]) {
|
||||
itemMap[key] = {
|
||||
type,
|
||||
name: item.name,
|
||||
chapterRange: [...(data.chapterRange || [])],
|
||||
};
|
||||
} else {
|
||||
itemMap[key].chapterRange = Array.from(new Set([...itemMap[key].chapterRange, ...(data.chapterRange || [])]));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const result: ResultItem[] = Object.values(itemMap);
|
||||
//查询资产是否是衍生资产
|
||||
const assetsData = await u.db("o_assets").where("id", assetsId).select("assetsId").first();
|
||||
if (!assetsData) return { code: 500, message: "资产不存在" };
|
||||
@ -109,7 +60,6 @@ export default router.post(
|
||||
//获取到视觉手册
|
||||
const visualManual = await u.getArtPrompt(project.artStyle as string, "art_skills", config.visualManual);
|
||||
if (!visualManual) return res.status(500).send(error("视觉手册未定义"));
|
||||
findItemByName(result, name, config.itemType);
|
||||
const systemPrompt = visualManual;
|
||||
try {
|
||||
const { _output } = (await u.Ai.Text("universalAi").invoke({
|
||||
|
||||
@ -40,7 +40,6 @@ export default router.post(
|
||||
data.map((i:any) => i.id!),
|
||||
)
|
||||
.select( "o_assets.id", "o_assets.name");
|
||||
console.log("%c Line:36 🍎 assets2AudioData", "background:#3f7cff", assets2AudioData);
|
||||
const repleAssets:Record<number,{id:number;name:string}[]> = {};
|
||||
assets2AudioData.forEach((item) => {
|
||||
if (!repleAssets[item.id]) repleAssets[item.id] = [item];
|
||||
|
||||
@ -1,133 +0,0 @@
|
||||
import express from "express";
|
||||
import { success } from "@/lib/responseFormat";
|
||||
import db from "@/utils/db";
|
||||
import type { DB } from "@/types/database";
|
||||
import knex from "knex";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { tr } from "zod/locales";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 迁移数据
|
||||
export default router.post(
|
||||
"/",
|
||||
async (req, res) => {
|
||||
// return res.status(200).send({
|
||||
// success: true,
|
||||
// message: '数据迁移功能已关闭,建议手动迁移数据后删除旧数据库文件'
|
||||
// });
|
||||
//连接旧数据库,读取数据
|
||||
try {
|
||||
let db2: knex.Knex | null = null;
|
||||
//读取旧数据库路径
|
||||
let db2Path: string;
|
||||
if (typeof process.versions?.electron !== "undefined") {
|
||||
const { app } = require("electron");
|
||||
const userDataDir: string = app.getPath("userData");
|
||||
db2Path = path.join(userDataDir, "db2.sqlite");
|
||||
} else {
|
||||
db2Path = path.join(process.cwd(), "db2.sqlite");
|
||||
}
|
||||
const dbDir = path.dirname(db2Path);
|
||||
// 确保数据库目录存在
|
||||
if (!fs.existsSync(dbDir)) {
|
||||
fs.mkdirSync(dbDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(db2Path)) {
|
||||
return res.status(404).send({
|
||||
success: false,
|
||||
message: `源数据库文件不存在: ${db2Path}`
|
||||
});
|
||||
}
|
||||
//连接旧数据库
|
||||
db2 = knex({
|
||||
client: "better-sqlite3",
|
||||
connection: {
|
||||
filename: db2Path,
|
||||
},
|
||||
useNullAsDefault: true,
|
||||
});
|
||||
//需要迁移的旧数据表
|
||||
const db2TableNames = [
|
||||
't_project',
|
||||
't_assets',
|
||||
't_event',
|
||||
't_image',
|
||||
't_novel',
|
||||
't_outline',
|
||||
't_script',
|
||||
't_storyboard',
|
||||
't_video',
|
||||
]
|
||||
//新数据库的表
|
||||
const dbTableNames = [
|
||||
'o_project',
|
||||
'o_assets',
|
||||
'o_event',
|
||||
'o_eventChapter',
|
||||
'o_image',
|
||||
'o_novel',
|
||||
'o_outline',
|
||||
'o_outlineNovel',
|
||||
'o_script',
|
||||
'o_scriptAssets',
|
||||
'o_scriptOutline',
|
||||
'o_storyboard',
|
||||
'o_storyboardScript',
|
||||
'o_video',
|
||||
]
|
||||
|
||||
for (const tableName of db2TableNames) {
|
||||
try {
|
||||
// 从 db2 读取数据
|
||||
const sourceData = await db2(tableName).select('*');
|
||||
for (const item of sourceData) {
|
||||
//迁移项目表
|
||||
if (tableName === 't_project') {
|
||||
// await db("o_project").insert({
|
||||
// name: item.name,
|
||||
// intro: item.intro,
|
||||
// type: item.type,
|
||||
// artStyle: item.artStyle,
|
||||
// videoRatio: item.videoRatio,
|
||||
// createTime: item.createTime,
|
||||
// userId: item.userId,
|
||||
// projectType: "基于小说原文"
|
||||
// })
|
||||
}
|
||||
//迁移资产表
|
||||
if (tableName === 't_assets') {
|
||||
}
|
||||
//迁移事件表
|
||||
if (tableName === 't_event') { }
|
||||
//迁移图片表
|
||||
if (tableName === 't_image') { }
|
||||
//迁移小说表
|
||||
if (tableName === 't_novel') { }
|
||||
//迁移大纲表
|
||||
if (tableName === 't_outline') { }
|
||||
//迁移脚本表
|
||||
if (tableName === 't_script') { }
|
||||
//迁移分镜面板
|
||||
if (tableName === 't_storyboard') { }
|
||||
//迁移视频表
|
||||
if (tableName === 't_video') { }
|
||||
}
|
||||
// // 将数据插入到 db 中
|
||||
// const targetTableName = dbTableNames[db2TableNames.indexOf(tableName)];
|
||||
// await db(targetTableName).insert(sourceData);
|
||||
// console.log(`成功迁移表 ${tableName} 的数据到 ${targetTableName}`);
|
||||
} catch (error) {
|
||||
console.error(`连接旧数据库失败: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('连接旧数据库失败:', error);
|
||||
}
|
||||
return res.status(200).send({
|
||||
success: true,
|
||||
message: '数据迁移功能已关闭,建议手动迁移数据后删除旧数据库文件'
|
||||
});
|
||||
}
|
||||
);
|
||||
@ -12,7 +12,7 @@ export default router.post(
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { modelId } = req.body;
|
||||
const [id, name] = modelId.split(":");
|
||||
const [id, name] = modelId.split(/:(.+)/);
|
||||
const models = await u.vendor.getModelList(id);
|
||||
const findData = models.find((i: any) => i.modelName == name);
|
||||
res.status(200).send(success(findData));
|
||||
|
||||
@ -5,7 +5,6 @@ import sharp from "sharp";
|
||||
import { success } from "@/lib/responseFormat";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
import { Output } from "ai";
|
||||
import { urlToBase64 } from "@/utils/vm";
|
||||
const router = express.Router();
|
||||
|
||||
export default router.post(
|
||||
@ -28,14 +27,6 @@ export default router.post(
|
||||
.leftJoin("o_image", "o_assets.imageId", "o_image.id")
|
||||
.whereIn("o_assets.id", parentIds as number[])
|
||||
.select("o_assets.id", "o_image.filePath", "o_assets.describe");
|
||||
const assetsSrcArr = await Promise.all(
|
||||
parentAssetsData.map(async (item) => {
|
||||
return {
|
||||
src: await u.oss.getFileUrl(item.filePath),
|
||||
id: item.id,
|
||||
};
|
||||
}),
|
||||
);
|
||||
assetsDataArr.forEach((i: any) => {
|
||||
const parent = parentAssetsData.find((item) => item.id === i.assetsId);
|
||||
if (parent) {
|
||||
@ -43,8 +34,8 @@ export default router.post(
|
||||
}
|
||||
});
|
||||
const imageUrlRecord: Record<number, string> = {};
|
||||
assetsSrcArr.forEach((item) => {
|
||||
imageUrlRecord[item.id] = item.src;
|
||||
parentAssetsData.forEach((item) => {
|
||||
if (item.filePath) imageUrlRecord[item.id] = item.filePath;
|
||||
});
|
||||
const rolePrompt = u.getArtPrompt(projectSettingData!.artStyle!, "art_skills", "art_character_derivative");
|
||||
const toolPrompt = u.getArtPrompt(projectSettingData!.artStyle!, "art_skills", "art_prop_derivative");
|
||||
@ -91,8 +82,9 @@ export default router.post(
|
||||
},
|
||||
],
|
||||
});
|
||||
await u.db("o_assets").where("id", item.id).update({ prompt: text });
|
||||
|
||||
const imageBase64 = imageUrlRecord[item.assetsId!] ? await urlToBase64(imageUrlRecord[item.assetsId!]) : null;
|
||||
const imageBase64 = imageUrlRecord[item.assetsId!] ? await u.oss.getImageBase64(imageUrlRecord[item.assetsId!]) : null;
|
||||
try {
|
||||
const repeloadObj = {
|
||||
prompt: text,
|
||||
@ -113,7 +105,6 @@ export default router.post(
|
||||
);
|
||||
const savePath = `/${projectId}/assets/${scriptId}/${item.type}/${u.uuid()}.jpg`;
|
||||
await imageCls.save(savePath);
|
||||
await u.db("o_assets").where("id", item.id).update({ prompt: text });
|
||||
await u.db("o_image").where({ id: imageId }).update({ state: "已完成", filePath: savePath });
|
||||
return {
|
||||
id: item.id!,
|
||||
|
||||
@ -13,6 +13,11 @@ export default router.post(
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { id, projectId } = req.body;
|
||||
const assetsFirstData = await u.db("o_assets").where("id", id).first();
|
||||
if (!assetsFirstData) {
|
||||
return res.status(404).send({ error: "资源未找到" });
|
||||
}
|
||||
if (assetsFirstData?.flowId) await u.db("o_imageFlow").where("id", assetsFirstData?.flowId).delete();
|
||||
await u.db("o_assets").where("id", id).delete();
|
||||
await u.db("o_assets2Storyboard").where("assetId", id).delete();
|
||||
res.status(200).send(success({ message: "视频删除成功" }));
|
||||
|
||||
@ -7,6 +7,9 @@ import axios from "axios";
|
||||
const router = express.Router();
|
||||
|
||||
async function urlToBase64(imageUrl: string): Promise<string> {
|
||||
if (imageUrl.startsWith("/oss/")) {
|
||||
return await u.oss.getImageBase64(u.replaceUrl(imageUrl));
|
||||
}
|
||||
const response = await axios.get(imageUrl, { responseType: "arraybuffer" });
|
||||
const contentType = response.headers["content-type"] || "image/png";
|
||||
const base64 = Buffer.from(response.data, "binary").toString("base64");
|
||||
|
||||
@ -21,6 +21,13 @@ export default router.post(
|
||||
node.data.image = node.data.image ? await u.oss.getFileUrl(node.data.image) : "";
|
||||
} else if (node.type === "generated") {
|
||||
node.data.generatedImage = node.data.generatedImage ? await u.oss.getFileUrl(node.data.generatedImage) : "";
|
||||
console.log("%c Line:25 🍋 node.data.references", "background:#42b983", node.data.references);
|
||||
|
||||
node.data.references = await Promise.all(node.data.references.map(async (item: { image: string }) => {
|
||||
return {
|
||||
image: await u.oss.getFileUrl(item.image)
|
||||
}
|
||||
}));
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
@ -14,12 +14,16 @@ export default router.post(
|
||||
async (req, res) => {
|
||||
const { edges, nodes } = req.body;
|
||||
nodes.forEach((node: any) => {
|
||||
console.log("%c Line:17 🌮 node", "background:#465975", node);
|
||||
if (node.type == "upload") {
|
||||
node.data.image = node.data.image ? u.replaceUrl(node.data.image) : "";
|
||||
}
|
||||
|
||||
if (node.type == "generated") {
|
||||
node.data.generatedImage = node.data.generatedImage ? u.replaceUrl(node.data.generatedImage) : "";
|
||||
node.data.references.forEach((item: { image: string }) => {
|
||||
item.image = item.image ? u.replaceUrl(item.image) : "";
|
||||
});
|
||||
}
|
||||
});
|
||||
const [insertFlowId] = await u.db("o_imageFlow").insert({
|
||||
|
||||
@ -21,6 +21,9 @@ export default router.post(
|
||||
|
||||
if (node.type == "generated") {
|
||||
node.data.generatedImage = node.data.generatedImage ? u.replaceUrl(node.data.generatedImage) : "";
|
||||
node.data.references.forEach((item: { image: string }) => {
|
||||
item.image = item.image ? u.replaceUrl(item.image) : "";
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -86,6 +86,7 @@ export default router.post(
|
||||
} else {
|
||||
try {
|
||||
const storyboardData = await u.db("o_storyboard").where("scriptId", episodesId);
|
||||
|
||||
await Promise.all(
|
||||
storyboardData.map(async (i) => {
|
||||
if (i.filePath) {
|
||||
|
||||
@ -25,7 +25,8 @@ export default router.post(
|
||||
} = req.body;
|
||||
const sqlData = await u.db("o_agentWorkData").where("projectId", String(projectId)).andWhere("episodesId", String(episodesId)).first();
|
||||
const filterDatas = data.storyboard.filter((i) => !i.id);
|
||||
if (data.storyboard && data.storyboard.length && !filterDatas.length)
|
||||
if (data.storyboard && data.storyboard.length && !filterDatas.length) {
|
||||
try {
|
||||
await Promise.all(
|
||||
data.storyboard
|
||||
.filter((i) => i.id)
|
||||
@ -35,6 +36,12 @@ export default router.post(
|
||||
});
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("更新分镜排序失败", error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!sqlData) {
|
||||
await u.db("o_agentWorkData").insert({
|
||||
projectId,
|
||||
|
||||
@ -91,7 +91,7 @@ export default router.post(
|
||||
const storyboardData = await Promise.all(
|
||||
lastStoryboard.map(async (i) => {
|
||||
return {
|
||||
associateAssetsIds: await u.db("o_assets2Storyboard").where("storyboardId", i.id).select("assetId").pluck("assetId"),
|
||||
associateAssetsIds: await u.db("o_assets2Storyboard").where("storyboardId", i.id).orderBy("rowid").select("assetId").pluck("assetId"),
|
||||
src: i.filePath ? await u.oss.getFileUrl(i.filePath) : "",
|
||||
id: i.id,
|
||||
trackId: i.trackId,
|
||||
@ -100,6 +100,7 @@ export default router.post(
|
||||
state: i.state,
|
||||
scriptId: i.scriptId,
|
||||
reason: i.reason,
|
||||
videoDesc: i.videoDesc
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
@ -5,7 +5,6 @@ import sharp from "sharp";
|
||||
import { error, success } from "@/lib/responseFormat";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
import { Output, tool } from "ai";
|
||||
import { urlToBase64 } from "@/utils/vm";
|
||||
import { assetItemSchema } from "@/agents/productionAgent/tools";
|
||||
const router = express.Router();
|
||||
export type AssetData = z.infer<typeof assetItemSchema>;
|
||||
@ -50,18 +49,33 @@ export default router.post(
|
||||
const projectSettingData = await u.db("o_project").where("id", projectId).select("imageModel", "imageQuality", "artStyle", "videoRatio").first();
|
||||
|
||||
const storyboardData = await u.db("o_storyboard").where("scriptId", scriptId).whereIn("id", finalStoryboardIds);
|
||||
const assetData = await u
|
||||
.db("o_assets")
|
||||
.leftJoin("o_assets2Storyboard", "o_assets.id", "o_assets2Storyboard.assetId")
|
||||
.whereIn("o_assets2Storyboard.storyboardId", finalStoryboardIds)
|
||||
.select("o_assets2Storyboard.storyboardId", "o_assets.imageId");
|
||||
// 按 rowid 顺序查出每个 storyboard 关联的 assetId 有序列表
|
||||
const assets2StoryboardRows = await u
|
||||
.db("o_assets2Storyboard")
|
||||
.whereIn("storyboardId", finalStoryboardIds)
|
||||
.orderBy("rowid")
|
||||
.select("storyboardId", "assetId");
|
||||
|
||||
// 收集所有 assetId,批量查对应的 imageId
|
||||
const allAssetIds = [...new Set(assets2StoryboardRows.map((r: any) => r.assetId))];
|
||||
const assetImageMap: Record<number, number> = {};
|
||||
if (allAssetIds.length > 0) {
|
||||
const assetRows = await u.db("o_assets").whereIn("id", allAssetIds).select("id", "imageId");
|
||||
assetRows.forEach((row: any) => {
|
||||
assetImageMap[row.id] = row.imageId;
|
||||
});
|
||||
}
|
||||
|
||||
// 按 rowid 顺序重建 assetRecord,值为有序的 imageId 列表
|
||||
const assetRecord: Record<number, number[]> = {};
|
||||
assetData.forEach((item: any) => {
|
||||
assets2StoryboardRows.forEach((item: any) => {
|
||||
if (!assetRecord[item.storyboardId]) {
|
||||
assetRecord[item.storyboardId] = [];
|
||||
}
|
||||
assetRecord[item.storyboardId].push(item.imageId);
|
||||
const imageId = assetImageMap[item.assetId];
|
||||
if (imageId != null) {
|
||||
assetRecord[item.storyboardId].push(imageId);
|
||||
}
|
||||
});
|
||||
|
||||
res.status(200).send(
|
||||
@ -142,7 +156,7 @@ async function getAssetsImageBase64(imageIds: number[]) {
|
||||
const filePath = id2Path.get(id);
|
||||
if (filePath) {
|
||||
try {
|
||||
return await urlToBase64(await u.oss.getFileUrl(filePath));
|
||||
return await u.oss.getImageBase64(filePath);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -12,8 +12,9 @@ export default router.post(
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { id } = req.body;
|
||||
const storyboardData = await u.db("o_storyboard").where("id", id).select("id", "track", "trackId").first();
|
||||
const storyboardData = await u.db("o_storyboard").where("id", id).select("id", "track", "trackId", "flowId").first();
|
||||
if (!storyboardData) return res.status(400).send(error("未找到该分镜"));
|
||||
if (storyboardData?.flowId) await u.db("o_imageFlow").where("id", storyboardData?.flowId).delete();
|
||||
const trackData = await u.db("o_storyboard").where("track", storyboardData.track).select("id");
|
||||
if (trackData.length == 1) await u.db("o_videoTrack").where("id", storyboardData.trackId).delete();
|
||||
await u.db("o_storyboard").where("id", id).delete();
|
||||
|
||||
@ -13,6 +13,9 @@ export default router.post(
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { projectId, scriptId, duration } = req.body;
|
||||
const data = await u.db("o_project").where("id", projectId).first();
|
||||
const video = data?.videoModel?.split(":");
|
||||
const vemdor = await u.vendor.getModelList(video?.[0]!);
|
||||
const [id] = await u.db("o_videoTrack").insert({
|
||||
projectId,
|
||||
scriptId,
|
||||
|
||||
33
src/routes/production/workbench/checkVideoStateList.ts
Normal file
33
src/routes/production/workbench/checkVideoStateList.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({
|
||||
projectId: z.number(),
|
||||
scriptId: z.number(),
|
||||
videoIds: z.array(z.number()),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { projectId, scriptId, videoIds } = req.body;
|
||||
const videoList = await u
|
||||
.db("o_video")
|
||||
.whereIn("id", videoIds)
|
||||
.whereIn("state", ["生成成功", "生成失败"])
|
||||
.select("id", "state", "errorReason", "filePath");
|
||||
res.status(200).send(
|
||||
success(
|
||||
await Promise.all(
|
||||
videoList.map(async (s) => ({
|
||||
...s,
|
||||
src: s.filePath ? await u.oss.getFileUrl(s.filePath) : "",
|
||||
})),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -13,6 +13,9 @@ export default router.post(
|
||||
async (req, res) => {
|
||||
const { id } = req.body;
|
||||
await u.db("o_videoTrack").where("id", id).delete();
|
||||
await u.db("o_storyboard").where("trackId", id).update({
|
||||
trackId: null,
|
||||
});
|
||||
res.status(200).send(success({ message: "视频段删除成功" }));
|
||||
},
|
||||
);
|
||||
|
||||
@ -117,7 +117,7 @@ export default router.post(
|
||||
.where("id", videoId)
|
||||
.update({
|
||||
state: "生成失败",
|
||||
errorReason: error instanceof Error ? error.message : "未知错误",
|
||||
errorReason: u.error(error).message,
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import express from "express";
|
||||
import u from "@/utils";
|
||||
import { z } from "zod";
|
||||
import { success } from "@/lib/responseFormat";
|
||||
import { success, error } from "@/lib/responseFormat";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
import { info } from "node:console";
|
||||
const router = express.Router();
|
||||
@ -32,7 +32,7 @@ export default router.post(
|
||||
.select("videoDesc", "prompt", "track", "duration", "shouldGenerateImage")
|
||||
.first();
|
||||
// 查询分镜关联的资产ID
|
||||
const assetRows = await u.db("o_assets2Storyboard").where("storyboardId", item.id).select("assetId");
|
||||
const assetRows = await u.db("o_assets2Storyboard").where("storyboardId", item.id).orderBy("rowid").select("assetId");
|
||||
const associateAssetsIds = assetRows.map((row: any) => row.assetId);
|
||||
return {
|
||||
...storyboard,
|
||||
@ -42,7 +42,12 @@ export default router.post(
|
||||
}
|
||||
if (item.sources === "assets") {
|
||||
// 查询素材
|
||||
const assetsData = await u.db("o_assets").leftJoin("o_image","o_image.id","o_assets.imageId").where("o_assets.id", item.id).select("o_assets.id", "o_assets.type", "o_assets.name","o_image.filePath").first();
|
||||
const assetsData = await u
|
||||
.db("o_assets")
|
||||
.leftJoin("o_image", "o_image.id", "o_assets.imageId")
|
||||
.where("o_assets.id", item.id)
|
||||
.select("o_assets.id", "o_assets.type", "o_assets.name", "o_image.filePath")
|
||||
.first();
|
||||
return {
|
||||
...assetsData,
|
||||
_type: "assets", // 标记类型
|
||||
@ -61,7 +66,7 @@ export default router.post(
|
||||
id: item.id,
|
||||
type: item.type,
|
||||
name: item.name,
|
||||
filePath:item.filePath
|
||||
filePath: item.filePath,
|
||||
});
|
||||
if (item._type === "storyboard")
|
||||
storyboard.push({
|
||||
@ -73,7 +78,7 @@ export default router.post(
|
||||
shouldGenerateImage: item.shouldGenerateImage,
|
||||
});
|
||||
}
|
||||
const [id, modelData] = model.split(":");
|
||||
const [id, modelData] = model.split(/:(.+)/);
|
||||
const projectData = await u.db("o_project").select("*").where({ id: projectId }).first();
|
||||
const videoPrompt = await u.db("o_prompt").where("type", "videoPromptGeneration").first();
|
||||
let videoPromptGeneration = "" as string | undefined;
|
||||
@ -86,7 +91,10 @@ export default router.post(
|
||||
const visualManual = u.getArtPrompt(artStyle, "art_skills", "art_storyboard_video");
|
||||
const content = `
|
||||
**模型名称**:${modelData},
|
||||
**资产信息**(角色、场景、道具):${assets.filter(i => i.filePath).map((i) => `[${i.id},${i.type},${i.name}]`).join(",")},
|
||||
**资产信息**(角色、场景、道具):${assets
|
||||
.filter((i) => i.filePath)
|
||||
.map((i) => `[${i.id},${i.type},${i.name}]`)
|
||||
.join(",")},
|
||||
**分镜信息**:${storyboard.map(
|
||||
(i) => `<storyboardItem
|
||||
videoDesc='${i.videoDesc}'
|
||||
@ -94,7 +102,6 @@ export default router.post(
|
||||
></storyboardItem>`,
|
||||
)},
|
||||
`;
|
||||
console.log("%c Line:87 🌮 content", "background:#2eafb0", content);
|
||||
|
||||
try {
|
||||
const { text } = await u.Ai.Text("universalAi").invoke({
|
||||
@ -114,8 +121,8 @@ export default router.post(
|
||||
prompt: text,
|
||||
});
|
||||
res.status(200).send(success(text));
|
||||
} catch (error) {
|
||||
res.status(500).send(error);
|
||||
} catch (e) {
|
||||
res.status(400).send(error(u.error(e).message));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
39
src/routes/production/workbench/getFileUrl.ts
Normal file
39
src/routes/production/workbench/getFileUrl.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import express from "express";
|
||||
import u from "@/utils";
|
||||
import { z } from "zod";
|
||||
import { success } from "@/lib/responseFormat";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
import { id } from "zod/locales";
|
||||
const router = express.Router();
|
||||
|
||||
export default router.post(
|
||||
"/",
|
||||
validateFields({
|
||||
items: z.array(z.object({
|
||||
id: z.number(),
|
||||
sources: z.string()
|
||||
}))
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { items } = req.body;
|
||||
const result: Record<string, string> = {};
|
||||
const storyboardIds = items.filter((item: any) => item.sources == "storyboard").map((item: any) => item.id)
|
||||
const totalFilePaths = []
|
||||
if (storyboardIds.length) {
|
||||
const storyBoardPaths = await u.db("o_storyboard").whereIn("id", storyboardIds).select("id", "filePath");
|
||||
totalFilePaths.push(...storyBoardPaths.map(i => ({ id: i.id, filePath: i.filePath, sources: "storyboard" })))
|
||||
}
|
||||
const assetsIds = items.filter((item: any) => item.sources == "assets").map((item: any) => item.id)
|
||||
if (assetsIds.length) {
|
||||
const assetsPaths = await u.db("o_assets").leftJoin("o_image", "o_image.id", "o_assets.imageId").whereIn("o_assets.id", assetsIds).select("o_assets.id", "o_image.filePath");
|
||||
totalFilePaths.push(...assetsPaths.map(i => ({ id: i.id, filePath: i.filePath, sources: "assets" })))
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
totalFilePaths.map(async (item: { id: string, filePath: string, sources: string }) => {
|
||||
result[`${item.id}:${item.sources}`] = item.filePath ? await u.oss.getFileUrl(item.filePath) : "";
|
||||
}))
|
||||
|
||||
res.status(200).send(success({ data: result }));
|
||||
},
|
||||
);
|
||||
@ -37,14 +37,18 @@ export default router.post(
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { projectId, scriptId } = req.body;
|
||||
const projectData = await u.db("o_project").where("id", projectId).select("id", "videoModel").first();
|
||||
const projectData = await u.db("o_project").where("id", projectId).select("id", "videoModel", "mode").first();
|
||||
|
||||
if (!projectData?.videoModel) {
|
||||
return res.status(400).json(success("项目未配置视频模型"));
|
||||
}
|
||||
const [videoId, videoModelName] = projectData.videoModel.split(":");
|
||||
const models = await u.vendor.getModelList(videoId);
|
||||
const findData = models.find((i: any) => i.modelName == videoModelName);
|
||||
const isRef = findData.mode.every((i: any) => Array.isArray(i));
|
||||
let videoMode = "";
|
||||
try {
|
||||
videoMode = JSON.parse(projectData?.mode ?? "");
|
||||
} catch (e) {
|
||||
videoMode = projectData?.mode ?? "";
|
||||
}
|
||||
const isRef = Array.isArray(videoMode) ? true : false;
|
||||
|
||||
const storyboardList = await u.db("o_storyboard").where({ scriptId, projectId }).orderBy("index", "asc");
|
||||
await Promise.all(
|
||||
@ -105,7 +109,6 @@ export default router.post(
|
||||
);
|
||||
}
|
||||
|
||||
const id = await u.db("o_project").where({ id: projectId }).select("id").first();
|
||||
const trackData = await u.db("o_videoTrack").where({ projectId, scriptId });
|
||||
const videoList = await u.db("o_video").whereIn(
|
||||
"videoTrackId",
|
||||
@ -131,8 +134,8 @@ export default router.post(
|
||||
seenAssetIds.add(a.id);
|
||||
return true;
|
||||
});
|
||||
const hasImageAssetData = uniqueAssets.filter(i => i.src)
|
||||
const notHasImageAssetData = uniqueAssets.filter(i => !i.src)
|
||||
const hasImageAssetData = uniqueAssets.filter((i) => i.src);
|
||||
const notHasImageAssetData = uniqueAssets.filter((i) => !i.src);
|
||||
|
||||
return [...hasImageAssetData, ...storyboardMedias, ...notHasImageAssetData];
|
||||
})(),
|
||||
@ -143,6 +146,7 @@ export default router.post(
|
||||
id: v.id!,
|
||||
src: v.filePath ? await u.oss.getFileUrl(v.filePath) : "",
|
||||
state: v.state === "已完成" ? "已完成" : v.state === "生成中" ? "生成中" : v.state === "生成失败" ? "生成失败" : "未生成",
|
||||
errorReason: v?.errorReason ?? "",
|
||||
})),
|
||||
),
|
||||
});
|
||||
|
||||
20
src/routes/production/workbench/updateVideoDuration.ts
Normal file
20
src/routes/production/workbench/updateVideoDuration.ts
Normal file
@ -0,0 +1,20 @@
|
||||
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(),
|
||||
duration: z.number().optional(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { id, duration } = req.body;
|
||||
await u.db("o_videoTrack").where("id", id).update({
|
||||
duration,
|
||||
});
|
||||
res.status(200).send(success("更新成功"));
|
||||
},
|
||||
);
|
||||
@ -9,13 +9,11 @@ export default router.post(
|
||||
validateFields({
|
||||
id: z.number(),
|
||||
prompt: z.string().optional(),
|
||||
duration: z.number().optional(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { id, prompt, duration } = req.body;
|
||||
await u.db("o_videoTrack").where("id", id).update({
|
||||
prompt,
|
||||
duration,
|
||||
});
|
||||
res.status(200).send(success("更新成功"));
|
||||
},
|
||||
|
||||
@ -18,9 +18,6 @@ export default router.post(
|
||||
await u.db("o_agentWorkData").where("projectId", id).delete();
|
||||
const novelData = await u.db("o_novel").where("projectId", id).select("id");
|
||||
const novelId = novelData.map((item: any) => item.id);
|
||||
if (novelId.length > 0) {
|
||||
await u.db("o_outlineNovel").whereIn("novelId", novelId).delete();
|
||||
}
|
||||
//删除项目下的原文
|
||||
await u.db("o_novel").where("projectId", id).delete();
|
||||
// 删除项目下的剧本信息
|
||||
|
||||
22
src/routes/project/getModelDetails.ts
Normal file
22
src/routes/project/getModelDetails.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import express from "express";
|
||||
import { success, error } from "@/lib/responseFormat";
|
||||
import u from "@/utils";
|
||||
import { z } from "zod";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
const router = express.Router();
|
||||
|
||||
export default router.post(
|
||||
"/",
|
||||
validateFields({
|
||||
key: z.enum(["scriptAgent", "productionAgent"]),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { key } = req.body;
|
||||
const data = await u.db("o_agentDeploy").select("o_agentDeploy.*").where("o_agentDeploy.key", key).first();
|
||||
const [id, modelName] = data ? data.modelName.split(/:(.+)/) : [];
|
||||
const models = await u.vendor.getModelList(id);
|
||||
const model = models.find((m) => m.modelName === modelName);
|
||||
if (!model) return res.status(400).send(error("未找到模型"));
|
||||
res.status(200).send(success(model));
|
||||
},
|
||||
);
|
||||
35
src/routes/script/getAiRegex.ts
Normal file
35
src/routes/script/getAiRegex.ts
Normal file
@ -0,0 +1,35 @@
|
||||
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({
|
||||
content: z.string(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { content } = req.body;
|
||||
const systemPrompt = `你是一个正则表达式专家。用户会提供一段剧本文本,你需要分析其中的集/章节分隔模式,返回一个JavaScript正则表达式字符串。
|
||||
|
||||
要求:
|
||||
1. 正则必须包含两个捕获组:第一个捕获组匹配集数/章节编号(数字或中文数字),第二个捕获组匹配该集的标题/名称(scriptName)。
|
||||
2. 返回格式为 /正则表达式/g,例如:/第\s*([0-9一二三四五六七八九十百千万]+)\s*集\s*([^\n\r]*)/g
|
||||
3. 只返回正则表达式字符串本身,不要有任何其他解释文字或markdown格式。
|
||||
4. 如果文本中没有明显的章节分隔模式,返回空字符串。`;
|
||||
|
||||
const resText = await u.Ai.Text("universalAi").invoke({
|
||||
system: systemPrompt,
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: content.slice(0, 2000),
|
||||
},
|
||||
],
|
||||
});
|
||||
const result = (resText.text || "").trim();
|
||||
res.status(200).send(success(result));
|
||||
},
|
||||
);
|
||||
@ -25,22 +25,8 @@ export default router.post(
|
||||
const zip = await axios.get(url, { responseType: "arraybuffer" }).then((res) => res.data);
|
||||
fs.writeFileSync(`${rootDir}/latest.zip`, zip);
|
||||
await compressing.zip.uncompress(`${rootDir}/latest.zip`, rootDir);
|
||||
const tempServerPath = u.getPath(["temp", "serve"]);
|
||||
if (fs.existsSync(tempServerPath)) {
|
||||
fs.cpSync(tempServerPath, u.getPath(["serve"]), { recursive: true, force: true });
|
||||
}
|
||||
const webPath = u.getPath(["temp", "web"]);
|
||||
if (fs.existsSync(webPath)) {
|
||||
fs.cpSync(webPath, u.getPath(["web"]), { recursive: true, force: true });
|
||||
}
|
||||
const tempSkillsPath = u.getPath(["temp", "skills"]);
|
||||
if (fs.existsSync(tempSkillsPath)) {
|
||||
fs.cpSync(tempSkillsPath, u.getPath(["skills"]), { recursive: true, force: true });
|
||||
}
|
||||
const tempModelsPath = u.getPath(["temp", "models"]);
|
||||
if (fs.existsSync(tempModelsPath)) {
|
||||
fs.cpSync(tempModelsPath, u.getPath(["models"]), { recursive: true, force: true });
|
||||
}
|
||||
const dataDir = u.getPath();
|
||||
fs.cpSync(rootDir, dataDir, { recursive: true, force: true });
|
||||
fs.rmSync(rootDir, { recursive: true, force: true });
|
||||
res.status(200).send(success(`更新${version}成功,5秒后重启`));
|
||||
}
|
||||
|
||||
@ -14,10 +14,12 @@ export default router.post(
|
||||
modelName: z.string(),
|
||||
vendorId: z.string().nullable(),
|
||||
desc: z.string(),
|
||||
temperature: z.number().optional(),
|
||||
maxOutputTokens: z.number().optional(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { id, name, model, modelName, vendorId, desc } = req.body;
|
||||
await u.db("o_agentDeploy").where({ id }).update({ id, name, model, modelName, vendorId, desc });
|
||||
const { id, name, model, modelName, vendorId, desc, temperature, maxOutputTokens } = req.body;
|
||||
await u.db("o_agentDeploy").where({ id }).update({ id, name, model, modelName, vendorId, desc, temperature, maxOutputTokens });
|
||||
res.status(200).send(success("配置成功"));
|
||||
},
|
||||
);
|
||||
|
||||
@ -4,6 +4,8 @@ import u from "@/utils";
|
||||
const router = express.Router();
|
||||
|
||||
export default router.post("/", async (req, res) => {
|
||||
const data = await u.db("o_agentDeploy").leftJoin("o_vendorConfig", "o_vendorConfig.id", "o_agentDeploy.vendorId").select("o_agentDeploy.*");
|
||||
res.status(200).send(success(data));
|
||||
const allData = await u.db("o_agentDeploy").leftJoin("o_vendorConfig", "o_vendorConfig.id", "o_agentDeploy.vendorId").select("o_agentDeploy.*");
|
||||
const qrdinaryData = allData.filter((item: any) => !item.key?.includes(":"));
|
||||
const advancedData = allData.filter((item: any) => item.key?.includes(":"));
|
||||
res.status(200).send(success({ qrdinaryData, advancedData }));
|
||||
});
|
||||
|
||||
29
src/routes/setting/dbConfig/clearTable.ts
Normal file
29
src/routes/setting/dbConfig/clearTable.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import express from "express";
|
||||
import { success, error } from "@/lib/responseFormat";
|
||||
import { db } from "@/utils/db";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
export default router.post("/", async (req, res) => {
|
||||
try {
|
||||
const { tableName } = req.body;
|
||||
if (!tableName || typeof tableName !== "string") {
|
||||
return res.status(400).send(error("请提供有效的表名"));
|
||||
}
|
||||
|
||||
// 验证表名存在(防止SQL注入)
|
||||
const tableExists: { name: string }[] = await db.raw(
|
||||
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
|
||||
[tableName],
|
||||
);
|
||||
if (tableExists.length === 0) {
|
||||
return res.status(400).send(error("表不存在"));
|
||||
}
|
||||
|
||||
await db.raw(`DELETE FROM "${tableName}"`);
|
||||
|
||||
res.status(200).send(success(`表 ${tableName} 已清空`));
|
||||
} catch (err: any) {
|
||||
res.status(500).send(error(err?.message || "清空表失败"));
|
||||
}
|
||||
});
|
||||
26
src/routes/setting/dbConfig/dbInfo.ts
Normal file
26
src/routes/setting/dbConfig/dbInfo.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import express from "express";
|
||||
import { success, error } from "@/lib/responseFormat";
|
||||
import { db } from "@/utils/db";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
export default router.get("/", async (req, res) => {
|
||||
try {
|
||||
const tables: { name: string }[] = await db.raw(
|
||||
`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'knex_%'`,
|
||||
);
|
||||
|
||||
const tableInfo = [];
|
||||
for (const table of tables) {
|
||||
const countResult = await db.raw(`SELECT COUNT(*) as count FROM "${table.name}"`);
|
||||
tableInfo.push({
|
||||
name: table.name,
|
||||
rowCount: countResult[0]?.count ?? 0,
|
||||
});
|
||||
}
|
||||
|
||||
res.status(200).send(success(tableInfo));
|
||||
} catch (err: any) {
|
||||
res.status(500).send(error(err?.message || "获取数据库信息失败"));
|
||||
}
|
||||
});
|
||||
29
src/routes/setting/dbConfig/exportData.ts
Normal file
29
src/routes/setting/dbConfig/exportData.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import express from "express";
|
||||
import { success, error } from "@/lib/responseFormat";
|
||||
import { db } from "@/utils/db";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
export default router.get("/", async (req, res) => {
|
||||
try {
|
||||
const tables: { name: string }[] = await db.raw(
|
||||
`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'knex_%'`,
|
||||
);
|
||||
|
||||
const data: Record<string, any[]> = {};
|
||||
for (const table of tables) {
|
||||
data[table.name] = await db.raw(`SELECT * FROM "${table.name}"`);
|
||||
}
|
||||
|
||||
const exportData = {
|
||||
exportTime: Date.now(),
|
||||
tables: data,
|
||||
};
|
||||
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.setHeader("Content-Disposition", `attachment; filename=toonflow-backup-${Date.now()}.json`);
|
||||
res.status(200).send(JSON.stringify(exportData, null, 2));
|
||||
} catch (err: any) {
|
||||
res.status(500).send(error(err?.message || "导出失败"));
|
||||
}
|
||||
});
|
||||
55
src/routes/setting/dbConfig/importData.ts
Normal file
55
src/routes/setting/dbConfig/importData.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import express from "express";
|
||||
import { success, error } from "@/lib/responseFormat";
|
||||
import { db } from "@/utils/db";
|
||||
import initDB from "@/lib/initDB";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
export default router.post("/", async (req, res) => {
|
||||
try {
|
||||
const { tables: importTables } = req.body;
|
||||
if (!importTables || typeof importTables !== "object") {
|
||||
return res.status(400).send(error("无效的导入数据格式"));
|
||||
}
|
||||
|
||||
// 删除所有现有表
|
||||
const existingTables: { name: string }[] = await db.raw(
|
||||
`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'knex_%'`,
|
||||
);
|
||||
|
||||
await db.raw("PRAGMA foreign_keys = OFF");
|
||||
for (const table of existingTables) {
|
||||
await db.schema.dropTableIfExists(table.name);
|
||||
}
|
||||
await db.raw("PRAGMA foreign_keys = ON");
|
||||
|
||||
// 重新初始化表结构
|
||||
await initDB(db as any);
|
||||
|
||||
// 导入数据
|
||||
await db.raw("PRAGMA foreign_keys = OFF");
|
||||
for (const [tableName, rows] of Object.entries(importTables)) {
|
||||
if (!Array.isArray(rows) || rows.length === 0) continue;
|
||||
|
||||
// 验证表名合法性(防止SQL注入)
|
||||
const tableExists = await db.raw(
|
||||
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
|
||||
[tableName],
|
||||
);
|
||||
if (tableExists.length === 0) continue;
|
||||
|
||||
// 清空表数据后插入导入数据
|
||||
await db.raw(`DELETE FROM "${tableName}"`);
|
||||
// 分批插入,每批100条
|
||||
for (let i = 0; i < rows.length; i += 100) {
|
||||
const batch = rows.slice(i, i + 100);
|
||||
await db(tableName).insert(batch);
|
||||
}
|
||||
}
|
||||
await db.raw("PRAGMA foreign_keys = ON");
|
||||
|
||||
res.status(200).send(success("数据库导入成功"));
|
||||
} catch (err: any) {
|
||||
res.status(500).send(error(err?.message || "导入失败"));
|
||||
}
|
||||
});
|
||||
26
src/routes/setting/modelMap/bindingPrompt.ts
Normal file
26
src/routes/setting/modelMap/bindingPrompt.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import express from "express";
|
||||
import { error, success } from "@/lib/responseFormat";
|
||||
import u from "@/utils";
|
||||
import { z } from "zod";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
const router = express.Router();
|
||||
|
||||
export default router.post(
|
||||
"/",
|
||||
validateFields({
|
||||
vendorId: z.string(),
|
||||
model: z.string(),
|
||||
prompt: z.string(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { vendorId, model, prompt } = req.body;
|
||||
const data = await u.db("o_modelPrompt").where("model", model).andWhere("vendorId", vendorId).select("*").first();
|
||||
if (data) {
|
||||
await u.db("o_modelPrompt").where("model", model).andWhere("vendorId", vendorId).update({ prompt });
|
||||
res.status(200).send(success("绑定成功"));
|
||||
} else {
|
||||
await u.db("o_modelPrompt").insert({ vendorId, model, prompt });
|
||||
res.status(200).send(success("绑定成功"));
|
||||
}
|
||||
},
|
||||
);
|
||||
33
src/routes/setting/modelMap/getImageAndVideoModel.ts
Normal file
33
src/routes/setting/modelMap/getImageAndVideoModel.ts
Normal file
@ -0,0 +1,33 @@
|
||||
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 dataList = await u.db("o_vendorConfig").select("id").where("enable", 1);
|
||||
if (!dataList || dataList.length === 0) {
|
||||
return res.status(404).send({ error: "模型未找到" });
|
||||
}
|
||||
const data = await Promise.all(
|
||||
dataList.map(async (item) => {
|
||||
const vendor = u.vendor.getVendor(item.id!);
|
||||
const promptList = await u.db("o_modelPrompt").andWhere("vendorId", vendor.id).select("*");
|
||||
const promptMap = new Map(promptList.map((p) => [p.model, p.prompt]));
|
||||
const models = await u.vendor.getModelList(item.id!);
|
||||
const filteredModels = models
|
||||
.filter((m: any) => m.type === "video")
|
||||
.map((m: any) => ({
|
||||
name: m.name,
|
||||
type: m.type as "image" | "video",
|
||||
model: m.modelName,
|
||||
prompt: promptMap.get(m.modelName) ?? "",
|
||||
}));
|
||||
return {
|
||||
id: item.id,
|
||||
name: vendor.name,
|
||||
promptList: filteredModels,
|
||||
};
|
||||
}),
|
||||
);
|
||||
res.status(200).send(success(data));
|
||||
});
|
||||
@ -41,6 +41,11 @@ export default (nsp: Namespace) => {
|
||||
});
|
||||
let abortController: AbortController | null = null;
|
||||
|
||||
const thinkConfig: agent.AgentContext["thinkConfig"] = {
|
||||
think: false,
|
||||
thinlLevel: 0,
|
||||
};
|
||||
|
||||
socket.on("updateContext", (data: { isolationKey: string; projectId: number; scriptId: number }, callback) => {
|
||||
isolationKey = data.isolationKey;
|
||||
resTool = new ResTool(socket, {
|
||||
@ -66,52 +71,14 @@ export default (nsp: Namespace) => {
|
||||
abortSignal: currentController.signal,
|
||||
resTool,
|
||||
msg,
|
||||
thinkConfig,
|
||||
};
|
||||
|
||||
try {
|
||||
const textStream = await agent.decisionAI(ctx);
|
||||
|
||||
let currentMsg = ctx.msg;
|
||||
let text = currentMsg.text();
|
||||
|
||||
const syncCurrentMessage = () => {
|
||||
if (ctx.msg === currentMsg) return;
|
||||
text.complete();
|
||||
currentMsg.complete();
|
||||
currentMsg = ctx.msg;
|
||||
text = currentMsg.text();
|
||||
};
|
||||
|
||||
let aborted = false;
|
||||
try {
|
||||
for await (const chunk of textStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
syncCurrentMessage();
|
||||
text.append(chunk);
|
||||
}
|
||||
} catch (err: any) {
|
||||
if (err.name === "AbortError" || currentController.signal.aborted) {
|
||||
aborted = true;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
syncCurrentMessage();
|
||||
if (aborted) {
|
||||
text.append("[已停止]");
|
||||
text.complete();
|
||||
currentMsg.stop();
|
||||
} else {
|
||||
text.complete();
|
||||
currentMsg.complete();
|
||||
}
|
||||
}
|
||||
await agent.runDecisionAI(ctx);
|
||||
} catch (err: any) {
|
||||
if (err.name !== "AbortError" && !currentController.signal.aborted) {
|
||||
const errorMsg = u.error(err).message;
|
||||
console.error("[productionAgent] chat error:", errorMsg);
|
||||
ctx.msg.text(errorMsg).complete();
|
||||
ctx.msg.error();
|
||||
console.error("[productionAgent] chat error:", u.error(err).message);
|
||||
}
|
||||
} finally {
|
||||
if (abortController === currentController) {
|
||||
@ -120,6 +87,12 @@ export default (nsp: Namespace) => {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("updateThinkConfig", (data: { think: boolean; thinlLevel: 0 | 1 | 2 | 3 }) => {
|
||||
thinkConfig.think = data.think;
|
||||
thinkConfig.thinlLevel = data.thinlLevel;
|
||||
console.log("[productionAgent] 更新思考配置:", thinkConfig);
|
||||
});
|
||||
|
||||
socket.on("stop", () => {
|
||||
abortController?.abort();
|
||||
abortController = null;
|
||||
|
||||
@ -40,6 +40,11 @@ export default (nsp: Namespace) => {
|
||||
});
|
||||
let abortController: AbortController | null = null;
|
||||
|
||||
const thinkConfig: agent.AgentContext["thinkConfig"] = {
|
||||
think: false,
|
||||
thinlLevel: 0,
|
||||
};
|
||||
|
||||
socket.on("chat", async (data: { content: string }) => {
|
||||
const { content } = data;
|
||||
abortController?.abort();
|
||||
@ -55,51 +60,14 @@ export default (nsp: Namespace) => {
|
||||
abortSignal: currentController.signal,
|
||||
resTool,
|
||||
msg,
|
||||
thinkConfig,
|
||||
};
|
||||
|
||||
try {
|
||||
const textStream = await agent.decisionAI(ctx);
|
||||
|
||||
let currentMsg = ctx.msg;
|
||||
let text = currentMsg.text();
|
||||
|
||||
const syncCurrentMessage = () => {
|
||||
if (ctx.msg === currentMsg) return;
|
||||
text.complete();
|
||||
currentMsg.complete();
|
||||
currentMsg = ctx.msg;
|
||||
text = currentMsg.text();
|
||||
};
|
||||
|
||||
let aborted = false;
|
||||
try {
|
||||
for await (const chunk of textStream) {
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1));
|
||||
syncCurrentMessage();
|
||||
text.append(chunk);
|
||||
}
|
||||
} catch (err: any) {
|
||||
if (err.name === "AbortError" || currentController.signal.aborted) {
|
||||
aborted = true;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
syncCurrentMessage();
|
||||
if (aborted) {
|
||||
text.complete();
|
||||
currentMsg.stop();
|
||||
} else {
|
||||
text.complete();
|
||||
currentMsg.complete();
|
||||
}
|
||||
}
|
||||
await agent.runDecisionAI(ctx);
|
||||
} catch (err: any) {
|
||||
if (err.name !== "AbortError" && !currentController.signal.aborted) {
|
||||
const errorMsg = u.error(err).message;
|
||||
console.error("[scriptAgent] chat error:", errorMsg);
|
||||
ctx.msg.text(errorMsg).complete();
|
||||
ctx.msg.error();
|
||||
console.error("[scriptAgent] chat error:", u.error(err).message);
|
||||
}
|
||||
} finally {
|
||||
if (abortController === currentController) {
|
||||
@ -108,6 +76,12 @@ export default (nsp: Namespace) => {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("updateThinkConfig", (data: { think: boolean; thinlLevel: 0 | 1 | 2 | 3 }) => {
|
||||
thinkConfig.think = data.think;
|
||||
thinkConfig.thinlLevel = data.thinlLevel;
|
||||
console.log("[scriptAgent] 更新思考配置:", thinkConfig);
|
||||
});
|
||||
|
||||
socket.on("stop", () => {
|
||||
abortController?.abort();
|
||||
abortController = null;
|
||||
|
||||
13
src/types/database.d.ts
vendored
13
src/types/database.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
// @db-hash 9248d7bcfe0a1bc57e5b9bc33d8c7d83
|
||||
// @db-hash 88c167ba73e2771e7b043419ca5089dd
|
||||
//该文件由脚本自动生成,请勿手动修改
|
||||
|
||||
export interface memories {
|
||||
@ -18,9 +18,12 @@ export interface o_agentDeploy {
|
||||
'disabled'?: boolean | null;
|
||||
'id'?: number;
|
||||
'key'?: string | null;
|
||||
'maxOutputTokens'?: number | null;
|
||||
'model'?: string | null;
|
||||
'modelName'?: string | null;
|
||||
'name'?: string | null;
|
||||
'temperature'?: number | null;
|
||||
'type'?: string | null;
|
||||
'vendorId'?: string | null;
|
||||
}
|
||||
export interface o_agentWorkData {
|
||||
@ -88,6 +91,12 @@ export interface o_imageFlow {
|
||||
'flowData': string;
|
||||
'id'?: number;
|
||||
}
|
||||
export interface o_modelPrompt {
|
||||
'id'?: number;
|
||||
'model'?: string | null;
|
||||
'prompt'?: string | null;
|
||||
'vendorId'?: string | null;
|
||||
}
|
||||
export interface o_novel {
|
||||
'chapter'?: string | null;
|
||||
'chapterData'?: string | null;
|
||||
@ -201,6 +210,7 @@ export interface o_user {
|
||||
'password'?: string | null;
|
||||
}
|
||||
export interface o_vendorConfig {
|
||||
'code'?: string | null;
|
||||
'enable'?: number | null;
|
||||
'id'?: string;
|
||||
'inputValues'?: string | null;
|
||||
@ -240,6 +250,7 @@ export interface DB {
|
||||
"o_eventChapter": o_eventChapter;
|
||||
"o_image": o_image;
|
||||
"o_imageFlow": o_imageFlow;
|
||||
"o_modelPrompt": o_modelPrompt;
|
||||
"o_novel": o_novel;
|
||||
"o_outline": o_outline;
|
||||
"o_outlineNovel": o_outlineNovel;
|
||||
|
||||
122
src/utils/ai.ts
122
src/utils/ai.ts
@ -4,26 +4,82 @@ import axios from "axios";
|
||||
import { transform } from "sucrase";
|
||||
import u from "@/utils";
|
||||
|
||||
type AiType = "scriptAgent" | "productionAgent" | "universalAi";
|
||||
type AiType =
|
||||
| "scriptAgent"
|
||||
| "productionAgent"
|
||||
| "universalAi"
|
||||
| "scriptAgent:decisionAgent"
|
||||
| "scriptAgent:supervisionAgent"
|
||||
| "scriptAgent:storySkeletonAgent"
|
||||
| "scriptAgent:adaptationStrategyAgent"
|
||||
| "scriptAgent:scriptAgent"
|
||||
| "productionAgent:decisionAgent"
|
||||
| "productionAgent:supervisionAgent"
|
||||
| "productionAgent:deriveAssetsAgent"
|
||||
| "productionAgent:generateAssetsAgent"
|
||||
| "productionAgent:directorPlanAgent"
|
||||
| "productionAgent:storyboardGenAgent"
|
||||
| "productionAgent:storyboardPanelAgent"
|
||||
| "productionAgent:storyboardTableAgent";
|
||||
|
||||
type FnName = "textRequest" | "imageRequest" | "videoRequest" | "ttsRequest";
|
||||
|
||||
const AiTypeValues: AiType[] = ["scriptAgent", "productionAgent", "universalAi"];
|
||||
const AiTypeValues: AiType[] = [
|
||||
"scriptAgent",
|
||||
"productionAgent",
|
||||
"universalAi",
|
||||
"scriptAgent:decisionAgent",
|
||||
"scriptAgent:supervisionAgent",
|
||||
"scriptAgent:storySkeletonAgent",
|
||||
"scriptAgent:adaptationStrategyAgent",
|
||||
"scriptAgent:scriptAgent",
|
||||
"productionAgent:decisionAgent",
|
||||
"productionAgent:supervisionAgent",
|
||||
"productionAgent:deriveAssetsAgent",
|
||||
"productionAgent:generateAssetsAgent",
|
||||
"productionAgent:directorPlanAgent",
|
||||
"productionAgent:storyboardGenAgent",
|
||||
"productionAgent:storyboardPanelAgent",
|
||||
"productionAgent:storyboardTableAgent",
|
||||
"universalAi",
|
||||
];
|
||||
async function resolveModelName(value: AiType | `${string}:${string}`): Promise<`${string}:${string}`> {
|
||||
if (AiTypeValues.includes(value as AiType)) {
|
||||
const agentDeployData = await u.db("o_agentDeploy").where("key", value).first();
|
||||
if (!agentDeployData?.modelName) throw new Error(`${value}模型未配置`);
|
||||
return agentDeployData.modelName as `${number}:${string}`;
|
||||
let modelName = null;
|
||||
if (!agentDeployData?.modelName) {
|
||||
const [mainly] = agentDeployData!.key!.split(/:(.+)/);
|
||||
const mainlyData = await u.db("o_agentDeploy").where("key", mainly).first();
|
||||
if (!mainlyData?.modelName) throw new Error(`未找到部署配置 ${value}`);
|
||||
modelName = mainlyData.modelName;
|
||||
}
|
||||
modelName = agentDeployData?.modelName || modelName;
|
||||
return modelName as `${number}:${string}`;
|
||||
}
|
||||
return value as `${number}:${string}`;
|
||||
}
|
||||
|
||||
async function getModelConfig(value: AiType | `${string}:${string}`) {
|
||||
if (AiTypeValues.includes(value as AiType)) {
|
||||
const agentDeployData = await u.db("o_agentDeploy").where("key", value).first();
|
||||
if (!agentDeployData?.modelName) {
|
||||
const [mainly] = agentDeployData!.key!.split(/:(.+)/);
|
||||
const mainlyData = await u.db("o_agentDeploy").where("key", mainly).first();
|
||||
if (!mainlyData?.modelName) throw new Error(`未找到部署配置 ${value}`);
|
||||
return mainlyData;
|
||||
}
|
||||
return agentDeployData;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function getVendorTemplateFn(
|
||||
fnName: "textRequest",
|
||||
modelName: `${string}:${string}`,
|
||||
): Promise<(think?: boolean, thinkLevel?: 0 | 1 | 2 | 3) => any>;
|
||||
async function getVendorTemplateFn(fnName: Exclude<FnName, "textRequest">, modelName: `${string}:${string}`): Promise<(input: any) => any>;
|
||||
async function getVendorTemplateFn(fnName: FnName, modelName: `${string}:${string}`): Promise<any> {
|
||||
const [id, name] = modelName.split(":");
|
||||
const [id, name] = modelName.split(/:(.+)/);
|
||||
const vendorConfigData = await u.db("o_vendorConfig").where("id", id).first();
|
||||
if (!vendorConfigData) throw new Error(`未找到供应商配置 id=${id}`);
|
||||
const modelList = await u.vendor.getModelList(id);
|
||||
@ -55,7 +111,7 @@ async function withTaskRecord<T>(
|
||||
fn: (modelName: `${string}:${string}`, think: Boolean, thinkLevel: 0 | 1 | 2 | 3) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const modelName = await resolveModelName(modelKey);
|
||||
const [id, model] = modelName.split(":");
|
||||
const [_, model] = modelName.split(/:(.+)/);
|
||||
const taskRecord = await u.task(projectId, taskClass, model, { describe: describe, content: relatedObjects });
|
||||
try {
|
||||
const result = await fn(modelName, false, 0);
|
||||
@ -89,46 +145,37 @@ class AiText {
|
||||
this.think = think;
|
||||
this.thinkLevel = thinkLevel;
|
||||
}
|
||||
async invoke(input: Omit<Parameters<typeof generateText>[0], "model">) {
|
||||
private async resolveModel(middleware?: any | any[]) {
|
||||
const switchAiDevTool = await u.db("o_setting").where("key", "switchAiDevTool").first();
|
||||
const modelName = await resolveModelName(this.AiType);
|
||||
const sdkFn = await getVendorTemplateFn("textRequest", modelName);
|
||||
const baseModel = await sdkFn(this.think, this.thinkLevel);
|
||||
const mws = [
|
||||
...(switchAiDevTool?.value === "1" ? [devToolsMiddleware()] : []),
|
||||
...(middleware ? (Array.isArray(middleware) ? middleware : [middleware]) : []),
|
||||
];
|
||||
return mws.length > 0 ? wrapLanguageModel({ model: baseModel, middleware: mws.length === 1 ? mws[0] : mws }) : baseModel;
|
||||
}
|
||||
async invoke(input: Omit<Parameters<typeof generateText>[0], "model">) {
|
||||
const config = await getModelConfig(this.AiType);
|
||||
|
||||
return generateText({
|
||||
...(input.tools && { stopWhen: stepCountIs(Object.keys(input.tools).length * 50) }),
|
||||
...input,
|
||||
model:
|
||||
switchAiDevTool?.value === "1"
|
||||
? wrapLanguageModel({
|
||||
model: await sdkFn(this.think, this.thinkLevel),
|
||||
middleware: devToolsMiddleware(),
|
||||
})
|
||||
: await sdkFn(this.think, this.thinkLevel),
|
||||
model: await this.resolveModel(),
|
||||
...(config?.temperature && { temperature: config.temperature }),
|
||||
...(config?.maxOutputTokens && { maxOutputTokens: config.maxOutputTokens }),
|
||||
} as Parameters<typeof generateText>[0]);
|
||||
}
|
||||
async stream(input: Omit<Parameters<typeof streamText>[0], "model">) {
|
||||
const switchAiDevTool = await u.db("o_setting").where("key", "switchAiDevTool").first();
|
||||
const modelName = await resolveModelName(this.AiType);
|
||||
const sdkFn = await getVendorTemplateFn("textRequest", modelName);
|
||||
const config = await getModelConfig(this.AiType);
|
||||
|
||||
return streamText({
|
||||
...(input.tools && { stopWhen: stepCountIs(Object.keys(input.tools).length * 50) }),
|
||||
...input,
|
||||
model:
|
||||
switchAiDevTool?.value == "1"
|
||||
? wrapLanguageModel({
|
||||
model: sdkFn(this.think, this.thinkLevel),
|
||||
middleware: [
|
||||
devToolsMiddleware(),
|
||||
extractReasoningMiddleware({
|
||||
tagName: "reasoning_content",
|
||||
}),
|
||||
],
|
||||
})
|
||||
: wrapLanguageModel({
|
||||
model: sdkFn(this.think, this.thinkLevel),
|
||||
middleware: extractReasoningMiddleware({
|
||||
tagName: "reasoning_content",
|
||||
}),
|
||||
}),
|
||||
model: await this.resolveModel(extractReasoningMiddleware({ tagName: "reasoning_content", separator: "\n" })),
|
||||
...(config?.temperature && { temperature: config.temperature }),
|
||||
...(config?.maxOutputTokens && { maxOutputTokens: config.maxOutputTokens }),
|
||||
} as Parameters<typeof streamText>[0]);
|
||||
}
|
||||
}
|
||||
@ -168,7 +215,7 @@ class AiImage {
|
||||
const modelName = await resolveModelName(this.key);
|
||||
const exec = async (mn: `${string}:${string}`) => {
|
||||
const fn = await getVendorTemplateFn("imageRequest", mn);
|
||||
await referenceList2imageBase642(mn.split(":")[0], input);
|
||||
await referenceList2imageBase642(mn.split(/:(.+)/)[0], input);
|
||||
this.result = await fn(input);
|
||||
if (this.result.startsWith("http")) this.result = await urlToBase64(this.result);
|
||||
return this;
|
||||
@ -212,7 +259,8 @@ class AiVideo {
|
||||
const modelName = await resolveModelName(this.key);
|
||||
const exec = async (mn: `${string}:${string}`) => {
|
||||
const fn = await getVendorTemplateFn("videoRequest", mn);
|
||||
await referenceList2imageBase642(mn.split(":")[0], input);
|
||||
await referenceList2imageBase642(mn.split(/:(.+)/)[0], input);
|
||||
|
||||
this.result = await fn(input);
|
||||
if (this.result.startsWith("http")) this.result = await urlToBase64(this.result);
|
||||
return this;
|
||||
@ -237,7 +285,7 @@ class AiAudio {
|
||||
const modelName = await resolveModelName(this.key);
|
||||
const exec = async (mn: `${string}:${string}`) => {
|
||||
const fn = await getVendorTemplateFn("ttsRequest", mn);
|
||||
await referenceList2imageBase642(mn.split(":")[0], input);
|
||||
await referenceList2imageBase642(mn.split(/:(.+)/)[0], input);
|
||||
this.result = await fn(input);
|
||||
if (this.result.startsWith("http")) this.result = await urlToBase64(this.result);
|
||||
return this;
|
||||
|
||||
@ -50,7 +50,9 @@ class OSS {
|
||||
await this.ensureInit();
|
||||
const safePath = normalizeUserPath(userRelPath);
|
||||
// URL 始终使用 /,所以这里需要将系统分隔符转回 /
|
||||
let url = `http://127.0.0.1:10588/${prefix}/`;
|
||||
let url = `/${prefix}/`;
|
||||
if (process.env.ossURL && process.env.ossURL !== "") url = process.env.ossURL + `/${prefix}/`;
|
||||
if (process.env.NODE_ENV == "dev") url = `http://localhost:10588/${prefix}/`;
|
||||
if (isEletron()) url = `http://localhost:${process.env.PORT}/${prefix}/`;
|
||||
return `${url}${safePath.split(path.sep).join("/")}`;
|
||||
}
|
||||
|
||||
@ -54,8 +54,8 @@ export default function runCode(code: string, vendor?: Record<string, any>) {
|
||||
|
||||
return exports as Record<string, any>;
|
||||
}
|
||||
export function logger(logstring: string) {
|
||||
console.log("【VM】" + logstring);
|
||||
export function logger(logstring: any) {
|
||||
console.log("【VM】" + JSON.stringify(logstring));
|
||||
}
|
||||
/**
|
||||
* 压缩图片,目标字节数不高于 size
|
||||
|
||||
@ -1338,10 +1338,10 @@ basic-auth@~2.0.1:
|
||||
dependencies:
|
||||
safe-buffer "5.1.2"
|
||||
|
||||
better-sqlite3@^12.8.0:
|
||||
version "12.8.0"
|
||||
resolved "https://registry.npmmirror.com/better-sqlite3/-/better-sqlite3-12.8.0.tgz#ec9ccd4a426a35f3b9355c147af6c92a6ddd6862"
|
||||
integrity sha512-RxD2Vd96sQDjQr20kdP+F+dK/1OUNiVOl200vKBZY8u0vTwysfolF6Hq+3ZK2+h8My9YvZhHsF+RSGZW2VYrPQ==
|
||||
better-sqlite3@^12.9.0:
|
||||
version "12.9.0"
|
||||
resolved "https://registry.npmmirror.com/better-sqlite3/-/better-sqlite3-12.9.0.tgz#32498c99ba3fb36f604fbb5c70667c5f68c00414"
|
||||
integrity sha512-wqUv4Gm3toFpHDQmaKD4QhZm3g1DjUBI0yzS4UBl6lElUmXFYdTQmmEDpAFa5o8FiFiymURypEnfVHzILKaxqQ==
|
||||
dependencies:
|
||||
bindings "^1.5.0"
|
||||
prebuild-install "^7.1.1"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user