Files
short-drama-agent-front/README.md
T

327 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-domAPI 契约、组件交互和异步生命周期测试
- 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. 图库每 6 秒读取一次真实记录,弹窗只在打开时查询该形态图片。数据库存在 pending / generating 时暂停再次生图;网络错误不自动重试有费用的请求。HTTP 200 中的批量部分失败单独展示。
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 或浏览器视觉联调。请勿用正式项目随意制造失败以测试恢复。