From 7c10411c15011f3ffe49edacda3b161b317552aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E5=B8=85?= <2944435683>
Date: Tue, 31 Mar 2026 21:52:00 +0800
Subject: [PATCH 1/4] no message
---
src/routes/project/deleteVisualManual.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/routes/project/deleteVisualManual.ts b/src/routes/project/deleteVisualManual.ts
index eeeb8c6..5d35333 100644
--- a/src/routes/project/deleteVisualManual.ts
+++ b/src/routes/project/deleteVisualManual.ts
@@ -15,7 +15,6 @@ export default router.post(
async (req, res) => {
try {
const { name } = req.body as { name: string };
- console.log("%c Line:18 🍓 name", "background:#2eafb0", name);
// 安全校验:不允许包含路径分隔符、纯数字,防止越级删除或误删项目目录
if (name.includes("/") || name.includes("\\") || name === "." || name === ".." || /^\d+$/.test(name)) {
From a53ff46de2926f39a94b200e4592f44d6bd2b962 Mon Sep 17 00:00:00 2001
From: zhishi <1951671751@qq.com>
Date: Tue, 31 Mar 2026 22:30:43 +0800
Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=88=86=E9=95=9C?=
=?UTF-8?q?=E8=A1=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
data/skills/production_agent_decision.md | 226 +-----------------
src/agents/productionAgent/index.ts | 2 +-
src/agents/scriptAgent/index.ts | 2 +-
src/agents/scriptAgent/tools.ts | 7 +-
src/lib/initDB.ts | 13 +-
.../production/editImage/saveImageFlow.ts | 4 +-
src/routes/production/getFlowData.ts | 25 +-
src/routes/production/getStoryboardData.ts | 9 -
.../storyboard/batchAddStoryboardInfo.ts | 60 ++++-
.../storyboard/getStoryboardData.ts | 5 -
src/types/database.d.ts | 78 ++++--
11 files changed, 131 insertions(+), 300 deletions(-)
diff --git a/data/skills/production_agent_decision.md b/data/skills/production_agent_decision.md
index 6c23eaa..7e6f519 100644
--- a/data/skills/production_agent_decision.md
+++ b/data/skills/production_agent_decision.md
@@ -1,223 +1,3 @@
-# 决策层 Agent 技能指令
-
-你是视频制作项目的**决策层 Agent**,**只负责决策和任务派发**:理解用户意图、拆解任务、调度执行层与监督层、把控质量。
-你是唯一与用户直接对接的 Agent,执行层和监督层只接收你派发的指令。
-
-**核心原则:**
-- **决策层不执行具体任务**,不读取工作区数据(不调用 get_flowData),不直接操作任何资产或分镜数据。所有具体工作由执行层完成。
-- **决策层不做执行层的判断**,执行层返回什么结论就基于该结论决策下一步。
-
-## 核心职责
-
-1. **需求分析**:解析用户请求,判断属于流水线哪个阶段
-2. **任务拆解**:将复杂请求分解为可执行的子任务
-3. **调度执行**:通过 `run_sub_agent_execution` 派发任务到执行层
-4. **质量管控**:通过 `run_sub_agent_supervision` 调用监督层审核产出物
-5. **记忆检索**:通过 `deepRetrieve` 获取历史上下文和项目进度记忆
-
----
-
-## 制作流水线
-
-五个阶段**必须按顺序执行**:
-
-```
-阶段1: 衍生资产分析 → 阶段2: 衍生资产生成(可选) → 阶段3: 导演规划 → 阶段4: 构建分镜表 → 阶段5: 生成分镜
-```
-
-### 全局约束
-
-- **资产约束**:阶段3、4、5 只能使用资产库中已存在的资产(含阶段1已写入的衍生资产)
-- **异步操作**:阶段2的图片生成、阶段5的分镜图片生成均为异步操作,派发后告知用户等待即可
-- **审核规则**:仅阶段3(导演规划)和阶段4(构建分镜表)需要审核,执行完毕后自动派发监督层
-
----
-
-### 阶段1:衍生资产分析
-
-| 项 | 说明 |
-|----|------|
-| 派发 | 执行层分析剧本,识别并写入衍生资产信息 |
-| 输出 | 衍生资产分析报告 + 衍生资产写入结果(或"无需衍生"结论) |
-| 前置条件 | 剧本和资产已存在于工作区 |
-| 审核 | 不需要 |
-
-**决策层行为:**
-
-| 执行层返回 | 决策层操作 |
-|-----------|-----------|
-| "不需要衍生资产" | 向用户简要告知,直接进入阶段3 |
-| 衍生资产清单(已写入) | 展示给用户,询问是否确认生成图片 |
-
-**用户确认分支(仅有新增资产时):**
-
-| 用户反馈 | 操作 |
-|----------|------|
-| 确认全部生成 | 进入阶段2 |
-| 部分生成 | 将用户选择的子集传递给阶段2 |
-| 跳过 | 直接进入阶段3,告知后续仅使用现有资产 |
-| 调整清单 | 重新派发分析或将调整后清单传递给阶段2 |
-
-> 约束:阶段1必须完成衍生资产信息写入;分析结果需展示给用户确认是否进入图片生成,且不可自动进入阶段2。
-
----
-
-### 阶段2:衍生资产生成(可选)
-
-| 项 | 说明 |
-|----|------|
-| 派发 | 执行层对已写入的衍生资产生成图片 |
-| 输入 | 用户确认需要生成图片的衍生资产清单(来自阶段1) |
-| 输出 | 图片生成启动 |
-| 前置条件 | 阶段1完成且用户确认生成 |
-| 审核 | 不需要 |
-
-**决策层行为:** 将用户确认的资产清单(或子集)派发给执行层。返回确认后,告知用户图片生成中,直接进入阶段3。
-
----
-
-### 阶段3:导演规划
-
-| 项 | 说明 |
-|----|------|
-| 派发 | 执行层制定导演拍摄计划 |
-| 输出 | 导演拍摄计划(执行层通过 set_plane 同步到前端) |
-| 质量门 | 计划覆盖全部剧情、节奏合理、与资产匹配 |
-| 前置条件 | 阶段1完成(含跳过阶段2的情况) |
-| 审核 | **需要** → 执行完毕后自动派发监督层 |
-
-**阶段特有约束:** 规划中引用的角色、道具、场景必须在资产列表中存在。
-
----
-
-### 阶段4:构建分镜表
-
-| 项 | 说明 |
-|----|------|
-| 派发 | 执行层将剧本拆分为分镜,生成结构化分镜表 |
-| 输出 | 结构化分镜表(执行层通过 set_flowData 保存) |
-| 质量门 | 分镜拆分粒度合理、字段完整、关联资产正确 |
-| 前置条件 | 阶段3(导演规划)完成 |
-| 审核 | **需要** → 执行完毕后自动派发监督层 |
-
-**阶段特有约束:** `associateAssetsIds` 中的索引必须指向资产库中实际存在的资产。
-
----
-
-### 阶段5:生成分镜
-
-| 项 | 说明 |
-|----|------|
-| 派发 | 执行层调用图片生成接口生成分镜图片 |
-| 输出 | 生成的分镜图片 |
-| 前置条件 | 阶段4完成且用户确认 |
-| 审核 | 不需要 |
-
-**决策层行为:** 执行层返回确认后,告知用户图片生成已启动,流程结束。
-
----
-
-## 调度与派发规范
-
-### 派发指令要求
-
-**派发给执行层和监督层的任务指令正文严格不超过100字。** 执行层已具备完整技能指令,只需告知任务类型和关键参数。
-
-### 执行层派发
-
-使用 `run_sub_agent_execution` 调用执行层:
-
-```
-run_sub_agent_execution(
- prompts: "<按模板构建的具体指令>"
-)
-```
-
-### 审核派发与结果处理
-
-阶段3或阶段4执行完毕后:
-1. 将执行层返回的确认消息展示给用户
-2. **紧接着自动调用监督层审核**(无需等待用户指示)
-
-```
-run_sub_agent_supervision(
- prompts: "请审核【{阶段名}】的产出物。审核维度:{维度列表}"
-)
-```
-
-监督层审核完毕后将报告展示给用户。决策层**等待用户回复**,根据反馈操作:
-
-| 用户反馈 | 操作 |
-|----------|------|
-| 通过 / 下一阶段 | 派发下一阶段任务 |
-| 需要修复 | 根据用户指示构建修复指令,派发执行层 |
-| 重做 | 重新派发当前阶段任务 |
-
-### 调度决策树
-
-| 用户请求 | 处理规则 |
-|----------|----------|
-| 明确指定阶段 | 检查前置条件 → 派发该阶段 |
-| "从头开始" / "完整制作" | 从阶段1顺序执行 |
-| "继续" / "下一步" | `deepRetrieve` 获取进度 → 从当前阶段继续 |
-| "修改/优化 X" | 定位对应阶段 → 派发修改任务 |
-| 模糊请求 | `deepRetrieve` 获取进度 → 从当前阶段继续 |
-
----
-
-## 指令模板
-
-### 执行派发格式
-
-```
-你是执行层Agent,请执行【{任务类型}】任务。
-目标:{一句话目标}
-上下文:{必要数据摘要}
-要求:
-1. {具体步骤1}
-2. {具体步骤2}
-约束:{特殊约束条件}
-```
-
-### 修复派发格式
-
-```
-你是执行层Agent,请修复【{任务类型}】的以下问题。
-用户确认的修复项:
-1. {问题} → 修改为:{方案}
-保持其余内容不变。
-```
-
-> 修复指令中只包含用户明确确认要修的项,不包含用户未回应或跳过的问题。
-
----
-
-## 记忆检索策略
-
-在以下场景使用 `deepRetrieve`:
-1. **新会话开始**:检索项目当前进度、已完成阶段
-2. **用户提到之前的内容**:检索相关历史产出摘要
-3. **质量问题追溯**:检索之前的审核结果和修改记录
-4. **判断前置条件**:检索各阶段是否已完成
-
-> `deepRetrieve` 用于检索历史记忆和进度状态,不用于读取工作区当前数据。
-
----
-
-## 与用户交互规范
-
-1. **进度汇报**:每完成一个阶段,汇报结果摘要和下一步计划
-2. **审核结果展示**:阶段3、4由监督层审核后展示报告,等待用户反馈
-3. **等待用户决策**:审核发现问题时,**必须等待用户明确指示**后再执行修复,不可自行决定
-4. **不暴露内部机制**:不向用户提及 Agent 名称、工具名称等实现细节
-
----
-
-## 错误处理
-
-| 场景 | 处理 |
-|------|------|
-| 执行层返回错误 | 分析原因,调整指令重新派发(最多重试2次) |
-| 监督层发现质量问题 | 等待用户确认修复方案 → 派发修复指令 |
-| 前置条件不满足 | 提示用户需先完成哪个阶段 |
-| 记忆检索无结果 | 请求用户提供必要上下文 |
+你是一个测试流程助手,你专门生成假数据:
+你必须使用XML格式写入工作区分镜面板:
+现在请根据哟用户指令直接输出xml假数据
diff --git a/src/agents/productionAgent/index.ts b/src/agents/productionAgent/index.ts
index 082c430..3f1bbae 100644
--- a/src/agents/productionAgent/index.ts
+++ b/src/agents/productionAgent/index.ts
@@ -138,7 +138,7 @@ function createSubAgent(parentCtx: AgentContext) {
"你必须使用如下XML格式写入工作区:\n```",
"拍摄计划:内容",
"分镜表:内容",
- "分镜面板: ",
+ "分镜面板: ",
"```",
].join("\n");
// "剧本:",
diff --git a/src/agents/scriptAgent/index.ts b/src/agents/scriptAgent/index.ts
index b0b1c5a..f705382 100644
--- a/src/agents/scriptAgent/index.ts
+++ b/src/agents/scriptAgent/index.ts
@@ -176,7 +176,7 @@ function createSubAgent(parentCtx: AgentContext) {
prompt,
system:
systemPrompt +
- `\n你必须使用如下XML格式写入工作区:\nXML不得添加任何额外标签剧本内容剧本内容剧本内容`,
+ `\n你必须使用如下XML格式写入工作区:\nXML不得添加任何额外标签剧本内容- 剧本内容
- 剧本内容
`,
name: "编剧",
memoryKey: "assistant:execution:script",
});
diff --git a/src/agents/scriptAgent/tools.ts b/src/agents/scriptAgent/tools.ts
index 2a267e4..2950ed6 100644
--- a/src/agents/scriptAgent/tools.ts
+++ b/src/agents/scriptAgent/tools.ts
@@ -11,6 +11,7 @@ export const ScriptSchema = z.object({
export const planData = z.object({
storySkeleton: z.string().describe("故事骨架"),
adaptationStrategy: z.string().describe("改编策略"),
+ script: z.string().describe("剧本内容"),
});
export type planData = z.infer;
@@ -60,12 +61,10 @@ export default (toolCpnfig: ToolConfig) => {
console.log("[tools] get_planData", key);
const thinking = msg.thinking(`正在获取${planDataKeyLabels[key]}工作区数据...`);
const planData: planData = await new Promise((resolve) => socket.emit("getPlanData", { key }, (res: any) => resolve(res)));
- const value = planData[key];
- const valueStr = typeof value === "object" ? JSON.stringify(value, null, 2) : String(value ?? "");
- thinking.appendText(`获取到${planDataKeyLabels[key]}:\n` + valueStr);
+ thinking.appendText(`获取到${planDataKeyLabels[key]}:\n` + planData[key]);
thinking.updateTitle(`获取${planDataKeyLabels[key]}完成`);
thinking.complete();
- return valueStr || "无数据";
+ return planData[key] ?? "无数据";
},
}),
get_novel_text: tool({
diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts
index cf28c09..e1a344b 100644
--- a/src/lib/initDB.ts
+++ b/src/lib/initDB.ts
@@ -480,22 +480,13 @@ description: 专注于从剧本内容中提取所使用的资产(角色、场
builder: (table) => {
table.integer("id").notNullable();
table.integer("scriptId");
- table.text("title");
table.text("prompt");
- table.text("videoPrompt");
- table.text("description");
table.text("filePath");
- table.text("model");
- table.text("mode");
table.text("duration");
- table.text("resolution");
- table.text("frameMode");
- table.text("camera");
- table.text("sound");
- table.text("lines");
table.text("state");
- table.text("group");
+ table.integer("trackId");
table.text("reason");
+ table.integer("projectId");
table.integer("index");
table.integer("createTime");
table.primary(["id"]);
diff --git a/src/routes/production/editImage/saveImageFlow.ts b/src/routes/production/editImage/saveImageFlow.ts
index 46fba9a..544afdd 100644
--- a/src/routes/production/editImage/saveImageFlow.ts
+++ b/src/routes/production/editImage/saveImageFlow.ts
@@ -14,9 +14,10 @@ export default router.post(
id: z.number().nullable().optional(),
type: z.enum(["role", "scene", "storyboard", "clip", "tool"]),
episodesId: z.number(),
+ projectId: z.number(),
}),
async (req, res) => {
- const { edges, nodes, imageUrl, id, type, episodesId } = req.body;
+ const { edges, nodes, imageUrl, id, type, episodesId, projectId } = req.body;
let imagePath = "";
try {
imagePath = new URL(imageUrl).pathname;
@@ -59,6 +60,7 @@ export default router.post(
filePath: imagePath,
scriptId: episodesId,
createTime: Date.now(),
+ projectId,
});
insertFlowId = storyboardId;
}
diff --git a/src/routes/production/getFlowData.ts b/src/routes/production/getFlowData.ts
index 46a859d..f42d068 100644
--- a/src/routes/production/getFlowData.ts
+++ b/src/routes/production/getFlowData.ts
@@ -73,24 +73,7 @@ export default router.post(
storyboard: [],
//todo:矫正workbench数据
workbench: {
- videoList: [
- {
- id: 1,
- prompt: "动起来",
- filePath: await u.oss.getFileUrl("/artStyle/5d96256a-1610-43a6-a469-c2385cc2287e.jpg"),
- duration: 4,
- scriptId: 1,
- selectedVideoId: 1,
- },
- {
- id: 2,
- prompt: "跳起来",
- filePath: await u.oss.getFileUrl("/artStyle/5d96256a-1610-43a6-a469-c2385cc2287e.jpg"),
- duration: 4,
- scriptId: 1,
- selectedVideoId: 1,
- },
- ],
+ videoList: [],
},
//todo:矫正封面数据
poster: {
@@ -178,14 +161,8 @@ export default router.post(
...existing,
id: i.id,
index: i.index,
- title: i.title,
- description: i.description,
- camera: i.camera,
duration: i.duration ? +i.duration : 0,
- frameMode: i.frameMode,
prompt: i.prompt,
- lines: i.lines,
- sound: i.sound,
associateAssetsIds: assets2StoryboardMap[i.id!] ?? [],
src: i.filePath,
state: i.state,
diff --git a/src/routes/production/getStoryboardData.ts b/src/routes/production/getStoryboardData.ts
index b307380..62466a6 100644
--- a/src/routes/production/getStoryboardData.ts
+++ b/src/routes/production/getStoryboardData.ts
@@ -17,7 +17,6 @@ export default router.post(
storyboardData.map(async (i) => {
return {
...i,
- title: i.title,
filePath: i.filePath ? await u.oss.getFileUrl(i.filePath!) : "",
};
}),
@@ -66,19 +65,11 @@ export default router.post(
);
return {
id: String(item.id),
- camera: item.camera ? Number(item.camera) : undefined,
createTime: item.createTime ?? undefined,
- description: item.description ?? undefined,
duration: item.duration ? Number(item.duration) : undefined,
filePath: item.filePath || undefined,
- frameMode: item.frameMode ? Number(item.frameMode) : undefined,
- mode: item.mode ?? "",
- model: item.model ?? "",
prompt: item.prompt ?? undefined,
- resolution: item.resolution ?? undefined,
scriptId: item.scriptId ?? undefined,
- sound: item.sound ? Number(item.sound) : undefined,
- title: item.title ?? undefined,
characters: charactersWithUrl,
};
}),
diff --git a/src/routes/production/storyboard/batchAddStoryboardInfo.ts b/src/routes/production/storyboard/batchAddStoryboardInfo.ts
index 64fba53..f238cd2 100644
--- a/src/routes/production/storyboard/batchAddStoryboardInfo.ts
+++ b/src/routes/production/storyboard/batchAddStoryboardInfo.ts
@@ -1,10 +1,17 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
-import { success } from "@/lib/responseFormat";
+import { error, success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
-
+interface Storyboard {
+ id: number;
+ track: string;
+ src: string | null;
+ associateAssetsIds: number[];
+ duration: number;
+ state: string;
+}
export default router.post(
"/",
validateFields({
@@ -12,24 +19,25 @@ export default router.post(
z.object({
prompt: z.string(),
duration: z.number(),
- group: z.number(),
+ track: z.string(),
state: z.string(),
src: z.string().nullable(),
associateAssetsIds: z.array(z.number()),
}),
),
scriptId: z.number(),
+ projectId: z.number(),
}),
async (req, res) => {
- const { data, scriptId } = req.body;
+ const { data, scriptId, projectId } = req.body;
if (!data.length) return res.status(400).send({ success: false, message: "数据不能为空" });
for (const item of data) {
const [id] = await u.db("o_storyboard").insert({
prompt: item.prompt,
duration: String(item.duration),
- group: String(item.group),
state: item.state,
scriptId,
+ projectId,
createTime: Date.now(),
});
if (item.associateAssetsIds?.length) {
@@ -40,8 +48,46 @@ export default router.post(
})),
);
}
+ item.id = id;
}
- const lastStoryboard = await u.db("o_storyboard").where("scriptId", scriptId);
- return res.status(200).send(success(lastStoryboard));
+ //根据track分组
+ const storyboardGroupByTrack: Record = {};
+ data.forEach((item: any) => {
+ if (!storyboardGroupByTrack[item.track]) {
+ storyboardGroupByTrack[item.track] = [];
+ }
+ storyboardGroupByTrack[item.track].push(item.id);
+ });
+
+ //循环
+ for (const track in storyboardGroupByTrack) {
+ const [trackId] = await u.db("o_videoTrack").insert({
+ scriptId,
+ projectId,
+ });
+ const storyboardIds = storyboardGroupByTrack[track] ?? [];
+ await u.db("o_storyboard").whereIn("id", storyboardIds).update({ trackId });
+ }
+ const lastStoryboard = await u
+ .db("o_storyboard")
+ .where("scriptId", scriptId)
+ .select("id", "trackId", "prompt", "duration", "state", "scriptId", "reason", "filePath");
+ if (!lastStoryboard || !lastStoryboard.length) return res.status(400).send(error("为查到分镜数据"));
+ const storyboardData = await Promise.all(
+ lastStoryboard.map(async (i) => {
+ return {
+ associateAssetsIds: await u.db("o_assets2Storyboard").where("storyboardId", i.id).select("assetId").pluck("assetId"),
+ src: i.filePath ? await u.oss.getFileUrl(i.filePath) : "",
+ id: i.id,
+ trackId: i.trackId,
+ prompt: i.prompt,
+ duration: Number(i.duration),
+ state: i.state,
+ scriptId: i.scriptId,
+ reason: i.reason,
+ };
+ }),
+ );
+ return res.status(200).send(success(storyboardData));
},
);
diff --git a/src/routes/production/storyboard/getStoryboardData.ts b/src/routes/production/storyboard/getStoryboardData.ts
index 6a90c68..4125257 100644
--- a/src/routes/production/storyboard/getStoryboardData.ts
+++ b/src/routes/production/storyboard/getStoryboardData.ts
@@ -31,12 +31,7 @@ export default router.post(
storyboardData.map(async (i: any) => {
return {
id: i.id,
- title: i.title,
prompt: i.prompt,
- description: i.description,
- camera: i.camera,
- lines: i.lines,
- sound: i.sound,
state: i.state,
src: i.filePath ? await u.oss.getFileUrl(i.filePath!) : "",
};
diff --git a/src/types/database.d.ts b/src/types/database.d.ts
index 6635502..6d8457b 100644
--- a/src/types/database.d.ts
+++ b/src/types/database.d.ts
@@ -1,6 +1,49 @@
-// @db-hash c2029b55b7dcdcf64788dafc34799fea
+// @db-hash c145f43374602285beea82bbd51eaec8
//该文件由脚本自动生成,请勿手动修改
+export interface _o_storyboard_old_20260331 {
+ 'camera'?: string | null;
+ 'createTime'?: number | null;
+ 'description'?: string | null;
+ 'duration'?: string | null;
+ 'filePath'?: string | null;
+ 'frameMode'?: string | null;
+ 'id'?: number;
+ 'index'?: number | null;
+ 'lines'?: string | null;
+ 'mode'?: string | null;
+ 'model'?: string | null;
+ 'prompt'?: string | null;
+ 'reason'?: string | null;
+ 'resolution'?: string | null;
+ 'scriptId'?: number | null;
+ 'sound'?: string | null;
+ 'state'?: string | null;
+ 'title'?: string | null;
+ 'videoPrompt'?: string | null;
+}
+export interface _o_storyboard_old_20260331_1 {
+ 'camera'?: string | null;
+ 'createTime'?: number | null;
+ 'description'?: string | null;
+ 'duration'?: string | null;
+ 'filePath'?: string | null;
+ 'frameMode'?: string | null;
+ 'id'?: number;
+ 'index'?: number | null;
+ 'lines'?: string | null;
+ 'mode'?: string | null;
+ 'model'?: string | null;
+ 'prompt'?: string | null;
+ 'reason'?: string | null;
+ 'resolution'?: string | null;
+ 'scriptId'?: number | null;
+ 'sound'?: string | null;
+ 'state'?: string | null;
+ 'title'?: string | null;
+ 'track'?: string | null;
+ 'videoPrompt'?: string | null;
+}
export interface memories {
'content': string;
'createTime': number;
@@ -114,7 +157,6 @@ export interface o_project {
'imageModel'?: string | null;
'imageQuality'?: string | null;
'intro'?: string | null;
- 'mode'?: string | null;
'name'?: string | null;
'projectType'?: string | null;
'type'?: string | null;
@@ -162,26 +204,17 @@ export interface o_skillList {
'updateTime': number;
}
export interface o_storyboard {
- 'camera'?: string | null;
'createTime'?: number | null;
- 'description'?: string | null;
'duration'?: string | null;
'filePath'?: string | null;
- 'frameMode'?: string | null;
- 'group'?: string | null;
'id'?: number;
'index'?: number | null;
- 'lines'?: string | null;
- 'mode'?: string | null;
- 'model'?: string | null;
+ 'projectId'?: number | null;
'prompt'?: string | null;
'reason'?: string | null;
- 'resolution'?: string | null;
'scriptId'?: number | null;
- 'sound'?: string | null;
'state'?: string | null;
- 'title'?: string | null;
- 'videoPrompt'?: string | null;
+ 'trackId'?: number | null;
}
export interface o_tasks {
'describe'?: string | null;
@@ -218,8 +251,22 @@ export interface o_video {
'projectId'?: number | null;
'scriptId'?: number | null;
'state'?: string | null;
+ 'storyboardId'?: number | null;
'time'?: number | null;
- 'videoTrackId'?: number | null;
+}
+export interface o_videoConfig {
+ 'audio'?: number | null;
+ 'createTime'?: number | null;
+ 'data'?: string | null;
+ 'duration'?: number | null;
+ 'id'?: number;
+ 'mode'?: string | null;
+ 'model'?: string | null;
+ 'prompt'?: string | null;
+ 'resolution'?: string | null;
+ 'storyboardId'?: number | null;
+ 'updateTime'?: number | null;
+ 'videoId'?: number | null;
}
export interface o_videoTrack {
'id'?: number;
@@ -229,6 +276,8 @@ export interface o_videoTrack {
}
export interface DB {
+ "_o_storyboard_old_20260331": _o_storyboard_old_20260331;
+ "_o_storyboard_old_20260331_1": _o_storyboard_old_20260331_1;
"memories": memories;
"o_agentDeploy": o_agentDeploy;
"o_agentWorkData": o_agentWorkData;
@@ -254,5 +303,6 @@ export interface DB {
"o_user": o_user;
"o_vendorConfig": o_vendorConfig;
"o_video": o_video;
+ "o_videoConfig": o_videoConfig;
"o_videoTrack": o_videoTrack;
}
From 2e4f78eae15c4e39f363eca3f3f5923f29223174 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E5=B8=85?= <2944435683>
Date: Tue, 31 Mar 2026 22:46:17 +0800
Subject: [PATCH 3/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=B5=84=E4=BA=A7?=
=?UTF-8?q?=E7=94=9F=E6=88=90=E5=A4=B1=E8=B4=A5=E5=8E=9F=E5=9B=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/lib/initDB.ts | 2 ++
src/routes/assets/getAssetsApi.ts | 2 +-
.../batchGenerateImageAssets.ts | 5 +++-
.../assetsGenerate/batchPolishAssetsPrompt.ts | 9 ++++--
src/routes/assetsGenerate/generateAssets.ts | 5 +++-
.../assetsGenerate/polishAssetsPrompt.ts | 4 +++
src/routes/cornerScape/getAllAssets.ts | 5 ++--
src/types/database.d.ts | 29 ++++++++++++++++++-
8 files changed, 53 insertions(+), 8 deletions(-)
diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts
index cf28c09..c66a7e2 100644
--- a/src/lib/initDB.ts
+++ b/src/lib/initDB.ts
@@ -453,6 +453,7 @@ description: 专注于从剧本内容中提取所使用的资产(角色、场
table.integer("projectId");
table.integer("startTime");
table.string("promptState");
+ table.text("promptErrorReason");
table.primary(["id"]);
table.unique(["id"]);
},
@@ -469,6 +470,7 @@ description: 专注于从剧本内容中提取所使用的资产(角色、场
table.text("model");
table.text("resolution");
table.text("state");
+ table.text("errorReason");
table.text("reason");
table.primary(["id"]);
table.unique(["id"]);
diff --git a/src/routes/assets/getAssetsApi.ts b/src/routes/assets/getAssetsApi.ts
index 8910fbe..c3d95b1 100644
--- a/src/routes/assets/getAssetsApi.ts
+++ b/src/routes/assets/getAssetsApi.ts
@@ -34,7 +34,7 @@ export default router.post(
let childQuery = u
.db("o_assets")
.leftJoin("o_image", "o_assets.imageId", "o_image.id")
- .select("o_assets.*", "o_image.filePath", "o_image.state")
+ .select("o_assets.*", "o_image.filePath", "o_image.state", "o_image.errorReason")
.where("o_assets.projectId", projectId)
.andWhere("o_assets.type", type)
.whereNotNull("o_assets.assetsId");
diff --git a/src/routes/assetsGenerate/batchGenerateImageAssets.ts b/src/routes/assetsGenerate/batchGenerateImageAssets.ts
index 55e4e30..9cd1094 100644
--- a/src/routes/assetsGenerate/batchGenerateImageAssets.ts
+++ b/src/routes/assetsGenerate/batchGenerateImageAssets.ts
@@ -142,7 +142,10 @@ export default router.post("/", validateFields(requestSchema), async (req, res)
await u.db("o_assets").where("id", item.id).update({ imageId });
} catch (e: any) {
- await u.db("o_image").where("id", imageId).update({ state: "生成失败" });
+ await u
+ .db("o_image")
+ .where("id", imageId)
+ .update({ state: "生成失败", errorReason: u.error(e).message });
}
}),
);
diff --git a/src/routes/assetsGenerate/batchPolishAssetsPrompt.ts b/src/routes/assetsGenerate/batchPolishAssetsPrompt.ts
index 1738e99..72c9c07 100644
--- a/src/routes/assetsGenerate/batchPolishAssetsPrompt.ts
+++ b/src/routes/assetsGenerate/batchPolishAssetsPrompt.ts
@@ -127,13 +127,18 @@ export default router.post(
await u.db("o_assets").where("id", item.assetsId).update({ prompt: _output, promptState: "已完成" });
} catch (e: any) {
- await u.db("o_assets").where("id", item.assetsId).update({ promptState: "生成失败" });
+ await u
+ .db("o_assets")
+ .where("id", item.assetsId)
+ .update({ promptState: "失败", promptErrorReason: u.error(e).message });
}
}),
);
// 后台执行,不等待结果
- Promise.all(tasks).catch(() => {});
+ Promise.all(tasks).catch((err: any) => {
+ res.status(500).send(error(err));
+ });
return res.status(200).send(success({ total: items.length }));
},
diff --git a/src/routes/assetsGenerate/generateAssets.ts b/src/routes/assetsGenerate/generateAssets.ts
index 830c536..1c32f5d 100644
--- a/src/routes/assetsGenerate/generateAssets.ts
+++ b/src/routes/assetsGenerate/generateAssets.ts
@@ -134,7 +134,10 @@ export default router.post("/", validateFields(requestSchema), async (req, res)
return res.status(200).send(success({ path, assetsId: id }));
} catch (e) {
- await u.db("o_image").where("id", imageId).update({ state: "生成失败" });
+ await u
+ .db("o_image")
+ .where("id", imageId)
+ .update({ state: "生成失败", errorReason: u.error(e).message });
return res.status(400).send(error(u.error(e).message || "图片生成失败"));
}
});
diff --git a/src/routes/assetsGenerate/polishAssetsPrompt.ts b/src/routes/assetsGenerate/polishAssetsPrompt.ts
index c02decc..438af1e 100644
--- a/src/routes/assetsGenerate/polishAssetsPrompt.ts
+++ b/src/routes/assetsGenerate/polishAssetsPrompt.ts
@@ -110,6 +110,10 @@ export default router.post(
res.status(200).send(success({ prompt: _output, assetsId }));
} catch (e: any) {
+ await u
+ .db("o_assets")
+ .where("id", assetsId)
+ .update({ promptState: "失败", promptErrorReason: u.error(e).message });
return res.status(500).send(error(e?.data?.error?.message ?? e?.message ?? "生成失败"));
}
},
diff --git a/src/routes/cornerScape/getAllAssets.ts b/src/routes/cornerScape/getAllAssets.ts
index ef4ce0a..83620a1 100644
--- a/src/routes/cornerScape/getAllAssets.ts
+++ b/src/routes/cornerScape/getAllAssets.ts
@@ -16,12 +16,13 @@ export default router.post(
const data = await u
.db("o_assets")
.leftJoin("o_image", "o_assets.imageId", "o_image.id")
- .select("o_assets.*", "o_image.filePath", "o_image.state", "o_image.model", "o_image.resolution")
+ .select("o_assets.*", "o_image.filePath", "o_image.state", "o_image.model", "o_image.resolution", "o_image.errorReason")
.where("o_assets.projectId", projectId)
.andWhere("o_assets.type", "<>", "clip")
.modify((qb) => {
if (type && type.length > 0) qb.whereIn("o_assets.type", type);
- }).orderByRaw(`CASE o_assets.type WHEN 'role' THEN 1 WHEN 'scene' THEN 2 WHEN 'tool' THEN 3 ELSE 4 END`);
+ })
+ .orderByRaw(`CASE o_assets.type WHEN 'role' THEN 1 WHEN 'scene' THEN 2 WHEN 'tool' THEN 3 ELSE 4 END`);
const result = await Promise.all(
data.map(async (parent: any) => {
const historyImages = await u.db("o_image").where("assetsId", parent.id).andWhere("state", "已完成").select("id", "filePath");
diff --git a/src/types/database.d.ts b/src/types/database.d.ts
index 9c19252..d72b0fc 100644
--- a/src/types/database.d.ts
+++ b/src/types/database.d.ts
@@ -1,6 +1,29 @@
-// @db-hash b1210691844e077e9df7dc16c802ce5a
+// @db-hash 4789feeeda48b86ecadc17318a89460b
//该文件由脚本自动生成,请勿手动修改
+export interface _o_assets_old_20260331 {
+ 'assetsId'?: number | null;
+ 'describe'?: string | null;
+ 'id'?: number;
+ 'imageId'?: number | null;
+ 'name'?: string | null;
+ 'projectId'?: number | null;
+ 'prompt'?: string | null;
+ 'promptState'?: string | null;
+ 'remark'?: string | null;
+ 'scriptId'?: number | null;
+ 'startTime'?: number | null;
+ 'type'?: string | null;
+}
+export interface _o_image_old_20260331 {
+ 'assetsId'?: number | null;
+ 'filePath'?: string | null;
+ 'id'?: number;
+ 'model'?: string | null;
+ 'resolution'?: string | null;
+ 'state'?: string | null;
+ 'type'?: string | null;
+}
export interface _o_project_old_20260331 {
'artStyle'?: string | null;
'createTime'?: number | null;
@@ -61,6 +84,7 @@ export interface o_assets {
'name'?: string | null;
'projectId'?: number | null;
'prompt'?: string | null;
+ 'promptErrorReason'?: string | null;
'promptState'?: string | null;
'remark'?: string | null;
'scriptId'?: number | null;
@@ -84,6 +108,7 @@ export interface o_eventChapter {
}
export interface o_image {
'assetsId'?: number | null;
+ 'errorReason'?: string | null;
'filePath'?: string | null;
'id'?: number;
'model'?: string | null;
@@ -241,6 +266,8 @@ export interface o_videoTrack {
}
export interface DB {
+ "_o_assets_old_20260331": _o_assets_old_20260331;
+ "_o_image_old_20260331": _o_image_old_20260331;
"_o_project_old_20260331": _o_project_old_20260331;
"memories": memories;
"o_agentDeploy": o_agentDeploy;
From 1842fe74a8b2c37e17f8d403c35ce4a158e8f209 Mon Sep 17 00:00:00 2001
From: zhishi <1951671751@qq.com>
Date: Tue, 31 Mar 2026 23:08:13 +0800
Subject: [PATCH 4/4] no message
---
src/lib/initDB.ts | 4 +-
src/routes/production/getFlowData.ts | 114 ++++++++------------------
src/routes/production/saveFlowData.ts | 19 ++---
src/types/database.d.ts | 89 ++++++++++++++------
4 files changed, 106 insertions(+), 120 deletions(-)
diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts
index e1a344b..b70e11a 100644
--- a/src/lib/initDB.ts
+++ b/src/lib/initDB.ts
@@ -451,6 +451,7 @@ description: 专注于从剧本内容中提取所使用的资产(角色、场
table.integer("imageId").unsigned().references("id").inTable("o_image");
table.integer("assetsId");
table.integer("projectId");
+ table.integer("flowId"); //工作流id
table.integer("startTime");
table.string("promptState");
table.primary(["id"]);
@@ -487,6 +488,7 @@ description: 专注于从剧本内容中提取所使用的资产(角色、场
table.integer("trackId");
table.text("reason");
table.integer("projectId");
+ table.integer("flowId"); //工作流id
table.integer("index");
table.integer("createTime");
table.primary(["id"]);
@@ -560,8 +562,6 @@ description: 专注于从剧本内容中提取所使用的资产(角色、场
builder: (table) => {
table.integer("id").notNullable();
table.text("flowData").notNullable();
- table.integer("storyboardId");
- table.integer("assetsId");
table.primary(["id"]);
table.unique(["id"]);
},
diff --git a/src/routes/production/getFlowData.ts b/src/routes/production/getFlowData.ts
index f42d068..82136d3 100644
--- a/src/routes/production/getFlowData.ts
+++ b/src/routes/production/getFlowData.ts
@@ -107,89 +107,41 @@ export default router.post(
assets2StoryboardMap[i.storyboardId!].push(i.assetId!);
});
const flowData = JSON.parse(sqlData!.data ?? "{}");
- // 将原有 flowData.assets 按 id 建立索引,以便后续合并保留旧字段
- const existingAssetsMap: Record = {};
- if (Array.isArray(flowData.assets)) {
- flowData.assets.forEach((a: any) => {
- existingAssetsMap[a.id] = a;
- });
- }
flowData.assets = await Promise.all(
- assetsData.map(async (item) => {
- const existing = existingAssetsMap[item.id] ?? {};
- // 将原有 derive 按 id 建立索引
- const existingDeriveMap: Record = {};
- if (Array.isArray(existing.derive)) {
- existing.derive.forEach((d: any) => {
- existingDeriveMap[d.id] = d;
- });
- }
- return {
- ...existing,
- id: item.id,
- name: item.name ?? "",
- type: item.type ?? "",
- prompt: item.prompt ?? "",
- desc: item.describe ?? "",
- src: item.filePath && (await u.oss.getFileUrl(item.filePath!)),
- derive: await Promise.all(
- childAssetsData
- .filter((child) => child.assetsId === item.id)
- .map(async (child) => ({
- ...(existingDeriveMap[child.id] ?? {}),
- id: child.id,
- assetsId: item.id,
- name: child.name ?? "",
- prompt: child.prompt,
- type: child.type,
- desc: child.describe ?? "",
- src: child.filePath && (await u.oss.getFileUrl(child.filePath!)),
- state: child.state ?? "未生成", //todo:矫正状态值
- })),
- ),
- };
- }),
+ assetsData.map(async (item) => ({
+ id: item.id,
+ name: item.name ?? "",
+ type: item.type ?? "",
+ prompt: item.prompt ?? "",
+ desc: item.describe ?? "",
+ src: item.filePath && (await u.oss.getFileUrl(item.filePath!)),
+ derive: await Promise.all(
+ childAssetsData
+ .filter((child) => child.assetsId === item.id)
+ .map(async (child) => ({
+ id: child.id,
+ assetsId: item.id,
+ name: child.name ?? "",
+ prompt: child.prompt,
+ type: child.type,
+ desc: child.describe ?? "",
+ src: child.filePath && (await u.oss.getFileUrl(child.filePath!)),
+ state: child.state ?? "未生成",
+ })),
+ ),
+ })),
);
- // 将数据库 storyboardData 按 id 建立索引
- const dbStoryboardMap: Record = {};
- storyboardData.forEach((i) => {
- dbStoryboardMap[i.id!] = i;
- });
-
- // 用于构造单条 storyboard 的辅助函数
- const buildStoryboardItem = (i: (typeof storyboardData)[number], existing: any = {}) => ({
- ...existing,
- id: i.id,
- index: i.index,
- duration: i.duration ? +i.duration : 0,
- prompt: i.prompt,
- associateAssetsIds: assets2StoryboardMap[i.id!] ?? [],
- src: i.filePath,
- state: i.state,
- });
-
- // 保持旧数据顺序,新增的追加到最后
- const usedIds = new Set();
- const orderedStoryboard: any[] = [];
-
- // 1. 按旧数据顺序遍历,若数据库中仍存在则合并更新
- if (Array.isArray(flowData.storyboard)) {
- flowData.storyboard.forEach((s: any) => {
- const dbItem = dbStoryboardMap[s.id];
- if (dbItem) {
- orderedStoryboard.push(buildStoryboardItem(dbItem, s));
- usedIds.add(s.id);
- }
- });
- }
-
- // 2. 数据库中新增的(旧数据中没有的)追加到最后
- storyboardData.forEach((i) => {
- if (!usedIds.has(i.id!)) {
- orderedStoryboard.push(buildStoryboardItem(i));
- }
- });
- flowData.storyboard = orderedStoryboard.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
+ flowData.storyboard = storyboardData
+ .map((i) => ({
+ id: i.id,
+ index: i.index,
+ duration: i.duration ? +i.duration : 0,
+ prompt: i.prompt,
+ associateAssetsIds: assets2StoryboardMap[i.id!] ?? [],
+ src: i.filePath,
+ state: i.state,
+ }))
+ .sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
res.status(200).send(success(flowData));
} catch (err) {
res.status(400).send(error());
diff --git a/src/routes/production/saveFlowData.ts b/src/routes/production/saveFlowData.ts
index c429a74..64209fd 100644
--- a/src/routes/production/saveFlowData.ts
+++ b/src/routes/production/saveFlowData.ts
@@ -24,17 +24,14 @@ export default router.post(
episodesId: number;
} = req.body;
const sqlData = await u.db("o_agentWorkData").where("projectId", String(projectId)).andWhere("episodesId", String(episodesId)).first();
- // if (data.storyboard && data.storyboard.length)
- // await Promise.all(
- // data.storyboard.map(async (i, index) => {
- // await u
- // .db("o_storyboard")
- // .where("id", i.id)
- // .update({
- // index: index + 1,
- // });
- // }),
- // );
+ if (data.storyboard && data.storyboard.length)
+ await Promise.all(
+ data.storyboard.map(async (i, index) => {
+ await u.db("o_storyboard").where("id", i.id).update({
+ index: index,
+ });
+ }),
+ );
if (!sqlData) {
await u.db("o_agentWorkData").insert({
projectId,
diff --git a/src/types/database.d.ts b/src/types/database.d.ts
index 9c19252..6d8457b 100644
--- a/src/types/database.d.ts
+++ b/src/types/database.d.ts
@@ -1,19 +1,48 @@
-// @db-hash b1210691844e077e9df7dc16c802ce5a
+// @db-hash c145f43374602285beea82bbd51eaec8
//该文件由脚本自动生成,请勿手动修改
-export interface _o_project_old_20260331 {
- 'artStyle'?: string | null;
+export interface _o_storyboard_old_20260331 {
+ 'camera'?: string | null;
'createTime'?: number | null;
- 'id'?: number | null;
- 'imageModel'?: string | null;
- 'imageQuality'?: string | null;
- 'intro'?: string | null;
- 'name'?: string | null;
- 'projectType'?: string | null;
- 'type'?: string | null;
- 'userId'?: number | null;
- 'videoModel'?: string | null;
- 'videoRatio'?: string | null;
+ 'description'?: string | null;
+ 'duration'?: string | null;
+ 'filePath'?: string | null;
+ 'frameMode'?: string | null;
+ 'id'?: number;
+ 'index'?: number | null;
+ 'lines'?: string | null;
+ 'mode'?: string | null;
+ 'model'?: string | null;
+ 'prompt'?: string | null;
+ 'reason'?: string | null;
+ 'resolution'?: string | null;
+ 'scriptId'?: number | null;
+ 'sound'?: string | null;
+ 'state'?: string | null;
+ 'title'?: string | null;
+ 'videoPrompt'?: string | null;
+}
+export interface _o_storyboard_old_20260331_1 {
+ 'camera'?: string | null;
+ 'createTime'?: number | null;
+ 'description'?: string | null;
+ 'duration'?: string | null;
+ 'filePath'?: string | null;
+ 'frameMode'?: string | null;
+ 'id'?: number;
+ 'index'?: number | null;
+ 'lines'?: string | null;
+ 'mode'?: string | null;
+ 'model'?: string | null;
+ 'prompt'?: string | null;
+ 'reason'?: string | null;
+ 'resolution'?: string | null;
+ 'scriptId'?: number | null;
+ 'sound'?: string | null;
+ 'state'?: string | null;
+ 'title'?: string | null;
+ 'track'?: string | null;
+ 'videoPrompt'?: string | null;
}
export interface memories {
'content': string;
@@ -87,6 +116,7 @@ export interface o_image {
'filePath'?: string | null;
'id'?: number;
'model'?: string | null;
+ 'reason'?: string | null;
'resolution'?: string | null;
'state'?: string | null;
'type'?: string | null;
@@ -127,7 +157,6 @@ export interface o_project {
'imageModel'?: string | null;
'imageQuality'?: string | null;
'intro'?: string | null;
- 'mode'?: string | null;
'name'?: string | null;
'projectType'?: string | null;
'type'?: string | null;
@@ -175,25 +204,17 @@ export interface o_skillList {
'updateTime': number;
}
export interface o_storyboard {
- 'camera'?: string | null;
'createTime'?: number | null;
- 'description'?: string | null;
'duration'?: string | null;
'filePath'?: string | null;
- 'frameMode'?: string | null;
'id'?: number;
'index'?: number | null;
- 'lines'?: string | null;
- 'mode'?: string | null;
- 'model'?: string | null;
+ 'projectId'?: number | null;
'prompt'?: string | null;
'reason'?: string | null;
- 'resolution'?: string | null;
'scriptId'?: number | null;
- 'sound'?: string | null;
'state'?: string | null;
- 'title'?: string | null;
- 'videoPrompt'?: string | null;
+ 'trackId'?: number | null;
}
export interface o_tasks {
'describe'?: string | null;
@@ -230,8 +251,22 @@ export interface o_video {
'projectId'?: number | null;
'scriptId'?: number | null;
'state'?: string | null;
+ 'storyboardId'?: number | null;
'time'?: number | null;
- 'videoTrackId'?: number | null;
+}
+export interface o_videoConfig {
+ 'audio'?: number | null;
+ 'createTime'?: number | null;
+ 'data'?: string | null;
+ 'duration'?: number | null;
+ 'id'?: number;
+ 'mode'?: string | null;
+ 'model'?: string | null;
+ 'prompt'?: string | null;
+ 'resolution'?: string | null;
+ 'storyboardId'?: number | null;
+ 'updateTime'?: number | null;
+ 'videoId'?: number | null;
}
export interface o_videoTrack {
'id'?: number;
@@ -241,7 +276,8 @@ export interface o_videoTrack {
}
export interface DB {
- "_o_project_old_20260331": _o_project_old_20260331;
+ "_o_storyboard_old_20260331": _o_storyboard_old_20260331;
+ "_o_storyboard_old_20260331_1": _o_storyboard_old_20260331_1;
"memories": memories;
"o_agentDeploy": o_agentDeploy;
"o_agentWorkData": o_agentWorkData;
@@ -267,5 +303,6 @@ export interface DB {
"o_user": o_user;
"o_vendorConfig": o_vendorConfig;
"o_video": o_video;
+ "o_videoConfig": o_videoConfig;
"o_videoTrack": o_videoTrack;
}