# FSD M11 · 评估与工具

LLMS 索引： [llms.txt](/llms.txt)

---

> [← 总则](/qmtv/fsd-qmtv/00-%E6%80%BB%E5%88%99/) ｜ [附录 →](/qmtv/fsd-qmtv/99-%E9%99%84%E5%BD%95/) ｜ 上游：[PRD §4 M11](/qmtv/product/prd-qmtv-v1/)
> 实现落点：`backend/internal/domain/evaluation/`（model/service〔workbench+watchVideo〕/service_eval〔评估流水线〕/service_review〔审片双入口〕/service_viral/repo）+ `cmd/server/workbench_handlers.go` + `cmd/server/evaluation_handlers.go` + `cmd/server/routes.go:239-267`（挂载，审片 4 条 :264-267 物理居中）。事实基准=Go 代码；冻结版 `qmtv/server/workbench.js`/`evaluation.js`/`index.js:490-513`（viral）仅差异对拍参照。
> 域内要点：**评估冻结-结算**是全站唯一 TypeReserve 台账面（总则 §1 词条的展开落点）；审片双入口 404 文案分叉（classic 'task not found' vs director 'not found'）；审片面**零 SSE 零通知**；watchVideo 状态丢失不 emit；wire 全蛇形；PRD §4 M11 已登记差异 ①~⑭（prd-qmtv-v1.md:216）引用不重立。上传档位 up80（工作台）/up10（评估）。

### M11 评估与工具

14 端点全量（workbench 2+审片 4+eval 6+viral 2）。三扣费面三制式：工作台 TOOLS 固定价、审片 10（空分镜先退后拒）、评估 TypeReserve 冻结-结算、viral 5——四制式互不同源（quirk 富矿域）。

#### F11.01 工作台工具提交（workbench/tasks POST）

> 对应 PRD：§4 M11 · POST /api/workbench/tasks ｜ 状态：实现 ｜ 实现落点：workbench_handlers.go:18-54、service.go:141-221 ｜ UI：WorkbenchView（E2E-GEN-02 已实现——toast「去字幕完成」；confirm 仅 repaint 空描述分支）

##### 1 功能定义

视频工作台三工具（一键转绘 20/去字幕 10/转高清 15）提交：扣费→异步处理→SSE workbench done。

##### 2 触发条件与前置状态

登录态；tool key 白名单（TOOLS map）；余额不足 402；**双载荷**（multipart 视频/JSON 文本，PRD ⑩）。

##### 3 输入与校验

`{tool, video_id?/描述}`——repaint 需描述（前端 confirm 分支对应）；taskId 无=空串（台账「工作台·X（-N）」service.go:176-178 逐字，冻结 workbench.js:52）。

##### 4 处理流程

TryDeduct（固定价，settings 无此键）→ INSERT workbench_tasks（status='processing'）→ **异步 goroutine**（提交段同步返回）→ watchVideo 编排（F11.02）。

##### 5 输出与结果状态

`{id, status:'processing'}`（wb_ 行投影）；列表窄投影不含 params 全文（model.go `json:"-"` 面：OutPath/VideoStatus JOIN 伴列）。

##### 6 状态流转

processing→done（SSE workbench done 帧）/failed（视频链失败联动）；「任务状态丢失」为终态旁支（不 emit，F11.02 §7）。

##### 7 边界与异常

| 条件 | 系统行为 | 提示/码 |
|---|---|---|
| tool 非三值 | 400 | TOOLS 键校验 |
| 余额不足 | 402 | 统一信封 |
| 提交后进程重启 | RecoverStuck 回队（PRD ⑨，F11.02 §4） | — |

##### 8 权限与数据规则

`authed + amw` 属主面；up80 档（workbench.js:12 multer 80MB 对齐，handler 单文件双保险 500「File too large」:35-37）。

#### F11.02 工作台列表/轮询/启动恢复（workbench/tasks GET）

