diff --git a/data/skills/script-agent/decision/SKILL.md b/data/skills/script-agent/decision/SKILL.md index 90c7d62..6f921c9 100644 --- a/data/skills/script-agent/decision/SKILL.md +++ b/data/skills/script-agent/decision/SKILL.md @@ -29,6 +29,7 @@ description: >- | 集数 | 总共拆分为几集 | 7集 | | 单集时长 | 每集目标时长(分钟) | 2.5分钟 | | 原著范围 | 改编覆盖的章节范围 | 第1-35章 | +| 章节ID列表 | 本次任务涉及的章节ID(用于事件检索) | [1,2,3,4,5] | | 平台规格 | 画面比例(竖屏/横屏) | 竖屏9:16 | | 风格定位 | 短剧整体风格标签 | 诡异修仙+心理悬疑 | | 付费策略 | 前几集免费、从第几集设付费点 | 前2集免费,第3集起付费 | @@ -50,6 +51,7 @@ description: >- - 集数:{totalEpisodes}集 - 单集时长:{episodeDuration}分钟(约{wordsPerEpisode}字台词) - 原著范围:第{startChapter}-{endChapter}章 +- 章节ID列表:{chapterIds} - 平台规格:{platform} - 风格定位:{style} - 付费策略:{paywall} @@ -72,24 +74,24 @@ description: >- ### 阶段1:事件提取(Event Extraction) - **触发词**:提取事件、分析章节、事件列表、event -- **输入**:原著小说章节文本 +- **输入**:章节ID列表(由系统提示词中的章节映射表解析) - **输出**:结构化事件表(章节、角色、核心事件、主线关系、信息点数、预估时长、情绪强度) - **派发指令模板**: ``` 你是执行层Agent,请执行【事件提取】任务。 -目标:从原著第{start}章到第{end}章提取结构化事件表。 +目标:基于章节ID获取结构化事件表。 要求: -1. 调用 get_novel_text 获取原著文本 -2. 按事件提取规范逐章分析 -3. 输出标准事件表格式 -4. 调用 set_planData_event 保存结果 +1. 按系统提示词中的章节映射表,确定章节ID数组 ids:number[] +2. 调用 get_novel_events 获取事件数据(传入 ids:number[]) +3. 按事件提取规范整理为标准事件表格式 +4. 将事件表作为后续阶段上下文返回(不写入 planData) ``` ### 阶段2:故事骨架(Story Skeleton) - **触发词**:故事骨架、分集、三幕结构、skeleton -- **输入**:事件表(阶段1产出) +- **输入**:事件表(通过 get_novel_events 获取) - **输出**:三幕结构 + 分集决策 + 全局删减记录 + 付费卡点设计 - **前置条件**:事件表已完成 - **派发指令模板**: @@ -98,7 +100,7 @@ description: >- 你是执行层Agent,请执行【故事骨架搭建】任务。 目标:基于已有事件表构建故事骨架。 要求: -1. 调用 get_planData 获取当前事件表 +1. 调用 get_novel_events 获取当前任务章节的事件表(传入 ids:number[]) 2. 设计三幕结构,明确每幕功能、核心问题、幕末转折 3. 制定分集决策({totalEpisodes}集×{episodeDuration}分钟),每集包含戏剧功能、核心场景、章节分配、删减决策、集末钩子、付费点 4. 记录全局删减决策 @@ -108,7 +110,7 @@ description: >- ### 阶段3:改编策略(Adaptation Strategy) - **触发词**:改编策略、改编决策、改编原则、adaptation -- **输入**:事件表 + 故事骨架(阶段1-2产出) +- **输入**:事件表(通过 get_novel_events 获取) + 故事骨架(阶段2产出) - **输出**:核心改编原则 + 删除决策 + 世界观呈现策略 - **前置条件**:故事骨架已完成 - **派发指令模板**: @@ -117,7 +119,7 @@ description: >- 你是执行层Agent,请执行【改编策略制定】任务。 目标:基于事件表和故事骨架制定改编策略。 要求: -1. 调用 get_planData 获取事件表和故事骨架 +1. 调用 get_novel_events 获取事件表(传入 ids:number[]),并调用 get_planData 获取故事骨架 2. 确立核心改编原则(故事核优先、双线剪辑策略、恐怖克制原则) 3. 列出主要删除决策及理由 4. 制定世界观呈现策略 @@ -127,8 +129,8 @@ description: >- ### 阶段4:剧本编写(Script Writing) - **触发词**:写剧本、编剧、分镜脚本、script -- **输入**:事件表 + 故事骨架 + 改编策略(阶段1-3产出) -- **输出**:分集剧本(节拍结构 + 分镜脚本) +- **输入**:事件表(通过 get_novel_events 获取) + 故事骨架 + 改编策略(阶段2-3产出) +- **输出**:分集剧本(节拍结构 + 分镜脚本)并写入 SQLite - **前置条件**:改编策略已完成 - **派发指令模板**: @@ -137,13 +139,24 @@ description: >- 目标:编写第{ep}集剧本。 集信息:{从骨架获取的该集信息} 要求: -1. 调用 get_planData 获取全部工作区数据 +1. 调用 get_novel_events 获取该集对应章节事件(传入 ids:number[]),并调用 get_planData 获取故事骨架与改编策略 2. 按节拍结构编写,严格控制总时长在{episodeDuration}分钟(约{wordsPerEpisode}字台词) 3. 每个节拍包含:场景描述、画面描述、台词、内心独白 4. 竖屏9:16格式,注意画面构图适配 -5. 调用 set_planData_script 保存结果 +5. 仅在用户确认后调用 insert_script_to_sqlite 写入剧本(SQL操作) ``` +### 阶段4额外安全规则(SQL写入) + +`insert_script_to_sqlite` 为 SQL 写入操作,决策层必须先与用户明确对话确认,再允许执行层写入: + +1. 先向用户展示待写入剧本摘要,并询问:`是否确认写入数据库?` +2. 仅当用户明确回复“确认/是/同意”后,才可派发写入指令 +3. 派发剧本写入任务时,指令中必须包含:`用户已确认写入SQL: 是` +4. 若用户未确认或拒绝,禁止派发 SQL 写入 + +当用户要求删除剧本时,决策层必须提醒:`剧本删除请在道具本管理中手动删除`。 + ## 调度规则 ### 派发执行任务 @@ -206,8 +219,10 @@ run_sub_agent( 1. **进度汇报**:每完成一个阶段,向用户汇报结果摘要和下一步计划 2. **审核结果展示**:将监督层的完整审核报告展示给用户,包括问题、建议和亮点 3. **等待用户决策**:审核发现问题时,**必须等待用户明确指示**后再执行修复,不可自行决定 -4. **确认关键决策**:涉及大幅偏离既定策略的修改时,先咨询用户 -5. **不暴露内部机制**:不向用户提及 Agent 名称、工具名称等实现细节 +4. **SQL写入确认**:调用 `insert_script_to_sqlite` 前,必须完成用户明确确认 +5. **删除请求提醒**:用户要求删除剧本时,提醒其在道具本管理中手动删除 +6. **确认关键决策**:涉及大幅偏离既定策略的修改时,先咨询用户 +7. **不暴露内部机制**:不向用户提及 Agent 名称、工具名称等实现细节 ## 错误处理 diff --git a/data/skills/script-agent/decision/references/pipeline.md b/data/skills/script-agent/decision/references/pipeline.md index 2a44cd3..513040b 100644 --- a/data/skills/script-agent/decision/references/pipeline.md +++ b/data/skills/script-agent/decision/references/pipeline.md @@ -18,17 +18,17 @@ ### 阶段1:事件提取 ``` -输入:原著小说文本(第1-35章) -处理:逐章提取结构化事件 -输出:planData.event(Markdown事件表) -工具:get_novel_text → set_planData_event +输入:章节ID数组 ids:number[](由系统提示词中的章节映射表提供) +处理:调用事件检索工具并整理为标准事件表 +输出:事件表(Markdown,作为后续阶段上下文,不写入 planData) +工具:get_novel_events(ids:number[]) 质量门:章节覆盖率100%、角色名统一、强主线≥20章 ``` ### 阶段2:故事骨架 ``` -输入:planData.event +输入:事件表(通过 get_novel_events(ids:number[]) 获取) 处理:三幕分割、按项目配置分集、删减决策、钩子设计 输出:planData.storySkeleton 工具:get_planData → set_planData_storySkeleton @@ -39,7 +39,7 @@ ### 阶段3:改编策略 ``` -输入:planData.event + planData.storySkeleton +输入:事件表(get_novel_events) + planData.storySkeleton 处理:提炼改编原则、确定删减依据、世界观呈现策略 输出:planData.adaptationStrategy 工具:get_planData → set_planData_adaptationStrategy @@ -50,12 +50,13 @@ ### 阶段4:剧本编写 ``` -输入:planData.event + planData.storySkeleton + planData.adaptationStrategy +输入:事件表(get_novel_events) + planData.storySkeleton + planData.adaptationStrategy 处理:按集编写(可并行或逐集) -输出:planData.script -工具:get_planData + get_novel_text → set_planData_script +输出:SQLite 中的剧本记录 +工具:get_novel_events + get_planData + get_novel_text → insert_script_to_sqlite 质量门:时长合规、台词字数、画面可执行、资产一致 前置条件:阶段3通过审核 +附加前置条件:用户已明确确认写入 SQL ``` ## 阶段间交互协议 diff --git a/data/skills/script-agent/execution/SKILL.md b/data/skills/script-agent/execution/SKILL.md index 0b014e6..16c7567 100644 --- a/data/skills/script-agent/execution/SKILL.md +++ b/data/skills/script-agent/execution/SKILL.md @@ -3,20 +3,19 @@ name: execution description: >- 短剧改编执行层Agent技能。负责接收决策层派发的具体任务并执行,涵盖事件提取、 故事骨架搭建、改编策略制定、剧本编写四大任务类型。使用 get_novel_text 读取原著, - 使用 get_planData 获取工作区状态,使用 set_planData 系列工具保存产出物。 + 使用 get_novel_events 获取章节事件数据,使用 get_planData 获取工作区状态,使用写入工具保存产出物。 当收到决策层的 run_sub_agent 调用时激活。 --- # 执行层 Agent 技能指令 你是短剧改编项目的**执行层 Agent**,只接收决策层派发的任务指令并执行。 -你不与用户直接交互,所有产出物通过 `set_planData_*` 写入工作区。 +你不与用户直接交互,骨架与策略写入 planData,剧本写入 SQLite。 ## 工作区数据结构 ```typescript const planData = { - event: string, // 章节事件表 storySkeleton: string, // 故事骨架 adaptationStrategy: string, // 改编策略 script: string, // 剧本内容 @@ -24,7 +23,16 @@ const planData = { ``` - 读取:`get_planData` → 返回完整 planData 对象 -- 写入:`set_planData_event` / `set_planData_storySkeleton` / `set_planData_adaptationStrategy` / `set_planData_script` +- 事件读取:`get_novel_events(ids:number[])` → 返回指定章节ID的事件数据 +- 写入:`set_planData_storySkeleton` / `set_planData_adaptationStrategy` / `insert_script_to_sqlite` + +### SQL写入安全约束(剧本) + +`insert_script_to_sqlite` 属于 SQL 写入操作,执行前必须满足以下条件: + +1. 决策层指令中明确包含:`用户已确认写入SQL: 是` +2. 若未包含该确认标记,执行层必须拒绝写入并返回:`缺少用户确认,未执行 SQL 写入` +3. 执行层不处理剧本删除请求;如收到删除诉求,返回提醒:`请在道具本管理中手动删除剧本` ## 项目背景 @@ -52,8 +60,9 @@ const planData = { **执行流程**: -1. 调用 `get_novel_text` 获取指定章节范围的原著文本 -2. 逐章分析,提取以下维度: +1. 根据决策层传入的章节ID,构建 `ids:number[]` +2. 调用 `get_novel_events(ids:number[])` 获取结构化事件数据 +3. 逐章分析,提取以下维度: | 字段 | 说明 | 示例 | |------|------|------| @@ -65,8 +74,8 @@ const planData = { | 预估集长 | 秒数 | 45秒 | | 情绪强度 | 情绪标签 | 冲突+恐怖 | -3. 生成汇总统计(总章节、强主线章节数、可压缩章节、预估总时长、目标时长、压缩比) -4. 调用 `set_planData_event` 保存 Markdown 表格格式的事件表 +4. 生成汇总统计(总章节、强主线章节数、可压缩章节、预估总时长、目标时长、压缩比) +5. 输出 Markdown 表格格式的事件表,作为后续任务上下文(不写入 planData) **输出格式**:参考 [event-format.md](references/event-format.md) @@ -83,7 +92,7 @@ const planData = { **执行流程**: -1. 调用 `get_planData` 获取已有事件表 +1. 调用 `get_novel_events(ids:number[])` 获取已有事件表 2. 确定故事核(一句话总结整部剧的核心吸引力) 3. 提炼隐线(人物弧:主角的内在成长轨迹) 4. 设计三幕结构: @@ -122,7 +131,7 @@ const planData = { **执行流程**: -1. 调用 `get_planData` 获取事件表和故事骨架 +1. 调用 `get_novel_events(ids:number[])` 获取事件表,并调用 `get_planData` 获取故事骨架 2. 制定核心改编原则(3-5条),每条原则必须: - 明确优先级 - 给出正面指导("应该做什么")和负面边界("不应该做什么") @@ -152,7 +161,7 @@ const planData = { **执行流程**: -1. 调用 `get_planData` 获取全部工作区数据(事件表、骨架、改编策略) +1. 调用 `get_novel_events(ids:number[])` 获取事件表,并调用 `get_planData` 获取骨架与改编策略 2. 根据指定集数,从骨架中获取该集的: - 覆盖章节范围 - 戏剧功能 @@ -168,7 +177,7 @@ const planData = { - 画面描述(构图、运镜、视觉重点) - 台词/旁白/内心独白 - 表演指示(情绪、动作细节) -6. 调用 `set_planData_script` 保存 +6. 仅当指令中包含 `用户已确认写入SQL: 是` 时,调用 `insert_script_to_sqlite` 写入剧本 **输出格式**:参考 [script-format.md](references/script-format.md) @@ -181,8 +190,9 @@ const planData = { ## 通用执行规范 -1. **先读后写**:执行任何任务前,先调用 `get_planData` 了解当前工作区状态 +1. **先读后写**:执行任何任务前,先调用 `get_planData` 了解工作区状态,并按需调用 `get_novel_events(ids:number[])` 获取事件数据 2. **增量更新**:如果工作区已有内容,在其基础上修改而非全部覆盖(除非指令明确要求重写) 3. **格式一致**:严格按照对应的输出格式规范,使用 Markdown 格式 4. **任务边界**:只执行指令中明确要求的任务,不越权执行其他阶段 -5. **异常上报**:遇到无法处理的情况(如缺少前置数据),在返回结果中明确说明 \ No newline at end of file +5. **异常上报**:遇到无法处理的情况(如缺少前置数据),在返回结果中明确说明 +6. **SQL安全执行**:未收到明确用户确认时,禁止调用 `insert_script_to_sqlite` \ No newline at end of file diff --git a/src/agents/productionAgent/tools.ts b/src/agents/productionAgent/tools.ts index 8483193..97684c6 100644 --- a/src/agents/productionAgent/tools.ts +++ b/src/agents/productionAgent/tools.ts @@ -6,10 +6,12 @@ import ResTool from "@/socket/resTool"; export const deriveAssetSchema = z.object({ id: z.number().describe("衍生资产ID,如果新增则为空").optional(), assetsId: z.string().describe("关联的资产ID"), + prompt: z.string().describe("生成提示词"), name: z.string().describe("衍生资产名称"), desc: z.string().describe("衍生资产描述"), src: z.string().describe("衍生资产资源路径"), state: z.enum(["未生成", "生成中", "已完成", "生成失败"]).describe("衍生资产生成状态"), + type: z.enum(["role", "tool", "scene", "clip"]).describe("衍生资产类型"), }); export const assetItemSchema = z.object({ assetsId: z.string().describe("资产唯一标识"), diff --git a/src/agents/scriptAgent/index.ts b/src/agents/scriptAgent/index.ts index bffc0b9..1bd4dda 100644 --- a/src/agents/scriptAgent/index.ts +++ b/src/agents/scriptAgent/index.ts @@ -35,14 +35,30 @@ function buildSystemPrompt(skillPrompt: string, mem: Awaited `- ${i.id}: 第${i.index}章`).join("\n")}\n\n`; + console.log("%c Line:57 🍧 prefixSystem", "background:#ea7e5c", prefixSystem); const { textStream } = await u.Ai.Text("scriptAgent").stream({ system: prefixSystem + systemPrompt, @@ -92,7 +108,10 @@ export async function executionAI(ctx: AgentContext) { } export async function supervisionAI(ctx: AgentContext) { - const { isolationKey, text, abortSignal } = ctx; + const { isolationKey, text, abortSignal, resTool } = ctx; + + resTool.systemMessage("监督层AI 接管聊天"); + const memory = new Memory("scriptAgent", isolationKey); const [skill, mem] = await Promise.all([useSkill("script-agent", "supervision"), memory.get(text)]); @@ -127,11 +146,10 @@ function runSubAgent(parentCtx: AgentContext) { //运行子Agent const subTextStream = await fn({ ...parentCtx, text: prompt }); - let msg: ReturnType; + let msg = parentCtx.resTool.textMessage(); let fullResponse = ""; for await (const chunk of subTextStream) { - if (!msg!) msg = parentCtx.resTool.textMessage(); msg.send(chunk); fullResponse += chunk; } diff --git a/src/agents/scriptAgent/tools.ts b/src/agents/scriptAgent/tools.ts index edc0831..800850e 100644 --- a/src/agents/scriptAgent/tools.ts +++ b/src/agents/scriptAgent/tools.ts @@ -1,10 +1,21 @@ import { tool, Tool } from "ai"; +import u from "@/utils"; import { z } from "zod"; import _ from "lodash"; import ResTool from "@/socket/resTool"; +export const AssetSchema = z.object({ + id: z.number().describe("衍生资产ID,如果新增则为空").optional(), + assetsId: z.string().describe("关联的资产ID"), + prompt: z.string().describe("生成提示词"), + name: z.string().describe("衍生资产名称"), + desc: z.string().describe("衍生资产描述"), + src: z.string().describe("衍生资产资源路径").optional(), + state: z.enum(["未生成", "生成中", "已完成", "生成失败"]).describe("衍生资产生成状态,新增默认未生成"), + type: z.enum(["role", "tool", "scene", "clip"]).describe("衍生资产类型"), +}); + export const planData = z.object({ - event: z.string().describe("章节事件"), storySkeleton: z.string().describe("故事骨架"), adaptationStrategy: z.string().describe("改编策略"), script: z.string().describe("剧本内容"), @@ -20,6 +31,22 @@ const planDataKeyLabels = Object.fromEntries( export default (resTool: ResTool, toolsNames?: string[]) => { const { socket } = resTool; const tools: Record = { + get_novel_events: tool({ + description: "获取章节事件", + inputSchema: z.object({ + ids: z.array(z.number()).describe("章节id"), + }), + execute: async ({ ids }) => { + resTool.systemMessage(`正在阅读 章节事件 数据...`); + console.log("[tools] get_novel_events", ids); + const data = await u + .db("o_novel") + .select("id", "chapterIndex as index", "reel", "chapter", "chapterData", "event", "eventState") + .whereIn("id", ids); + const eventString = data.map((i: any) => [`第${i.index}章,标题:${i.chapter},事件:${i.event}`].join("\n")).join("\n"); + return eventString; + }, + }), get_planData: tool({ description: "获取工作区数据", inputSchema: z.object({ @@ -42,16 +69,6 @@ export default (resTool: ResTool, toolsNames?: string[]) => { return ""; }, }), - set_planData_event: tool({ - description: "保存章节事件到工作区", - inputSchema: z.object({ value: planData.shape.event }), - execute: async ({ value }) => { - console.log("[tools] set_planData event", value); - resTool.systemMessage("正在保存 章节事件 数据"); - socket.emit("setPlanData", { key: "event", value }); - return true; - }, - }), set_planData_storySkeleton: tool({ description: "保存故事骨架到工作区", inputSchema: z.object({ value: planData.shape.storySkeleton }), @@ -72,13 +89,23 @@ export default (resTool: ResTool, toolsNames?: string[]) => { return true; }, }), - set_planData_script: tool({ - description: "保存剧本内容到工作区", - inputSchema: z.object({ value: planData.shape.script }), - execute: async ({ value }) => { - console.log("[tools] set_planData script", value); - resTool.systemMessage("正在保存 剧本 数据"); - socket.emit("setPlanData", { key: "script", value }); + insert_script_to_sqlite: tool({ + description: "将剧本内容插入sqlite数据库,供后续业务使用", + inputSchema: z.object({ + list: z.array(AssetSchema), + }), + execute: async ({ list }) => { + console.log("[tools] insert_script_to_sqlite", list); + await u.db("o_assets").insert( + list.map((i) => ({ + name: i.name, + prompt: i.prompt, + type: i.type, + describe: i.desc, + projectId: resTool.data.projectId, + state: "未生成", + })), + ); return true; }, }), diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts index a17ae71..f79a057 100644 --- a/src/lib/initDB.ts +++ b/src/lib/initDB.ts @@ -329,7 +329,7 @@ export default async (knex: Knex, forceInit: boolean = false): Promise => }, //flowData-剧本 { - name: "o_flowData", + name: "o_agentWorkData", builder: (table) => { table.integer("id").notNullable(); table.integer("projectId"); diff --git a/src/router.ts b/src/router.ts index 71fd85a..15f2fc1 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash 61bac5fab20be7b63f8e2cda7f6945b6 +// @routes-hash d482a1b197a774825d3bc1c4ca8b70c5 import { Express } from "express"; import route1 from "./routes/agents/clearMemory"; @@ -61,24 +61,26 @@ import route57 from "./routes/script/delScript"; import route58 from "./routes/script/exportScript"; import route59 from "./routes/script/getScrptApi"; import route60 from "./routes/script/updateScript"; -import route61 from "./routes/setting/agentDeploy/deployAgentModel"; -import route62 from "./routes/setting/agentDeploy/getAgentDeploy"; -import route63 from "./routes/setting/agentDeploy/updateKey"; -import route64 from "./routes/setting/dbConfig/clearData"; -import route65 from "./routes/setting/getTextModel"; -import route66 from "./routes/setting/loginConfig/getUser"; -import route67 from "./routes/setting/loginConfig/updateUserPwd"; -import route68 from "./routes/setting/memoryConfig/getMemory"; -import route69 from "./routes/setting/memoryConfig/sureMemory"; -import route70 from "./routes/setting/vendorConfig/addVendor"; -import route71 from "./routes/setting/vendorConfig/deleteVendor"; -import route72 from "./routes/setting/vendorConfig/getVendorList"; -import route73 from "./routes/setting/vendorConfig/modelTest"; -import route74 from "./routes/setting/vendorConfig/updateVendor"; -import route75 from "./routes/task/getTaskApi"; -import route76 from "./routes/task/getTaskCategories"; -import route77 from "./routes/task/taskDetails"; -import route78 from "./routes/test/test"; +import route61 from "./routes/scriptAgent/getPlanData"; +import route62 from "./routes/scriptAgent/setPlanData"; +import route63 from "./routes/setting/agentDeploy/deployAgentModel"; +import route64 from "./routes/setting/agentDeploy/getAgentDeploy"; +import route65 from "./routes/setting/agentDeploy/updateKey"; +import route66 from "./routes/setting/dbConfig/clearData"; +import route67 from "./routes/setting/getTextModel"; +import route68 from "./routes/setting/loginConfig/getUser"; +import route69 from "./routes/setting/loginConfig/updateUserPwd"; +import route70 from "./routes/setting/memoryConfig/getMemory"; +import route71 from "./routes/setting/memoryConfig/sureMemory"; +import route72 from "./routes/setting/vendorConfig/addVendor"; +import route73 from "./routes/setting/vendorConfig/deleteVendor"; +import route74 from "./routes/setting/vendorConfig/getVendorList"; +import route75 from "./routes/setting/vendorConfig/modelTest"; +import route76 from "./routes/setting/vendorConfig/updateVendor"; +import route77 from "./routes/task/getTaskApi"; +import route78 from "./routes/task/getTaskCategories"; +import route79 from "./routes/task/taskDetails"; +import route80 from "./routes/test/test"; export default async (app: Express) => { app.use("/api/agents/clearMemory", route1); @@ -141,22 +143,24 @@ export default async (app: Express) => { app.use("/api/script/exportScript", route58); app.use("/api/script/getScrptApi", route59); app.use("/api/script/updateScript", route60); - app.use("/api/setting/agentDeploy/deployAgentModel", route61); - app.use("/api/setting/agentDeploy/getAgentDeploy", route62); - app.use("/api/setting/agentDeploy/updateKey", route63); - app.use("/api/setting/dbConfig/clearData", route64); - app.use("/api/setting/getTextModel", route65); - app.use("/api/setting/loginConfig/getUser", route66); - app.use("/api/setting/loginConfig/updateUserPwd", route67); - app.use("/api/setting/memoryConfig/getMemory", route68); - app.use("/api/setting/memoryConfig/sureMemory", route69); - app.use("/api/setting/vendorConfig/addVendor", route70); - app.use("/api/setting/vendorConfig/deleteVendor", route71); - app.use("/api/setting/vendorConfig/getVendorList", route72); - app.use("/api/setting/vendorConfig/modelTest", route73); - app.use("/api/setting/vendorConfig/updateVendor", route74); - app.use("/api/task/getTaskApi", route75); - app.use("/api/task/getTaskCategories", route76); - app.use("/api/task/taskDetails", route77); - app.use("/api/test/test", route78); + app.use("/api/scriptAgent/getPlanData", route61); + app.use("/api/scriptAgent/setPlanData", route62); + app.use("/api/setting/agentDeploy/deployAgentModel", route63); + app.use("/api/setting/agentDeploy/getAgentDeploy", route64); + app.use("/api/setting/agentDeploy/updateKey", route65); + app.use("/api/setting/dbConfig/clearData", route66); + app.use("/api/setting/getTextModel", route67); + app.use("/api/setting/loginConfig/getUser", route68); + app.use("/api/setting/loginConfig/updateUserPwd", route69); + app.use("/api/setting/memoryConfig/getMemory", route70); + app.use("/api/setting/memoryConfig/sureMemory", route71); + app.use("/api/setting/vendorConfig/addVendor", route72); + app.use("/api/setting/vendorConfig/deleteVendor", route73); + app.use("/api/setting/vendorConfig/getVendorList", route74); + app.use("/api/setting/vendorConfig/modelTest", route75); + app.use("/api/setting/vendorConfig/updateVendor", route76); + app.use("/api/task/getTaskApi", route77); + app.use("/api/task/getTaskCategories", route78); + app.use("/api/task/taskDetails", route79); + app.use("/api/test/test", route80); } diff --git a/src/routes/production/getFlowData.ts b/src/routes/production/getFlowData.ts index f9a81e7..b7fa46f 100644 --- a/src/routes/production/getFlowData.ts +++ b/src/routes/production/getFlowData.ts @@ -14,7 +14,7 @@ export default router.post( }), async (req, res) => { const { projectId, episodesId } = req.body; - const sqlData = await u.db("o_flowData").where({ projectId, episodesId }).first(); + const sqlData = await u.db("o_agentWorkData").where({ projectId, episodesId }).first(); const scriptData = await u.db("o_script").where("projectId", projectId).first(); diff --git a/src/routes/production/saveFlowData.ts b/src/routes/production/saveFlowData.ts index 14fd7e1..73b7670 100644 --- a/src/routes/production/saveFlowData.ts +++ b/src/routes/production/saveFlowData.ts @@ -15,16 +15,16 @@ export default router.post( }), async (req, res) => { const { projectId, episodesId } = req.body; - const sqlData = await u.db("o_flowData").where({ projectId, episodesId }).first(); + const sqlData = await u.db("o_agentWorkData").where({ projectId, episodesId }).first(); if (!sqlData) { - await u.db("o_flowData").insert({ + await u.db("o_agentWorkData").insert({ projectId, episodesId, data: JSON.stringify(req.body.data), }); } else { await u - .db("o_flowData") + .db("o_agentWorkData") .where({ projectId, episodesId }) .update({ data: JSON.stringify(req.body.data), diff --git a/src/routes/script/addScript.ts b/src/routes/script/addScript.ts index 2d9f00b..de7977d 100644 --- a/src/routes/script/addScript.ts +++ b/src/routes/script/addScript.ts @@ -22,15 +22,20 @@ export default router.post( projectId, createTime: Date.now(), }); - const assetsData = await u.db("o_assets").whereIn("id", assets).select(); - const assetsIds = assetsData.map((item) => item.id); - const insertData = assetsIds.map((i) => { - return { - scriptId, - assetId: i, - }; - }); - await u.db("o_scriptAssets").insert(insertData); + if (assets.length) { + const assetsData = await u.db("o_assets").whereIn("id", assets).select(); + if (assetsData.length) { + const assetsIds = assetsData.map((item) => item.id); + const insertData = assetsIds.map((i) => { + return { + scriptId, + assetId: i, + }; + }); + await u.db("o_scriptAssets").insert(insertData); + } + } + res.status(200).send(success({ message: "添加剧本成功" })); }, ); diff --git a/src/routes/script/updateScript.ts b/src/routes/script/updateScript.ts index 6915206..02ac819 100644 --- a/src/routes/script/updateScript.ts +++ b/src/routes/script/updateScript.ts @@ -20,15 +20,20 @@ export default router.post( name, content, }); - const assetsData = await u.db("o_assets").whereIn("id", assets).select(); - await u.db("o_scriptAssets").where({ scriptId: id }).delete(); - const insertData = assetsData.map((item) => { - return { - scriptId: id, - assetId: item.id, - }; - }); - await u.db("o_scriptAssets").insert(insertData); + if (assets.length) { + const assetsData = await u.db("o_assets").whereIn("id", assets).select(); + await u.db("o_scriptAssets").where({ scriptId: id }).delete(); + if (assetsData.length) { + const insertData = assetsData.map((item) => { + return { + scriptId: id, + assetId: item.id, + }; + }); + await u.db("o_scriptAssets").insert(insertData); + } + } + res.status(200).send(success({ message: "编辑剧本成功" })); }, ); diff --git a/src/routes/scriptAgent/getPlanData.ts b/src/routes/scriptAgent/getPlanData.ts new file mode 100644 index 0000000..9ca8ad6 --- /dev/null +++ b/src/routes/scriptAgent/getPlanData.ts @@ -0,0 +1,36 @@ +import express from "express"; +import { 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({ + projectId: z.number(), + agentType: z.enum(["scriptAgent"]), + }), + async (req, res) => { + const { projectId, agentType } = req.body; + const data = await u.db("o_agentWorkData").where({ id: projectId, key: agentType }).first(); + + if (!data) { + await u.db("o_agentWorkData").insert({ + id: projectId, + key: agentType, + data: JSON.stringify({ + storySkeleton: "", + adaptationStrategy: "", + }), + }); + return res.status(200).send( + success({ + storySkeleton: "", + adaptationStrategy: "", + }), + ); + } + res.status(200).send(success(JSON.parse(data.data ?? "{}"))); + }, +); diff --git a/src/routes/scriptAgent/setPlanData.ts b/src/routes/scriptAgent/setPlanData.ts new file mode 100644 index 0000000..e7ac9e3 --- /dev/null +++ b/src/routes/scriptAgent/setPlanData.ts @@ -0,0 +1,28 @@ +import express from "express"; +import { 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({ + projectId: z.number(), + agentType: z.enum(["scriptAgent"]), + data: z.object({ + storySkeleton: z.string(), + adaptationStrategy: z.string(), + }), + }), + async (req, res) => { + const { projectId, agentType, data } = req.body; + await u + .db("o_agentWorkData") + .where({ id: projectId, key: agentType }) + .update({ + data: JSON.stringify(data), + }); + res.status(200).send(success()); + }, +); diff --git a/src/socket/resTool.ts b/src/socket/resTool.ts index 91d2e47..fbac487 100644 --- a/src/socket/resTool.ts +++ b/src/socket/resTool.ts @@ -2,7 +2,12 @@ import u from "@/utils"; import { Socket } from "socket.io"; class ResTool { - constructor(public socket: Socket) {} + public socket: Socket; + public data: Record; + constructor(socket: Socket, data: Record = {}) { + this.socket = socket; + this.data = data; + } textMessage(name: string = "AI") { const messageId = u.uuid(); diff --git a/src/socket/routes/scriptAgent.ts b/src/socket/routes/scriptAgent.ts index a543f78..18071c9 100644 --- a/src/socket/routes/scriptAgent.ts +++ b/src/socket/routes/scriptAgent.ts @@ -35,7 +35,9 @@ export default (nsp: Namespace) => { console.log("[scriptAgent] 已连接:", socket.id); - const resTool = new ResTool(socket); + const resTool = new ResTool(socket, { + projectId: socket.handshake.auth.projectId, + }); let abortController: AbortController | null = null; socket.on("message", async (text: string) => { diff --git a/src/types/database.d.ts b/src/types/database.d.ts index f8ebc17..f27634d 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,4 +1,4 @@ -// @db-hash 5c0247c298d78d118c90ddfde129e6e6 +// @db-hash 5ea1f1cf9926d08390093d10da66e6ae //该文件由脚本自动生成,请勿手动修改 export interface memories { @@ -22,6 +22,15 @@ export interface o_agentDeploy { 'name'?: string | null; 'vendorId'?: number | null; } +export interface o_agentWorkData { + 'createTime'?: number | null; + 'data'?: string | null; + 'espisodeId'?: number | null; + 'id'?: number; + 'key'?: string | null; + 'projectId'?: number | null; + 'updateTime'?: number | null; +} export interface o_artStyle { 'id'?: number; 'name'?: string | null; @@ -195,6 +204,7 @@ export interface o_videoConfig { export interface DB { "memories": memories; "o_agentDeploy": o_agentDeploy; + "o_agentWorkData": o_agentWorkData; "o_artStyle": o_artStyle; "o_assets": o_assets; "o_assets2Storyboard": o_assets2Storyboard;