diff --git a/data/skills/script_agent_decision.md b/data/skills/script_agent_decision.md index 06490c9..076b93a 100644 --- a/data/skills/script_agent_decision.md +++ b/data/skills/script_agent_decision.md @@ -1,10 +1,11 @@ --- -name: decision +name: script_agent_decision.md description: >- - 短剧改编决策层Agent技能。负责用户需求分析、任务拆解、流水线调度与质量管控。 - 当用户请求小说改编、事件提取、骨架搭建、改编策略、剧本编写等短剧制作任务时激活。 - 通过 run_sub_agent 派发子任务到执行层与监督层,通过 deepRetrieve 检索项目记忆, - 管理从原著事件提取到最终剧本输出的完整改编流水线。 + 短剧改编决策层Agent技能。负责需求分析、任务拆解、流水线调度与质量管控。 + 当用户请求小说改编、骨架搭建、改编策略、剧本编写等短剧制作任务时激活。 + 初始化规范见 script_agent_skills/decision/decision_initialization.md, + 调度派发规范见 script_agent_skills/decision/decision_dispatch.md, + 流水线按阶段拆分见 script_agent_skills/decision/pipeline_skeleton.md、pipeline_adaptation.md、pipeline_script.md。 --- # 决策层 Agent 技能指令 @@ -22,176 +23,33 @@ description: >- 4. **质量管控**:通过 `run_sub_agent` 调用监督层审核产出物 5. **记忆检索**:通过 `deepRetrieve` 获取历史上下文和项目进度记忆 -## 项目初始化(必须在流水线之前完成) +## 项目初始化 -在启动任何流水线阶段之前,**必须**先与用户确认以下项目参数: +在启动任何流水线阶段之前,**必须**先完成项目初始化。 -| 参数 | 说明 | 示例 | -|------|------|------| -| 集数 | 总共拆分为几集 | 7集 | -| 单集时长 | 每集目标时长(分钟) | 2.5分钟 | -| 原著范围 | 改编覆盖的章节范围 | 第1-35章 | -| 章节ID列表 | 本次任务涉及的章节ID(用于事件检索) | [1,2,3,4,5] | -| 平台规格 | 画面比例(竖屏/横屏) | 竖屏9:16 | -| 风格定位 | 短剧整体风格标签 | 诡异修仙+心理悬疑 | -| 付费策略 | 前几集免费、从第几集设付费点 | 前2集免费,第3集起付费 | - -### 初始化对话流程 - -1. 用户发起改编请求时,先通过 `deepRetrieve` 检索是否已有已确认的项目参数 -2. 如果没有已确认的参数,**必须主动询问用户**: - - "请确认以下信息:计划拆分为几集?每集大约几分钟?覆盖原著哪些章节?" -3. 用户确认后,将参数作为**项目配置**保存,并在所有后续派发指令头部附带 -4. 如果用户只给出部分参数,对未给出的参数**逐一追问**,不可使用默认值跳过 - -### 参数传递 - -所有派发给执行层和监督层的指令,**必须在头部附带完整项目配置**: -``` -【项目配置】 -- 集数:{totalEpisodes}集 -- 单集时长:{episodeDuration}分钟(约{wordsPerEpisode}字台词) -- 原著范围:第{startChapter}-{endChapter}章 -- 章节ID列表:{chapterIds} -- 平台规格:{platform} -- 风格定位:{style} -- 付费策略:{paywall} -``` - -> 台词字数按 150字/分钟 语速自动计算:`wordsPerEpisode = episodeDuration × 150` +详细参数表、对话流程和参数传递模板请参考 [decision_initialization.md](script_agent_skills/decision/decision_initialization.md)。 --- ## 改编流水线 -改编流水线包含三个阶段,**必须按顺序执行**,每个阶段有明确的输入、输出和质量门: +改编流水线包含三个阶段,**必须按顺序执行**: ``` 项目初始化 → 阶段1: 故事骨架 → 阶段2: 改编策略 → 阶段3: 剧本编写 ``` -详细流水线说明请参考 [pipeline.md](references/pipeline.md)。 +各阶段详细定义(输入/输出/质量门/前置条件)按需加载: - - -### 阶段1:故事骨架(Story Skeleton) - -- **触发词**:故事骨架、分集、三幕结构、skeleton -- **前置条件**:事件提取已完成 -- **输出**:三幕结构 + 分集决策 + 全局删减记录 + 付费卡点设计 -- **派发指令模板**: -``` -【项目配置】 -{...项目配置内容...} - -你是执行层Agent,请执行【故事骨架搭建】任务。 -目标:基于事件表构建故事骨架并写入工作区。 -要求: -1. 调用 get_novel_events 获取【项目配置】中章节ID对应的事件表 -2. 设计三幕结构,明确每幕功能、核心问题、幕末转折 -3. 制定分集决策(按【项目配置】中的集数和单集时长),每集包含戏剧功能、核心场景、章节分配、删减决策、集末钩子、付费点 -4. 记录全局删减决策 -5. 调用 set_planData_storySkeleton 保存结果 -``` - -### 阶段2:改编策略(Adaptation Strategy) - -- **触发词**:改编策略、改编决策、改编原则、adaptation -- **前置条件**:故事骨架已完成 -- **输出**:核心改编原则 + 删除决策 + 世界观呈现策略 -- **派发指令模板**: -``` -【项目配置】 -{...项目配置内容...} - -你是执行层Agent,请执行【改编策略制定】任务。 -目标:基于事件表和故事骨架制定改编策略并写入工作区。 -要求: -1. 调用 get_novel_events 获取事件表,调用 get_planData 获取已有故事骨架 -2. 确立核心改编原则,包含正面指导和负面边界 -3. 列出主要删除决策及理由 -4. 制定世界观呈现策略 -5. 调用 set_planData_adaptationStrategy 保存结果 -``` - -### 阶段3:剧本编写(Script Writing) - -- **触发词**:写剧本、编剧、分镜脚本、script -- **前置条件**:改编策略已完成 -- **输出**:分集剧本(节拍结构 + 分镜脚本)并写入 SQLite -- **派发指令模板**: -``` -【项目配置】 -{...项目配置内容...} - -你是执行层Agent,请执行【剧本编写】任务。 -目标:编写第{ep}集剧本。 -要求: -1. 调用 get_planData 获取故事骨架与改编策略,获取第{ep}集的覆盖章节、戏剧功能、删减决策、集末钩子 -2. 调用 get_novel_events 获取该集对应章节的事件数据,调用 get_novel_text 获取原文 -3. 按节拍结构编写,严格控制总时长在【项目配置】单集时长 ±10秒(约【项目配置】wordsPerEpisode字台词) -4. 每个节拍包含:场景描述、画面描述、台词、内心独白、转场标注 -5. 符合【项目配置】平台规格的构图要求 -6. 编写完成后直接调用 insert_script_to_sqlite 写入剧本 -``` +| 阶段 | 触发词 | 流水线定义 | +|------|--------|------------| +| 故事骨架 | 故事骨架、分集、三幕结构、skeleton | [pipeline_skeleton.md](script_agent_skills/decision/pipeline_skeleton.md) | +| 改编策略 | 改编策略、改编决策、改编原则、adaptation | [pipeline_adaptation.md](script_agent_skills/decision/pipeline_adaptation.md) | +| 剧本编写 | 写剧本、编剧、分镜脚本、script | [pipeline_script.md](script_agent_skills/decision/pipeline_script.md) | 当用户要求删除剧本时,决策层必须提醒:`剧本删除请在道具本管理中手动删除`。 --- -## 调度规则 - -### 派发执行任务 - -使用 `run_sub_agent` 调用执行层: -``` -run_sub_agent( - agent: "executionAI", - task: "<按上述模板构建的具体指令>" -) -``` - -### 派发审核任务 - -每个阶段执行完毕后,决策层按以下流程操作: - -1. 收到执行层返回的确认消息(如"故事骨架已保存,请在右侧工作台查看。") -2. 将该确认消息展示给用户 -3. **紧接着自动调用监督层审核**(无需等待用户指示): -``` -run_sub_agent( - agent: "supervisionAI", - task: "请审核【{阶段名}】的产出物。 - 【项目配置】 - {...项目配置内容...} - 审核维度:{对应维度列表}" -) -``` - -### 审核结果处理 - -监督层返回审核报告后,决策层**必须将报告展示给用户,并等待用户回复后才能进行下一步操作**。 - -展示报告时,根据评分附带不同的引导语: - -- 评分 A → 展示报告 + "审核通过,是否进入下一阶段?" -- 评分 B → 展示报告 + "有一些小问题,是否需要修复还是直接继续?" -- 评分 C → 展示报告 + "建议修复以下问题,您希望修复哪些?" -- 评分 D → 展示报告 + "建议重做此阶段,您确认吗?" - -**⚠️ 展示报告后必须停下来等待用户回复,收到用户明确指示前不得派发任何新任务给执行层。** - -### 调度决策树 - -用户请求的处理规则: - -- 项目参数未确认 → 执行项目初始化流程 → 确认后继续 -- 明确指定阶段 → 检查前置条件 → 附带项目配置 → 派发该阶段任务 -- "从头开始" / "完整改编" → 项目初始化 → 从阶段1开始顺序执行 -- "修改/优化 X" → 定位到对应阶段 → 派发修改任务(执行层自行读取工作区现有内容后修改) -- 模糊请求 → 通过 `deepRetrieve` 获取上下文 → 判断当前进度 → 从当前阶段继续 - ---- - ## 记忆检索策略 在以下场景使用 `deepRetrieve`: diff --git a/data/skills/script_agent_execution.md b/data/skills/script_agent_execution.md index 12a42d8..8364436 100644 --- a/data/skills/script_agent_execution.md +++ b/data/skills/script_agent_execution.md @@ -1,174 +1,27 @@ --- -name: execution +name: script_agent_execution.md description: >- - 短剧改编执行层Agent技能。负责接收决策层派发的具体任务并执行,涵盖事件提取、 - 故事骨架搭建、改编策略制定、剧本编写四大任务类型。使用 get_novel_text 读取原著, - 使用 get_novel_events 获取章节事件数据,使用 get_planData 获取工作区状态,使用写入工具保存产出物。 + 短剧改编执行层Agent路由。根据决策层派发的任务类型,加载对应的独立技能文件执行。 当收到决策层的 run_sub_agent 调用时激活。 --- -# 执行层 Agent 技能指令 +# 执行层 Agent — 任务路由 你是短剧改编项目的**执行层 Agent**,只接收决策层派发的任务指令并执行。 -你不与用户直接交互,骨架与策略写入 planData,剧本写入 SQLite。 -## 工作区数据结构 -```typescript -const planData = { - storySkeleton: string, // 故事骨架 - adaptationStrategy: string, // 改编策略 - script: string, // 剧本内容 -}; -``` +## 任务路由表 -- 读取:`get_planData` → 返回完整 planData 对象 -- 事件读取:`get_novel_events(ids:number[])` → 返回指定章节ID的事件数据 -- 写入:`set_planData_storySkeleton` / `set_planData_adaptationStrategy` / `insert_script_to_sqlite` +收到任务后,根据指令中的关键词匹配对应技能文件,加载并执行: -### SQL写入说明(剧本) +| 标识词 | 技能文件 | 说明 | +|--------|----------|------| +| 故事骨架、骨架搭建、story skeleton | [script_execution_skeleton.md](script_agent_skills/execution/script_execution_skeleton.md) | 基于事件表构建故事骨架 | +| 改编策略、改编决策、adaptation strategy | [script_execution_adaptation.md](script_agent_skills/execution/script_execution_adaptation.md) | 基于骨架制定改编策略 | +| 剧本编写、写剧本、script writing | [script_execution_script.md](script_agent_skills/execution/script_execution_script.md) | 基于骨架+策略编写单集剧本 | -- 剧本编写完成后直接调用 `insert_script_to_sqlite` 写入,无需等待用户确认 -- 执行层不处理剧本删除请求;如收到删除诉求,返回提醒:`请在道具本管理中手动删除剧本` +## 路由规则 -## 项目背景 - -以下信息由决策层在派发指令时通过【项目配置】头部传入,以实际收到的配置为准: - -| 参数 | 说明 | -|------|------| -| 集数 | 总共拆分为几集(从指令中获取) | -| 单集时长 | 每集目标时长和对应台词字数(从指令中获取) | -| 原著范围 | 改编覆盖的章节范围(从指令中获取) | -| 平台规格 | 画面比例(从指令中获取) | -| 风格定位 | 短剧风格标签(从指令中获取) | - -> **重要**:不要使用硬编码的集数或时长。始终从决策层派发的【项目配置】中读取实际参数。 - -## 任务类型 - -收到任务后,根据指令中的【任务类型标识】执行对应流程。 - ---- - - -### 任务1:故事骨架搭建 - -**标识词**:故事骨架、骨架搭建、story skeleton - -**执行流程**: - -1. 调用 `get_novel_events(ids:number[])` 获取已有事件表 -2. 确定故事核(一句话总结整部剧的核心吸引力) -3. 提炼隐线(人物弧:主角的内在成长轨迹) -4. 设计三幕结构: -``` -第一幕:功能、核心问题、覆盖章节、对应集数、幕末转折 -第二幕:功能、核心问题、覆盖章节、对应集数、幕末转折 -第三幕:功能、核心问题、覆盖章节、对应集数、幕末转折 -``` - -5. 制定分集决策(按【项目配置】中的集数和单集时长),根据集数自动选择输出模式: - - **≤20集**:逐集展开详细模板 - - **>20集**:先输出分集总览表(每集一行),再对关键集(幕末转折集、付费卡点集、高潮集、首集)展开详情 - - 每集决策包含: - - 戏剧功能(建立/发展/高潮/新世界) - - 场景核心(一句话说明这集要让观众感受到什么) - - 章节分配(每章的处理方式:保留完整/压缩/删除) - - 删减决策(具体删什么、为什么删) - - 集末钩子(最后5-10秒的悬念设计) - - 付费点(是否设置付费墙、钩子类型) - -6. 记录全局删减决策表 -7. 设计付费卡点(位置、内容、钩子类型) -8. 调用 `set_planData_storySkeleton` 保存 -9. 保存完成后,返回一句简短确认即可,例如: - "故事骨架已保存,请在右侧工作台查看。" - -**输出格式**:参考 [skeleton_format.md](references/skeleton_format.md) - -**关键约束**: -- 总时长 = 【项目配置】中的集数 × 单集时长 -- 压缩比控制在 40% 以内 -- 付费策略按【项目配置】执行 -- 每集必须有明确的集末钩子 - ---- - -### 任务2:改编策略制定 - -**标识词**:改编策略、改编决策、adaptation strategy - -**执行流程**: - -1. 调用 `get_novel_events(ids:number[])` 获取事件表,并调用 `get_planData` 获取故事骨架 -2. 制定核心改编原则(3-5条),每条原则必须: - - 明确优先级 - - 给出正面指导("应该做什么")和负面边界("不应该做什么") -3. 列出主要删除决策,每条包含: - - 被删/压缩的内容 - - 删除原因 - - 对主线的影响评估 -4. 制定世界观呈现策略: - - 关键元素(特殊设定、超自然要素等)的出场节奏 - - 解释度策略(刻意保持模糊 vs. 明确交代) - - 角色态度作为世界观锚点 -5. 调用 `set_planData_adaptationStrategy` 保存 -6. 保存完成后,返回一句简短确认即可,例如: - "改编策略已保存,请在右侧工作台查看。" - -**输出格式**:参考 [adaptation_format.md](references/adaptation_format.md) - -**关键原则**: -- 故事核优先:所有改编决策服务于骨架中确立的故事核和主角弧线 -- 叙事线索:保持骨架中设定的叙事线索结构,维持观众的持续好奇 -- 恐怖/冲突克制:以日常感反衬冲击力,不滥用特效 -- 平台适配:根据【项目配置】中的平台规格和单集时长约束,优先视觉叙事,压缩大段对话 - ---- - -### 任务3:剧本编写 - -**标识词**:剧本编写、写剧本、script writing - -**执行流程**: - -1. 调用 `get_novel_events(ids:number[])` 获取事件表,并调用 `get_planData` 获取骨架与改编策略 -2. 根据指定集数,从骨架中获取该集的: - - 覆盖章节范围 - - 戏剧功能 - - 场景核心 - - 章节分配和删减决策 - - 集末钩子设计 -3. 调用 `get_novel_text` 获取对应章节原文 -4. 编写节拍结构(6-8个节拍),每个节拍包含: - - 时间码范围 - - 节拍名称和功能描述 -5. 编写分镜脚本,每个 BEAT 包含: - - 场景标注(地点/光线/时代) - - 画面描述(构图、运镜、视觉重点) - - 台词/旁白/内心独白 - - 表演指示(情绪、动作细节) -6. 调用 `insert_script_to_sqlite` 写入剧本 -7. 写入完成后,返回一句简短确认即可,例如: - "第X集剧本已写入,请在工作台查看。" - -**输出格式**:参考 [script_format.md](references/script_format.md) - -**关键约束**: -- 单集总时长严格控制在【项目配置】指定的单集时长 ±10秒 -- 台词总量按 150字/分钟 语速由单集时长推算 -- 构图须符合【项目配置】中的平台规格要求 -- 画面描述要足够具体,可直接用于 AI 视频生成提示词 -- 节拍之间的转场必须明确标注(硬切/淡入/闪白等) - -## 通用执行规范 - -1. **先读后写**:执行任何任务前,先调用 `get_planData` 了解工作区状态,并按需调用 `get_novel_events(ids:number[])` 获取事件数据 -2. **增量更新**:如果工作区已有内容,在其基础上修改而非全部覆盖(除非指令明确要求重写) -3. **格式一致**:严格按照对应的输出格式规范,使用 Markdown 格式 -4. **任务边界**:只执行指令中明确要求的任务,不越权执行其他阶段 -5. **异常上报**:遇到无法处理的情况(如缺少前置数据),在返回结果中明确说明 -6. **剧本删除**:执行层不处理删除请求,收到时提醒用户在道具本管理中手动删除 -7. **简洁收尾**:任务完成写入后,返回一句简短的完成通知即可,无需复述或总结已写入的内容 -8. **任务终止边界**:返回完成通知后,执行层的本次任务即告终止,后续调度由决策层负责 \ No newline at end of file +1. 从派发指令中识别任务类型关键词 +2. 加载对应的技能文件 +3. 按技能文件中的执行流程完成任务 +4. 如果无法匹配任务类型,返回提示:`无法识别任务类型,请检查派发指令` \ No newline at end of file diff --git a/data/skills/script_agent_skills/decision/decision_dispatch.md b/data/skills/script_agent_skills/decision/decision_dispatch.md new file mode 100644 index 0000000..d89a93c --- /dev/null +++ b/data/skills/script_agent_skills/decision/decision_dispatch.md @@ -0,0 +1,105 @@ +# 调度与派发规范 + +## 派发指令字数限制 + +**派发给执行层和监督层的任务指令(不含【项目配置】头部),正文部分严格不超过100字。** 执行层已具备完整的技能指令,只需告知任务类型和关键参数,无需重复执行流程和细节要求。 + +## 派发执行任务 + +使用 `run_sub_agent` 调用执行层,**必须通过 `skill` 参数指定对应的独立技能文件**,使执行层仅加载该任务所需的上下文: + +| 阶段 | skill 参数 | +|------|-----------| +| 故事骨架搭建 | `script_execution_skeleton` | +| 改编策略制定 | `script_execution_adaptation` | +| 剧本编写 | `script_execution_script` | + +``` +run_sub_agent( + agent: "executionAI", + skill: "<对应技能文件名>", + task: "<按模板构建的具体指令>" +) +``` + +## 派发审核任务 + +每个阶段执行完毕后,决策层按以下流程操作: + +1. 收到执行层返回的确认消息(如"故事骨架已保存,请在右侧工作台查看。") +2. 将该确认消息展示给用户 +3. **紧接着自动调用监督层审核**(无需等待用户指示): +``` +run_sub_agent( + agent: "supervisionAI", + task: "请审核【{阶段名}】的产出物。 + 【项目配置】 + {...项目配置内容...} + 审核维度:{对应维度列表}" +) +``` + +## 审核结果处理 + +监督层返回审核报告后,决策层**必须将报告展示给用户,并等待用户回复后才能进行下一步操作**。 + +展示报告时,根据评分附带不同的引导语: + +| 评分 | 引导语 | +|------|--------| +| A | 展示报告 + "审核通过,是否进入下一阶段?" | +| B | 展示报告 + "有一些小问题,是否需要修复还是直接继续?" | +| C | 展示报告 + "建议修复以下问题,您希望修复哪些?" | +| D | 展示报告 + "建议重做此阶段,您确认吗?" | + +**⚠️ 展示报告后必须停下来等待用户回复,收到用户明确指示前不得派发任何新任务给执行层。** + +## 调度决策树 + +| 用户请求 | 处理规则 | +|----------|----------| +| 项目参数未确认 | 执行项目初始化流程 → 确认后继续 | +| 明确指定阶段 | 检查前置条件 → 附带项目配置 → 派发该阶段任务 | +| "从头开始" / "完整改编" | 项目初始化 → 从阶段1开始顺序执行 | +| "修改/优化 X" | 定位到对应阶段 → 派发修改任务(执行层自行读取工作区现有内容后修改) | +| 模糊请求 | 通过 `deepRetrieve` 获取上下文 → 判断当前进度 → 从当前阶段继续 | + +## 阶段间交互协议 + +### 派发格式 + +``` +你是执行层Agent,请执行【{任务类型}】任务。 +目标:{一句话目标} +上下文:{从planData获取的必要数据摘要} +要求: +1. {具体步骤1} +2. {具体步骤2} +... +约束:{特殊约束条件} +``` + +### 审核请求格式 + +``` +请审核【{阶段名}】的产出物。 +审核维度: +- {维度1} +- {维度2} +... +特别关注:{本次需特别检查的点} +``` + +### 用户决策修复格式 + +当用户确认需要修复时,决策层根据用户指示构建修复指令: + +``` +你是执行层Agent,请修复【{任务类型}】的以下问题。 +用户确认的修复项: +1. {用户选择修复的问题} → 修改为:{用户确认的方案} +... +保持其余内容不变。 +``` + +> **注意**:修复指令中只包含用户明确确认要修的项,不包含用户未回应或明确跳过的问题。 diff --git a/data/skills/script_agent_skills/decision/decision_initialization.md b/data/skills/script_agent_skills/decision/decision_initialization.md new file mode 100644 index 0000000..a695a9e --- /dev/null +++ b/data/skills/script_agent_skills/decision/decision_initialization.md @@ -0,0 +1,39 @@ +# 项目初始化规范 + +在启动任何流水线阶段之前,**必须**先与用户确认以下项目参数: + +## 项目参数表 + +| 参数 | 说明 | 示例 | +|------|------|------| +| 集数 | 总共拆分为几集 | 7集 | +| 单集时长 | 每集目标时长(分钟) | 2.5分钟 | +| 原著范围 | 改编覆盖的章节范围 | 第1-35章 | +| 章节ID列表 | 本次任务涉及的章节ID(用于事件检索) | [1,2,3,4,5] | +| 平台规格 | 画面比例(竖屏/横屏) | 竖屏9:16 | +| 风格定位 | 短剧整体风格标签 | 诡异修仙+心理悬疑 | +| 付费策略 | 前几集免费、从第几集设付费点 | 前2集免费,第3集起付费 | + +## 初始化对话流程 + +1. 用户发起改编请求时,先通过 `deepRetrieve` 检索是否已有已确认的项目参数 +2. 如果没有已确认的参数,**必须主动询问用户**: + - "请确认以下信息:计划拆分为几集?每集大约几分钟?覆盖原著哪些章节?" +3. 用户确认后,将参数作为**项目配置**保存,并在所有后续派发指令头部附带 +4. 如果用户只给出部分参数,对未给出的参数**逐一追问**,不可使用默认值跳过 + +## 参数传递模板 + +所有派发给执行层和监督层的指令,**必须在头部附带完整项目配置**: +``` +【项目配置】 +- 集数:{totalEpisodes}集 +- 单集时长:{episodeDuration}分钟(约{wordsPerEpisode}字台词) +- 原著范围:第{startChapter}-{endChapter}章 +- 章节ID列表:{chapterIds} +- 平台规格:{platform} +- 风格定位:{style} +- 付费策略:{paywall} +``` + +> 台词字数按 150字/分钟 语速自动计算:`wordsPerEpisode = episodeDuration × 150` diff --git a/data/skills/script_agent_skills/decision/pipeline_adaptation.md b/data/skills/script_agent_skills/decision/pipeline_adaptation.md new file mode 100644 index 0000000..fab3d15 --- /dev/null +++ b/data/skills/script_agent_skills/decision/pipeline_adaptation.md @@ -0,0 +1,27 @@ +# 阶段2:改编策略(Adaptation Strategy) + +## 全局流程 + +每个阶段执行流程如下: + +1. 决策层分析用户请求,通过 deepRetrieve 获取项目记忆,判断当前阶段 +2. 决策层派发任务给执行层,执行层写入 planData +3. 决策层派发审核任务给监督层,监督层生成审核报告 +4. 决策层将审核报告 + 产出摘要展示给用户 +5. 用户决策:通过 → 进入下一阶段 | 修复 → 再次审核 | 重做 → 重新派发 + +## 阶段定义 + +``` +输入:事件表(get_novel_events) + planData.storySkeleton +处理:提炼改编原则、确定删减依据、世界观呈现策略 +输出:planData.adaptationStrategy +工具:get_planData → set_planData_adaptationStrategy +质量门:原则与骨架一致、服务于故事核 +前置条件:阶段1(故事骨架)通过审核 +``` + +## 阶段约束 + +- 阶段1-2 **必须串行**(后续阶段依赖前置输出) +- 审核与执行**串行**(先执行后审核,审核报告展示给用户,用户确认后进入下一阶段或修复) diff --git a/data/skills/script_agent_skills/decision/pipeline_script.md b/data/skills/script_agent_skills/decision/pipeline_script.md new file mode 100644 index 0000000..ba538b5 --- /dev/null +++ b/data/skills/script_agent_skills/decision/pipeline_script.md @@ -0,0 +1,28 @@ +# 阶段3:剧本编写(Script Writing) + +## 全局流程 + +每个阶段执行流程如下: + +1. 决策层分析用户请求,通过 deepRetrieve 获取项目记忆,判断当前阶段 +2. 决策层派发任务给执行层,执行层写入 planData +3. 决策层派发审核任务给监督层,监督层生成审核报告 +4. 决策层将审核报告 + 产出摘要展示给用户 +5. 用户决策:通过 → 进入下一阶段 | 修复 → 再次审核 | 重做 → 重新派发 + +## 阶段定义 + +``` +输入:事件表(get_novel_events) + planData.storySkeleton + planData.adaptationStrategy +处理:按集编写(可并行或逐集) +输出:SQLite 中的剧本记录 +工具:get_novel_events + get_planData + get_novel_text → insert_script_to_sqlite +质量门:时长合规、台词字数、画面可执行、资产一致 +前置条件:阶段2(改编策略)通过审核 +附加前置条件:用户已明确确认写入 SQL +``` + +## 并行策略 + +- 阶段3 的多集剧本**可以并行**编写(互不依赖) +- 审核与执行**串行**(先执行后审核,审核报告展示给用户,用户确认后进入下一阶段或修复) diff --git a/data/skills/script_agent_skills/decision/pipeline_skeleton.md b/data/skills/script_agent_skills/decision/pipeline_skeleton.md new file mode 100644 index 0000000..09c3ea9 --- /dev/null +++ b/data/skills/script_agent_skills/decision/pipeline_skeleton.md @@ -0,0 +1,27 @@ +# 阶段1:故事骨架(Story Skeleton) + +## 全局流程 + +每个阶段执行流程如下: + +1. 决策层分析用户请求,通过 deepRetrieve 获取项目记忆,判断当前阶段 +2. 决策层派发任务给执行层,执行层写入 planData +3. 决策层派发审核任务给监督层,监督层生成审核报告 +4. 决策层将审核报告 + 产出摘要展示给用户 +5. 用户决策:通过 → 进入下一阶段 | 修复 → 再次审核 | 重做 → 重新派发 + +## 阶段定义 + +``` +输入:事件表(通过 get_novel_events(ids:number[]) 获取) +处理:三幕分割、按项目配置分集、删减决策、钩子设计 +输出:planData.storySkeleton +工具:get_planData → set_planData_storySkeleton +质量门:集数×单集时长符合配置、章节全覆盖、情绪曲线合理 +前置条件:事件提取已完成 +``` + +## 阶段约束 + +- 阶段1-2 **必须串行**(后续阶段依赖前置输出) +- 审核与执行**串行**(先执行后审核,审核报告展示给用户,用户确认后进入下一阶段或修复) diff --git a/data/skills/script_agent_skills/execution/adaptation_format.md b/data/skills/script_agent_skills/execution/adaptation_format.md new file mode 100644 index 0000000..a449b28 --- /dev/null +++ b/data/skills/script_agent_skills/execution/adaptation_format.md @@ -0,0 +1,42 @@ +# 改编策略输出格式规范 + +输出为 Markdown,整体结构如下: + +``` +# {作品名} - 关键决策记录 +--- +## 核心改编原则(3-5条) +## 主要删除决策 +## 世界观呈现策略 +``` + +--- + +## 核心改编原则 + +每条原则包含三层: + +1. **{原则名}**(2-6字) + - ✅ 正面指导:应该做什么 + - ❌ 负面边界:不应该做什么 + +必须覆盖以下维度: +- **叙事核心**:作品的本质吸引力 +- **结构策略**:多线叙事的处理方式 +- **风格标尺**:情绪/冲突/悬疑的度 +- **载体约束**:短剧平台的特殊限制如何影响改编 + +## 主要删除决策 + +每条包含: +- **被删/压缩内容**(精确到章节或场景) +- **原因**:节奏拖沓 / 信息密度低 / 载体不支持 / 主线贡献弱 +- **替代方案**:压缩为蒙太奇、一句话带过、或完全删除 + +## 世界观呈现策略 + +回答以下问题: +1. 关键设定元素以什么节奏出场? +2. 对设定的解释度?(完全模糊 / 暗示 / 明确交代) +3. 哪个角色作为世界观锚点?(通过谁的态度建立世界观) +4. 观众视角对齐谁?(和主角一起发现 / 上帝视角) diff --git a/data/skills/script_agent_skills/execution/script_execution_adaptation.md b/data/skills/script_agent_skills/execution/script_execution_adaptation.md new file mode 100644 index 0000000..8021104 --- /dev/null +++ b/data/skills/script_agent_skills/execution/script_execution_adaptation.md @@ -0,0 +1,41 @@ +--- +name: script_execution_adaptation +description: >- + 执行层技能:改编策略制定。基于事件表和故事骨架制定核心改编原则、删除决策和世界观呈现策略,写入 planData。 +--- + +# 改编策略制定 + +## 工具 + +| 操作 | 调用 | +|------|------| +| 读取工作区 | `get_planData` | +| 读取事件 | `get_novel_events(ids:number[])` | +| 写入策略 | `set_planData_adaptationStrategy` | + +## 执行流程 + +1. 调用 `get_novel_events(ids)` 获取事件表,调用 `get_planData` 获取故事骨架 +2. **阐述思路**(200-300字):核心改编原则方向、删减大方向、世界观呈现思路 +3. 按 [adaptation_format.md](adaptation_format.md) 格式,依次完成: + - 核心改编原则(3-5条):含优先级、正面指导、负面边界 + - 主要删除决策:被删/压缩内容、原因、对主线影响 + - 世界观呈现策略:关键元素出场节奏、解释度策略、角色态度锚点 +4. 调用 `set_planData_adaptationStrategy` 保存 +5. 返回简短确认,如:"改编策略已保存,请在右侧工作台查看。" + +**输出格式**:严格参照 [adaptation_format.md](adaptation_format.md) + +## 约束 + +- 所有改编决策服务于骨架中确立的故事核和主角弧线 +- 保持骨架中设定的叙事线索结构,维持观众的持续好奇 +- 根据【项目配置】中的平台规格和单集时长约束,优先视觉叙事,压缩大段对话 +- 所有参数从【项目配置】读取,禁止硬编码 + +## 注意事项 + +- 执行前先调用 `get_planData` 确认工作区状态;已有内容在其基础上修改,除非指令要求重写 +- 只执行改编策略任务,不越权执行其他阶段 +- 完成写入后返回一句确认即可,不复述内容;返回后本次任务终止 diff --git a/data/skills/script_agent_skills/execution/script_execution_script.md b/data/skills/script_agent_skills/execution/script_execution_script.md new file mode 100644 index 0000000..31b5164 --- /dev/null +++ b/data/skills/script_agent_skills/execution/script_execution_script.md @@ -0,0 +1,42 @@ +--- +name: script_execution_script +description: >- + 执行层技能:剧本编写。基于事件表、故事骨架和改编策略编写单集剧本,写入 SQLite。 +--- + +# 剧本编写 + +## 工具 + +| 操作 | 调用 | +|------|------| +| 读取工作区 | `get_planData` | +| 读取事件 | `get_novel_events(ids:number[])` | +| 读取原文 | `get_novel_text` | +| 写入剧本 | `insert_script_to_sqlite` | + +## 执行流程 + +1. 调用 `get_novel_events(ids)` 获取事件表,调用 `get_planData` 获取骨架与改编策略 +2. 从骨架中提取本集信息:覆盖章节、戏剧功能、场景核心、删减决策、集末钩子 +3. 调用 `get_novel_text` 获取对应章节原文 +4. **阐述思路**(200-300字):场景组织方式、重点情绪与冲突、节奏把控思路 +5. 按 [script_format.md](script_format.md) 格式编写剧本:文件头 → 剧情梗概 → 出场角色表 → 场景表 → 剧本正文 +6. 调用 `insert_script_to_sqlite` 写入 +7. 返回简短确认,如:"第X集剧本已写入,请在工作台查看。" + +**输出格式**:严格参照 [script_format.md](script_format.md) + +## 约束 + +- 单集时长控制在【项目配置】指定值 ±10秒,台词量按 150字/分钟 推算(禁止硬编码) +- 构图符合【项目配置】中的平台规格 +- △场景描述要足够具体,描写"人怎么干"而非仅"人干什么",可直接用于 AI 视频生成 +- 场景之间用 `---` 分隔 + +## 注意事项 + +- 执行前先调用 `get_planData` 确认工作区状态;已有内容在其基础上修改,除非指令要求重写 +- 只执行剧本编写,不越权执行其他阶段 +- 不处理剧本删除请求,收到时提醒:`请在道具本管理中手动删除剧本` +- 完成写入后返回一句确认即可,不复述内容;返回后本次任务终止 diff --git a/data/skills/script_agent_skills/execution/script_execution_skeleton.md b/data/skills/script_agent_skills/execution/script_execution_skeleton.md new file mode 100644 index 0000000..464b79f --- /dev/null +++ b/data/skills/script_agent_skills/execution/script_execution_skeleton.md @@ -0,0 +1,45 @@ +--- +name: script_execution_skeleton +description: >- + 执行层技能:故事骨架搭建。基于事件表构建三幕结构、分集决策、删减记录和付费卡点,写入 planData。 +--- + +# 故事骨架搭建 + +## 工具 + +| 操作 | 调用 | +|------|------| +| 读取工作区 | `get_planData` | +| 读取事件 | `get_novel_events(ids:number[])` | +| 写入骨架 | `set_planData_storySkeleton` | + +## 执行流程 + +1. 调用 `get_novel_events(ids)` 获取事件表 +2. **阐述思路**(200-300字):核心吸引力判断、三幕划分思路、分集策略方向 +3. 构建骨架内容: + - 故事核:一句话总结整部剧的核心吸引力 + - 隐线:主角的内在成长轨迹(人物弧) + - 三幕结构:每幕的功能、核心问题、覆盖章节、对应集数、幕末转折 + - 分集决策:按 [skeleton_format.md](skeleton_format.md) 格式,根据集数自动选择逐集展开(≤20集)或总览+关键集展开(>20集) + - 全局删减决策表 + - 付费卡点设计 +4. 调用 `set_planData_storySkeleton` 保存 +5. 返回简短确认,如:"故事骨架已保存,请在右侧工作台查看。" + +**输出格式**:严格参照 [skeleton_format.md](skeleton_format.md) + +## 约束 + +- 总时长 = 集数 × 单集时长(从【项目配置】读取,禁止硬编码) +- 压缩比 ≤ 40% +- 每集必须有集末钩子 +- 付费策略按【项目配置】执行 +- 章节必须与事件表一致,不允许出现不存在的章节 + +## 注意事项 + +- 执行前先调用 `get_planData` 确认工作区状态;已有内容在其基础上修改,除非指令要求重写 +- 只执行骨架搭建,不越权执行其他阶段 +- 完成写入后返回一句确认即可,不复述内容;返回后本次任务终止 diff --git a/data/skills/script_agent_skills/execution/script_format.md b/data/skills/script_agent_skills/execution/script_format.md new file mode 100644 index 0000000..91bf139 --- /dev/null +++ b/data/skills/script_agent_skills/execution/script_format.md @@ -0,0 +1,287 @@ +# 剧本输出格式规范 + +## 一、文件头 + +```markdown +# {作品名} EP{NN}:{集标题} +# 目标时长:{单集时长}分钟 ≈ {台词字数}字台词 +# 平台:{平台规格} | 风格:{风格标签} | 节拍:{节拍概要} + +--- +``` + +## 二、剧情梗概 + +```markdown +## 剧情梗概 + +{本集的故事高层概括,包含:主要冲突、关键转折、情感弧线,200-300字} + +--- +``` + +## 三、本集出场角色与定妆信息 + +```markdown +## 出场角色 + +| 角色 | 角色说明 | 定妆描述 | +|------|----------|---------| +| {角色名} | {性格、身份、角色功能} | {服装、发型、妆容等视觉特征} | +| ... | ... | ... | + +--- +``` + +- 只列出本集出场的角色 +- 角色说明应涵盖人物身份和在本集的关键作用 +- 定妆信息需与美术资产包保持一致,避免后续修改时重复描述 + +## 四、场景说明 + +```markdown +## 场景表 + +| 场景 | 时间 | 氛围 | 说明 | +|------|------|------|------| +| {场景名} | {时间设定} | {整体氛围/光线} | {视觉风格要点} | +| ... | ... | ... | ... | + +--- +``` + +- 按出现顺序列举所有场景 +- 氛围描述帮助后续美术统一视觉调性 +- 说明栏强调该场景的视觉重点或技术难点 + +## 五、剧本内容结构 + +AI短剧剧本采用标准剧本格式,用△标记场景描述,详细描写"人怎么干"。 + +### 场景段落格式 + +``` + +{场号} {场景名} {时间}/{光线} +人物:{人物1} {人物2} {人物3} 众{身份}若干 + +△{场景环境、布景的详细描述} +△{人物动作、表情、语气的具体描写} +△{继续描写人物状态变化} +{人物名1}:{对话内容} +{人物名2}:{对话内容} +△{后续动作场景描述} +△{人物反应、表情等细节} + +OS({人物名},{情绪}): +{内心独白或旁白内容} + +--- + +{场号} {场景名} {时间}/{光线} +人物:{人物1} {人物2} 众{身份}若干 + +△{场景开场描述} +△{人物动作和表情描写} +{人物名}:{对话内容} + +--- + +{场号} {场景名} {时间}/{光线} +人物:{人物1} {人物2} {人物3} 众{身份}若干 + +△{场景动作描述} +{人物名}:{对话内容} +△{人物反应和后续动作描写} +{人物名}:{对话内容} +△{场景收尾描述} +``` + +### 格式规范 + +**场景标题** +- 格式:`{场号} {场景名} {时间}/{光线}` +- 示例:`1-1 {具体场景名} 日/内` +- 时间可选:日/夜、晨/午/晚 +- 光线:内(室内)/ 外(室外) + +**人物列表** +- 格式:`人物:{人物名1} {人物名2} ...`(空格分隔) +- 只列本场景出现的人物 +- 若干人物用"众{身份}若干"表示 + +**场景描述** +- 标记:`△` 开头 +- 详细描述场景环境、布景、人物动作、表情、语气等 +- 描写"人怎么干"而非仅"人干什么" + +**人物台词** +- 格式:`{人物名}:{台词}` +- 简洁直观,细节已在△描述中体现 + +**旁白/内心独白** +- OS格式:`OS({人物名},{情绪}):`(Off Screen 画外音) +- V.S格式:`V.S.({人物名},{情绪}):`(Voice over 旁白) +- 示例:`OS({主角名},{具体情绪}):` 或 `V.S.(众{身份},{具体情绪}):` + +**转场** +- 场景之间用 `---` 分隔 + +## 六、画面描述规范 + +画面描述必须足够具体,可直接用于 AI 视频生成提示词: + +### 必须包含 +- **镜头类型**:特写/近景/中景/全景/远景 +- **人物动作**:具体到肢体和表情 +- **光线条件**:光源方向、色温、明暗比 +- **关键道具**:与剧情相关的物品 + +### 竖屏适配 +- 人物居中构图为主 +- 避免横向全景(竖屏无法展示) +- 特写和近景优先(竖屏对面部表情呈现效果好) +- 上下构图利用竖屏优势(如俯视/仰视) + +## 七、台词规范 + +- 对话标注格式:`{人物名}:{台词}` +- 表演指示关键词:平静、愤怒、崩溃、冷笑、低沉、颤抖、用力、轻声等 +- 单句台词不超过20字(竖屏短视频观众阅读速度) + +## 八、转场标注 + +节拍之间必须标注转场方式: + +| 标注 | 说明 | 适用场景 | +|------|------|----------| +| `[硬切]` | 无过渡直接切 | 场景对比强烈、制造冲击 | +| `[淡入]` | 缓慢显现 | 时间流逝、梦境进入 | +| `[闪白]` | 强白光过渡 | 世界切换(幻觉↔现实) | +| `[闪黑]` | 黑屏过渡 | 意识丧失、恐怖预兆 | +| `[叠化]` | 画面重叠过渡 | 蒙太奇、记忆闪回 | + +## 九、时长控制 + +- 目标:按项目配置的单集时长 ±10秒 +- 台词量:按 150字/分钟 语速计算 +- 每个场景段落20-60秒 +- 纯画面段落(无台词)最长15秒 + +## 十、自查清单(仅供内部校验,不输出到剧本中) + +编写完成后,按以下清单逐项自查,发现问题直接修正后再写入,无需将清单本身输出: + +- [ ] 台词总字数符合时长要求 +- [ ] 总时长在目标范围内 +- [ ] 每个场景段落有充分的△描述 +- [ ] 所有转场已标注 +- [ ] 集末转折与整体架构一致 +- [ ] 角色外貌描写符合资产包 +- [ ] 场景描写符合资产包 +- [ ] 竖屏构图(无横向全景) + +## 十一、禁止输出的内容 + +以下内容**严禁**出现在剧本输出中: + +- **台词字数统计**:不输出台词字数汇总或统计信息 +- **版本标记**:集标题不得附加"修订版""v2""定稿"等版本后缀,保持原始标题 +- **幕/节拍时间标注**:不输出类似"第一幕:XXX(0s–40s)"的幕结构或节拍时间段 +- **镜头技术标注**:△描述中不得附加"全景·缓推·约6秒""特写·俯拍"等镜头语言括注 +- **自查清单**:不输出自查清单本身 +- **任何元信息**:不输出字数统计、场景数量统计、创作说明等非剧本内容 + +剧本输出只包含:文件头 → 剧情梗概 → 出场角色表 → 场景表 → 剧本正文(△描述 + 台词 + OS/V.S.) + +## 附录:完整示例 + +``` +# 凌天诀 EP01:废物宗主 +# 目标时长:4分钟 ≈ 600字台词 +# 平台:竖屏9:16 | 风格:玄幻·热血·逆袭 | 节拍:羞辱→隐忍→觉醒 + +--- + +## 剧情梗概 + +青云宗主殿内,曾经的天才宗主凌玄被副宗主沈清辞当众羞辱。三年前凌玄独闯万妖窟修为尽废,沦为宗内人人唾弃的废物。沈清辞联合凌玄的未婚妻苏晚卿,在众弟子面前对凌玄施以暴行,逼他交出宗主令。凌玄在血泊中隐忍不发,眼神浑浊如死水,任由拳脚加身。然而就在苏晚卿将退婚书扔在他脸上的瞬间,凌玄体内沉寂三年的封印出现一道裂痕,一缕金色灵气从丹田涌出。凌玄压下异变,默默将退婚书收入怀中,在众人的嘲笑声中被拖出大殿。无人注意到,他低头时嘴角浮现一丝冰冷的弧度。 + +--- + +## 出场角色 + +| 角色 | 角色说明 | 定妆描述 | +|------|----------|---------| +| 凌玄 | 青云宗宗主,三年前修为尽废,隐忍蛰伏,本集核心受难者 | 衣衫褴褛的灰白色残破宗主袍,头发凌乱遮住半张脸,脸上血污斑驳,棱角分明 | +| 沈清辞 | 副宗主,野心勃勃的篡位者,本集主要施暴者 | 银白色副宗主袍,束发整齐,面容俊朗但眼神阴鸷 | +| 苏晚卿 | 凌玄未婚妻,已倒向沈清辞,本集背叛者 | 紫色长袍,丹凤眼,妆容精致,气质冷艳 | +| 弟子甲 | 沈清辞手下,负责押送凌玄 | 青云宗普通弟子服,面相凶悍 | +| 弟子乙 | 沈清辞手下,负责押送凌玄 | 青云宗普通弟子服,身材壮硕 | + +--- + +## 场景表 + +| 场景 | 时间 | 氛围 | 说明 | +|------|------|------|------| +| 青云宗主殿 | 日 | 破败、压抑、灰尘弥漫 | 香炉倾倒,青石板地面,石柱林立,光线从破损的屋顶缝隙漏入 | +| 青云宗主殿高台 | 日 | 居高临下、权力压迫 | 高台上设有宗主座,俯瞰整个大殿,光线从背后打入形成逆光剪影 | +| 宗门长廊 | 日 | 冷清、孤寂 | 长廊两侧石柱投下规律的阴影,尽头是刺眼的白光 | + +--- + + +1-1 青云宗主殿 日/内 +人物:凌玄 弟子甲 弟子乙 众弟子若干 + +△破旧的青云宗主殿,香炉倾倒在地,灰尘在从屋顶缝隙漏入的光柱中缓缓飘浮。 +△两名弟子粗暴地拖拽着一个衣衫褴褛的男人穿过大殿。男人头发凌乱遮住半张脸,衣襟沾满暗红色血迹,双脚无力地在青石板上拖出两道长长的血痕。 +△弟子甲猛地抬脚,一脚踹在男人腰间,力道之大让男人整个身体弓成虾状,闷哼声在空旷的大殿中回荡。 +弟子甲:走快点,废物! +弟子乙:堂堂宗主,现在连狗都不如! +△男人被扔进殿中央,脸重重砸在冰冷的青石板上,鲜血从嘴角缓缓流出,在石板上洇开一小片暗红。 +△他缓缓抬起头,露出一张棱角分明但满是血污的脸——正是凌玄。 +△凌玄的眼神浑浊无光,像一潭死水。但在他低下头的瞬间,眼底深处闪过一丝不属于废人的冰冷光芒,转瞬即逝。 + +OS(凌玄,低沉、压抑): +三年了……再忍一忍。 + +--- + +1-2 青云宗主殿高台 日/内 +人物:沈清辞 苏晚卿 众长老若干 + +△高台之上,沈清辞一身银白色副宗主袍端坐在宗主座旁,右臂搂着身穿紫色长袍的苏晚卿。逆光从他身后打入,在地面投下巨大的阴影。 +△苏晚卿丹凤眼微微上挑,嘴角挂着若有若无的笑意,纤细的手指轻轻抚过沈清辞胸口的衣襟,动作亲昵而挑衅。 +△沈清辞缓缓起身,脸上挂着胜利者的从容微笑,一步步走下高台,每一步靴底都在青石板上敲出清脆的回响。 +△众长老分列两侧,有的低头不语双手微颤,有的眼神闪烁不敢直视,无人敢看向殿中央的凌玄。 +沈清辞:凌玄,三年了,你这废物还真能装。 + +--- + +1-3 青云宗主殿 日/内 +人物:凌玄 沈清辞 苏晚卿 众弟子若干 众长老若干 + +△沈清辞走到凌玄面前,居高临下地审视着他,皮靴的尖端轻轻挑起凌玄的下巴,像审视一条垂死的狗。 +沈清辞:抬起头,让本座看看你现在的样子。 +△凌玄缓缓抬头,脸上血污斑驳,眼神依然浑浊,嘴唇微微翕动却没有发出声音。 +△沈清辞突然收回脚,猛地踹在凌玄胸口。凌玄整个人倒飞出去,后背重重撞在石柱上,石柱表面震落一片灰尘。 +△凌玄从嘴角咳出一口鲜血,身体沿着石柱无力地滑落在地,胸口的衣襟被踹出一个深深的脚印。 +沈清辞:三年前你独闯万妖窟,修为尽废,本座还以为你能翻身……没想到就是个彻头彻尾的废物。 +△殿内弟子们发出嗤笑声,眼神中满是轻蔑和幸灾乐祸。笑声在空旷的大殿中层层叠叠地回荡。 + +V.S.(众弟子,嘲笑): +废物……废物…… + +△苏晚卿从高台上款款走下,手中捏着一张折好的纸,走到凌玄面前蹲下身,将退婚书轻轻贴在他满是血污的脸上,然后松手,纸张缓缓滑落到地面。 +苏晚卿:凌玄,你我的婚约,到此为止。 +△凌玄低头看着地上的退婚书,沉默片刻,伸出颤抖的手将它捡起,缓缓折好收入怀中。 +△就在这一瞬间,凌玄丹田深处一道金色裂纹无声地亮起又熄灭,他的瞳孔猛地收缩了一下,随即恢复浑浊。 +△凌玄被两名弟子架起拖向殿外。他低着头,凌乱的头发遮住了脸,没有人看到他嘴角缓缓浮现的一丝冰冷弧度。 + +OS(凌玄,低沉、隐忍中带着一丝锋芒): +退婚书……我收下了。 + +[闪黑] +``` diff --git a/data/skills/script_agent_skills/execution/skeleton_format.md b/data/skills/script_agent_skills/execution/skeleton_format.md new file mode 100644 index 0000000..ed43ab3 --- /dev/null +++ b/data/skills/script_agent_skills/execution/skeleton_format.md @@ -0,0 +1,95 @@ +# 故事骨架输出格式规范 + +输出为 Markdown,整体结构如下: + +``` +# {作品名} - 故事骨架 +--- +## 故事核(一句话) +## 隐线(人物弧) +## 三幕结构 +## 分集决策 ← 根据集数选择模式A或模式B +## 全局删减决策记录 +## 付费卡点设计 +``` + +--- + +## 故事核 + +> {一句话总结本剧最核心的吸引力,≤50字} + +**最吸引人的本质:** {解释为什么这个故事核有吸引力} + +## 隐线(人物弧) + +描述主角的内在成长轨迹,格式: + +> 被X定义为Y → 用Y的方式Z → 发现Y本身是W + +说明每集如何推进这条弧,外在冲突是载体而非目的。 + +## 三幕结构 + +每幕包含: + +``` +### 第{N}幕:{标题}(第X-Y章 → 集A-B) +**功能:** {建立/发展/高潮/收尾} +**核心问题:** {本幕要让观众追问的问题} +**幕末转折:** {一句话描述转折点} +``` + +## 分集决策 + +根据【项目配置】总集数自动选择输出模式: + +### 模式A:逐集展开(≤20集) + +``` +### 集{N}:{集标题}(第X-Y章) +**戏剧功能:** {建立/发展/高潮前积累/高潮+余波/新世界建立/新高潮+开放结局} +**场景核心:** {一句话——这集要给观众什么体验} +**章节分配:** +- 第X章:{保留完整/压缩/删除}(核心场景**加粗**) +- 第Y章:... +**删减决策:** {删什么、为什么} +**集末钩子:** {最后5-10秒的台词或画面} +**付费点:** {无 / 有+类型} +``` + +### 模式B:总览表 + 关键集展开(>20集) + +**第一步**——分集总览表,每集一行: + +| 集 | 集标题 | 章节范围 | 戏剧功能 | 场景核心 | 章节处理 | 集末钩子 | 付费点 | +|----|--------|----------|----------|----------|----------|----------|--------| + +> 「章节处理」列:`章号:处理` 用 `/` 分隔,如 `3保留/4压缩/5删`;未提及默认保留。 + +**第二步**——对以下关键集用模式A模板展开详情: +- 🔴 幕末转折集、付费卡点集、高潮集 +- 🟡 首集 + +## 全局删减决策记录 + +| 决策 | 被删/压缩内容 | 原因 | +|------|--------------|------| +| 删 | {具体内容} | {原因} | +| 压缩 | {具体内容} | {原因} | + +## 付费卡点设计 + +| 位置 | 内容 | 类型 | +|------|------|------| +| 集{N}末 | {卡点内容} | {智识钩子/悬念钩子/情感钩子/世界观钩子} | + +--- + +## 自查清单(生成后内部校验,不输出) + +- [ ] 总集数、每集时长符合【项目配置】 +- [ ] 前2集无付费点 +- [ ] 每集有集末钩子,三幕均有幕末转折 +- [ ] 删减记录与分集中的删减一致 +- [ ] 章节编号与事件表一致,无虚构章节 \ No newline at end of file diff --git a/data/skills/script_agent_skills/supervision/script_supervision_adaptation.md b/data/skills/script_agent_skills/supervision/script_supervision_adaptation.md new file mode 100644 index 0000000..5e5b574 --- /dev/null +++ b/data/skills/script_agent_skills/supervision/script_supervision_adaptation.md @@ -0,0 +1,37 @@ +# 改编策略审核 + +基于 [supervision_common.md](supervision_common.md) 中的通用规范执行审核。 + +## 数据准备 + +1. 调用 `get_planData` 获取改编策略和骨架数据 +2. 从【项目配置】读取:付费策略、平台规格、单集时长 + +## 审核维度 + +| 审核项 | 标准 | 严重程度 | +|--------|------|----------| +| 与骨架一致 | 删除决策与骨架中的删减记录一致;所有原则服务于故事核 | 严重 | +| 原则质量 | 3-5条核心原则,每条有正面指导和负面边界 | 中等 | +| 载体适配 | 有世界观呈现策略;考虑了平台规格和单集时长的约束 | 中等 | + +## 跨阶段一致性检查 + +改编策略需与骨架进行一致性校验: + +- **删减决策一致**:策略中的删除决策必须在骨架的删减记录中有对应;骨架中标注"保留完整"的场景,策略不能标注为删除 +- **故事核对齐**:所有改编原则必须服务于骨架中确立的故事核 + +如发现不一致,标记为**严重问题**。 + +## 详细审核标准 + +### 故事核对齐(严重) +- 所有改编原则必须服务于骨架中确立的故事核 +- 删减的内容不能包含体现故事核的关键场景 +- 保留的内容必须推动主角弧线的核心转变 + +### 与骨架一致性(严重) +- 改编策略中的删除决策,必须在骨架的删减记录中有对应 +- 骨架中标注"保留完整"的场景,改编策略不能标注为删除 +- 交叉检查方法:将两者的删减列表逐一比对 diff --git a/data/skills/script_agent_skills/supervision/script_supervision_script.md b/data/skills/script_agent_skills/supervision/script_supervision_script.md new file mode 100644 index 0000000..2b875f0 --- /dev/null +++ b/data/skills/script_agent_skills/supervision/script_supervision_script.md @@ -0,0 +1,61 @@ +# 剧本审核 + +基于 [supervision_common.md](supervision_common.md) 中的通用规范执行审核。 + +## 数据准备 + +1. 调用 `get_planData` 获取剧本、骨架和改编策略数据 +2. 调用 `get_novel_events(ids:number[])` 获取事件表数据 +3. 从【项目配置】读取:单集时长、平台规格、资产包(如有) + +## 审核维度 + +| 审核项 | 标准 | 严重程度 | +|--------|------|----------| +| 时长与字数 | 总时长符合单集时长 ±10秒;台词字数按 150字/分钟 推算(±50字) | 严重 | +| 画面可执行 | 画面描述足够具体,可直接用于 AI 提示词生成 | 严重 | +| 内容覆盖 | 骨架分配的章节内容全部体现;标注的删减/压缩已执行 | 严重 | +| 资产一致性 | 角色外貌、场景描写与【项目配置】中的资产包一致(未传入资产包则跳过并注明) | 严重 | +| 节拍与衔接 | 6-8个节拍各有时间码;转场方式明确;集末钩子与骨架一致;情绪过渡自然 | 中等 | +| 构图适配 | 符合【项目配置】中的平台规格构图要求 | 中等 | + +## 跨阶段一致性检查 + +剧本需与骨架和改编策略进行一致性校验: + +- **时长落实**:剧本实际时长是否符合骨架中该集的时长分配 +- **删减落实**:骨架和策略中标注的删减/压缩是否在剧本中执行 +- **钩子落实**:骨架中设计的集末钩子是否在剧本中体现 +- **资产一致**:角色外貌和场景描写是否与资产包吻合(未传入则跳过并注明"未收到资产配置,资产一致性审核已跳过") + +如发现不一致,标记为**严重问题**。 + +## 详细审核标准 + +### 时长合规性(严重) +验证方法: +1. 统计全部台词字数(含旁白、内心独白) +2. 按150字/分钟语速换算 +3. 加上纯画面段落时长(每段5-15秒) +4. 总时长应在【项目配置】单集时长 ±10秒范围内 + +### 画面可执行性(严重) +每个画面描述必须包含: +- 可识别的镜头类型(特写/近景/中景/全景) +- 具体的人物动作(不能写"角色做了某事") +- 可视化的环境要素(光线、色调、道具) + +不通过示例: +- "李火旺感到害怕" ← 情绪状态,不是画面 +- "场景很恐怖" ← 抽象,不可执行 + +通过示例: +- "李火旺后退半步,目光下移盯着地面那道黑色湿痕,右手微微发抖" ← 具体、可拍摄 + +### 角色视觉一致性(严重) +每个BEAT中出场角色的外貌描写,必须与【项目配置】中传入的角色资产包吻合。 +若未传入角色资产包,跳过此项。 + +### 场景氛围一致性(严重) +场景描写须与【项目配置】中传入的场景资产包保持一致,包括色调、光线、道具等视觉要素。 +若未传入场景资产包,跳过此项。 diff --git a/data/skills/script_agent_skills/supervision/script_supervision_skeleton.md b/data/skills/script_agent_skills/supervision/script_supervision_skeleton.md new file mode 100644 index 0000000..7faf6ad --- /dev/null +++ b/data/skills/script_agent_skills/supervision/script_supervision_skeleton.md @@ -0,0 +1,45 @@ +# 故事骨架审核 + +基于 [supervision_common.md](supervision_common.md) 中的通用规范执行审核。 + +## 数据准备 + +1. 调用 `get_planData` 获取骨架数据 +2. 调用 `get_novel_events(ids:number[])` 获取事件表数据 +3. 从【项目配置】读取:集数、单集时长、付费策略、章节范围 + +## 审核维度 + +| 审核项 | 标准 | 严重程度 | +|--------|------|----------| +| 结构完整性 | 故事核存在且聚焦主角内在冲突;三幕均有功能、核心问题、幕末转折 | 严重 | +| 分集与时长 | 分集数恰好等于【项目配置】集数;每集时长符合单集时长 ±10秒 | 严重 | +| 章节全覆盖 | 【项目配置】指定的原著章节全部被分配到具体集数 | 严重 | +| 叙事设计 | 删减有据、集末钩子齐全、付费卡点符合策略、情绪曲线有起伏、人物弧每集推进 | 中等 | + +## 跨阶段一致性检查 + +骨架作为首个产出阶段,需与事件表进行一致性校验: + +- **章节全覆盖**:事件表中的章节是否全部被骨架分配到具体集数,逐一核对无遗漏 +- **主线判定一致**:骨架中对事件主线强度的引用是否与事件表中的标注矛盾 + +如发现不一致,标记为**严重问题**。 + +## 详细审核标准 + +### 三幕功能验证(严重) +- 第一幕必须完成"建立"功能:规则建立、悬疑建立、动机激活 +- 第二幕必须完成"冲突"功能:主要矛盾展开、计划执行、代价付出 +- 第三幕必须完成"拓展/结局"功能:新世界、新能力、开放悬念 + +### 情绪曲线验证(中等) +全剧情绪分布应根据实际集数设计"波浪上升"模式: +- 不允许连续3集都是同一情绪强度 +- 最高潮应在中后期 +- 高潮后应有节奏缓冲再推向新高潮 + +### 付费卡点合理性(中等) +- 付费策略按【项目配置】中的设定执行 +- 付费点必须放在"观众最想知道后续"的位置 +- 钩子类型应多样化(不全是悬念钩子) diff --git a/data/skills/script_agent_skills/supervision/supervision_common.md b/data/skills/script_agent_skills/supervision/supervision_common.md new file mode 100644 index 0000000..df0d0eb --- /dev/null +++ b/data/skills/script_agent_skills/supervision/supervision_common.md @@ -0,0 +1,47 @@ +# 监督层通用规范 + +本文件定义所有审核任务共享的报告格式、评分标准和审核原则。 + +## 审核报告格式 + +```markdown +# 审核报告:{审核对象} + +## 总评 +- **评分**:{A/B/C/D} +- **概要**:{一句话总评,可顺带肯定亮点} + +## 问题清单 + +| # | 严重程度 | 审核项 | 问题 | 建议方案 | +|---|----------|--------|------|----------| +| 1 | 🔴 严重 | {审核项} | {一句话描述} | {多选方案用"/"分隔} | +| 2 | 🟡 中等 | {审核项} | {一句话描述} | {修复建议} | +| 3 | ⚪ 轻微 | {审核项} | {一句话描述} | {修复建议} | + +## 需要您决定(仅 C/D 级或严重问题存在多选方案时输出) +1. {选择题} +``` + +### 精简规则 + +- 审核通过的项目不出现在报告中 +- 同类轻微问题合并为一行 +- B 级及以上省略「需要您决定」区块 + +## 评分标准 + +| 评分 | 严重问题 | 中等问题 | +|------|----------|----------| +| A — 可直接使用 | 0 | ≤2 | +| B — 小修后可用 | 0 | ≤5 | +| C — 需较大修改 | 1-2 | 不限 | +| D — 建议重做 | ≥3 | 不限 | + +## 通用审核原则 + +1. **工具调取优先**:所有审核依据必须通过工具实际读取,不得凭记忆或上下文摘要审核 +2. **可执行优先**:标准是"能不能用",不是"完不完美" +3. **问题具体化**:每个问题指向具体位置和内容,不说"整体不够好" +4. **建议多元化**:严重问题提供多个可选方案 +5. **动态基准**:数值判断以【项目配置】为唯一基准;配置中未明确的参数以合理比例推算,并在报告中注明 diff --git a/data/skills/script_agent_supervision.md b/data/skills/script_agent_supervision.md index 624323a..14cd755 100644 --- a/data/skills/script_agent_supervision.md +++ b/data/skills/script_agent_supervision.md @@ -1,133 +1,32 @@ --- -name: supervision +name: script_agent_supervision.md description: >- - 短剧改编监督层Agent技能。负责审核执行层产出物的质量、一致性和完整性。 - 检查事件表覆盖度、骨架结构合理性、改编策略自洽性、剧本节拍与时长控制。 - 在决策层通过 run_sub_agent 调用时激活,返回审核报告和修改建议。 + 短剧改编监督层Agent路由。根据决策层派发的审核任务类型,加载对应的独立技能文件执行。 + 当收到决策层的 run_sub_agent 调用时激活。 --- -# 监督层 Agent 技能指令 +# 监督层 Agent — 任务路由 -你是短剧改编项目的**监督层 Agent**,负责审核执行层的产出物质量并提出意见。 -你由决策层通过 `run_sub_agent` 调用,返回结构化审核报告。 +你是短剧改编项目的**监督层 Agent**,只接收决策层派发的审核任务并执行。 **核心原则:你只提出问题和建议,不做任何修改决策。所有修改决定权属于用户。** -决策层收到你的报告后,会将问题和建议展示给用户,由用户决定: -- 哪些问题需要修复 -- 哪些建议采纳、哪些忽略 -- 是否需要重做某个阶段 +## 任务路由表 -## 审核流程 +收到任务后,根据指令中的关键词匹配对应技能文件,加载并执行: -> **重要**:监督层的所有数据必须通过工具调用获取,**不得依赖对话记忆、上下文或决策层指令中的内容摘要**来替代实际数据读取。 +| 标识词 | 技能文件 | 说明 | +|--------|----------|------| +| 骨架审核、审核骨架、review skeleton | [script_supervision_skeleton.md](script_agent_skills/supervision/script_supervision_skeleton.md) | 审核故事骨架的结构、分集与覆盖度 | +| 策略审核、审核改编策略、review adaptation | [script_supervision_adaptation.md](script_agent_skills/supervision/script_supervision_adaptation.md) | 审核改编策略与骨架的一致性 | +| 剧本审核、审核剧本、review script | [script_supervision_script.md](script_agent_skills/supervision/script_supervision_script.md) | 审核剧本的时长、画面与内容覆盖 | -1. 调用 `get_planData` 获取待审核的工作区数据(骨架、改编策略等) -2. 调用 `get_novel_events(ids:number[])` 获取事件表数据(用于跨阶段一致性检查) -3. 从任务指令中的【项目配置】读取基准参数(集数、单集时长、付费策略等) -4. 根据任务指令确认审核对象(骨架/改编策略/剧本) -5. 按对应审核维度逐项检查,**所有数值标准均以【项目配置】中的参数为基准动态推算,不使用任何硬编码数值** -6. 生成审核报告,包含评分、问题列表和修改建议 -7. 返回报告给决策层(决策层将报告展示给用户,由用户决定后续操作) +所有审核任务共享的报告格式、评分标准和通用原则见 [supervision_common.md](script_agent_skills/supervision/supervision_common.md)。 -## 审核维度 +## 路由规则 -> **重要**:以下审核项中涉及数量、时长、比例的标准,均须从【项目配置】动态读取计算,不得使用固定数字。 - - -### 故事骨架审核 - -| 审核项 | 标准 | 严重程度 | -|--------|------|----------| -| 结构完整性 | 故事核存在且聚焦主角内在冲突;三幕均有功能、核心问题、幕末转折 | 严重 | -| 分集与时长 | 分集数恰好等于【项目配置】集数;每集时长符合单集时长 ±10秒 | 严重 | -| 章节全覆盖 | 【项目配置】指定的原著章节全部被分配到具体集数 | 严重 | -| 叙事设计 | 删减有据、集末钩子齐全、付费卡点符合策略、情绪曲线有起伏、人物弧每集推进 | 中等 | - -### 改编策略审核 - -| 审核项 | 标准 | 严重程度 | -|--------|------|----------| -| 与骨架一致 | 删除决策与骨架中的删减记录一致;所有原则服务于故事核 | 严重 | -| 原则质量 | 3-5条核心原则,每条有正面指导和负面边界 | 中等 | -| 载体适配 | 有世界观呈现策略;考虑了平台规格和单集时长的约束 | 中等 | - -### 剧本审核 - -| 审核项 | 标准 | 严重程度 | -|--------|------|----------| -| 时长与字数 | 总时长符合单集时长 ±10秒;台词字数按 150字/分钟 推算(±50字) | 严重 | -| 画面可执行 | 画面描述足够具体,可直接用于 AI 提示词生成 | 严重 | -| 内容覆盖 | 骨架分配的章节内容全部体现;标注的删减/压缩已执行 | 严重 | -| 资产一致性 | 角色外貌、场景描写与【项目配置】中的资产包一致(未传入资产包则跳过并注明) | 严重 | -| 节拍与衔接 | 6-8个节拍各有时间码;转场方式明确;集末钩子与骨架一致;情绪过渡自然 | 中等 | -| 构图适配 | 符合【项目配置】中的平台规格构图要求 | 中等 | - -详细审核标准请参考 [quality_criteria.md](references/quality_criteria.md)。 - -## 审核报告格式 - -报告将由决策层转达给用户,应简洁、可操作,避免冗余: -```markdown -# 审核报告:{审核对象} - -## 总评 -- **评分**:{A/B/C/D}(A=可直接使用,B=小修后可用,C=需要较大修改,D=建议重做) -- **概要**:{一句话总评} - -## 问题清单 - -> 按严重程度排序,严重问题排最前。无问题的严重程度级别直接省略。 - -| # | 严重程度 | 审核项 | 问题 | 建议方案 | -|---|----------|--------|------|----------| -| 1 | 🔴 严重 | {审核项} | {一句话描述} | {修复方案,可列多个选项用"/"分隔} | -| 2 | 🟡 中等 | {审核项} | {一句话描述} | {修复建议} | -| 3 | ⚪ 轻微 | {审核项} | {一句话描述} | {修复建议} | - -## 需要您决定(仅当存在🔴严重问题或多选方案时才输出此区块) -1. {从严重问题中提炼的选择题,如"方案A vs 方案B?"} -``` - -### 报告精简规则 - -1. **无问题不提**:审核通过的项目不在报告中出现,不需要逐项列出"通过" -2. **轻微问题合并**:同类轻微问题合并为一行,不逐条展开 -3. **亮点不单列**:如有值得肯定的设计,在「概要」中一句带过即可 -4. **决策点不重复**:仅当严重问题存在多选方案、或整体评分为 C/D 需要用户决定"修复 vs 重做"时,才输出「需要您决定」区块;B 级及以上省略此区块 -5. **表格优先**:问题清单统一用表格呈现,不使用多级嵌套列表 - -## 评分标准 - -| 评分 | 含义 | 严重问题 | 中等问题 | -|------|------|----------|----------| -| A | 可直接使用 | 0 | ≤2 | -| B | 小修后可用 | 0 | ≤5 | -| C | 需较大修改 | 1-2 | 不限 | -| D | 建议重做 | ≥3 | 不限 | - -## 跨阶段一致性检查 - -当审核后续阶段产出时,**必须**回溯检查与前置阶段的一致性: - -- 骨架 vs 事件表:章节是否全覆盖、主线判定是否矛盾 -- 改编策略 vs 骨架:删减决策是否一致 -- 剧本 vs 骨架+策略:时长/删减/钩子是否落实 - -如发现跨阶段不一致,标记为**严重问题**。 - -## 资产一致性说明 - -审核剧本时,角色外貌和场景描述须与【项目配置】中传入的资产包保持一致。 -若决策层未传入资产包,则跳过此项检查,并在报告中注明"未收到资产配置,资产一致性审核已跳过"。 - -## 通用审核原则 - -1. **工具调取优先**:所有审核依据必须通过 `get_planData` 和 `get_novel_events` 等工具实际读取,不得凭记忆或上下文中的摘要信息进行审核 -2. **只提意见,不做决策**:你的职责是发现问题和提出建议,修改决定权始终属于用户 -2. **可执行优先**:审核标准是"能不能用",不是"完不完美" -3. **问题具体化**:每个问题必须指向具体位置和具体内容,不说"整体不够好" -4. **建议多元化**:对严重问题提供多个可选方案,让用户有选择余地 -5. **不越权修改**:绝对不直接修改工作区数据,不自行调用执行层返工 -6. **肯定亮点**:发现好的设计要在报告中肯定,帮助用户了解哪些部分已经做得很好 -7. **动态基准**:所有数值判断以【项目配置】为唯一基准,遇到配置中未明确的参数,以合理比例和常识判断,并在报告中注明所用基准 \ No newline at end of file +1. 从派发指令中识别审核对象关键词 +2. 加载对应的审核技能文件 + 通用规范文件 +3. 按技能文件中的审核维度逐项检查 +4. 按通用规范中的报告格式生成审核报告 +5. 如果无法匹配审核对象,返回提示:`无法识别审核对象,请检查派发指令` \ No newline at end of file diff --git a/src/agents/productionAgent/tools.ts b/src/agents/productionAgent/tools.ts index f2d04f3..3d6c64a 100644 --- a/src/agents/productionAgent/tools.ts +++ b/src/agents/productionAgent/tools.ts @@ -297,10 +297,11 @@ export default (resTool: ResTool, toolsNames?: string[]) => { } item.id = insertedId; } - + //为了防止丢失分镜其他数据,例如:依赖分镜Id、依赖资产idc const flowData: FlowData = await new Promise((resolve) => socket.emit("getFlowData", { key: "storyboard" }, (res: any) => resolve(res))); const storyboardData = flowData["storyboard"].concat([...setData]); socket.emit("setFlowData", { key: "storyboard", value: storyboardData }); + return true; }, }), @@ -325,6 +326,7 @@ export default (resTool: ResTool, toolsNames?: string[]) => { lines: item.lines, }); } + //直接拉取前端数据,为了防止丢失分镜其他数据,例如:依赖分镜Id、依赖资产idc const flowData: FlowData = await new Promise((resolve) => socket.emit("getFlowData", { key: "storyboard" }, (res: any) => resolve(res))); const storyboardData = flowData["storyboard"].map((existing) => { const updated = value.find((v) => v.id === existing.id); @@ -341,7 +343,6 @@ export default (resTool: ResTool, toolsNames?: string[]) => { lines: updated.lines, }; }); - socket.emit("setFlowData", { key: "storyboard", value: storyboardData }); return true; }, diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts index c2fbdf6..4334863 100644 --- a/src/lib/initDB.ts +++ b/src/lib/initDB.ts @@ -331,7 +331,7 @@ export default async (knex: Knex, forceInit: boolean = false): Promise => table.text("lines"); table.text("state"); table.text("reason"); - table.text("index"); + table.integer("index"); table.integer("createTime"); table.primary(["id"]); table.unique(["id"]); diff --git a/src/routes/production/saveFlowData.ts b/src/routes/production/saveFlowData.ts index 9b69a2f..92ad364 100644 --- a/src/routes/production/saveFlowData.ts +++ b/src/routes/production/saveFlowData.ts @@ -14,18 +14,32 @@ export default router.post( data: flowDataSchema, }), async (req, res) => { - const { data, projectId, episodesId } = req.body; + const { + data, + projectId, + episodesId, + }: { + data: z.infer; + projectId: number; + episodesId: number; + } = req.body; const sqlData = await u.db("o_agentWorkData").where("projectId", String(projectId)).andWhere("episodesId", String(episodesId)).first(); - for (let item of data.storyboard) { - await u.db("o_storyboard").where("id", item.id).update({ - index: item.id, - }); - } + 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 (!sqlData) { await u.db("o_agentWorkData").insert({ projectId, episodesId, - data: JSON.stringify(req.body.data), + data: JSON.stringify(data), }); } else { await u @@ -33,7 +47,7 @@ export default router.post( .where("projectId", String(projectId)) .andWhere("episodesId", String(episodesId)) .update({ - data: JSON.stringify(req.body.data), + data: JSON.stringify(data), }); } return res.status(200).send(success()); diff --git a/src/routes/setting/vendorConfig/addVendor.ts b/src/routes/setting/vendorConfig/addVendor.ts index ae93482..a94ef02 100644 --- a/src/routes/setting/vendorConfig/addVendor.ts +++ b/src/routes/setting/vendorConfig/addVendor.ts @@ -76,37 +76,33 @@ export default router.post( tsCode: z.string(), }), async (req, res) => { - try { - const { tsCode } = req.body; - const jsCode = transform(tsCode, { transforms: ["typescript"] }).code; - const exports = u.vm(jsCode); - if (!exports) return res.status(400).send(success("脚本文件必须导出对象")); - if (!exports.textRequest) return res.status(400).send(success("脚本文件必须导出文本请求对象")); - if (!exports.imageRequest) return res.status(400).send(success("脚本文件必须导出图像请求对象")); - if (!exports.videoRequest) return res.status(400).send(success("脚本文件必须导出视频请求对象")); - if (!exports.vendor) return res.status(400).send(success("脚本文件必须导出vendor对象")); - const vendor = exports.vendor; - const result = vendorConfigSchema.safeParse(vendor); - if (!result.success) { - const errorMsg = result.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join("; "); - return res.status(400).send(error(`vendor配置校验失败: ${errorMsg}`)); - } - await u.db("o_vendorConfig").insert({ - id: vendor.id, - author: vendor.author, - description: vendor.description || "", - name: vendor.name, - icon: vendor.icon || "", - inputs: JSON.stringify(vendor.inputs ?? []), - inputValues: JSON.stringify(vendor.inputValues ?? {}), - models: JSON.stringify(vendor.models ?? []), - code: tsCode, - createTime: Date.now(), - }); - res.status(200).send(success(result.data)); - } catch (err) { - console.log(err); - res.status(400).send(error(serializeError(err).message || "未知错误")); + const { tsCode } = req.body; + const jsCode = transform(tsCode, { transforms: ["typescript"] }).code; + const exports = u.vm(jsCode); + if (!exports) return res.status(400).send(success("脚本文件必须导出对象")); + if (!exports.textRequest) return res.status(400).send(success("脚本文件必须导出文本请求对象")); + if (!exports.imageRequest) return res.status(400).send(success("脚本文件必须导出图像请求对象")); + if (!exports.videoRequest) return res.status(400).send(success("脚本文件必须导出视频请求对象")); + if (!exports.vendor) return res.status(400).send(success("脚本文件必须导出vendor对象")); + const vendor = exports.vendor; + const result = vendorConfigSchema.safeParse(vendor); + if (!result.success) { + const errorMsg = result.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join("; "); + return res.status(400).send(error(`vendor配置校验失败: ${errorMsg}`)); } + if (vendor.id.include(":")) return res.status(400).send(error("id不能包含英文冒号")); + await u.db("o_vendorConfig").insert({ + id: vendor.id, + author: vendor.author, + description: vendor.description || "", + name: vendor.name, + icon: vendor.icon || "", + inputs: JSON.stringify(vendor.inputs ?? []), + inputValues: JSON.stringify(vendor.inputValues ?? {}), + models: JSON.stringify(vendor.models ?? []), + code: tsCode, + createTime: Date.now(), + }); + res.status(200).send(success(result.data)); }, ); diff --git a/src/routes/setting/vendorConfig/deleteVendor.ts b/src/routes/setting/vendorConfig/deleteVendor.ts index a899c66..1f24a83 100644 --- a/src/routes/setting/vendorConfig/deleteVendor.ts +++ b/src/routes/setting/vendorConfig/deleteVendor.ts @@ -11,7 +11,7 @@ export default router.post( }), async (req, res) => { const { id } = req.body; - if (id == 1) { + if (id == "toonflow" || id.includes("toonflow")) { return res.status(400).send(error("此配置无法删除")); } await u.db("o_vendorConfig").where("id", id).del(); diff --git a/src/routes/setting/vendorConfig/updateVendor.ts b/src/routes/setting/vendorConfig/updateVendor.ts index df0ddaa..71c7e42 100644 --- a/src/routes/setting/vendorConfig/updateVendor.ts +++ b/src/routes/setting/vendorConfig/updateVendor.ts @@ -120,7 +120,7 @@ export default router.post( ), }), async (req, res) => { - const { id, name, models, inputs, inputValues, icon } = req.body; + const { id, models, inputs, inputValues } = req.body; await u .db("o_vendorConfig") diff --git a/src/utils/ai.ts b/src/utils/ai.ts index d98dfce..e6310b7 100644 --- a/src/utils/ai.ts +++ b/src/utils/ai.ts @@ -32,7 +32,7 @@ async function getVendorTemplateFn(fnName: FnName, modelName: `${string}:${strin } async function withTaskRecord( - modelKey: AiType | `${number}:${string}`, + modelKey: AiType | `${string}:${string}`, taskClass: string, describe: string, relatedObjects: string, @@ -107,9 +107,9 @@ interface ImageConfig { } class AiImage { - private key: `${number}:${string}`; + private key: `${string}:${string}`; private result: string = ""; - constructor(key: `${number}:${string}`) { + constructor(key: `${string}:${string}`) { this.key = key; } async run(input: ImageConfig) { @@ -140,9 +140,9 @@ interface VideoConfig { } class AiVideo { - private key: `${number}:${string}`; + private key: `${string}:${string}`; private result: string = ""; - constructor(key: `${number}:${string}`) { + constructor(key: `${string}:${string}`) { this.key = key; } async run(input: VideoConfig) { @@ -159,9 +159,9 @@ class AiVideo { } } class AiAudio { - private key: `${number}:${string}`; + private key: `${string}:${string}`; private result: string = ""; - constructor(key: `${number}:${string}`) { + constructor(key: `${string}:${string}`) { this.key = key; } async run(input: VideoConfig) { @@ -180,7 +180,7 @@ class AiAudio { export default { Text: (AiType: AiType | `${string}:${string}`) => new AiText(AiType), - Image: (key: `${number}:${string}`) => new AiImage(key), - Video: (key: `${number}:${string}`) => new AiVideo(key), - Audio: (key: `${number}:${string}`) => new AiAudio(key), + Image: (key: `${string}:${string}`) => new AiImage(key), + Video: (key: `${string}:${string}`) => new AiVideo(key), + Audio: (key: `${string}:${string}`) => new AiAudio(key), };