> 对应 PRD：§4 M11 · GET /api/workbench/tasks ｜ 状态：实现 ｜ 实现落点：workbench_handlers.go:57-66、service.go:225-304 ｜ UI：WorkbenchView 列表+轮询 ｜ 场景挂钩：E2E-GEN-02（间接）

##### 1 功能定义

本人工作台任务列表 + watchVideo 轮询状态机 + 服务重启悬挂恢复。

##### 2 触发条件与前置状态

列表登录态（按 user_id）；watchVideo 由 F11.01 提交后 goroutine 内启动（非 HTTP 端点）。

##### 3 输入与校验

无参数（全量本人任务，无分页——照冻结 :78-123）。

##### 4 处理流程

watchVideo（service.go:228-260）：首 tick **3s**/步进 **5s**/上限 **180 次**（model.go:117-122 可注入常量）→ VideoStatusOf 查 M3 videos 行 → done：SetWorkbenchDone+hub.Emit workbench done；视频 failed：SetWorkbenchWatchFailed 联动；**状态丢失（!found 或超次）：置失败后直接 return 不 emit**（:238-241——PRD ⑥：冻结 :84 同分支无 bus.emit）。
RecoverStuck：启动扫 processing 悬挂行→重挂 watchVideo（PRD ⑨，二十续迁移面）。

##### 5 输出与结果状态

列表行+status（含 done/failed/「任务状态丢失」文案面）。

##### 6 状态流转

与 F11.01 §6 同一张状态机（本节是驱动器）。

##### 7 边界与异常

| 条件 | 系统行为 | 提示/码 |
|---|---|---|
| 轮询超 180 次 | 置「任务状态丢失」**无 SSE 帧**（quirk 照抄——前端轮询兜底可见） | — |
| 超时**不退款** | 扣费不回（PRD ⑥ 已登记） | — |
| goroutine panic | recover 吞（service.go:227——防崩保护，watchVideo 假漏覆写测试教训面） | — |

##### 8 权限与数据规则

`authed + amw`；轮询消费 M3 videos 表跨域读（VideoStatusOf 窄投影三列）。

#### F11.03 智能审片·写（review 双入口 POST）

> 对应 PRD：§4 M11 · POST /api/tasks/:id/review、POST /api/director3d/:id/review ｜ 状态：实现 ｜ 实现落点：workbench_handlers.go:69-92、service_review.go:21-73 ｜ UI：DashboardView/VideoView 审片（classic）+ Director3DView 审片（director）｜ 场景挂钩：无

##### 1 功能定义

智能审片提交：按 scope 拉分镜→LLM/Mock 逐镜评审→review_reports 落行。**双入口同表同逻辑、404 文案分叉**。

##### 2 触发条件与前置状态

classic：task 存在+属主，404「**task not found**」（service_review.go:24）；director：404「**not found**」（:34）——两哨兵不同字（model.go:224/:227，PRD ⑦）；空分镜：**先退台账再 400**「审片退回：无分镜（+10）」（:52-58，Refund 唯一口 nil claim）。

##### 3 输入与校验

无 body（scope 由服务端定）；审片费 10 固定（402 走统一信封）。

##### 4 处理流程

TryDeduct「智能审片（-10）」→ 拉分镜（classic 走 shots/director 走 director_shots——**跨域共表 COALESCE 可空列读**，PRD ⑪ 炸点修复面）→ LLM 截 **40 条**（firstN :95）→ mockReview：阈值 0.22/0.5/0.7 三档 issue（high/mid/low，:140-146）+维度分 `78+rand20`，主体一致性 −6，clamp [55,98]（:157-161）→ review_reports 落行（scope/target_id 归属）。

##### 5 输出与结果状态

`{id}`（report 行 id）；详情走 F11.04。

##### 6 状态流转

同步完成（review_reports 一次落定，无 processing 态）。

##### 7 边界与异常

