Files
short-drama-agent-front/README.md
T
GouJ bae69c3c62 feat: 接入分镜导演设计与即时视觉状态工作台
增加单集和批量生成、修复诊断、正式镜头检查、参考图、生成规格与视频提示词。
补齐接口契约、竞态保护和确认交互测试,保持现有两条工作流。
2026-08-28 14:14:25 +08:00

187 lines
13 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 的前端工作台。支持 `create-drama``breakdown``storyboard` 工作区,使用真实后端 API,不包含演示数据或浏览器端模型调用。
## 启动
需要 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 绑定修复 |
| 分镜检查 | 按剧集、Beat、正式 Shot ID 浏览;导演设计、环境与主体即时状态;单集覆盖率与 JSON 导出 |
| 分镜生成 | Direction / VisualState 单集生成、项目批量补齐、覆盖重生成;并发和自动修复次数;部分失败诊断 |
| 镜头工具 | 主体参考图与缺失原因、确定性 GenerationSpec 查询与导出、单镜头/批量视频提示词 |
尚未实现:手工编辑剧本或分镜设计(后端暂无对应写接口)、主体图生成、实际视频生成、用户登录。模型输出按纯文本显示,避免执行不可信 HTML。参考图只接受 HTTP(S) 或后端 `/storage/` 路径。
## 技术与规范
- Vite 8、Vue 3、TypeScript、Vue Router
- Tailwind CSS 4,通过 `@tailwindcss/vite` 集成
- Reka UIDialog、Tabs、Checkbox、Progress 等无样式基础组件
- 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/workflows` | checkpoint 选择、执行记录、长请求互斥与操作确认 |
| `src/components/ui` | 跨业务使用的 Reka UI 封装与公共展示组件 |
| `src/composables` | 具备取消和竞态保护的轮询 |
| `src/lib` | HTTP、错误格式、日期和导出工具 |
| `src/router` | 按 graph 拆分的懒加载路由 |
每个功能模块通过 `index.ts` 暴露公共入口。业务类型和行为函数均添加中文职责注释。不要把下一条 graph 的服务继续堆进 `App.vue`
## 接口基线
对齐后端 `qianlanse/short-drama-agent``dev`
`6ce284b9d93e8c9d0b7ca57d265148e354642095`
| HTTP | 路径(以 /api 为前缀) | 用途 |
| --- | --- | --- |
| GET / POST | `/projects` | 项目列表 / 创建剧本 |
| GET | `/projects/:id` | 正式数据库详情、剧集、角色、世界观与审核 |
| GET | `/projects/:id/checkpoints` | 两条 graph 的 checkpoint;前端按 workflowName 过滤 |
| 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` |
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 仍使用镜头描述和参考图,**尚未消费 GenerationSpec**。没有独立 GET Prompt 接口,“读取/生成提示词”仍是 POST;不存在 Prompt 时会调用模型,因此必须确认。`force: false` 复用已有正文;批量响应只有计数和失败列表,不能凭计数构造 Prompt 正文。`generated` 是后端处理成功数,可能包含已存在但状态不为 `prompt_ready` 的复用项。
### 后端限制
目前 `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 无正文时经确认生成、有正文且不覆盖时复用。不提交实际视频任务。
自动测试使用模拟 API,覆盖两条既有流程及分镜 API 参数、依赖判断、正式 ID 合并、校验与部分失败、切换剧集的竞态、查询错误恢复、Prompt 确认和纯文本展示。不等同于真实模型、MySQL 或浏览器视觉联调。请勿用正式项目随意制造失败以测试恢复。