跳转到主要内容

FSD M10 · 导演与融合

← 总则 | 附录 → | 上游:PRD §4 M10 实现落点:backend/internal/domain/director/(model/split/repo/service/service_assets/export 单包多文件)+ cmd/server/director_handlers.go(28 handler)+ generation 侧双表通路三锚点(model.go:56-69 ShotView.Tbl / service_video.go:191-229 DirectorShotVideo / repo.go:261-283 LinkShotVideo)+ cmd/server/routes.go:203-238(挂载)。事实基准=Go 代码;冻结版 qmtv/server/director.js(11)/fusion.js(17)仅差异对拍参照。 域内要点:双表通路——本域写 director_shots(M2 拆解台是 shots 表勿混),生成链经 ShotView.Tbl 显式表名打回;扣费面六处(三处硬编码照抄);ZIP 导入导出;wire 全蛇形+派生视图尾插键;对账口径:routes.go:209/:223 注释「11+17」系冻结源文件口径(#1/#2 冻结在 fusion.js:221/:227 却排导演注释块),物理分组=导演 13+融合 15;PRD §4 M10 已登记差异 ①~⑮(prd-qmtv-v1.md:208)+v1.12 变更行三件(二十续 A1 form-tag/A2 空数组/A3 episodes 404 文案)引用不重立。ID 前缀 dpr_/dep_/dir_(tasks 侧 task_id=‘dir_’+project_id 约定=PRD ⑩)。

M10 导演与融合

28 端点全量。四零域反转:本域扣费面六处为全站最密(extract 总额扣+单价退/generate-image/fusion 硬编码 3/convert 硬编码 30/remix/资产生成);split 双阈值 1200·800 合参(PRD ①);审片入口在 M11(:266-267)share 在 M6 组(:115,冻结 index.js:574)——同前缀勿误收。

F10.01 项目列表与创建(director3d GET/POST)

对应 PRD:§4 M10 · GET/POST /api/director3d | 状态:实现 | 实现落点:director_handlers.go:21-52、service.go:110-137、repo.go(projects 段)| UI:Director3DView 项目列表 | 场景挂钩:E2E-DIR-01(待实现,清单 :21——建项目→拆分集→分镜图生成)

1 功能定义

导演工作台项目面:列表(带分集预览)与创建(即时双阈值拆分集)。

2 触发条件与前置状态

登录态;create 前置 script_text 必填 400「剧本文本必填」(model.go:161,fusion.js:229——创建端点落在 fusion.js 冻结源,对账口径注记见册尾)。

3 输入与校验

{name, style_id, face_style, script_text, kind}(handlers :36-42;style_id 非空透传无白名单——vs face_style 白名单 service.go:130-132,quirk);name/style_id 截断照冻结 fusion.js:232。

4 处理流程

create:INSERT dpr_ 行 → SplitEpisodes(script, 800)(fusion 阈值;director resplit 用 1200——两处刻意不同源勿统一,split.go:98-111 合参)逐集 INSERT dep_(标题缺省「第N集」)。

5 输出与结果状态

列表=ProjectRow+episodes 尾插(service.go:110-113);create 返回 {id, episodes: n} 形态(照冻结 :227-236)。

6 状态流转

director_projects 无状态列;分集数创建即定(resplit 才重切)。

7 边界与异常
条件系统行为提示/码
script_text 空400「剧本文本必填」
无「第X集」标记按长度 800 块切分(chunkBlocks,split.go:103-105)—
8 权限与数据规则

authed + amw;列表按 user_id 属主过滤;org_shared 列随行下发(M6 共享面消费)。

F10.02 项目详情/删除/重切分(:id GET/DELETE、resplit POST)

对应 PRD:§4 M10 · GET/DELETE /api/director3d/:id、POST /api/director3d/:id/resplit | 状态:实现 | 实现落点:director_handlers.go:80-112、service.go:139-183、repo.go:158-184 | UI:Director3DView | 场景挂钩:E2E-DIR-01(拆分集段)

1 功能定义

项目详情(含分集树)、删除(级联两删序)、重切分(1200 阈值重跑)。

2 触发条件与前置状态

属主校验:非本人 403「forbidden」(model.go:146);不存在 404「not found」(:145)——文案分叉:『episode not found』系 extract/shots/convert 三处共享哨兵默认值(model.go:147),本面经 A3 重映射不直出。

3 输入与校验

resplit 前置项目存在+属主;script_text 不接受(重切用库内原 script——冻结同形)。

4 处理流程
  • 详情:项目+分集树(episodes 尾插)+style_name JOIN(projectWithStyle service.go:212-215)。
  • 删除:按 episode IN 子查询级联删 shots→episodes→项目(repo.go:158-166)——与 resplit 两删序不同(resplit 按 project_id 直删 :182-184),quirk 照抄冻结 :85-88 vs :95-96。
  • resplit:删旧分集+分镜(按 project 直删)→ SplitEpisodes(script, 1200) 重插(service.go:165-176;1200 阈值——PRD ①)。
5 输出与结果状态

详情=ProjectWithEpisodes;删除/重切恒 true(无 404 面——quirk:删除查在先恒 ok service.go:149-157)。

6 状态流转

分集/分镜随 resplit 整体重建(旧 shots 含 video_id 一并清除——重建语义照冻结)。

7 边界与异常
条件系统行为提示/码
非本人项目403「forbidden」
项目不存在404「not found」
resplit 后为空文单分集兜底(chunkBlocks 全文一块)—
8 权限与数据规则

authed + amw 属主面;级联删除顺序固定禁事务(中途失败半态=冻结同形)。

F10.03 分集详情(episodes/:eid GET)

对应 PRD:§4 M10 · GET /api/director3d/episodes/:eid | 状态:实现 | 实现落点:director_handlers.go:113-123、service.go:186-232、repo.go(episode JOIN 段)| UI:Director3DView L3 分集工作台 | 场景挂钩:E2E-DIR-01(工作台装载)

1 功能定义

分集工作台装载面:分集行+全部分镜(含图/视频产物 URL)+资产三组,一响应全量。

2 触发条件与前置状态

URL 无 :id 项目段——属主按 ep.project_id → projects.user_id JOIN 判:非本人 403「forbidden」(service.go:231;冻结 director.js:117 逐字);不存在 404「not found」(:222-226 本路由将共享哨兵 ErrEpisodeNotFound 重映射为 ErrNotFound——二十续 A3:冻结 :116 此面专属 ’not found’;’episode not found’ 仅 extract/shots/convert 三处直出)。

3 输入与校验

路径 :eid 无格式校验;无分页(全量分镜一次下发)。

4 处理流程

episodes 行 → shots 按 slot_no 序(每镜 slots 槽位组 service.go:267-278)→ assets 按 kind 三组 characters/scenes/props(:280-285)→ 图/视频经 imageFilePath/videoFilePath 解析 URL(export.go:137-152,store.Read 存在性守卫)。

5 输出与结果状态

{episode, shots:[{...shot, fields, slots, image_url?, video_url?}], assets:{characters, scenes, props}} 键形全蛇形。

6 状态流转

零写面;shot.status 消费面(processing/video_done 等由 F10.06/07 写入)。

7 边界与异常
条件系统行为提示/码
分集不存在404「not found」(A3 重映射 ErrEpisodeNotFound→ErrNotFound;’episode not found’ 仅 extract/shots/convert 三处直出)
跨项目访问他人分集403「forbidden」(属主按 project 判)
8 权限与数据规则

authed + amw;assets 三组按 kind 聚合(本域 task_id=‘dir_’+project_id 约定隔离——PRD ⑩,M6 projectRank 依赖此形态)。

F10.04 资产提取(extract-assets POST)

对应 PRD:§4 M10 · POST /api/director3d/:id/episodes/:eid/extract-assets | 状态:实现 | 实现落点:director_handlers.go:124-140、service.go:453-490、repo.go(assets 段)| UI:Director3DView「提取资产」| 场景挂钩:E2E-DIR-01(集成实测 5 目标——含锚点前残余段 quirk)

1 功能定义

从分集文本提取角色/场景/道具三组资产并逐张生成立绘占位图:总额一次扣+逐张失败退单价 continue(PRD ⑨)。

2 触发条件与前置状态

属主双校验:项目+分集(eid↔project 无关联校验例外面——本端点校验关联,PRD ⑥ 注convert 例外);无可提取资产 400「没有可提取的资产」(model.go:148)。

3 输入与校验

无 body;目标数由 splitScenes 解析决定。

4 处理流程

DeleteAssetsByTask 先清后插(service.go:468——重提取抹掉含导入的全部项目资产,quirk 照抄冻结 :153)→ 总额 ImageCost×N 一次 TryDeduct「导演工作台资产提取 ×N(-M)」(:461-464,taskKey=‘dir_’+pid)→ 逐张 Generate 失败:域内 Refund 唯一口退单价(nil claim 无防重面)+continue(:474-480,文案「资产图提取失败自动退回(+单价):{err≤80}」)→ 风格前缀拼接 prompt(service.go:466,vs 资产生成后缀拼接——两源刻意不同,service_assets.go:109-117 注)。

5 输出与结果状态

{created: n, assets:{characters, scenes, props}}(同 F10.03 三组形态)。

6 状态流转

assets 行即插即生成(无队列)——与 F10.11 队列制不同源。

7 边界与异常
条件系统行为提示/码
零目标400(扣费前校验)「没有可提取的资产」
单张生成失败退单价+跳过,不整单失败(continue)台账「资产图提取失败自动退回(+10):…」
「道具:XX」行「道具」命中 character 正则(charColonRe [\p{Han}]{2,3}[::] service.go:26 无排除——PRD ③)—
「第一集」锚点前残余段亦成场景目标(lookaheadSplit 残余段入 raw,split.go:40-42——PRD ②)—
8 权限与数据规则

authed + amw 属主面;退款唯一口在域内 Refund(nil claim——extract 无认领制,与视频 ClaimVideoRefund 不同制)。

F10.05 分镜生成与编辑(shots POST、shots/:id PUT)

对应 PRD:§4 M10 · POST /api/director3d/:id/episodes/:eid/shots、PUT /api/director3d/shots/:id | 状态:实现 | 实现落点:director_handlers.go:141-166、service.go:235-405、repo.go:235-244 | UI:Director3DView L3 分镜卡 | 场景挂钩:E2E-DIR-01(分镜编辑段)

1 功能定义

分镜批量生成(从场景草稿落 director_shots)与单镜编辑(image_prompt/duration 等槽位)。

2 触发条件与前置状态

生成前置:eid↔project 无关联校验(service.go:309 注「逐字」PRD ⑥——仅校验各自存在+项目属主);编辑前置:分镜属主(经 JOIN director_projects)。

3 输入与校验

生成 body {scope:[]} 按场景 no 过滤(handlers :128-131;空=全部);编辑 body ShotInput 蛇形(service.go:392-400);duration clamp 1-15s(videoCost 同参)。

4 处理流程

生成:SplitScenes 草稿(有标记 title=首行 slice40;无标记 rune>10 空行块+「第N场:未命名场景」,split.go:113-137)→ InsertShot 15 列 15?(repo.go:235-244——冻结字面 0 错位修后语义,PRD ④:resolution=草稿值、attempts=0)→ 分镜槽位组插入。 编辑:COALESCE 部分更新+video_id 不动(video 产物编辑不清)。

5 输出与结果状态

生成 {created: n};编辑恒 true;响应行键形蛇形(ShotRow model.go)。

6 状态流转

status 初始 ‘draft’(InsertShot 修后语义)→ F10.06 图生成 ‘processing’→(图成)→ F10.07 视频链 ‘video_done’。

7 边界与异常
条件系统行为提示/码
eid 与 :id 项目不匹配仍执行(无关联校验,PRD ⑥ quirk)—
编辑非本人分镜404/403DirectorShotForUser 查无「not found」
空场景文本零分镜插入,created=0—
8 权限与数据规则

authed + amw 属主面;本域写 director_shots(M2 拆解台写 shots——双表通路归属标注,总则 §1 词条)。

F10.06 分镜图生成(generate-image POST)

对应 PRD:§4 M10 · POST /api/director3d/shots/:id/generate-image | 状态:实现 | 实现落点:director_handlers.go:167-181、service.go:407-425 | UI:Director3DView 分镜卡「生成图」| 场景挂钩:E2E-DIR-01(分镜图生成段)

1 功能定义

单镜立绘/Storyboard 图生成:ImageCost 动态价扣费→generation.Generate(Mock SVG 或真实供应商)→images(kind=storyboard)+image_histories 落链。

2 触发条件与前置状态

分镜属主(DirectorShotForUser JOIN——ShotView.Tbl=‘director_shots’ 显式表名,generation/repo.go:261-275);余额不足 402。

3 输入与校验

无 body(prompt 由分镜 image_prompt 组装+风格前缀);provider 侧 size 白名单/4000 截断(generation/provider.go 通用守卫)。

4 处理流程

TryDeduct ImageCost「导演分镜图生成(-{cost})」(service.go:410-413)→ gen.Generate → 成功:images 行+InsertImageHistory(ih_ 前缀——ids.PrefixImageHistory director/repo.go:319 消费,与 task 域 si_ 双轨并存,DIF-29-4 三十期勘正口径)+分镜回填 image_id;失败:RefundGenError 502 信封+域内退款(:418-420,「导演分镜图生成失败自动退回(+{cost}):{err}」)。

5 输出与结果状态

{image_id, url, cost}(url=PathOf 落库口径)。

6 状态流转

shot.status=‘processing’(图链)→ 成功后回可生成视频态;重复生成追加 image_histories(历史链不截断)。

7 边界与异常
条件系统行为提示/码
余额不足402统一信封
provider 失败502+已退款「导演分镜图生成失败自动退回(+10):…」
Mock 分支SVG 字节级移植产物(mockassets)同步 done—
8 权限与数据规则

authed + amw 属主面;扣费 type=‘image’;images.kind=‘storyboard’ 与 M2 拆解图同表隔离(task_id 前缀 dir_)。

F10.07 分镜视频生成(generate-video POST)——双表通路

对应 PRD:§4 M10 · POST /api/director3d/shots/:id/generate-video | 状态:实现 | 实现落点:director_handlers.go:182-201、generation/service_video.go:191-229(DirectorShotVideo)、repo.go:274-283(LinkShotVideo)| UI:Director3DView 分镜卡「生成视频」| 场景挂钩:E2E-DIR-01(video_id 回填断言面)

1 功能定义

单镜视频生成(V2 动态价形态):经 generation 域双表通路打 director_shots——ShotView.Tbl 显式字段是冻结 pseudoShot._tbl 鸭子字段的 Go 显式化(PRD ⑤)。

2 触发条件与前置状态

分镜属主(DirectorShotForUser JOIN director_projects,Tbl=‘director_shots’ generation/repo.go:273);余额不足 402。

3 输入与校验

无 body;duration/ratio/resolution 取自分镜行(resolution 空回「1080p」COALESCE,repo.go:266);videoCost(secs) clamp 1-15s(service_video.go:201-213)。

4 处理流程

TryDeduct videoCost「导演分镜视频 {secs}s(-{cost})」(V2 计费形态)→ SmartVideo 编排(poll/SSE video 事件照 M3 四帧)→ 成功 LinkShotVideo(tbl='director_shots',…):UPDATE video_id+status=‘video_done’+attempts+1(repo.go:274-283 按 Tbl 动态表名);失败退款「导演分镜视频失败自动退回(+{cost})」(Mock desc 参数化——PRD ⑮ 后半)。

5 输出与结果状态

{video_id, url, cost};分镜 video_url 随 F10.03 详情解析。

6 状态流转

status→‘video_done’(终态;取消走 M3 cancel 面 taskId=‘dir_’+pid 隔离)。

7 边界与异常
条件系统行为提示/码
Link 失败videoFailFast 退款+500(service_video.go:316-318——DIF-29-22 failFast 口径)—
Mock 分支按 Tbl 打 director_shots 回填(冻结 Mock 分支 UPDATE shots 硬编码致导演分镜不回填——Go 按意图语义修,PRD ⑤ 登记)—
8 权限与数据规则

authed + amw 属主面;台账 type=‘video’;本节是全站唯一跨域写表通路(generation 域函数写 director 域表——经 Tbl 参数化而非 import,域边界守卫形态)。

F10.08 项目 ZIP 导出(:id/export GET)

对应 PRD:§4 M10 · GET /api/director3d/:id/export | 状态:实现 | 实现落点:director_handlers.go:202-213、export.go:26-162 | UI:Director3DView「导出项目」| 场景挂钩:无(E2E-EXP-01 为 M4 面)

1 功能定义

项目全量打包下载:六段 zip(project.json/episodes/*.txt/shots/EPxx.json/shots_all.json/images/EP{i}_shot{j}.png/videos/…svg)。

2 触发条件与前置状态

项目属主(403/404 同 F10.02);素材缺失静默跳过(store.Read 失败=冻结 fs.existsSync 守卫,export.go:118-133)。

3 输入与校验

无 body;文件名净化 [\\/:*?"<>|]→_(export.go:22)+slice20。

4 处理流程

zip.NewWriter 逐段 addZipEntry(:153-161):project.json(style 尾插+style_id 键保留 :38-49)→ episodes 文本 → shots 两形态 JSON → appendShotMedia 逐镜产物(store.Read,:118-133)→ 文件名 director-{pid前8}.zip(:86)→ zipRespond 二进制直出(application/zip+Content-Disposition)。

5 输出与结果状态

zip 字节流(PK 魔数——集成锚 integration_director_test.go:204-210 断言 :204 前缀)。

6 状态流转

零写面。

7 边界与异常
条件系统行为提示/码
分镜产物文件缺失跳过该条目(zip 不中断)—
空项目仅 project.json+空 episodes 段—
8 权限与数据规则

authed + amw 属主面;导出含全部素材字节(无脱敏)。

F10.09 项目 ZIP 导入(director3d/import POST)

对应 PRD:§4 M10 · POST /api/director3d/import(up20)| 状态:实现 | 实现落点:director_handlers.go:53-79、export.go:164-234 | UI:Director3DView「导入项目」| 场景挂钩:无

1 功能定义

v1 格式 ZIP 导入(project.json+episodes/*.txt)重建项目。

2 触发条件与前置状态

缺 ZIP 400「缺少 ZIP 文件」(model.go:158);解析失败 400「ZIP 解析失败:{e.message}」(:159,前缀拼接);限额 20MB(importZipLimit handlers :18+路由 up20,PRD ⑭)。

3 输入与校验

multipart file 字段;meta 必需 project.json(缺省兜底形态 export.go:192-234);episodes 字典序排列。

4 处理流程

zip.NewReader(内存)→ project.json 解析(meta 缺省兜底)→ episodes/*.txt 按文件名字典序重建(标题「{原名}(导入)」后缀)→ SplitEpisodes 文本再切(1200 阈值——director.js:268 导入源)。

5 输出与结果状态

{id, episodes: n}(同 create 形态)。

6 状态流转

新项目 enabled 语义同 create;旧项目不受扰。

7 边界与异常
条件系统行为提示/码
缺文件400「缺少 ZIP 文件」
非 ZIP/损坏400「ZIP 解析失败:…」
无 project.jsonmeta 缺省兜底继续(quirk)—
8 权限与数据规则

authed + amw;导入产物属主=当前用户;不导入素材字节(v1 仅文本结构——images/videos 不在包规格)。

F10.10 资产 CRUD 与公共池导入(assets 四件)

对应 PRD:§4 M10 · GET/POST /api/director3d/:id/assets、DELETE /api/director3d/assets/:id、POST /api/director3d/:id/assets/import | 状态:实现 | 实现落点:director_handlers.go:214-243/:300-327、service_assets.go:44-118/:417-435 | UI:Director3DView L1 资产面(公共池 ['asset-library'] 同 key)| 场景挂钩:无

1 功能定义

项目资产三组读写+资产库(asset_library 公共池)导入。

2 触发条件与前置状态

GET/POST 前置项目属主;DELETE 查在先恒 ok(service_assets.go:74-82);import 前置库资产存在 400「资产库资产不存在」(model.go:152)。

3 输入与校验

POST {name, style_id, face_style, script_text, kind}(handlers :36-42 复用)——name/kind 必填 400「名称与类型必填」(model.go:149);风格后缀拼接(service_assets.go:109-117 注「与 extract 前缀两源刻意不同」)。

4 处理流程

import:asset_library 行复制为项目 assets(task_id=‘dir_’+pid,公共池隔离靠前缀);DELETE 单行(级联 image 引用不动——image_id 保留孤儿兼容)。

5 输出与结果状态

列表=AssetRow+groups 三组尾插(service_assets.go:48-51 status 派生);AssetRow.StyleID/FaceStyle json:"-" 不出 wire(model.go:81-82)。

6 状态流转

queue_status 由 F10.12 写;status 派生(image_id 有无)。

7 边界与异常
条件系统行为提示/码
删除不存在资产200 恒 true(查在先不拦截——quirk)—
队列候选谓词image_id='' 代冻结 IS NULL(repo.go:451——MySQL NOT NULL DEFAULT ’’ 方言适配,PRD ⑮ 同族)—
8 权限与数据规则

authed + amw 属主面;公共池 asset_library 全站共享读(导入才落项目域)。

F10.11 资产生成(generate + batch-generate POST)

对应 PRD:§4 M10 · POST /api/director3d/assets/:id/generate、POST /api/director3d/:id/assets/batch-generate | 状态:实现 | 实现落点:director_handlers.go:244-271、service_assets.go:120-198 | UI:Director3DView 资产卡「生成」| 场景挂钩:无

1 功能定义

单个/批量资产立绘生成(ImageCost 计价);批量逐笔容错(失败回 queued 不整单失败)。

2 触发条件与前置状态

已生成资产入队 400「该资产已生成,无需入队」(model.go:150);batch:无 ids 且无待生成 400「没有待生成的资产」(:151)/有 ids 但全已生成 400「所选资产均已生成」(:150——双哨兵分叉 service_assets.go:163-167,二十续 A2 空数组方言收口)。

3 输入与校验

generate 无 body;batch {ids?:[]}——空数组=全量待生成(A2:MySQL IN () 500→Go 收口语义)。

4 处理流程

单发:TryDeduct「资产生成:{name}(-{cost})」→Generate→回填;失败退「资产生成:{name}失败自动退回(+{cost}):{err}」。批量:逐笔同上+失败 queue_status 回 queued 继续(:185-198)。

5 输出与结果状态

generate {image_id, url, cost};batch {generated: n, failed: m}(failed=剩余数语义)。

6 状态流转

queued→生成中→done(image_id 回填)/失败回 queued(可重试)。

7 边界与异常
条件系统行为提示/码
batch 空数组全量待生成语义(A2 收口)—
单笔失败退费+回 queued+continue—
mid-batch 余额耗尽后续笔 402 整批中断(已生成不回滚)—
8 权限与数据规则

authed + amw 属主面(batch ids 逐个校验属主);扣费 type=‘image’。

F10.12 待生成队列(queue 二件)

对应 PRD:§4 M10 · POST /api/director3d/assets/:id/queue、GET /api/director3d/:id/queue | 状态:实现 | 实现落点:director_handlers.go:272-299、service_assets.go:200-246、repo.go:18-26/:451 | UI:Director3DView 队列面板 | 场景挂钩:无

1 功能定义

资产入队/队列视图(持久化 queue_status)——批量排程前置面。

2 触发条件与前置状态

入队前置:已生成 400「该资产已生成,无需入队」;action 归一(非 unqueue 一律按 queue,service_assets.go:223-225 quirk 照抄 fusion.js:105)。

3 输入与校验

{action} 任意字符串(归一语义);视图无分页。

4 处理流程

入队:queue_status=‘queued’;出队:=’’/置空;视图:QueueItemRow 七键投影(repo.go:18-26)双键排序。启动恢复由 recovery.requeueAssets 承接(service_assets.go:211-212 注——重启丢队列态回补)。

5 输出与结果状态

入队/出队恒 true;视图 queued 列表。

6 状态流转

queued ⇄ 空(unqueue);done 由 F10.11 写。

7 边界与异常
条件系统行为提示/码
action 未知值按 queue 处理(归一 quirk)—
重启后 queued 行recovery 回补入队—
8 权限与数据规则

authed + amw 属主面;零扣费(入队不扣,生成才扣)。

F10.13 融合生图与图片改创(fusion 二件 + remix)

对应 PRD:§4 M10 · POST/GET /api/director3d/:id/fusion、POST /api/director3d/:id/remix | 状态:实现 | 实现落点:director_handlers.go:328-371、service_assets.go:249-383 | UI:Director3DView 融合 tab | 场景挂钩:无

1 功能定义

双图融合生图(cost=3 硬编码)+融合历史列表+单图改创(remix,ImageCost 计价)。

2 触发条件与前置状态

fusion:画面描述必填 400「请填写画面描述」(model.go:154);remix:原图存在 400「原图不存在」(:156)+改创说明必填「请填写改创说明」(:157)。

3 输入与校验

fusion {image_id_a, image_id_b, description, scene_id?}——scene_id 空串→NULL 指针(sceneIDPtr service_assets.go:509-514,scene_id || null 冻结同形);remix {image_id, instructions}。

4 处理流程

fusion:const cost = 3 TryDeduct「融合生图(-3)」(service_assets.go:260 注「非 ImageCost——差异登记 PRD ⑦」)→ 双图 prompt 组合 → images(kind=fusion) → fusion_items 行(响应带 cost :310)。remix:ImageCost「图片改创(-{cost})」(:366-369)→ images(kind=remix)。

5 输出与结果状态

fusion create {id, url, cost};list=融合历史(LIMIT 面);remix {image_id, url, cost}。

6 状态流转

零状态列(同步完成)。

7 边界与异常
条件系统行为提示/码
描述/说明空400(扣费前)「请填写画面描述」/「请填写改创说明」
原图不存在400「原图不存在」
fusion cost 调价不随 settings(硬编码 3——PRD ⑦,与 ImageCost 双轨)—
8 权限与数据规则

authed + amw 属主面(image_id 引用校验属主);fusion_items.scene_id 可空外键语义(NULL=非场景绑定)。

F10.14 参考视频(ref-videos 三件)

对应 PRD:§4 M10 · GET/POST /api/director3d/:id/ref-videos、DELETE /api/director3d/ref-videos/:id | 状态:实现 | 实现落点:director_handlers.go:372-425、service_assets.go:385-435 | UI:Director3DView 参考视频区 | 场景挂钩:无

1 功能定义

项目参考视频上传(60MB 新档位)/列表/删除。

2 触发条件与前置状态

上传前置文件存在 400「缺少视频文件」(model.go:158 族)+扩展名白名单 400「仅支持 mp4/webm/mov」(:159);限额 60MB(refVideoLimit handlers :19+路由 up60 routes.go:208 新档位——PRD ⑭;handler 单文件双保险 500「File too large」:391-393)。

3 输入与校验

multipart file+name/note form tag(handlers :403-407——json tag 恒不命中,二十续 A1 修复锚);name/note 可空。

4 处理流程

store.Put 大文件流 → ref_videos 行(rv_ 族)→ 列表蛇形投影;DELETE 恒 ok 不查行数(service_assets.go:430-435 quirk 照抄 fusion.js:215-218)。

5 输出与结果状态

上传 {id, url, name};列表 rv 行数组;删除恒 true。

6 状态流转

零状态(上传即可用)。

7 边界与异常
条件系统行为提示/码
扩展名非三白名单400「仅支持 mp4/webm/mov」
超 60MB路由 413/handler 500 双层「File too large」(handler 层)
删除不存在200 恒 true(quirk)—
8 权限与数据规则

authed + amw 属主面;素材字节落 MinIO/local(files 目录),wire 出 url=PathOf 口径。

F10.15 一键转剧(convert/:eid POST)

对应 PRD:§4 M10 · POST /api/director3d/:id/convert/:eid | 状态:实现 | 实现落点:director_handlers.go:426-436、service_assets.go:440-481 | UI:Director3DView「一键转剧」| 场景挂钩:无

1 功能定义

分集文本一键转剧:flat=30 硬编码扣费→Mock 视频即弃(不落 videos 表)。

2 触发条件与前置状态

eid↔project 有关联校验(WHERE id AND project_id,service_assets.go:451-453——PRD ⑥ 的 convert 例外面:convert 是唯一校验关联的端点);余额不足 402。

3 输入与校验

无 body;空场次→意图语义:ep.title 单场(:471-481——冻结 :262-267 fallback 对象调 .split 恒 TypeError 500,Go 按意图修,PRD ⑧ 登记)。

4 处理流程

const flat = 30 TryDeduct type='video'「一键转剧《{ep.title}》(-30)」taskID=裸 p.ID(:454-456——无 dir_ 前缀,PRD ⑦;集成断言 integration_director_test.go:229/:235 钉死)→ MakeVideo 占位 SVG 落盘 → 不落 videos 表(service_assets.go:440-441 注——与 M3 视频链不同源,产物一次性)。

5 输出与结果状态

{url, cost}(url 一次性产物链接)。

6 状态流转

无任务行无轮询(同步伪完成形态——M4 同款语义,status 无从查证)。

7 边界与异常
条件系统行为提示/码
eid 不属该项目404(关联校验——convert 例外 PRD ⑥)—
空场次单场兜底(意图语义 PRD ⑧)—
硬编码 30不随 settings(PRD ⑦)—
8 权限与数据规则

authed + amw 属主面;台账 type=‘video’ task_id=裸 pid(credit-records 按 taskId 聚合时与 M3 视频同族——m04 对账注记关联面)。


册尾端点覆盖对账(28/28)

对账 backend/cmd/server/routes.go:203-238 亲数 28 条 ↔ 本册 F10.01~F10.15。口径脚注:routes.go:209/:223 注释「导演面 11(director.js)/融合面 17(fusion.js)」系冻结源文件归属计数(#1/#2 冻结在 fusion.js:221/:227 却排导演注释块内);物理分组=导演功能 13+融合功能 15,28 总数自洽。非本域同前缀:share(M6 组 :115,冻结 index.js:574——m06 F6.05)/review(M11 :266-267)勿误收。

#端点(routes.go:line)节#端点(routes.go:line)节
1GET /director3d(:210)F10.0115POST /director3d/:id/assets(:225)F10.10
2POST /director3d(:211)F10.0116POST /director3d/assets/:id/generate(:226)F10.11
3POST /director3d/import(:212)F10.0917POST /director3d/:id/assets/batch-generate(:227)F10.11
4DELETE /director3d/:id(:213)F10.0218POST /director3d/assets/:id/queue(:228)F10.12
5GET /director3d/:id(:214)F10.0219GET /director3d/:id/queue(:229)F10.12
6POST /director3d/:id/resplit(:215)F10.0220DELETE /director3d/assets/:id(:230)F10.10
7GET /director3d/episodes/:eid(:216)F10.0321POST /director3d/:id/assets/import(:231)F10.10
8POST /director3d/:id/episodes/:eid/extract-assets(:217)F10.0422POST /director3d/:id/fusion(:232)F10.13
9POST /director3d/:id/episodes/:eid/shots(:218)F10.0523GET /director3d/:id/fusion(:233)F10.13
10PUT /director3d/shots/:id(:219)F10.0524POST /director3d/:id/remix(:234)F10.13
11POST /director3d/shots/:id/generate-image(:220)F10.0625GET /director3d/:id/ref-videos(:235)F10.14
12POST /director3d/shots/:id/generate-video(:221)F10.0726POST /director3d/:id/ref-videos(:236)F10.14
13GET /director3d/:id/export(:222)F10.0827DELETE /director3d/ref-videos/:id(:237)F10.14
14GET /director3d/:id/assets(:224)F10.1028POST /director3d/:id/convert/:eid(:238)F10.15

差异纪律:PRD §4 M10 ①~⑮ 全引用不重立;二十续 A1/A2/A3 引 PRD v1.12 变更行;quirk(双方一致 as-is)节内登记不立 DIF——本册零新立 DIF(差异面全在 PRD 已登记集合;image_id=’’ 谓词引 ⑮ 族)。