| 条件 | 系统行为 | 提示/码 |
|---|---|---|
| classic 任务不存在 | 404 | 「task not found」 |
| director 项目不存在 | 404 | 「not found」（**文案分叉勿统一**） |
| 无分镜 | **先退 10 再 400**（台账+拒绝双写） | 「审片退回：无分镜（+10）」 |

##### 8 权限与数据规则

`authed + amw` 属主面；**零 SSE 零通知**（全文件 grep Emit/InsertNotification 零命中——PRD ⑦，唯一不发通知的写路径）；扣费 type='review'。

#### F11.04 智能审片·读（review 双入口 GET）

> 对应 PRD：§4 M11 · GET /api/tasks/:id/review、GET /api/director3d/:id/review ｜ 状态：实现 ｜ 实现落点：workbench_handlers.go:81-116、service_review.go:76-88 ｜ UI：同 F11.03 读侧 ｜ 场景挂钩：无

##### 1 功能定义

审片报告读取：按 target 取最新报告（含逐镜 issues/维度分/总分）。

##### 2 触发条件与前置状态

属主校验同写侧（双 404 文案分叉同 F11.03 §2）；无报告返回 null 形态（非 404——照冻结 :198-203/:220-225）。

##### 3 输入与校验

路径 :id（classic=task id / director=project id）。

##### 4 处理流程

review_reports 按 target_id DESC 取首行 → report JSON 反序列化下发。

##### 5 输出与结果状态

`{report: {...}|null}`；issues 数组键形照 mockReview 产出（shot_no/level/message）。

##### 6 状态流转

零写面。

##### 7 边界与异常

| 条件 | 系统行为 | 提示/码 |
|---|---|---|
| 从未审过 | report=null（200） | — |
| 越权 | 404 双文案分叉 | 同 F11.03 |

##### 8 权限与数据规则

`authed + amw` 属主面；报告 JSON 全文下发（无脱敏）。

#### F11.05 评估配置与上传（evaluations/config + upload）

> 对应 PRD：§4 M11 · GET /api/evaluations/config、POST /api/evaluations/upload（up10）｜ 状态：实现 ｜ 实现落点：evaluation_handlers.go:17-53、service_eval.go:28-43/:47-90/:521-590 ｜ UI：EvaluationView 配置区+上传 ｜ 场景挂钩：无

##### 1 功能定义

评估价目配置读面（quick/deep 双价）+ 剧本文件上传解析（txt/docx、GBK 回退）。

##### 2 触发条件与前置状态

config 登录态；upload up10 档（原 studio cover 档复用）。

##### 3 输入与校验

config 无参；upload multipart `file`——.txt/.docx 白名单；**costOf settings 0 值回退默认**（service_eval.go:38-42 `err != nil || n == 0` → def，PRD ①；quick 默认 100/deep 300）。

##### 4 处理流程

- config：两价+引擎名——**engine『规则(Mock)』字面**（:48-51，与 F11.06 POST 面『规则』**两字面不同源**，PRD ②）。
- upload：GBK 判定（ToValidUTF8→U+FFFD 计数>max(2, 0.2%)→GB18030 解码 :521-534，M9 同族）→ .docx 走 zip 解包+XML 五实体反转义（&amp;/&lt;/&gt;/&quot;/&#N;，:537-590）→ 纯文本回传。

##### 5 输出与结果状态

config `{quick: n, deep: n, engine: str}`；upload `{text, name, chars}` 形态（rune 计数）。

##### 6 状态流转

零写面（upload 不落库——解析产物仅回显，落库在 F11.06 create）。

##### 7 边界与异常

| 条件 | 系统行为 | 提示/码 |
|---|---|---|
| settings 价=0 或解析失败 | 回默认 100/300（**0 不生效** quirk，PRD ①） | — |
| docx 损坏 | 解包错误透传 500 族 | — |

##### 8 权限与数据规则

`authed + amw`；价键 `eval_cost_quick`/`eval_cost_deep`（管理台计费配置可调——标「可调」族）。

#### F11.06 评估项目与流水线（evaluations 三件+runEval）

