# Short Drama Agent Front 短剧 Agent 的前端工作台。支持剧本创作、拆解、视觉风格、角色选角、主体形态、分镜设计、镜头首帧与视频生产,使用真实后端 API,不包含演示数据或浏览器端模型调用。 ## 最新同步(2026-09-04) - 对齐后端 `dev@05bb9e8b7e0a0e85303b16eb3a2ac634e01dd7eb`:图片/视频模型由后端统一配置,前端不再发送固定 Provider。 - 新增首帧视觉校验、有限自动修复、当前集小批量质量生成、视频抽样帧质量检查、视频修复候选与复检晋升、只读模型能力查询。默认不调用模型,付费操作需确认,结果可定位和导出。 - 保留主要布局和业务能力,导出/执行记录/提示词等次要入口收进菜单,长介绍和高级规则按需展开;关键错误、过期、未保存与费用提示继续直显。 - 全部业务抽屉统一挂载到 `body`,侧栏及遮罩覆盖完整视口,不受 `main/content` 裁切;保持原有宽度、正文内部滚动和关闭后配置草稿。 入口和边界见 [前端简化与质量功能同步](docs/frontend-simplification.md),接口覆盖见 [后端功能覆盖说明](docs/backend-coverage.md)。 ## 启动 需要 Node.js >= 22.18 和 pnpm 11。 ```bash pnpm install cp .env.example .env pnpm dev ``` 浏览器访问 http://localhost:5173。先在后端仓库启动 `pnpm dev`,默认监听 **3412**。 ```dotenv VITE_API_BASE_URL=/api API_PROXY_TARGET=http://localhost:3412 ``` 更改环境变量后重启 Vite。后端若运行在其他机器或端口,请修改 `API_PROXY_TARGET`。不能把 API Key、数据库密码等秘密写入任何 `VITE_*` 变量。 ## 功能 | 工作区 | 已实现 | | --- | --- | | 项目列表 | 真实项目读取、搜索、状态筛选、新建剧本 | | 剧本创作 | 主题/风格/集数配置、剧集目录与正文、角色、世界观、审核、执行记录、正文导出 | | 创作恢复 | 恢复剧集生成、恢复改写,操作前确认 | | 拆解配置 | 每组集数、人物/场景/道具模块选择、后端分组预览 | | 拆解结果 | 主体、别名、视觉形态、Episode → Beat → Shot、主体绑定、抽取任务状态、校验问题、JSON 导出 | | 拆解恢复 | 失败抽取重试、缺失剧集镜头补齐、分镜引用与 Form 绑定修复 | | 视觉风格 | AI 生成、人工编辑、分类 Prompt、JSON 硬约束、锁定;风格参考图地址登记、启停和删除 | | 主体身份 | 正式主体目录、单个/批量身份文本、人工编辑与锁定;无形态 Character 也可先完成身份 | | 角色选角 | 选角就绪检查、角色身份专用批量生成、后端图片模型 候选小批量生成、确认演员并原子锁定 Identity | | 身份母版 | 普通身份图与辅助视角、实际 Prompt 和来源追溯;Character 母版通过确认选角确定 | | 分镜检查 | 按剧集、Beat、正式 Shot ID 浏览;导演设计、环境与主体即时状态;单集覆盖率与 JSON 导出 | | 分镜生成 | Direction / VisualState 单集生成、项目批量补齐、覆盖重生成;并发和自动修复次数;部分失败诊断 | | 镜头工具 | 主体参考图与缺失原因、确定性 GenerationSpec 查询与导出、单镜头/批量视频提示词 | | 形态图片 | 正式形态图库、主图/候选图预览、图片历史与失败记录、后端图片模型 单图/批量生图、切换主参考图 | | 镜头生产 | Prompt/首帧/视频就绪诊断、后端图片模型 首帧候选、后端视频模型 任务、成片播放、主资产切换与失败重试 | 尚未实现:手工编辑剧本或分镜设计(后端暂无对应写接口)、用户登录。模型输出按纯文本显示,避免执行不可信 HTML。图片和视频只接受 HTTP(S) 或后端 `/storage/` 路径。 ## 技术与规范 - Vite 8、Vue 3、TypeScript、Vue Router - Tailwind CSS 4,通过 `@tailwindcss/vite` 集成 - Naive UI:布局、菜单、表格、选择器、输入框、按钮、弹窗、标签、折叠面板、进度和时间线 - Oxlint:脚本质量检查;ESLint:补充 Vue 模板语义 - Oxfmt(不是 `oxformat`):沿用后端四空格、单引号、无分号、无尾逗号的风格 - Vitest + Vue Test Utils + happy-dom:API 契约、组件交互和异步生命周期测试 - Lefthook + Commitlint:提交前执行检查,提交信息使用 `feat:`、`fix:`、`refactor:` 等 ```bash pnpm check # lint + format:check + typecheck + test pnpm format # 格式化 pnpm lint:fix # 修复可自动处理的问题 pnpm build # Vue 类型检查 + 生产构建 pnpm preview # 预览 dist,不含开发代理 ``` Oxfmt 不负责代码质量,Oxlint 不负责 Vue 的完整类型推导;Vue SFC 的类型检查由 `vue-tsc` 承担。未照搬后端 `--type-aware` 来冒充完整 Vue 类型检查。 ## 目录 | 目录 | 职责 | | --- | --- | | `src/features/projects` | 项目接口、类型、列表、新建弹窗、项目布局与共享上下文 | | `src/features/create-drama` | 剧本创作 graph 页面 | | `src/features/breakdown` | 拆解 graph 的 API、类型、配置页面、主体与分镜组件 | | `src/features/storyboard` | 分镜 API、类型、生成操作、依赖判断、设计与状态、镜头资源、生成回执 | | `src/features/subject-images` | 正式形态图库、图片生成参数、历史图片、主图选择与批量回执 | | `src/features/visual-style` | 项目视觉风格 API、类型、编辑器、锁定和风格参考图管理 | | `src/features/subject-identity` | 稳定身份 API、正式主体目录、文本编辑、生图配置、身份图库和母版切换 | | `src/features/production` | 视频提示词、镜头首帧、视频任务、就绪诊断、资产候选与批量回执 | | `src/features/workflows` | checkpoint 选择、执行记录、长请求互斥与操作确认 | | `src/components/ui` | Naive UI 公共封装、工作区滚动容器与图片展示 | | `src/composables` | 具备取消和竞态保护的轮询、系统主题与偏好持久化 | | `src/lib` | HTTP、错误格式、日期和导出工具 | | `src/router` | 按 graph 拆分的懒加载路由 | 每个功能模块通过 `index.ts` 暴露公共入口。业务类型和行为函数均添加中文职责注释。不要把下一条 graph 的服务继续堆进 `App.vue`。 ## 后台布局与主题 - 外层应用固定为视口高度;侧栏、顶栏、项目标题和工作流导航不会随正文滚动。 - 工作流只保留左侧导航,项目标题下不再重复展示相同标签。主体身份、分镜设计、镜头生产和图库采用内容优先布局:常用筛选/剧集选择/刷新在固定的紧凑工具栏,列表占据剩余高度。 - 项目标题栏只显示返回入口和名称,不再放置状态标签与刷新按钮;除形态图库使用手动刷新外,其他项目工作区每 6 秒自动刷新,读取失败时在错误提示内提供重试入口。 - 只有当前项目正式状态为 `completed` 才解锁下游工作区;草稿、生成中、待审核、失败和读取期间默认禁用下游导航。直接访问下游链接只显示返回剧本创作的引导,不挂载操作组件;轮询确认完成后自动解锁,切换项目立即重新判定。页面内提交守卫同步检查完成状态;这是前端交互限制,不代替后端权限与业务校验。 - 项目列表采用固定表头表格;剧本、分镜、身份与生产页的目录和详情独立滚动,其他工作区只滚动内容区。 - “我的剧本”状态筛选采用中号控件,与搜索框等高并扩大点击区域;刷新、主题、折叠和关闭等单图标按钮统一使用直角正方形,加载时保持尺寸不变,保留可访问名称。 - 目录、详情、执行记录、折叠操作区、图片历史和 JSON 查看区统一使用 Naive UI `NScrollbar`;外层只负责尺寸与裁切,不再设置原生 `overflow: auto`。内边距与横向排列放在 `content-class` 内容层,避免双滚动条。 - 身份与形态图库采用限高预览及紧邻其下的横向历史栏;缩略图固定宽度,保留全部候选、辅助视图、失败及进行中记录。点击仅切换预览,不自动切换母版或主图;图片尺寸规则放在非分层组件覆盖样式中,避免被 Naive 按钮默认宽度覆盖。 - 图片统一使用 `NImage`:身份/形态图库的详情大图采用 `contain`,完整显示人物与画面;母版小图、历史缩略图及形态/风格/分镜卡片、首帧缩略图保留 `cover`。母版与展示图片可点击原生预览查看原图;历史缩略图只切换记录,再点击大图查看原图。“查看图片与记录”仍单独打开历史管理。 - 拆解页固定精简状态栏与结果标签,设置、预览及恢复操作收进“拆解设置与恢复”面板;人物、场景、道具、分镜和任务明细共用独立结果滚动区,执行记录单独滚动。结果区占满剩余高度,切换标签回到顶部,轮询刷新或开关设置不重置阅读位置;失败与校验提示在面板关闭时仍然可见。 - 剧集正文按编号连续展示全部已写入剧集;点击目录定位正文,滚动正文同步高亮并保持当前目录项可见。目录分行显示集数和完整标题,执行记录可按需展开。切换角色/世界观等标签不会销毁阅读器或重置位置。 - 主体身份、分镜设计和镜头生产共用 `DirectoryItem`:编号、完整标题和状态分层展示,桌面目录为 240–280px,窄屏改为可横向滚动的条目。目录标题与筛选固定,只有列表滚动。拆解结果的导出按钮与标签同排右对齐;形态图片筛选按内容区宽度自动排成一行或两列网格。 - 侧栏导航与主体/剧集/镜头目录采用直角满行背景,移除列表两侧的内缩,悬停和选中态都铺满所在列。条目内部保留文字间距;窄屏横向目录仍保持独立滚动。 - 主体目录以母版缩略图搭配名称、编号与状态,默认用行背景和轻微间距区分条目。人物优先复用选角接口的母版;缺少地址的条目进入可视区域后才读取正式身份图库,不为整份目录轮询。无母版或加载失败显示人物/场景/道具图标,候选与形态图不会替代母版;点击缩略图只切换主体,刷新目录可重试读取。 - 分镜设计与镜头生产共用两级镜头目录:分组头展示 `BEAT 01` 和镜头数,组内仅显示“镜头 01”、标题及状态。分组头在本组内吸顶;窄屏横向模式才在条目上补回 Beat 归属。点击仍使用正式 Shot ID,不会混淆不同 Beat 的同号镜头。 - 身份、分镜、生产与图库的批量配置、说明和诊断统一放入 `WorkspaceTools`(Naive UI Drawer),按需覆盖当前工作区,不挤压列表。面板支持 Esc 或关闭按钮;关闭不会取消任务或清除配置。历史回执可从入口查看,新回执主动打开诊断;查询错误始终在外层可见。 - 生产步骤的操作按钮保留上下间距;`ConfirmAction` 用稳定根元素承接外部间距,避免多根弹窗组件吞掉 `class`。 - 右上角主题入口以太阳/月亮/显示器图标显示当前偏好,点击选择浅色、暗黑或跟随系统。默认跟随系统,选择保存在本机浏览器;存储被禁用时仍可在当前会话切换。后端连接设置固定在左侧导航底部,折叠时仅显示图标,导航菜单独立滚动。 - 主题按钮仅在点击时展开模式菜单,不再显示悬浮提示;保留屏幕阅读器名称。浅色 Tabs 分隔线使用 `#dadada`,暗黑模式继续使用深灰分隔线。 - 实心绿色按钮采用白色文字,正常/悬停/按下底色分别调整以保证可读性;禁用按钮为灰底灰字,保留原生 disabled 行为。分镜与生产页的剧集选择器不重复显示“剧集”前缀,保留可访问名称。 - 绿色选中复选框使用白色对勾;批量配置中的复选框与中号输入框共用 34px 控件行并垂直居中。浅色输入框按所在区域使用白底或浅灰底,与页面/抽屉或白色面板区分;聚焦与禁用反馈继续保留。 - 采用微信风格配色:浅色为浅灰背景与白色内容,暗色为近黑背景与深灰内容;绿色用于主操作、选中态和进度。按钮文字、目录文字与主绿色分别配置以保证对比度,错误/警告仍使用独立语义色。Naive UI 和业务内容共用主题,浏览器主题色随之切换;加载前应用偏好,减少主题闪烁。 - 全站采用低边框、直角样式:面板、提示框、标签、图片卡片和表单用背景层次代替静态描边;表格与长记录列表使用交替底色,抽屉用灰底承托内容。保留输入框聚焦/校验反馈、复选框、选中指示和必要的浮层阴影;开关、加载等功能图形不强制改形状。 - Tabs 例外保留底部分隔线,浅色和暗黑模式均区分导航与正文;选中下划线仍使用绿色。视觉风格工具栏将“图标+状态说明”与等高操作按钮分组,读取失败不再显示为“尚未创建”,锁定与未保存草稿的生成限制不变。 - 剧本正文的执行记录/导出/进入拆解,以及拆解结果的 JSON 导出统一放在 `NTabs` 的 `suffix` 插槽,与标签垂直居中并共用底线。浅色 Tabs 分隔线单独加深,不影响其它组件的低边框风格;窄内容区由容器断点把操作放到下一行,标签仍使用内置横向滚动。 - 拆解分镜区的剧集选择、节拍/镜头统计与“进入分镜设计”共用一条紧凑工具栏;“选择剧集”不拆行。选择器默认显示正文对应的真实剧集,轮询移除当前剧集时同步回退;没有剧情目标与情绪弧线时不保留空信息面板。 - 拆解人物、场景、道具共用固定斑马纹列表:奇数行常驻原悬停灰底,偶数行保留次级底色,整行不随鼠标或键盘焦点变色;内部控件仍保留交互与焦点反馈,搜索后的条纹顺序按可见列表重新计算。此类记录(含剧本角色设定)首项同样保留 20px 内边距,主题切换时背景色使用 160ms 过渡,并遵循系统减少动态效果设置。 - 拆解主体列表的搜索框统一靠左,图标使用 `NInput` 的 `prefix` 插槽;统计紧随输入框弱化显示,搜索时显示匹配数/总数,清空后恢复总数。搜索与统计垂直居中,窄内容区允许换行,不再左右分散。 - 展开后的每个形态使用独立直角色块,与所在主体条纹采用相反的主题灰阶;保留 16px 内边距、12px 块间距和名称/默认标签间距,奇偶行及搜索重排后均可区分内外层,不新增悬停变色。 - 拆解设置中“每组集数”和“抽取模块”使用相同标题间距;输入框、复选框与预览按钮对齐到 34px 控件行,模块说明独立放在下方。“集 / 组”保持单行,窄抽屉按实际内容宽度将操作和完整模块分组换行,校验与预览逻辑不变。 - 窄屏默认收起侧栏,目录与正文改用紧凑布局;执行记录仍可查看。长弹窗在自身内部滚动。 布局样式集中在 `src/admin.css`,业务排版保留在 `src/styles.css`。新增页面应使用 `WorkspacePage`(内容优先页开启 `compact`),低频操作使用 `WorkspaceTools`;避免通过 `body` 或 `window.scrollTo` 管理滚动。 本次 UI 重构保留前端 `dev@5551653` 的业务更新,包括过期形态图、主首帧和主视频的提示与更新入口。首帧默认只补当前剧集;存在过期主首帧时优先更新全项目过期项。非覆盖模式下的过期主视频重建完成后,会接替旧主视频;普通新增候选不自动替换主资产。 本地验收建议使用 1920×1080、1280×720 和窄屏视口:打开长剧本、长项目标题和多镜头项目,确认顶栏不移动、目录与正文能分别滚到底;切换暗黑模式后检查弹窗、下拉菜单、图片失败占位,刷新后主题应保持。 ## 接口基线 对齐后端 `qianlanse/short-drama-agent` 的 `dev`: `537dba89a18d571a6df24dae17494b09ce635c15`(2026-09-02 核对),包含正式形态提示词、三类主体母版继承、数量上限、身份/形态双参考首帧与视频就绪检查。本轮只修改前端,请确保后端依照其开发流程同步 Prisma migration 并重启服务。完整映射、已补能力和后端限制见 [后端功能覆盖说明](docs/backend-coverage.md)。 | HTTP | 路径(以 /api 为前缀) | 用途 | | --- | --- | --- | | GET / POST | `/projects` | 项目列表 / 创建剧本 | | GET | `/projects/:id` | 正式数据库详情、剧集、角色、世界观与审核 | | GET | `/projects/:id/checkpoints` | 两条 graph 的 checkpoint;前端按 workflowName 过滤 | | GET | `/projects/:id/metrics`、`/projects/:id/timeline/grouped` | 全量运行诊断;按需查询,支持工作流/节点筛选与 JSON 导出 | | POST | `/projects/:id/resume-generation` | 继续生成未完成剧集 | | POST | `/projects/:id/resume-rewrite` | 恢复审核与改写 | | GET | `/projects/:id/breakdown-preview?groupSize=3&modules=character,scene,prop` | 真实分组与任务预览 | | POST | `/projects/:id/breakdown/start` | 启动拆解 | | POST | `/projects/:id/breakdown/retry` | 仅重试失败的抽取 Task | | POST | `/projects/:id/breakdown/resume-shots` | 复用已成功剧集镜头,生成缺失剧集 | | POST | `/projects/:id/breakdown/resume-storyboard` | 修复已有镜头的 SubjectRef / Form,再持久化 | | GET | `/projects/:id/storyboard-directions?episodeNo=N` | 正式 Shot ID、导演设计、单集覆盖率 | | POST | `/projects/:id/storyboard-directions/generate-test` | 单集导演设计;明确发送 `persist: true` | | POST | `/projects/:id/storyboard-directions/generate` | 项目批量;`concurrency`、`force` | | GET | `/projects/:id/storyboard-visual-states?episodeNo=N` | 已持久化的环境、主体状态、单集覆盖率 | | POST | `/projects/:id/storyboard-visual-states/generate-test` | 单集即时状态;`persist: true`、`maxRepairAttempts` | | POST | `/projects/:id/storyboard-visual-states/generate` | 项目批量;增加 `maxRepairAttempts` | | GET | `/storyboard-shots/:shotId/references` | 主体形态参考图、缺失原因 | | GET | `/storyboard-shots/:shotId/generation-spec` | 后端确定性编译结果,不调用模型 | | POST | `/storyboard-shots/:shotId/video-prompt` | 复用已有 Prompt 或调用模型生成;`force` 控制覆盖 | | POST | `/projects/:id/video-prompts/generate` | 项目批量 Prompt;`concurrency`、`force` | | GET | `/projects/:id/subject-forms` | 正式 SubjectForm ID、主体名称/引用、主图与图片元数据;只读查询 | | GET | `/subject-forms/:formId/images` | 此形态的全部图片历史及实际 Prompt | | POST | `/subject-forms/:formId/images` | 单图生成;显式 `provider: seedream`,可选 Prompt 和成对尺寸,`setPrimary` | | PUT | `/subject-forms/:formId/images/:imageId/primary` | 选择已完成图片作为主参考图,不调用模型 | | POST | `/subject-forms/:formId/generation-prompt` | 单个正式提示词生成/重生成;`force` | | POST | `/projects/:id/subject-forms/generation-prompts` | 全项目提示词补齐/覆盖;`concurrency`、`force` | | POST | `/projects/:id/subject-images/generate` | 全项目批量生图;`provider`、`concurrency`、`force`、可选正整数 `limit` | | GET / PUT | `/projects/:id/visual-style` | 查询/人工保存视觉风格,包含分类 Prompt、硬约束和锁定 | | POST | `/projects/:id/visual-style/generate` | AI 生成风格;已有风格重生成显式 `force: true`,锁定时禁止 | | POST | `/projects/:id/visual-style/images` | 登记已有风格图片地址,不上传文件 | | PUT | `/projects/:id/visual-style/images/:imageId/enabled` | 风格图片启停 | | DELETE | `/projects/:id/visual-style/images/:imageId` | 删除风格图片记录,不删除远程文件 | | GET / PUT | `/subjects/:subjectId/identity` | 查询/人工编辑稳定身份;使用正式 Subject ID | | POST | `/subjects/:subjectId/identity/generate` | AI 生成身份文本,需要项目视觉风格 | | POST | `/projects/:id/subject-identities/generate` | 项目批量身份文本;`force`、`concurrency`,已锁定始终跳过 | | POST | `/projects/:id/character-identities/generate` | 只批量生成 Character Identity 文本 | | GET | `/projects/:id/character-casting/readiness` | 角色身份、候选、Anchor 与锁定状态汇总 | | POST | `/projects/:id/character-casting/candidates/generate` | 为缺少 Anchor 的角色小批量生成停用候选 | | GET / POST | `/subjects/:subjectId/identity/images` | 查询带 `isAnchor` 的身份图片/后端图片模型 生图 | | POST | `/subjects/:subjectId/identity/casting-candidates` | 单角色生成 primary 选角候选,不自动成为 Anchor | | PUT | `/subjects/:subjectId/identity/images/:imageId/anchor` | 将成功的 primary 候选设为身份母版 | | PUT | `/subjects/:subjectId/identity/images/:imageId/casting` | 确认 Character 选角:切换 Anchor 并锁定 Identity | | GET | `/projects/:id/video-prompts/readiness` | 项目视频提示词前置条件检查 | | GET / POST | `/projects/:id/keyframes/readiness`、`/keyframes/generate` | 首帧就绪检查与批量 后端图片模型 生图 | | GET / POST | `/storyboard-shots/:shotId/keyframes`、`/keyframe` | 单镜头首帧历史与生图 | | PUT | `/storyboard-shots/:shotId/keyframes/:keyframeId/primary` | 切换主首帧 | | GET / POST | `/projects/:id/videos/readiness`、`/videos/generate` | 视频前置检查与批量 后端视频模型 任务 | | GET | `/projects/:id/videos/status` | 项目最近视频任务状态 | | POST | `/projects/:id/videos/retry-failed` | 重试最近失败的视频任务 | | GET / POST | `/storyboard-shots/:shotId/videos` | 单镜头视频历史与任务创建 | | PUT | `/storyboard-shots/:shotId/videos/:videoId/primary` | 切换主视频 | | POST | `/projects/:id/production/start` | 高级串联入口;重复预检、费用确认,仅传两种 Provider,不生成首帧、不等待成片 | API 层也提供 `state` 与 `breakdown/latest` 方法。页面通过共享 checkpoint 查询取得阶段状态,避免重复拉取同样内容。 ### 异步与恢复约定 1. `POST /projects` 返回顶层 `202 { projectId, status }`,其他接口通常返回 `{ data }`;HTTP 层分别兼容。 2. Breakdown、Storyboard 和恢复接口目前是**长 HTTP 请求**。不设客户端短超时,不自动重试 POST。关闭页面只会丢失请求连接,**不会取消后端任务**。 3. 项目列表每 12 秒、项目详情每 6 秒串行刷新。形态图库暂停父布局和页面定时查询,返回其他工作区恢复轮询;图库直接链接被未完成状态拦截时可手动刷新项目状态。隐藏页面暂停自动查询。切换项目或离开布局时取消查询,旧响应不会覆盖新项目。 4. 抽取任务进度不是全流程进度。抽取完成之后还需要主体合并、形态、节拍、镜头和持久化。 5. 后端失败 checkpoint 可能只有错误。页面回看最近可用的完整快照以保留成果,同时使用最新记录的 execution 状态。显示的是**最近可用快照**,并不保证全部成果来自最后一次执行。 6. 后端并不为每个阶段提供持久化的 running 状态。没有明确终态时,页面显示“阶段快照 · 执行状态待确认”,不会猜测成功或失败。 7. 恢复操作要求确认后台已停止。当前只做浏览器会话内、项目级互斥,不能替代后端跨浏览器/跨用户的任务锁。断网后先检查后台和 checkpoint,不要立即重复点击。 8. 修改分组或模块后,必须重新预览再启动;重新拆解会调用完整流程,可能替换旧的主体和分镜。 ### Storyboard 约定 1. 入口为 `/projects/:projectId/storyboard`。先完成 Breakdown 的主体、形态、镜头与持久化,再生成 Direction,最后生成 VisualState。 2. 当前 Direction 服务读取**最新** Breakdown 的 `state.breakdownResult.storyboardEpisodeShots`;VisualState 读取顶层 `state.storyboardEpisodeShots`、`subjectCandidates`、`subjectForms`。页面不使用历史可恢复快照代替这些生成前置条件。历史快照只补充镜头标题和剧情描述。 3. 镜头 ID 来自正式数据库 GET,按 `shotId` 关联 Direction 和 VisualState。`shotNo` 仅在 Beat 内唯一,不能用它拼装接口 ID。VisualState 查询响应的环境字段是扁平结构,与单集生成返回的领域结构不同。 4. 单集入口虽然名为 `generate-test`,也是后端目前唯一的单集生成接口。页面发送 `persist: true`,通过校验才保存;**单集始终重生成**,不受批量的覆盖开关影响。 5. 批量默认 `force: false`,跳过完整剧集。重新点击“补齐”用于重试未完成项,没有虚构独立 retry 接口。`force: true` 才覆盖全部。VisualState 可设置非负整数修复次数,`0` 表示不修复。 6. VisualState 单集生成需要该集所有正式镜头都有 Direction;批量接口由后端逐集检查,缺少前置条件的集数会单独失败。HTTP 200 也可能包含校验失败或部分失败,页面展示逐集诊断和修复次数,不视为全成功。 7. 上游重生成**不会自动使下游旧数据失效**。覆盖 Direction 后请重生成 VisualState,修改设计/状态/参考图后按需覆盖 Prompt。覆盖率只说明字段已保存,不能证明下游与新版本一致。 8. 每 6 秒查询当前剧集的两类正式结果;这不是全项目实时进度。后端没有独立 Storyboard running / executionId 查询。回执只保留当前浏览器会话,切换页面不丢失,刷新浏览器会丢失。 9. 参考图和 GenerationSpec 按需 GET,切换镜头或设计变化时取消旧查询。GenerationSpec 需要有效的 Direction、VisualState 和形态关联,不生成图片或视频。 10. Video Prompt、Keyframe 与 Video 都有项目级 readiness。`force` 会重写 Prompt,普通首帧/视频新增候选;**过期首帧即使 force 也会更新主图**,非 force 的过期视频完成后会接替旧主视频。确认文案明确此差异。首帧支持可选 `limit` 和成对 `width`/`height`,只影响首帧,不污染提示词和视频参数。视频任务创建成功不代表成片完成,最终状态以后端轮询和持久化资产为准。 ### 形态图片约定 1. 入口为 `/projects/:projectId/subject-images`;项目导航、拆解主体列表和分镜参考图缺失提示均可进入。图库自动读取后端已生成图片,不需要重新生图才能显示。 2. 生图使用正式数据库 `SubjectForm.id`。Checkpoint 的领域 `formId` 不是数据库 ID,不能直接调用图片接口。项目列表包含 Identity Anchor 及图片的 `rawJson` 追溯字段,用于识别母版过期;完整实际 Prompt 在历史弹窗读取。 3. 单图明确发送 `provider: 'seedream'`,避免后端单图入口默认使用 mock。模型和凭证仅配置在后端,前端不保存 API Key。自定义 Prompt 优先,其次正式 `generationPrompt`;缺少时后端先调用文本模型生成并保存。`appearancePrompt` 仅为原始素材,不能直接充当最终 Prompt。可在形态卡片“提示词与生成”先生成、检查与导出正式提示词;后端尚无手工编辑保存接口。 4. 单图宽高同时留空使用后端默认 2K,自定义时必须同时提供正整数,具体尺寸限制仍由模型校验。当前 后端图片模型 Provider 没有使用 negativePrompt,所以页面不提供无效的负向提示词输入。 5. 单图生成新增历史记录,不删除旧图。无主图时默认勾选“生成成功后设为主图”;已有主图时默认不替换。候选图可以在历史弹窗二次确认后通过 PUT 设为主图,只允许已完成图片。 6. 批量默认跳过已有主图的形态;勾选“已有主图也新增候选图”发送 `force: true`。后端批量 force 只生成新图,**不会替换已有主图**。批量作用于整个项目,不受类型/文字/缺图筛选影响,也不接收单图的尺寸与自定义 Prompt。 7. 图库、镜头影响检查、关联素材和图片历史均不定时刷新;首次进入、切换查询目标、手动刷新及本次写操作完成后按需读取。“刷新图库”同时更新项目状态。数据库存在 pending / generating 时暂停再次生图;网络错误不自动重试有费用的请求。HTTP 200 中的批量部分失败单独展示。当前形态列表接口返回完整数组,无分页参数或游标,因此不显示分页或触底加载入口。筛选栏与有值的关联素材行共用一个不透明背景的吸顶容器,内部无 margin 断层;关联素材保持单行横向滚动、上下居中,图片区域沿正文向下滚动。 8. 图片使用持久化后的 `/storage/...` 地址,开发代理已配置。生产环境也必须代理 `/storage/`,不能让 SPA 回退返回 index.html。无效 URL、加载失败、无图和后端生成失败有各自提示;不会自动使用可能过期的 Provider 临时地址。 9. 设为主图后,回到分镜点击“刷新参考图”读取最新绑定。已有视频提示词不会自动重生成,需要按需覆盖。本页面不会调用 `/production/start` 或实际视频生成。 10. 人物、场景、道具均仅继承已锁定身份的当前母版;无母版或未锁定不继承。刷新过期形态只生成候选,验图后手动切换主图。批量图片可限制本次数量,回执独立展示因上限未执行数,不把它算作已有结果的跳过数。 11. 提示词批量入口有独立并发、覆盖和回执;默认补缺,覆盖会重写已有正式文本,但不改变历史图片、实际 Prompt 或主图。未完成剧本、运行中的任务及查询错误均阻止生成。 12. 生产页过期提示可点击直达镜头实际使用的形态;图库支持 `sourceShotId`/`subjectFormId` 定位、高亮和返回原镜头。顶部独立显示身份主图过期与下游首帧影响,检查失败不当作“没有过期”。两种后端就绪检查结果冲突时提示“状态待核对”,不建议据此重复生图;已知后端原因见 [覆盖说明](docs/backend-coverage.md#过期首帧与素材定位)。 ### 视觉风格、身份与形态的衔接 建议操作顺序:**剧本创作 → 剧本拆解 → 视觉风格 → 角色身份与选角 → 形态图片 → 分镜设计 → 镜头生产**。视觉风格也可以在拆解前准备;页面不会自动重生成已存在的下游资产。 | 层级 | 职责 | 本次可操作内容 | | --- | --- | --- | | VisualStyle | 项目整体美术与视觉语言 | 整体/人物/场景/道具 Prompt、JSON 字符串数组硬约束、锁定、风格图片记录 | | SubjectIdentity | 同一主体跨形态不变的特征 | 稳定身份描述、身份 Prompt、锁定、单个及批量 AI 文本生成 | | Character Casting | 确认具体演员身份 | 候选图、人工选择 Anchor、Identity 原子锁定、项目就绪检查 | | Identity Image | 固定主体身份或补充辅助视角 | Scene / Prop 母版及 Character front、three-quarter、full-body 辅助图 | | SubjectForm Image | 某个具体造型或状态的图片 | 原有单图/批量生图与主图选择;人物/场景图自动引用当前身份母版 | 1. 风格锁定仍用于阻止 AI 覆盖。Character 的 `isLocked` 同时是正式选角前置条件:必须具有 Identity、已确认的 primary Anchor 并锁定,Keyframe 才会就绪;确认选角接口会原子完成后两项。 2. 身份 AI 生成需要已创建 VisualStyle;身份图生成还需要已保存的非空 `generationPrompt`。不存在身份时不调用会报错的图片 GET。404 或网络失败不会被当作“尚未创建”。 3. 前端以正式 `subject-forms` 目录为基础,并合并 Character Casting readiness,因此尚无形态的角色也可先完成 Identity 和选角。Scene / Prop 若还没有 Form,仍不会凭 checkpoint 伪造正式 Subject ID。 4. 身份文本批量分为 Character 专用入口和全部主体高级入口。选角候选批量只处理 `missing_anchor`,受本批上限控制;`candidate_pending` 必须人工确认,不会由批量任务静默决定演员。 5. 身份图片的 `isAnchor` 来自专用 GET。Character primary 通过 Casting Candidate 接口生成且默认停用;点击确认演员后才成为 Anchor 并锁定 Identity。辅助视图不能直接成为母版。Scene / Prop 保留普通母版切换接口。 6. 普通身份生图不传 `referenceImageId` 时,由后端自动选择当前母版;无母版时按文本生成。指定时只能选择当前身份已完成的图片;候选图即使停用也可作为显式参考。Character Casting Candidate 是独立选角入口,即使已有 Anchor 也不会复用旧母版,避免旧演员身份污染新候选。尺寸成对留空或提供正整数。自定义 Prompt 会替换后端编译的完整文本,建议保留默认。 7. 目前**人物与场景形态生图**会自动注入当前身份母版,分别固定人物身份和空间骨架;道具暂不自动引用。没有身份或母版时,原形态生图流程仍可使用。已有母版但缺少 Provider 可访问远程地址时,后端会报错;本地 `/storage/` 能显示并不证明原始 Provider URL 仍可访问。前端显示后端错误,不自动重试消耗额度。 8. 修改风格或身份文本不会自动重生成旧图。更换已锁定母版后,形态图库会根据 `identityAnchorImageId` 标记旧主图过期;主动生成候选、验图并切换主图,再更新下游首帧。Keyframe 就绪检查也会比对母版与形态主图引用,不应绕过过期提示继续生产。旧记录无追溯字段时不推断它已匹配当前母版。 9. 风格参考图支持登记已有 HTTP(S)/`/storage/` 地址、分类、排序、启停和删除记录;**没有文件上传接口,也没有风格图 AI 生成接口**。当前身份图/形态图 Provider 调用不会自动消费风格参考图片,页面不暗示登记后已生效。 10. 编辑草稿与轮询分离。保存成功才清空草稿,失败保留;主体切换会提示放弃未保存修改。离开页面不会自动保存。所有新写操作沿用项目级会话互斥,生成前需要费用与后台任务确认,无法替代后端跨浏览器锁。 11. AI 生成 VisualStyle 与 Character Identity 时,若项目、世界观和角色事实都未指定人物背景,默认采用自然真实的中国人物选角基线。项目明确配置和角色事实优先于系统默认值,不限制后续使用其它国家、地区、族裔或肤色人物。 ### 后端限制 目前 `checkpoints` 接口返回完整历史与 state,没有分页或轻量状态接口。长篇剧本会增加轮询流量。下一步建议后端增加: - 持久化 executionId、运行状态、跨请求互斥和幂等键; - 精简的进度接口及按 graph 分页的 checkpoint; - 将 Breakdown 改为 202 异步任务提交,再以轮询或 SSE 读取进度。 前端未模拟这些能力,不调用 `stream-test` 来伪造进度。Storyboard 的单集 `generate-test` 仅在用户明确确认生成后调用。 ## 部署 `pnpm build` 生成 `dist`,使用 Nginx 等静态服务器部署。SPA 深层路由需要回退到 `index.html`。 开发代理只存在于 Vite dev server,`vite preview` 与生产环境需配置独立后端地址或反向代理。 ```nginx server { listen 80; root /var/www/short-drama-agent-front/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { # 保留 /api 前缀,不在 proxy_pass 后追加斜杠。 proxy_pass http://127.0.0.1:3412; proxy_http_version 1.1; proxy_set_header Host $host; proxy_read_timeout 3600s; proxy_send_timeout 3600s; proxy_buffering off; } location /storage/ { # 参考图由同一后端的静态资源服务提供。 proxy_pass http://127.0.0.1:3412; proxy_set_header Host $host; } } ``` 实际生成时间可能超过代理限制,仍建议将后端改为异步提交协议。部署前应给应用加访问控制;当前后端没有身份认证,不建议直接对公网开放。 ## 本地联调验收 1. 后端启动成功,前端项目列表能显示数据库项目。 2. 新建 3 集剧本,确认获取项目 ID 后进入创作页,完成后能读到正文。 3. 查看角色、世界观与审核,再进入拆解页;预览分组与模块。 4. 启动拆解,查看 checkpoint、主体、形态、每集 Beat / Shot 和绑定。 5. 在可控测试项目中触发故障,确认 retry / resume-shots / resume-storyboard 各自对应正确失败阶段。 6. 进入分镜设计,确认正式镜头 ID 与 Beat 对应;先生成单集 Direction,再生成 VisualState,检查覆盖率和主体状态。 7. 用小型测试项目验证批量补齐、跳过完整集、失败诊断和明确覆盖;确认关闭覆盖后不会重生成完整设计。 8. 给主体形态准备参考图,读取镜头参考图和 GenerationSpec;在镜头生产页核对 Prompt、首帧和视频三类 readiness。 9. 打开“形态图片”,检查已有主图自动显示;单个形态新增候选图,查看历史、失败原因和实际 Prompt,再设为主图。 10. 在小型测试项目中验证批量补齐与“已有主图也新增候选图”;回到分镜刷新参考图,确认使用新选择的主图。 11. 进入“视觉风格”,保存或生成风格,检查分类 Prompt 和硬约束;锁定后 AI 入口禁用,人工编辑仍可保存。登记一张已有风格图,检查启停和移除确认。 12. 进入“主体身份”,先补齐 Character Identity,再小批量生成选角候选。确认候选不会自动成为 Anchor,人工确认演员后 Identity 同时锁定且 readiness 变为 ready。 13. 为已确认演员生成 front / three-quarter / full-body 辅助图;确认辅助图不能直接设为母版。角色需要更多演员候选时使用单角色候选入口。 14. 对人物和场景形态分别新增图片,在图片详情检查当次母版 ID;旧主图应保持不变,手动切换后再刷新分镜参考图。人物、场景、道具均应在身份已锁定时继承当前母版。 15. 在镜头生产页生成单镜头首帧,确认规格同时列出 `identity-anchor` 与 `form-primary`。切换主首帧后再创建 后端视频模型 任务,等待完成后播放并选择主视频。 本轮新增测试覆盖风格 JSON/锁定/图片 DELETE、身份归并/前置条件/尺寸/显式参考图/母版切换、部分失败、旧响应、草稿保护与费用确认。模型调用均使用模拟 API。当前执行环境未能通过浏览器访问本地开发服务,**未完成浏览器视觉验收及真实模型联调**,请按上述步骤在本地验收。 自动测试使用模拟 API,覆盖既有流程、分镜接口与竞态,以及形态图片自动读取、正式 ID 生图、主图 PUT、费用确认、尺寸校验、候选图选择、批量部分失败和图片加载错误。不等同于真实模型、MySQL 或浏览器视觉联调。请勿用正式项目随意制造失败以测试恢复。