> 对应 PRD：§4 M11 · POST/GET /api/evaluations、GET /api/evaluations/:id ｜ 状态：实现 ｜ 实现落点：evaluation_handlers.go:54-101、service_eval.go:93-153/:226-321 ｜ UI：EvaluationView 列表+进度轮询 ｜ 场景挂钩：无（SSE eval 三态帧：stage/done/failed）

##### 1 功能定义

评估项目创建（TypeReserve 冻结扣费）→ 异步流水线（五 stage 推进+SSE）→ 终态结算。

##### 2 触发条件与前置状态

create：script_text 必填；mode ∑ {quick, deep}——**非法值静默归 quick 无 400**（service_eval.go:97-100，PRD ③）；余额不足 402。

##### 3 输入与校验

`{name, script_text, mode}`——name 缺省「未命名评估」族；script_text 落库截断（与 upload 解析面衔接）。

##### 4 处理流程

TryDeduct `type='reserve'`「剧本快速/深度评估冻结（-N，完成后结算）」**taskID=id**（:104-106 冻结 :252-253 逐字）→ INSERT eval_projects（status='running'）→ **异步 goRun**（:226 起，注入点便于测试）：五 stage 推进（解析/拆解/维度打分/汇总/出报告，SSE eval stage 帧逐发）→ Mock 确定性打分 `(v*7919)%40`（:398，冻结 :56 镜像）→ done：SetEvalDone（**无台账动作**——冻结即终态；TypeReserve 台账仅失败面全额退款消化）+SSE done；失败：**全额退款**「评估失败自动退回（+N）」+SSE failed+通知「评估失败：《name》…N 积分已退回」（evalFail :311-321，错误截 100）。

##### 5 输出与结果状态

create `{id}`；list=EvalListRow 定列七投影（model.go:173-181，Report `json:"-"` 不入列表）；:id=全行+report（终态才有）。

##### 6 状态流转

running→done/failed（SSE eval 帧+前端 3s 轮询双通道——E1 轮询机保留手管先例）；finished_at **UTC 形态**（PRD ④）。

##### 7 边界与异常

| 条件 | 系统行为 | 提示/码 |
|---|---|---|
| mode 乱值 | 归 quick（静默） | — |
| 流水线任一 stage 失败 | 全额退款+SSE failed+通知 | 「评估失败自动退回（+300）」 |
| Mock sleep | 1100/1500/900ms 三段（:287-291——**Mock 行为是契约**） | — |
| 模板缺键 | `<nil>` 透传（PRD ⑭） | — |

##### 8 权限与数据规则

`authed + amw` 属主面；**TypeReserve 是全站唯一冻结-结算制**（先冻结后按结果结算/失败全退——总则 §1 词条展开）；evalLLM 通道已接线（PRD ⑤，二十一期⑦）。

#### F11.07 评估报告下载（evaluations/:id/report GET）

> 对应 PRD：§4 M11 · GET /api/evaluations/:id/report ｜ 状态：实现 ｜ 实现落点：evaluation_handlers.go:102-114、service_eval.go:156-222 ｜ UI：EvaluationView「下载报告」｜ 场景挂钩：无

##### 1 功能定义

评估报告 GAE 模板渲染下载（docx 兼容 HTML 容器）。

##### 2 触发条件与前置状态

项目存在+属主；**status 非 done 时 report 缺失**→按冻结形态返回空/错误面。

##### 3 输入与校验

路径 :id；无 body。

##### 4 处理流程

report JSON → GAE 模板变量填充（七维表/总分/建议段）→ HTML 全文响应（前端 blob 下载——E1 保留 fetch+blob 先例）。

##### 5 输出与结果状态

text/html 全文（非 JSON 信封——下载面直出）；engine 字面「规则」（POST 面字面——PRD ② 双字面对照 F11.05）。

##### 6 状态流转

零写面。

##### 7 边界与异常

| 条件 | 系统行为 | 提示/码 |
|---|---|---|
| 未完成即取 | 空报告形态 | — |
| 越权 | 404 | — |

##### 8 权限与数据规则

`authed + amw` 属主面；报告含全维度明文。

#### F11.08 爆款分析（viral-analysis 二件）

> 对应 PRD：§4 M11 · GET/POST /api/viral-analysis ｜ 状态：实现 ｜ 实现落点：evaluation_handlers.go:115-138、service_viral.go:16-67、repo.go:397 ｜ UI：ViralAnalysisView ｜ 场景挂钩：无

##### 1 功能定义

爆款标题/文案四维建议生成（math/rand Mock）：单次扣 5 积分，历史保留最近 20 条。

##### 2 触发条件与前置状态

create：title 必填（空→400 族）；余额不足 402。

##### 3 输入与校验

`{title}`；**title 截 255**（slice :56，PRD ⑧ 二十一期 B2 补登）。

##### 4 处理流程

TryDeduct CostViral=5（billing.go:15）→ math/rand 四维 advice（score=`60+Intn(35)`、comment/emoji/duty 三键随机池，service_viral.go:44-50——**math/rand 非确定性 Mock**，PRD ⑧；与 eval 7919 确定性不同制）→ viral_analyses 落行（五列 INSERT）→ 响应。

##### 5 输出与结果状态

create `{id, advice:{score, comment, emoji, duty}}`；list=本人最近 **LIMIT 20**（repo.go:397），Result/Status `json:"-"`（model.go `json:"-"` 面）。

##### 6 状态流转

零状态（同步完成落行）。

##### 7 边界与异常

| 条件 | 系统行为 | 提示/码 |
|---|---|---|
| title 超 255 | 截断（不报错） | — |
| 历史超 20 | 旧条滚出（LIMIT 查询面） | — |

##### 8 权限与数据规则

`authed + amw` 属主面；扣费 type='viral'（TypeViral 独立常量——credit-records 单列归组）。

---

## 册尾端点覆盖对账（14/14）

对账 `backend/cmd/server/routes.go:239-267` 亲数 14 条 ↔ 本册 F11.01~F11.08（审片 4 条 :264-267 物理居 M11 段，:259-262 为 M13 spark 段——紧邻勿混）：

| # | 端点（routes.go:line） | 节 | # | 端点（routes.go:line） | 节 |
|---|---|---|---|---|---|
| 1 | POST /workbench/tasks（:247） | F11.01 | 8 | GET /evaluations/:id/report（:255） | F11.07 |
| 2 | GET /workbench/tasks（:248） | F11.02 | 9 | GET /viral-analysis（:257） | F11.08 |
| 3 | GET /evaluations/config（:250） | F11.05 | 10 | POST /viral-analysis（:258） | F11.08 |
| 4 | POST /evaluations/upload（:251） | F11.05 | 11 | POST /tasks/:id/review（:264） | F11.03 |
| 5 | GET /evaluations（:252） | F11.06 | 12 | GET /tasks/:id/review（:265） | F11.04 |
| 6 | GET /evaluations/:id（:253） | F11.06 | 13 | POST /director3d/:id/review（:266） | F11.03 |
| 7 | POST /evaluations（:254） | F11.06 | 14 | GET /director3d/:id/review（:267） | F11.04 |

（:249/:256/:259-263 为注释/空行/M13 spark 段邻接行，非端点。）

差异纪律：PRD §4 M11 ①~⑭ 全引用不重立；本册**零新立 DIF**（goroutine recover/三注入点系测试基建形态非行为差异，节内注记）；集成锚第十一链 EvaluationChain/第十二链 WorkbenchNotifyChain 在位（backend/integration_test.go）。

---

反链：

- [QMTV 功能规格说明书（FSD）v1.0 · 总则](/qmtv/fsd-qmtv/00-%E6%80%BB%E5%88%99/)
- [FSD 附录 · PRD 对照 / 代码域索引 / 差异台账](/qmtv/fsd-qmtv/99-%E9%99%84%E5%BD%95/)
