diff --git a/doco/src/__init__.py b/doco/src/doco/__init__.py similarity index 100% rename from doco/src/__init__.py rename to doco/src/doco/__init__.py diff --git a/doco/src/asr_adapter.py b/doco/src/doco/asr_adapter.py similarity index 100% rename from doco/src/asr_adapter.py rename to doco/src/doco/asr_adapter.py diff --git a/doco/src/cli.py b/doco/src/doco/cli.py similarity index 100% rename from doco/src/cli.py rename to doco/src/doco/cli.py diff --git a/doco/src/video_split.py b/doco/src/doco/video_split.py similarity index 100% rename from doco/src/video_split.py rename to doco/src/doco/video_split.py diff --git a/doco/tests/fixtures/mini_test.mp4 b/doco/tests/fixtures/mini_test.mp4 new file mode 100644 index 0000000..1f0b69e Binary files /dev/null and b/doco/tests/fixtures/mini_test.mp4 differ diff --git a/docs/Claude协作原则.md b/docs/Claude协作原则.md new file mode 100644 index 0000000..f74ae0f --- /dev/null +++ b/docs/Claude协作原则.md @@ -0,0 +1,11 @@ +**本文件是制片人刘通与 Claude(Opus 4.7 高级技术顾问)的协作原则,与项目宪法(.clinerules / project_plan.md / dev_plan.md / docs/git_workflow.md)并列。新对话接手时,请连同宪法一并阅读本文件。** + +------ + +**Claude 与我交流、沟通、协作时需要注意的原则** + +1. 全程使用简体中文。 +2. 我不懂代码编程,给我的解释说明和理由要尽量简明扼要。不要堆叠大量技术语言,说人话。 +3. 请参阅宪法文件中你(Claude)的定位:写具体 Plan 是 Cline 的事,不要架空 Cline 的 Plan 模式。除非特别必要(Cline 反复修改都过不去的坎)可以上手,以及制片人明确指定你可以操刀的具体工作。 +4. 给 Cline 的指令要用代码块封装起来,方便复制。 +5. 给我的回复要简明扼要,不要解释太多的中间过程和理由和分析,有不懂的我会问你。 \ No newline at end of file diff --git a/docs/backlog_md_TPS_工作台待办池_不丢视野_非排期_.md b/docs/backlog_md_TPS_工作台待办池_不丢视野_非排期_.md index ffef357..f1be19d 100644 --- a/docs/backlog_md_TPS_工作台待办池_不丢视野_非排期_.md +++ b/docs/backlog_md_TPS_工作台待办池_不丢视野_非排期_.md @@ -14,6 +14,10 @@ 有沉淀、有权限、可检索的系统。核心价值 = 经验从"靠人"变"靠系统"。 - 现有克制选择(不用 TS / 不用 Alembic / pgvector 不用独立向量库 / Session 不用 JWT)方向正确,保持。 +- ⚠️ 更新(2026-06-12):看板分析升级相关待办(原 F1-F8)已整体迁移到 + **TPS 看板分析升级子项目**。主 project 这边不再维护这部分待办。 + 子项目状态见 `寄存条_看板升级已外迁.md`。 +- doco 相关条目已外迁 --- diff --git a/docs/cross_project/分钟收视回放/分钟收视回放_主project答复_v1.md b/docs/cross_project/分钟收视回放/分钟收视回放_主project答复_v1.md new file mode 100644 index 0000000..47a71f7 --- /dev/null +++ b/docs/cross_project/分钟收视回放/分钟收视回放_主project答复_v1.md @@ -0,0 +1,364 @@ +# 主 project 答复 — 分钟收视回放子板块 + +> 版本:v1 +> 日期:2026-06-11 +> 作者:TPS 主 project 顾问 (Claude Opus 4.7) + 制片人 刘通 +> 状态:已采纳,待秒级 chat 接收并按本文件推进实现 +> 上一版:无 +> 对应文档:秒级收视 project《军事科技_分钟收视回放_子板块需求规格.md》v1(2026-06-10) + +--- + +## 一、本文件用途 + +回复秒级 chat 那份 PRD 第八节的 6 个对接问题,并把主 project 这边的**红线、修订建议、交付物期待**全部白纸黑字写下来。本文件是子板块继续推进的**最终输入**,秒级 chat 这边可基于此开干。 + +子板块结束前,要按本文件第九节的清单产出**五份交付物**给主 project。主 project 这边的 Cline 拿着五份交付物落代码,完成最终整合。 + +--- + +## 二、对 6 个对接问题的最终答复 + +### 1. TPS 工作台有没有"每期节目详情页"? + +**没有。子板块需要附带把详情页骨架建起来。** + +现状:仪表盘 (Dashboard) 是聚合视角,责编录入页 (EditorDesk) 是表单 + 列表,**没有"看单期 + 该期所有维度"的页面**。分钟收视回放需要这个容器,整个工作台早晚也需要这个页面,借这次一起做掉。 + +入口规划: +- 仪表盘柱图每根柱子点进去 → 详情页 +- EditorDesk 列表行点进去 → 详情页 +- 路由建议:`/episodes/:id`,`:id` 用 `episodes.id`(SERIAL 主键) + +详情页骨架要预留位置承载未来其他维度(审片意见、文稿、外拍信息等),分钟收视回放是其中**第一个模块**。 + +### 2. 数据库技术栈 + +**PostgreSQL 16 + pgvector(1536 维)**,ORM 是 **SQLModel(同步,非 async)**。 + +手写 SQL 走 `backend/sql/00X_*.sql`,不用 Alembic。 + +第五节那两张表的接入方式见第四节"数据模型修改建议"——简短版:**别新建"节目期次表",复用现有 `episodes` 表**;分钟数据表新建,命名 `episode_minute_ratings`,外键挂到 `episodes.id`。 + +### 3. 视频和截图存储方案 + +**最终决策:视频不入工作台。** + +- 视频本体由制片人在本地/百度网盘/极空间多渠道自存 +- 工作台只接收**截图**(27 张 jpg) +- 不再讨论服务端 ffmpeg、视频压缩、转码删源片等服务端方案 + +截图处理走**本地切图工具**(子板块产出,详见第五节): + +- 责编本地双击工具 → 拖入源片 → 自动切 27 张 480p 截图 + 命名好 +- 责编打开工作台 → 一键多文件上传截图(~5 MB 一次传完) + +截图存储:服务器文件系统 `/screenshots/{episode_id}/{分钟序号_两位数}.jpg`,数据库只存 URL。 + +### 4. 前端技术栈 + +**React 18 + Vite + Ant Design 5 + Zustand**,JavaScript(不用 TS),项目宪法锁定。 + +图表库选型: + +- **优先 @ant-design/charts**:与现有 AntD 5 视觉血缘最近,配色和圆角自然贴合 +- **次选 ECharts**:自定义 tooltip 模板灵活成熟 +- **已用过 Recharts**:仪表盘柱图已采用 + +**不要再引第三方图表库**。三选一即可,最终选哪个由 Cline 在 Plan 阶段定。 + +### 5. 后台异步任务怎么跑 + +**在"视频不入工作台 + 本地切图工具"决策下,服务端没有重型异步任务。** + +工作台后端只接收截图入库 + 跑数据校验(见第四节建议 E),都是毫秒级同步操作,**FastAPI BackgroundTasks 都用不上**。 + +如果未来某个新场景确实需要异步任务,再启用 FastAPI BackgroundTasks。**不引 Celery、不引 Redis 队列**——8 人栏目用这些是过度工程。 + +### 6. 录入身份/权限 + +**有完整用户系统**:Session + Cookie 认证,三角色拼音枚举锁定(`zhipianren` / `zebian` / `biandao`)。 + +写权限规则参照 `yearly_targets` 既有口径平移: + +- **POST/PATCH/DELETE 录入分钟数据 + 上传截图**:`zhipianren` + `zebian` 可写,`biandao` 返回 403 +- **GET 查看分钟回放**:三角色均可读 + +**实现细节**:FastAPI 后端直接从 session 拿 user_id 写入 `created_by` 字段,**前端不要把"录入人"作为字段提交**。 + +字段命名用 `created_by INTEGER REFERENCES users(id)`,**不要用 string 类型的"录入人姓名"**——主 project backlog 里有一条 "操作留痕 schema"(待办池 B2),分钟收视这张新表作为落地先例。 + +--- + +## 三、视频/截图最终方案(决策落地) + +### 责编一周一期的标准流程(最终版) + +``` +周二 21:20-21:47 节目播出 + ↓ +周二 22:00 后 责编到总编室账号抄 27 个份额数字(保留原方案) + ↓ +次日 责编打开本地切图工具 + ↓ + 拖入当期源片 mp4 → 工具自动切 27 张 480p jpg + + 自动命名为 01.jpg ~ 27.jpg + ↓ + 责编登录工作台 → 进入"节目期次"管理 + → 选择当期 episode(基于已录入的 episodes 记录) + → 进入分钟收视模块 + ↓ + 上传 27 张截图(多文件选择 / 拖拽) + → 服务器存到 /screenshots/{episode_id}/ + → 数据库写入 27 条 episode_minute_ratings 记录 + ↓ + 录入 27 个份额数字 + (推荐:"批量粘贴一列数字"输入框, + 从 Excel 复制 27 个数字粘贴后系统按行切分) + → 系统软校验(数据齐全?范围合理?均值与已录全期均值吻合?) + → 保存 + ↓ + 该期详情页里"分钟收视回放"模块即刻可看 +``` + +### 主 project 这边不做的事 + +- 服务端 ffmpeg(不需要) +- 视频上传接口(不需要) +- 视频压缩转码(不需要) +- 异步任务队列(不需要) +- 视频删除/清理脚本(不需要) + +--- + +## 四、数据模型修改建议(主 project 在此明确给出) + +> 任何 schema 改动**必须经主 project 顾问 (Opus) 审、配回补方案,Cline 不得自行动手**。这是项目红线。下面是建议方案,最终落地前还会过一遍审查。 + +### 建议 A:复用现有 `episodes` 表,**不新建"节目期次表"** + +现有 episodes 表已涵盖你需要的全部"节目期次"信息: + +| 你的字段 | 对应现有 episodes 字段 | +|---|---| +| 期次主键 | `id`(SERIAL) | +| 期数显示 | 前端从 `air_date` + `episode_number` 拼,不入库 | +| 节目名称 | `program_name` | +| 播出日期 | `air_date` | +| 播出时段 | 不入库,前端常量 "21:20-21:47" | +| 备注 | `notes` | + +理由:新建一张冗余表会割裂 episodes 与其他模块(收视成绩、外拍、未来选题、审片意见)的关联,破坏单一事实源。 + +### 建议 B:用 `episodes.id`(INTEGER)做外键,**不用"播出日期 string"做主键** + +秒级 chat v1 文档建议"期次主键用 `2026-06-09` 字符串"。这与 `episodes.id SERIAL` 体系冲突。 + +最终方案:分钟数据表用 `episode_id INTEGER REFERENCES episodes(id)` 外键,所有展示字符串("2026 年第 23 期 · 2026-06-09")由前端从 episodes 数据拼出,不入库。 + +### 建议 C:`收视份额` 用 `NUMERIC(6,4)`,**不用 float** + +与现有 `episodes.audience_share NUMERIC(6,4)` 类型对齐,避免浮点比较的怪事。 + +### 建议 D:新表 `episode_minute_ratings` 建议 schema + +```sql +CREATE TABLE IF NOT EXISTS episode_minute_ratings ( + id SERIAL PRIMARY KEY, + episode_id INTEGER NOT NULL REFERENCES episodes(id) ON DELETE CASCADE, + minute_index INTEGER NOT NULL CHECK (minute_index BETWEEN 1 AND 27), + audience_share NUMERIC(6,4) NOT NULL, + screenshot_url VARCHAR(500), + created_by INTEGER NOT NULL REFERENCES users(id), + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + UNIQUE(episode_id, minute_index) +); + +CREATE INDEX idx_minute_ratings_episode ON episode_minute_ratings (episode_id); +``` + +P1+ 扩展(多期对比、批注/标签):1.0 不建表,到 P1 触发时再说。当前 UNIQUE 复合键和外键设计已留好扩展空间。 + +### 建议 E:工作流补一个"软校验"环节 + +录入 27 个分钟份额时,系统应做**非阻塞**的合理性提示: + +- 27 个数字是否齐? +- 最大值/最小值是否在合理区间(如 0-3)? +- 27 个数字的平均值是否与已录的 `episodes.audience_share`(该期全期均值)大致吻合?误差 > 30% 给"数据可能录错"提示 + +不阻塞保存,只是温柔提醒。理由:分钟数据是栏目考核依据,权重最高,录错一个小数点不发现就一直错。 + +### 建议 F:批量导入接口复用现有 ExcelService + +23 期历史数据一次性导入:复用主 project 已有的 ExcelService 框架(Phase 2 Task 2 跑通),但单开一个 endpoint: + +- 上传一份"期次 × 27 列分钟份额"的 Excel +- 按行展开成 23 × 27 = 621 条 `episode_minute_ratings` 入库 +- 截图 URL 字段第一次导入时留空,后续走本地工具补传 + +### 建议 G:episodes 表是否要加视频 URL 字段? + +**不加。** + +因为视频不入工作台。如果未来某天想记录"这一期视频存在哪个网盘 / 哪个本地路径",可以走 `episodes.notes` 字段写自由文本,不需要专门字段。 + +--- + +## 五、本地切图工具规格(子板块产出物之一) + +子板块的 Claude 负责设计与实现这个工具。 + +### 5.1 形态 + +- 一个 Windows 上能跑的可执行文件(py 源码 + pyinstaller 打包成 exe) +- 双击即用,无安装步骤 +- 不依赖网络,不依赖工作台,完全离线 +- 不需要责编装 Python 环境 + +### 5.2 用户界面 + +简洁到极致: + +- 一个窗口,拖文件进去即可(或"选择文件"按钮) +- 接收 mp4 / mov / mkv 等常见格式 +- 进度条显示切图进度 +- 完成后弹"已生成 27 张截图于 [输出文件夹]" +- 自动打开输出文件夹 + +### 5.3 切图规则(与秒级 chat v1 文档保持一致) + +```bash +# 27 张截图,每分钟第 30 秒位置,480p (854 × 480) +for i in $(seq 0 26); do + sec=$((i*60+30)) # 0:30, 1:30, 2:30, ..., 26:30 + ffmpeg -i 源片.mp4 -ss $sec -vframes 1 -vf scale=854:480 \ + "$(printf "%02d" $((i+1))).jpg" -y +done +``` + +输出文件名规则:**`01.jpg` ~ `27.jpg`**(两位数,零填充,便于排序)。 + +### 5.4 输出文件夹组织 + +工具自动新建一个文件夹,命名建议:`截图_{源片文件名去后缀}_{日期}/`,里面 27 张 jpg。 + +### 5.5 ffmpeg 依赖 + +打包时把 ffmpeg.exe 一并塞进 exe,或者用 `imageio-ffmpeg` 包自动下载。**绝对不要让责编手动装 ffmpeg**。 + +### 5.6 错误处理 + +- 源片读不到 → 弹窗"文件无法读取,请检查格式" +- 源片时长 < 26 分 30 秒 → 弹窗"视频时长不足 27 分钟,是否继续?"(允许跳过缺失分钟) +- 输出文件夹已存在 → 自动加时间戳后缀 + +### 5.7 给责编的使用说明 + +子板块产出一份 `使用说明.md`,傻瓜级,要有截图。预期长度 200-400 字 + 3-5 张截图。 + +--- + +## 六、主 project 红线(不可越) + +子板块设计与实现过程中,下面这几条是**主 project 宪法**,任何方案不得违反: + +1. **改 schema 须主 project 顾问 (Opus) 审**:包括新建表、改字段、加字段。Cline / 子板块 Claude 不得自行动手。 +2. **角色枚举锁定拼音值**:`zhipianren` / `zebian` / `biandao`,不许新增枚举,不许用英文别名。 +3. **AI 给方向不给答案**:分钟收视回放的 P1+ 功能(多期对比找规律、批注 AI 建议等)若涉及 AI,必须保持"建议草稿 + 制片人审核"的三档置信度,不得 AI 直接拍板。 +4. **编导关联用"软引用 + 快照"**:本子板块如需展示编导信息,沿用 `episodes.editor_id` + `episodes.editor_name_snapshot` 双字段,不许新增编导关联字段。 +5. **收视颜色判定**:红=优秀(>摸高目标)/ 蓝=达标 / 绿=待提升(<基础目标)。反直觉规约,分钟收视回放折线图如果上色,按此规则。 +6. **AI 输出必须有"忽略 / 我来改写"否决权**:任何 AI 建议(如本子板块 P1+ 的 AI 找规律功能)必须给编导否决入口。 +7. **不引新依赖**:图表库三选一(@ant-design/charts / ECharts / Recharts),不引第四个;后端不引 Celery / Redis 队列。 + +--- + +## 七、子板块产出物清单(最终交付包) + +子板块结束前,请凝结成以下**五份交付物**,作为整体交付给主 project: + +### 产物 1:决策摘要 md + +记录子板块全程的关键决策。每条决策三句话: + +``` +决策 X:[一句话决策内容] + - 背景:为什么需要这个决策 + - 拍板理由:选这条不选那条的理由 + - 拍板人:[制片人 / 主 project 顾问 / 子 project Claude 建议+制片人采纳] +``` + +10-20 条决策足以讲清整个子板块"为什么这么做"。 + +### 产物 2:接口约定 md(最技术、最精确) + +把子板块与主 project 接驳的所有"接口"白纸黑字写出来: + +- **数据接口**:新建表 / 字段 / 类型 / 约束(细化到 SQL DDL 级别) +- **API 接口**:新增 endpoint URL / 方法 / 请求体 / 响应体 / 错误码 +- **UI 接口**:在主 project 哪个页面挂载、入口、路由 +- **权限接口**:哪些角色可以做什么操作 +- **存储接口**:截图存到哪个目录、命名规则、URL 拼接规则 + +要具体到"主 project 的 Cline 拿着这份就能写代码"的程度。**这是子 project 给主 project 的"合同"**。 + +### 产物 3:本地切图工具完整包 + +- `screenshot_tool.py`:源码,注释齐全 +- `screenshot_tool.exe`:打包好的可执行文件,责编双击即用 +- `使用说明.md`:傻瓜级文档 + 截图 + +工具规格见本文件第五节。 + +### 产物 4:未尽事项 backlog + +诚实写出"子板块讨论中提到但没做的事"。每条三行: + +- 是什么 +- 为什么没做(暂缓 / P1+ / 等条件成熟) +- 触发时机(什么时候应该捡起来) + +放进主 project 的 backlog 池子里。 + +### 产物 5:给主 project Claude 的"接手提示词" + +一两段话,告诉主 project 顾问"如果你是接手这件事的 Claude,最重要的三件事是 X、Y、Z"。 + +这次至少要包含: +- 复用 episodes 表,不新建节目期次表 +- 权限沿用 yearly_targets 口径 +- 本地切图工具与工作台零耦合,不在工作台 UI 里给它留接口 + +--- + +## 八、跨 project 协作规矩(子板块这边也要遵守) + +1. **不动主 project 代码**:子板块产出文档 + 独立工具,不写主 project 的实际代码。代码合入由主 project 的 Cline 完成。 +2. **遇到吃不准的事回主 project 问**:本次 v1 文档第八节就是好榜样,继续保持。 +3. **每份跨 project 文档顶部带元信息块**:版本、日期、作者、状态、上一版、主要变化(v2 以上必填)。 +4. **一份文档只谈一件事**:不要在分钟收视回放交付包里夹带其他议题。 + +--- + +## 九、给秒级 chat Claude 的明确动作清单 + +收到本文件后,请按下面顺序推进: + +1. **吸收本文件所有决策与红线**,回到秒级 chat 的 PRD v1,把不一致处标注出来(如果有) +2. **如有需要修订的地方,出 PRD v2**,顶部元信息块写明跟 v1 的变化点 +3. **设计本地切图工具**:与制片人讨论用户体验细节,定稿后凭工具规格让秒级 chat 的 Cline 实现(如果有)或制片人自己找 v0/Lovable 等工具生成 demo +4. **凝结成最终五份交付物**(第七节清单) +5. **交付给制片人**,由制片人带回主 project,主 project 顾问 (Opus) 审一遍,无冲突后主 project 的 Cline 落实施 + +--- + +## 十、附:版本演进规约 + +本文件未来如修订(v2+),顶部元信息块"主要变化"必须写清楚改了什么。 + +历史版本不覆盖,旧文件保留在 `docs/cross_project/` 目录(主 project 这边)以便回看决策史。 + +--- + +*本文件由主 project 顾问 (Claude Opus 4.7) 于 2026-06-11 基于与制片人刘通的两轮对话整理生成,供秒级收视项目接收使用。* diff --git a/docs/cross_project/分钟收视回放/分钟收视回放_立项备忘_v1.md b/docs/cross_project/分钟收视回放/分钟收视回放_立项备忘_v1.md new file mode 100644 index 0000000..3beb3c0 --- /dev/null +++ b/docs/cross_project/分钟收视回放/分钟收视回放_立项备忘_v1.md @@ -0,0 +1,119 @@ +# 子项目立项备忘 — 分钟收视回放 + +> 文档类型:子项目立项备忘 +> 子项目名称:分钟收视回放 +> 立项日期:2026-06-11 +> 子项目所在:秒级收视 project(Claude.ai 网页版的另一个 project) +> 当前状态:**推进中**(设计已收敛,进入子板块内部实现阶段) +> 主 project 联系人:制片人刘通 + Claude Opus 4.7 顾问 + +--- + +## 一、文档用途 + +未来主 project 这边新开 chat 时(必然会发生 Claude 失忆),新 Claude 通过此文件快速恢复"分钟收视回放子项目"的上下文。**它不重复 v1 答复 md 里的细节,只留指针 + 关键决策摘要**。 + +--- + +## 二、立项缘由 + +制片人在另一个 project(秒级收视)里讨论分钟收视数据怎么进工作台、怎么呈现。那边 Claude 写了一份 PRD(需求规格 v1, 2026-06-10),向主 project 这边提了 6 个对接问题。 + +主 project 这边讨论两轮后采纳"以子项目模式独立推进",并把答复凝结成正式 md 带回子项目。**这次是项目里第一次完整使用"子项目模式"**——既是分钟收视回放本身的立项,也是这套跨 project 协作工作流的首次实操。 + +--- + +## 三、关键决策摘要(已采纳,不要重复讨论) + +1. **视频不入工作台**:制片人多渠道自存(极空间/百度网盘/本地),工作台只接收截图 +2. **本地切图工具**:子板块产出,py + exe + 使用说明,与工作台零耦合 +3. **复用现有 episodes 表**:不新建"节目期次表",分钟数据表 `episode_minute_ratings` 外键挂到 `episodes.id` +4. **录入人字段用 `created_by INTEGER REFERENCES users(id)`**:不用 string,顺手落地 backlog B2 操作留痕 +5. **后端不上 Celery/Redis**:异步任务在视频不入库后基本消失,必要时用 FastAPI BackgroundTasks +6. **图表库三选一**:@ant-design/charts / ECharts / Recharts,不引第四个,最终由 Cline Plan 阶段定 +7. **详情页 `/episodes/:id` 骨架由本子板块附带建起来**:早晚要做,借这次一起 +8. **权限沿用 yearly_targets 口径**:zhipianren + zebian 可写,biandao 只读 + +--- + +## 四、子板块要交付什么(五份产物) + +子项目结束时,那边凝结以下交付包带回主 project: + +1. 决策摘要 md +2. 接口约定 md(含 SQL DDL、API endpoint、UI 接入点、权限规则、存储路径规则) +3. 本地切图工具完整包(py 源码 + exe + 使用说明) +4. 未尽事项 backlog +5. 给主 project Claude 顾问的"接手提示词" + +详见《分钟收视回放_主project答复_v1.md》第七节。 + +--- + +## 五、主 project 要做的事 + +**现在(推进期)**:不做事,不接收过程文档,等收交付包。 + +**收到交付包后**: + +1. 主 project 顾问 (Opus) 审一遍,看跟主项目红线有没有冲突 +2. 无冲突 → 主 project workspace 里让 Cline 落代码 +3. 有冲突 → 标出冲突点,回子项目修,循环 + +--- + +## 六、相关文档(指针) + +**外部输入**(子项目发来的): + +- 秒级 chat 的 PRD v1:《军事科技_分钟收视回放_子板块需求规格.md》(2026-06-10) + - 已在主 project files 中(制片人 2026-06-11 上传) + +**主 project 输出**(咱们这边给子项目的): + +- 《分钟收视回放_主project答复_v1.md》(2026-06-11) + - 建议归档位置:`docs/cross_project/分钟收视回放/分钟收视回放_主project答复_v1.md` + +**配套文档**: + +- 《跨project协作提示单_v1.md》(2026-06-11,制片人随身保存) + - 不在主 project 仓库内,是制片人个人工作流手册 + +--- + +## 七、预计回归时间 + +未明确锁定。子项目那边的 Claude 表示"没有什么不清楚的了",已在内部推进。 + +**触发主 project 这边介入的信号**: + +- 子项目带交付包过来(正常路径) +- 子项目过程中遇到吃不准的事 → 单点咨询主 project 顾问(不要整份过程稿上传) +- 超过 4 周还没收敛 → 主动 ping 一下,看是不是要重新切分 + +--- + +## 八、给未来失忆接手 Claude 的提示 + +如果你是几周后接手主 project 的 Claude,看到这份备忘,请记住: + +1. **分钟收视回放是一个独立推进的子项目**,主 project 不掺合其内部讨论 +2. **复用 episodes 表,不要新建节目期次表**——这是已经定死的决策,不重新讨论 +3. **改 schema 必须经 Opus 顾问审**,子项目交付包带 schema 修改建议时严守这条 +4. **本地切图工具与工作台零耦合**,工作台 UI 里不要给它留接口 +5. **视频不入工作台**——任何提议加视频上传接口的方案都已被否决 +6. **审查交付包是必经环节**,发现子项目设计违反主项目红线(如角色枚举、收视颜色判定)时直接打回 + +--- + +## 九、版本演进 + +本文件未来如需更新(v2+): + +- 子项目交付包接收后:更新"当前状态"为"已交付,整合中" +- Cline 实施完成后:更新"当前状态"为"已完成",加一节"实施回顾" +- 实施过程中如有重大决策变更:v2 顶部"主要变化"写明 + +--- + +*本立项备忘由主 project 顾问 (Claude Opus 4.7) 于 2026-06-11 制片人立项动作后随手生成。轻量、精简,未来失忆接手时由此恢复上下文。* diff --git a/docs/cross_project/看板升级分析/main/寄存条_看板升级已外迁.md b/docs/cross_project/看板升级分析/main/寄存条_看板升级已外迁.md new file mode 100644 index 0000000..0bfdc70 --- /dev/null +++ b/docs/cross_project/看板升级分析/main/寄存条_看板升级已外迁.md @@ -0,0 +1,65 @@ +# 寄存条:看板升级已外迁 + +> 留在主 project,让未来的 Claude 一眼知道:看板分析升级已经拉出去单独立项了。 +> 外迁时间:2026-06-12 + +--- + +## 外迁了什么 + +**TPS 看板分析升级**整体作为子项目,搬到独立 Claude project。 + +子项目聚焦:三层信息架构、双引擎象限图、AI 打标流水线、编导能力地图、本期诊断小结、看板 UI 设计。 + +子项目持有的核心资产:主项目签发的 Brief + 三份续接快照 + ground-truth 基准集 + 23 期文稿等。 + +--- + +## 主 project 不再讨论的话题 + +聊到下面这些词,**先问一句"这是子项目的事还是主 project 的事?"**——是子项目的事,提醒制片人切到子项目 chat。 + +关键词:看板升级 / 双引擎象限图 / 题材热度 / 叙事结构(作为字段)/ AI 打标 / Prompt 1/2/3 / ground-truth / episodes 加字段 / 23 期回填 / 能力地图 / 置信度三档 / 本期诊断小结 + +--- + +## 主 project 仍在管什么 + +- Phase 0-3 已落地的主干代码(episodes、editors、收视诊断基础) +- backend 全部 schema、API、迁移脚本 +- 前端全部 React 代码实施 +- 主干 Bug、性能优化、新需求(看板升级以外的) +- Cline 的全部 Plan + Act 操作 + +--- + +## 接收子项目交付物的接口 + +子项目交付物的具体接口约定,见**子项目主 Brief §六**(交付什么)。简要回顾: + +- **Schema 变更**:子项目出字段定义文档 → 主 project Cline 切 Plan + Opus 审 + 制片人批准 Act → `pg_dump` 备份 → 跑迁移 +- **前端实施**:子项目出设计 token + HTML mock + 视觉规范 → 主 project Cline 落 React +- **AI 打标**:沙盒 `ai-labeling/` 由子项目自治,主 project 不碰 +- **回填**:子项目出脚本设计 → 主 project 跑 + 制片人审 staging + +**纪律**: +- 只接稳定版,草稿不实施 +- 实施前 `pg_dump` 备份 +- 实施完成后回访子项目登记状态 + +--- + +## 开局口径 + +进主 project 新 chat: +> "续接 TPS 主项目。读 `寄存条_看板升级已外迁.md`。当前要做 [具体任务]。" + +--- + +## 万一子项目记录丢了 + +降级方案: +1. 主 project 这边还保留资产副本(xlsx + 11 份 docx + 部分 UI 参考图) +2. 决策史在 Gitea 有 git 历史(关键 commit `38f3728` 等) +3. 制片人本地应有副本 +4. **主 project 这边不要凭记忆重建子项目内容**——找制片人或重建子项目 diff --git a/docs/cross_project/看板升级分析/main2slave/INDEX.md b/docs/cross_project/看板升级分析/main2slave/INDEX.md new file mode 100644 index 0000000..c4011a8 --- /dev/null +++ b/docs/cross_project/看板升级分析/main2slave/INDEX.md @@ -0,0 +1,50 @@ +# 看板升级子项目 — 入口 + +> 这是 TPS 主 project 拆出来的子项目,聚焦"看板分析升级"。 +> 立项时间:2026-06-12 +> 顾问:Claude Opus 4.7 | 制片人:刘通 + +--- + +## 开局必读(顺序) + +1. `看板升级子项目_Brief.md` — 主项目签发的"交接宪法"(红线、技术栈、出入口接口)。**不在子项目内修改。** +2. `续接快照_看板分析升级_设计讨论_v4.md` — 最新决策史(往前可回溯 v3 / v1) +3. 上面两份读完,就有完整上下文了 + +--- + +## 已有资产 + +**决策史**: +- 续接快照 v1 / v3 / v4 — 整个看板升级讨论的完整记录 + +**数据基础**: +- `军事科技栏目收视诊断分析_v2.xlsx` — 双引擎模型源数据(主项目也留一份) +- 11 份节目文稿 `.docx` — AI 打标基准集源稿(主项目也留一份) + +**UI 参考**: +- `dashiboard首页原版.jpg` — 首屏改造起点(主项目也留一份) +- `dashiboard首页_拷贝.jpg` — 制片人批注稿 +- `色调字体倒角.webp` — 整体视觉资产(主项目也留一份) +- `简洁风_清晰.jpg` — DataEase 风格参考 + +**协作纪律**: +- `Claude协作原则.md` — 与主项目同源,沿用 + +**沙盒**: +- `ai-labeling/` 工作区(物理上仍在 `E:\tps-dashboard\ai-labeling\`) +- Prompt 2 v0.2 已锁,MiniMax M3 选定,ground-truth v0.2.1 锁定 + +--- + +## 子项目自由度 + +读完 Brief 你会注意到 §八"未决项"——那是子项目可自由发挥的部分。 +Brief 里没明确禁止、没在续接快照里拍板的事,都是讨论空间。 + +--- + +## 新 chat 开局第一句 + +> "续接 TPS 看板分析升级子项目。先读主 Brief 和续接快照 v4。本 project 是设计+PRD 产出,不动主 project 的 backend 代码。当前推进到 [具体任务]。" diff --git a/docs/cross_project/看板升级分析/main2slave/看板升级子项目_Brief.md b/docs/cross_project/看板升级分析/main2slave/看板升级子项目_Brief.md new file mode 100644 index 0000000..d972967 --- /dev/null +++ b/docs/cross_project/看板升级分析/main2slave/看板升级子项目_Brief.md @@ -0,0 +1,143 @@ +# 看板升级子项目 Brief + +> 主项目 → 子项目的"交接宪法":红线、技术栈、出入口接口 +> 起草日期:2026-06-12 +> 状态:子项目立项时由主项目顾问(Opus)签发,子项目内部不修改 + +--- + +## 一、为什么做 + +**痛点**:制片人和编导团队拿到的"收视成绩单"只能看到结果(均值、走势、单期高低), +看不到结构性原因。每次复盘要靠人工拼诊断(21 期那次花了若干周),无法持续。 + +**升级目标**:把仪表盘从"看成绩"升级为"能分析"—— +让"双引擎模型(题材热度 × 叙事结构)"这个一次性人工产出的分析框架, +变成一台**持续运转的诊断仪**。 + +--- + +## 二、做什么(功能边界,只列名) + +| 模块 | 简述 | +|---|---| +| 三层信息架构 | 纯算 / 打标后 / AI 起草,分层呈现 | +| 双引擎象限图 | 招牌视觉,题材热度 × 叙事结构 | +| AI 打标流水线 | Prompt 1/2/3 + MiniMax M3 + ground-truth | +| 编导能力地图 | 反排名,正反馈 | +| 本期诊断小结 | AI 起草 + 制片人审改后发布 | +| 时间选择器 | 实时脉搏 vs 周期复盘,边界永远可调 | + +**具体怎么做,子项目内部讨论,本 Brief 不预设方案。** + +--- + +## 三、怎么用(目标流程) + +- **每周**:制片人看"实时脉搏"——核心指标卡 + 近 9 期走势 +- **每月**:制片人看"题材分析"——题材汇总,关注异动 +- **每季**:制片人看"双引擎象限图 + 本期诊断小结"——周期复盘 +- **新节目入库**:AI 打标草稿 → staging 表 → 制片人审 → 落库 +- **编导维度**:制片人查能力地图,把强项做成全组可复用模板 +- **离职编导**:历史保留,面向当下视图可筛掉 + +--- + +## 四、不做什么(红线) + +子项目设计任何方案,**绝不**触碰以下: + +- ❌ **不做深色大屏**(留给 2.0 数据大屏蓝本) +- ❌ **不做编导排名**(团队视角走能力地图) +- ❌ **AI 不自动盖章下结论**(永远是"AI 出草稿,人拍板") +- ❌ **不引入新图表库**(继续 ECharts / @ant-design/charts) +- ❌ **不引入主 project 没有的技术栈** +- ❌ **不动主 project 已有的 schema**(改字段必须走 §六交付协议) +- ❌ **不做"未审字段直接上看板"**(置信度三档必须可辨) +- ❌ **不写 / 不改 AI 打标 Prompt 由 Cline 完成**(Cline 是执行者不是作者) + +--- + +## 五、技术栈约束(继承主 project) + +子项目所有设计必须能落在以下栈上,不引入新依赖: + +- **前端**:React 18 + Vite + AntD 5 + Zustand + ECharts / @ant-design/charts +- **后端**:FastAPI + SQLModel + PG 16 + pgvector +- **配色**:米色底 `#fbf9f1` + 深绿主色 `#6b8e6b` +- **三色色板**:红 `#c0584f` / 蓝 `#5b8db8` / 绿 `#7aa874` +- **基准线**:基础线 0.6448 / 摸高线 0.8989(2026) +- **AI 打标**:沙盒 `ai-labeling/`,生产模型 MiniMax M3,openai==1.55.0 锁版本 +- **部署**:腾讯云 4 核 8G(性能上限,凡是吃不动的方案直接否决) + +--- + +## 六、交付什么(出口接口) + +子项目产出最终要回到主 project 实施,**交付物必须满足以下接口**: + +### 6.1 Schema 变更类 +- 子项目出:**字段定义文档**(命名 / 类型 / 枚举 / nullable / 约束 / 回滚方案) +- 主 project 实施:**Cline 切 Plan → Opus 审 → 制片人批准 Act → `pg_dump` 备份 → 跑迁移** +- 不接受:子项目自己改主 project schema 或 `backend/` 任何代码 + +### 6.2 前端实施类 +- 子项目出:**设计 token JSON + HTML mock + 视觉规范文档** +- 主 project 实施:**Cline 按设计稿落 React 组件** +- 不接受:子项目自己写主 project 的 React 代码 + +### 6.3 AI 打标类 +- 子项目在 `ai-labeling/` 沙盒自治,**沙盒内 Cline 可直接 Act** +- 子项目出:**Prompt 文件 + ground-truth.json + 模型选型结论** +- 主 project 实施:**episodes_staging 表 schema 落库 + 审稿 UI 落地** + +### 6.4 回填类 +- 子项目出:**回填脚本设计文档 + 23 期回填策略** +- 主 project 实施:**Cline 跑脚本 + 制片人审 staging** + +### 6.5 通用约束 +- 子项目**不主动 push** 文件到主 project,**所有交付物由制片人决定时机** +- 主 project 只接**稳定版**,子项目内部草稿不交付 + +--- + +## 七、入口接口(子项目要知道的主 project 现状) + +- **Phase 0-3 已落地**:episodes / editors / 收视诊断基础数据,23 期 2026 年数据已入库 +- **现有视觉语言**:米色 + 深绿,卡片圆角 12px,AntD 5 默认行高 +- **现有 backlog**:主 project 这边的 backlog 已标注"看板升级条目已外迁" +- **现有沙盒**:`ai-labeling/` 工作区已搭建,Prompt 2 v0.2 已锁,MiniMax M3 已选定 +- **现有 git**:Gitea 落库,关键 commit `38f3728` + +--- + +## 八、未决项(归子项目自己拍板) + +以下不在本 Brief 内预设,**由子项目和制片人讨论决定**: + +- 横轴量化方法的具体公式 +- AI 打标 Prompt 1 / Prompt 3 的具体写法 +- 看板各屏幕的具体布局和交互 +- 双引擎象限图的具体视觉细节 +- 能力地图的具体可视化方案 +- episodes 新字段的最终命名 / 类型 / 是否多对多关联表 +- 置信度是单字段还是分字段 +- 时间窗口取多大 / 小样本怎么兜底等具体口径 + +--- + +## 九、决策史指向(不重复内容) + +子项目讨论前应该读的: +- `续接快照_看板分析升级_设计讨论.md`(v1,2026-06-09) +- `续接快照_看板分析升级_设计讨论_v3.md`(v3,2026-06-11 上午) +- `续接快照_看板分析升级_设计讨论_v4.md`(v4,2026-06-11 晚) +- `军事科技栏目收视诊断分析_v2.xlsx`(双引擎模型源数据) + +--- + +## 十、本 Brief 自身的修订规则 + +- 本 Brief 不在子项目内修改 +- 红线 / 技术栈如有变更,**主 project 这边发新版**,通过寄存条同步 +- 子项目可在自己的 chat 里讨论"建议主 project 调整某条红线",但调整动作只能在主 project 发生 diff --git a/docs/cross_project/看板升级分析/main2slave/迁移清单_主project操作指南.md b/docs/cross_project/看板升级分析/main2slave/迁移清单_主project操作指南.md new file mode 100644 index 0000000..d9ecfa4 --- /dev/null +++ b/docs/cross_project/看板升级分析/main2slave/迁移清单_主project操作指南.md @@ -0,0 +1,95 @@ +# 迁移清单 — 主 project 操作指南 + +> 用途:看板升级子项目立项时,主 project 这边的文件操作清单 +> 操作完即可丢弃 +> 制定时间:2026-06-12 + +--- + +## 资产分两类处理 + +### 🔵 子项目独有(主 project 这边删) + +纯决策记录性质,主 project 不再需要: + +1. `续接快照_看板分析升级_设计讨论.md`(v1) +2. `续接快照_看板分析升级_设计讨论_v3.md` +3. `续接快照_看板分析升级_设计讨论_v4.md` +4. `dashiboard首页_拷贝.jpg`(批注稿) +5. `简洁风_清晰.jpg`(参考图) + +### 🟢 两边都留(各保留一份) + +资产类性质,主 project 将来也可能用得到: + +1. `军事科技栏目收视诊断分析_v2.xlsx` — 数据基础 +2. 11 份节目文稿 `.docx`(硅基大脑、潜艇仿生 等) — 节目原始资料 +3. `dashiboard首页原版.jpg` — 主 project 实施 React 时要看 +4. `色调字体倒角.webp` — 整体视觉资产 + +--- + +## 主 project 这边的其他动作 + +### 新增 + +- 上传 `寄存条_看板升级已外迁.md` + +### 更新 + +- `backlog_md_TPS_工作台待办池_不丢视野_非排期_.md` 顶部加一段: + +```markdown +> ⚠️ 更新(2026-06-12):看板分析升级相关待办(原 F1-F8)已整体迁移到 +> **TPS 看板分析升级子项目**。主 project 这边不再维护这部分待办。 +> 子项目状态见 `寄存条_看板升级已外迁.md`。 +``` + +### 保留(不动) + +主干文档(README、Claude协作原则、phase 日志、doco 系列、git_workflow、_clinerules、_gitignore、001_init.sql、dev_plan、project_plan、Phase 3 续接快照系列)全部保留。 + +--- + +## 操作步骤 + +**Step 1 ─ 建子项目** +1. 新建 Claude project,名为 `TPS看板分析升级` +2. 上传 4 份新文件:`INDEX.md` + `看板升级子项目_Brief.md` + 拷贝一份 `Claude协作原则.md` +3. 上传 🔵 5 份子项目独有的文件 +4. 上传 🟢 14 份资产文件(主 project 也保留同名副本) + +**Step 2 ─ 清主 project + 寄存** +5. 删除 🔵 5 份文件 +6. 上传 `寄存条_看板升级已外迁.md` +7. 更新 `backlog` 顶部标注 + +**Step 3 ─ 验证** +8. 进主 project 新 chat:"读寄存条" → 看 Claude 是否懂"这部分外迁了,不在我这里讨论" +9. 进子项目新 chat:按 INDEX 开局口径 → 看 Claude 是否能正确进入顾问角色 + +--- + +## 操作后的拓扑 + +``` +TPS 主 project TPS 看板升级子项目 +───────────────────── ───────────────────── +├─ 主干文档(README/协作原则/phase 等) ├─ INDEX.md ★ +├─ doco/migration/git/init/dev/plan ├─ 看板升级子项目_Brief.md ★ +├─ Phase 3 续接快照系列 ├─ Claude协作原则.md(拷贝) +├─ backlog(顶部加标注) ├─ 续接快照 v1/v3/v4 +├─ 寄存条_看板升级已外迁.md ★ ├─ xlsx + 11 份 docx(副本) +├─ xlsx + 11 份 docx(副本) ├─ dashboard 首页原版(副本) +├─ dashboard 首页原版(副本) ├─ 色调字体倒角(副本) +└─ 色调字体倒角(副本) ├─ dashboard 首页_拷贝.jpg + └─ 简洁风_清晰.jpg +``` + +★ = 新增 + +--- + +## 拿不准的就先不动 + +任何一份文件去留拿不准的,**先保留**。文件保留比误删容易处理。 diff --git a/docs/cross_project/看板升级分析/slave/F3_横轴量化方法_PRD_v1.0.md b/docs/cross_project/看板升级分析/slave/F3_横轴量化方法_PRD_v1.0.md new file mode 100644 index 0000000..928b404 --- /dev/null +++ b/docs/cross_project/看板升级分析/slave/F3_横轴量化方法_PRD_v1.0.md @@ -0,0 +1,151 @@ +# F3 横轴量化方法 PRD v1.0 + +> 子项目交付物 · 看板分析升级 +> 状态:**v1.0 已锁**(2026-06-12 通哥审过 §2/§3/§4 决策) +> 起草时间:2026-06-12 +> 顾问:Claude Opus 4.7 | 制片人:刘通 +> 类型:薄 PRD(只解 v2 之后留下的开放点,已锁部分仅引用) + +--- + +## §1 引用已锁结论(不重述) + +本 PRD 是对已有结论的**补丁/收敛**,不替换。已锁部分直接参见以下来源: + +| 来源 | 已锁内容 | +|---|---| +| 续接快照 v2 §3 | 横轴公式 `X = 该题材在分析窗口内的均值份额 − 栏目均值份额`,零点 = 栏目均值,单位 = 收视份额绝对差 | +| 续接快照 v2 §4 | 双引擎象限图视觉规格:气泡大小 = 收视份额、气泡颜色 = 收视判定三色、气泡边框 = 开篇钩子三档、重叠用 jitter 解 | +| 主 project Claude 示意图(2026-06-10) | 23 期实际数据 + 模拟纵轴/钩子已可视化,制片人认可"不挤、不堆叠" | +| 续接快照 v3 §1.1 / v4 §3 | 纵轴从 3 档收为 2 档(主线演进 / 并列结构),Prompt 2 v0.2 + ground-truth v0.2.1 M3 100% 锁定 | +| 续接快照 v2 §2 字段二 | `equipment_domain` 多选 9 类:陆战装备 / 海军舰船 / 航空航天 / 导弹与反导 / 信息化 / 后勤保障 / 轻武器 / 跨域 / 其他 | + +本 PRD 解决 v2 之后留下的三个开放点:**多标签横轴取值规则、小样本兜底、视觉规格刷新到 2 档纵轴**。 + +--- + +## §2 决策一:多标签 → 横轴单点取值规则(Path A 全额法) + +`equipment_domain` 字段为多选(至少 1 项),但横轴一期只能落一个点。 + +### 2.1 规则 + +**每个 `equipment_domain` 标签独立维护自己的累计均值;一期节目标了 N 个标签,就把该期完整 share 直接记进**每一个**沾上的标签的均值池(全额、不瓜分、不加权)。** + +### 2.2 数学定义 + +``` +对每个 equipment_domain 标签 i: + base_i = 所有沾标签 i 的节目的 share 的算术平均 + = Σ(share_j, ∀ j 沾标签 i) / count(j 沾标签 i) + +栏目均值: + base_全栏目 = 所有节目的 share 的算术平均(单期单算) + +每期 ep 的横轴位置: + X(ep) = mean(base_i, ∀ i ∈ ep.equipment_domain) − base_全栏目 +``` + +### 2.3 示例 + +设当前 `海军舰船` 桶均值 = 0.69,`跨域` 桶均值 = 0.79,栏目均值 = 0.72。 + +- 一期标 `海军舰船 + 跨域`,share = 0.71 +- 该期 X 位置 = (0.69 + 0.79) / 2 − 0.72 = **+0.02**(略偏热) +- 这期 share = 0.71 同时记入 `海军舰船` 均值池(下次 base 重算用)和 `跨域` 均值池 + +**两点说明**: + +1. **均值更新方向自洽**:0.71 < 0.72(栏目均值),也低于"跨域 0.79"。记入两个桶后,两个桶的均值都会被这期略往下拉,符合"低于均值的样本拉低均值"的直觉。 +2. **不存在 ×N 放大**:之前讨论过的"按基值加权 × 标签数"方案因方向 bug(低于均值的样本可能反向拉高均值)被否决,详见 2026-06-12 续接讨论。 + +### 2.4 适用范围 + +本规则**仅用于横轴 X 值计算**。其他统计(能力地图、编导对比、scene_tags 分布等)的多标签处理另议。 + +--- + +## §3 决策二:小样本兜底规则 + +某 `equipment_domain` 桶若在当前分析窗口内样本量 n 较小,均值统计意义弱。视觉上需可辨。 + +### 3.1 兜底分档 + +| 桶样本量 | 视觉处理 | +|---|---| +| **n ≥ 3** | 正常显示,base 值直接入横轴坐标 | +| **n = 1 或 2** | 桶名右侧显示 `(n=X)` 灰色小字;桶内气泡描边改为虚线浅灰;tooltip 警示"样本不足,横轴位置参考价值有限" | +| **n = 0** | 桶不出现在横轴坐标系上(如 `陆战装备` 在 21 期场景下属此类,预留枚举值但暂不画) | + +### 3.2 阈值出处 + +n = 3 阈值的取法:统计上方差估计起码需 2 自由度,记录方便取 3。**这是初值,后续看实际分布可调**。 + +### 3.3 当前 21 期场景的小样本桶预测 + +按 v2 §2 九类 + 我对 21 期的初步映射(见配套回填提案表): + +- `导弹与反导` n=1(ep15 一期),**小样本桶** +- `信息化` n=1 或 2(取决于 ep03 是否归这里 vs 跨域),**可能小样本** +- `陆战装备` n=0,**不出现在坐标系** +- `后勤保障` n=0,**不出现在坐标系** +- `其他` n=0,**不出现在坐标系** + +其余 4 个桶(`海军舰船` / `航空航天` / `轻武器` / `跨域`)预计 n ≥ 3,正常显示。 + +--- + +## §4 决策三:视觉规格刷新(纵轴 3 档 → 2 档) + +v2 §4 视觉规格除以下差异外,**全部沿用**: + +| 元素 | v2 §4(3 档,旧) | 本版(2 档,新) | +|---|---|---| +| 纵轴档位 | 强主线悬念 / 主线演进 / 并列结构 | **主线演进 / 并列结构**(v3 §1.1 收为 2 档) | +| 纵轴坐标 | 三个水平基线 | 两个水平基线 | +| 同档内 jitter | ±0.3 | ±0.4(档少了,jitter 可适当加大避免聚拢) | +| 中线视觉 | 两条次级分隔 | **一条主分隔线显著加粗**,强调"主线 vs 并列"对照 | +| 上下区视觉重点 | 三层等权 | **两区中性等权**——纵轴不暗示偏好方向,呈现客观对照(2026-06-12 通哥拍板) | + +横轴部分全部沿用 v2 §4,无变化。 + +--- + +## §5 配套交付清单(子项目本轮其余产出) + +- [✅ 本文件] `F3_横轴量化方法_PRD_v1.0草稿.md` +- [⏳ 下批] `双引擎象限图_HTML_mock_v1.0.html`——基于本 PRD 的纵轴 2 档版可视化,可浏览器直开看交互 +- [⏳ 下批] `F3_算法验证脚本.py`——在子项目沙盒里跑通完整计算流程,输入 23 期 equipment_domain 多选 + share,输出各桶 base + 23 期 X 值表 + 数据校验报告 +- [⏳ 下批] `equipment_domain_字段定义文档.md`——按 Brief §6.1 格式,主 project Cline 拿去做 schema 迁移 +- [⏳ 下批] `23期_equipment_domain_回填提案表.md`——给制片人审,或转 Prompt 1a 的 ground-truth 输入 + +--- + +## §6 落地依赖(主 project Cline 工作清单) + +子项目这边的 5 份交付物全部锁定后,主 project Cline 可接手以下工作(均需切 Plan + Opus 审): + +1. **Schema 迁移**:`backend/sql/00X_add_equipment_domain.sql`(基于字段定义文档) +2. **23 期回填**:Prompt 1a 跑批结果落库 + 制片人审过的 8 期标题推断低置信度样本 +3. **后端 API endpoint**:横轴聚合数据接口 `GET /api/v1/episodes/quadrant-data`(或类似) +4. **前端 React/ECharts 组件**:基于本 PRD 的 HTML mock 1:1 翻译 + +--- + +## §7 后续可能调整项(本版不解,留入 backlog) + +- **时间窗口选择**:滚动窗口 vs 全部历史 vs 季度,默认设"全部历史",后续 UI 加切换器 +- **n ≥ 3 阈值的实际验证**:用 23 期 + 新片陆续入库 6 个月后看分布,必要时调阈值 +- **多标签规则是否升级**:本版用全额路 A,运行半年若发现不妥(如某桶均值长期被高频跨域期数刷高)再议升级到带权或 1/N 守恒版 +- **n=1/2 视觉表达细节**:虚线浅灰 vs 描边淡化 vs 加图例,等 HTML mock 出来后定 + +--- + +## §8 修订规则 + +本 PRD 锁定 v1.0 后: + +- v1.x 微调(视觉细节、阈值小动)在本子项目内修改 +- v2.0 重大变更(规则换路 B、取消纵轴 2 档等)需主 project 同步审,通过新一版续接快照固化 + +修订必留 changelog,谁、何时、改了什么、为什么改。 diff --git a/docs/cross_project/看板升级分析/slave/F3_横轴量化方法_PRD_v1.0草稿.md b/docs/cross_project/看板升级分析/slave/F3_横轴量化方法_PRD_v1.0草稿.md new file mode 100644 index 0000000..edf2a3b --- /dev/null +++ b/docs/cross_project/看板升级分析/slave/F3_横轴量化方法_PRD_v1.0草稿.md @@ -0,0 +1,151 @@ +# F3 横轴量化方法 PRD v1.0(草稿) + +> 子项目交付物 · 看板分析升级 +> 状态:**草稿**,等制片人审 + 锁定后转正式 v1.0 +> 起草时间:2026-06-12 +> 顾问:Claude Opus 4.7 | 制片人:刘通 +> 类型:薄 PRD(只解 v2 之后留下的开放点,已锁部分仅引用) + +--- + +## §1 引用已锁结论(不重述) + +本 PRD 是对已有结论的**补丁/收敛**,不替换。已锁部分直接参见以下来源: + +| 来源 | 已锁内容 | +|---|---| +| 续接快照 v2 §3 | 横轴公式 `X = 该题材在分析窗口内的均值份额 − 栏目均值份额`,零点 = 栏目均值,单位 = 收视份额绝对差 | +| 续接快照 v2 §4 | 双引擎象限图视觉规格:气泡大小 = 收视份额、气泡颜色 = 收视判定三色、气泡边框 = 开篇钩子三档、重叠用 jitter 解 | +| 主 project Claude 示意图(2026-06-10) | 23 期实际数据 + 模拟纵轴/钩子已可视化,制片人认可"不挤、不堆叠" | +| 续接快照 v3 §1.1 / v4 §3 | 纵轴从 3 档收为 2 档(主线演进 / 并列结构),Prompt 2 v0.2 + ground-truth v0.2.1 M3 100% 锁定 | +| 续接快照 v2 §2 字段二 | `equipment_domain` 多选 9 类:陆战装备 / 海军舰船 / 航空航天 / 导弹与反导 / 信息化 / 后勤保障 / 轻武器 / 跨域 / 其他 | + +本 PRD 解决 v2 之后留下的三个开放点:**多标签横轴取值规则、小样本兜底、视觉规格刷新到 2 档纵轴**。 + +--- + +## §2 决策一:多标签 → 横轴单点取值规则(Path A 全额法) + +`equipment_domain` 字段为多选(至少 1 项),但横轴一期只能落一个点。 + +### 2.1 规则 + +**每个 `equipment_domain` 标签独立维护自己的累计均值;一期节目标了 N 个标签,就把该期完整 share 直接记进**每一个**沾上的标签的均值池(全额、不瓜分、不加权)。** + +### 2.2 数学定义 + +``` +对每个 equipment_domain 标签 i: + base_i = 所有沾标签 i 的节目的 share 的算术平均 + = Σ(share_j, ∀ j 沾标签 i) / count(j 沾标签 i) + +栏目均值: + base_全栏目 = 所有节目的 share 的算术平均(单期单算) + +每期 ep 的横轴位置: + X(ep) = mean(base_i, ∀ i ∈ ep.equipment_domain) − base_全栏目 +``` + +### 2.3 示例 + +设当前 `海军舰船` 桶均值 = 0.69,`跨域` 桶均值 = 0.79,栏目均值 = 0.72。 + +- 一期标 `海军舰船 + 跨域`,share = 0.71 +- 该期 X 位置 = (0.69 + 0.79) / 2 − 0.72 = **+0.02**(略偏热) +- 这期 share = 0.71 同时记入 `海军舰船` 均值池(下次 base 重算用)和 `跨域` 均值池 + +**两点说明**: + +1. **均值更新方向自洽**:0.71 < 0.72(栏目均值),也低于"跨域 0.79"。记入两个桶后,两个桶的均值都会被这期略往下拉,符合"低于均值的样本拉低均值"的直觉。 +2. **不存在 ×N 放大**:之前讨论过的"按基值加权 × 标签数"方案因方向 bug(低于均值的样本可能反向拉高均值)被否决,详见 2026-06-12 续接讨论。 + +### 2.4 适用范围 + +本规则**仅用于横轴 X 值计算**。其他统计(能力地图、编导对比、scene_tags 分布等)的多标签处理另议。 + +--- + +## §3 决策二:小样本兜底规则 + +某 `equipment_domain` 桶若在当前分析窗口内样本量 n 较小,均值统计意义弱。视觉上需可辨。 + +### 3.1 兜底分档 + +| 桶样本量 | 视觉处理 | +|---|---| +| **n ≥ 3** | 正常显示,base 值直接入横轴坐标 | +| **n = 1 或 2** | 桶名右侧显示 `(n=X)` 灰色小字;桶内气泡描边改为虚线浅灰;tooltip 警示"样本不足,横轴位置参考价值有限" | +| **n = 0** | 桶不出现在横轴坐标系上(如 `陆战装备` 在 21 期场景下属此类,预留枚举值但暂不画) | + +### 3.2 阈值出处 + +n = 3 阈值的取法:统计上方差估计起码需 2 自由度,记录方便取 3。**这是初值,后续看实际分布可调**。 + +### 3.3 当前 21 期场景的小样本桶预测 + +按 v2 §2 九类 + 我对 21 期的初步映射(见配套回填提案表): + +- `导弹与反导` n=1(ep15 一期),**小样本桶** +- `信息化` n=1 或 2(取决于 ep03 是否归这里 vs 跨域),**可能小样本** +- `陆战装备` n=0,**不出现在坐标系** +- `后勤保障` n=0,**不出现在坐标系** +- `其他` n=0,**不出现在坐标系** + +其余 4 个桶(`海军舰船` / `航空航天` / `轻武器` / `跨域`)预计 n ≥ 3,正常显示。 + +--- + +## §4 决策三:视觉规格刷新(纵轴 3 档 → 2 档) + +v2 §4 视觉规格除以下差异外,**全部沿用**: + +| 元素 | v2 §4(3 档,旧) | 本版(2 档,新) | +|---|---|---| +| 纵轴档位 | 强主线悬念 / 主线演进 / 并列结构 | **主线演进 / 并列结构**(v3 §1.1 收为 2 档) | +| 纵轴坐标 | 三个水平基线 | 两个水平基线 | +| 同档内 jitter | ±0.3 | ±0.4(档少了,jitter 可适当加大避免聚拢) | +| 中线视觉 | 两条次级分隔 | **一条主分隔线显著加粗**,强调"主线 vs 并列"对照 | +| 上下区视觉重点 | 三层等权 | 上区(主线演进)略亮、下区(并列结构)略灰,**视觉上暗示偏好方向**(可选,等通哥决) | + +横轴部分全部沿用 v2 §4,无变化。 + +--- + +## §5 配套交付清单(子项目本轮其余产出) + +- [✅ 本文件] `F3_横轴量化方法_PRD_v1.0草稿.md` +- [⏳ 下批] `双引擎象限图_HTML_mock_v1.0.html`——基于本 PRD 的纵轴 2 档版可视化,可浏览器直开看交互 +- [⏳ 下批] `F3_算法验证脚本.py`——在子项目沙盒里跑通完整计算流程,输入 23 期 equipment_domain 多选 + share,输出各桶 base + 23 期 X 值表 + 数据校验报告 +- [⏳ 下批] `equipment_domain_字段定义文档.md`——按 Brief §6.1 格式,主 project Cline 拿去做 schema 迁移 +- [⏳ 下批] `23期_equipment_domain_回填提案表.md`——给制片人审,或转 Prompt 1a 的 ground-truth 输入 + +--- + +## §6 落地依赖(主 project Cline 工作清单) + +子项目这边的 5 份交付物全部锁定后,主 project Cline 可接手以下工作(均需切 Plan + Opus 审): + +1. **Schema 迁移**:`backend/sql/00X_add_equipment_domain.sql`(基于字段定义文档) +2. **23 期回填**:Prompt 1a 跑批结果落库 + 制片人审过的 8 期标题推断低置信度样本 +3. **后端 API endpoint**:横轴聚合数据接口 `GET /api/v1/episodes/quadrant-data`(或类似) +4. **前端 React/ECharts 组件**:基于本 PRD 的 HTML mock 1:1 翻译 + +--- + +## §7 后续可能调整项(本版不解,留入 backlog) + +- **时间窗口选择**:滚动窗口 vs 全部历史 vs 季度,默认设"全部历史",后续 UI 加切换器 +- **n ≥ 3 阈值的实际验证**:用 23 期 + 新片陆续入库 6 个月后看分布,必要时调阈值 +- **多标签规则是否升级**:本版用全额路 A,运行半年若发现不妥(如某桶均值长期被高频跨域期数刷高)再议升级到带权或 1/N 守恒版 +- **n=1/2 视觉表达细节**:虚线浅灰 vs 描边淡化 vs 加图例,等 HTML mock 出来后定 + +--- + +## §8 修订规则 + +本 PRD 锁定 v1.0 后: + +- v1.x 微调(视觉细节、阈值小动)在本子项目内修改 +- v2.0 重大变更(规则换路 B、取消纵轴 2 档等)需主 project 同步审,通过新一版续接快照固化 + +修订必留 changelog,谁、何时、改了什么、为什么改。 diff --git a/docs/cross_project/跨project协作提示单_v1.md b/docs/cross_project/跨project协作提示单_v1.md new file mode 100644 index 0000000..84bc744 --- /dev/null +++ b/docs/cross_project/跨project协作提示单_v1.md @@ -0,0 +1,224 @@ +# 跨 project 协作 — 制片人随身提示单 + +> 用途:每次想在主项目之外单开子 project 讨论某个模块时,照此提示单走一遍,避免漏环节、避免版本错位、避免子项目设计违反主项目宪法。 +> 适用:刘通在 Claude 网页版多 project 工作流下的所有"主项目 + 子项目"场景。 +> 维护人:刘通 + 主 project 顾问 (Claude Opus 4.7) +> 首版日期:2026-06-11 + +--- + +## 〇、什么是 PRD? + +**PRD = Product Requirements Document,产品需求文档**。 + +把"我想要个东西"翻译成"工程师可以照着做的具体规格"。一份合格的 PRD 回答: + +- 为什么做:解决谁的什么痛点 +- 做什么:功能边界、必做/不做 +- 怎么用:用户走完流程的样子 +- 数据形态:输入什么、输出什么、字段怎样 +- 不做什么:明确划红线,防止范围蔓延 + +子项目立项时,请那边的 Claude 写一份 PRD 跟主项目对接——这就是工程界的标准操作。 + +--- + +## 一、先判断:这事适不适合分子 project? + +分之前先想三个问题。三条都满足才适合分: + +1. **这个模块与主项目耦合深不深?** 耦合深的(改用户体系、改权限)就别分,分了沟通成本比省下的还高。 +2. **这个模块边界清不清?** 输入输出明确的(如分钟收视回放)分得开;边界模糊的(如"优化整体视觉风格")分不开。 +3. **工作量够不够大?** 特别小的事(改个字段名)直接在主项目谈完即可。三五次对话讨论不完的,才值得分。 + +**反例**:未来想做"AI 自动生成报题单"——这件事跟主项目的 TPS 模块、知识库、收视数据、编导画像全打通,**强耦合**,分子 project 反而割裂上下文。这种就在主项目里推进。 + +**正例**:分钟收视回放、本地切图工具、外拍资源管理子模块——边界清晰,可独立设计。 + +--- + +## 二、流程(四步) + +### 步骤 1:在主项目立"项"——先打招呼 + +子项目开干**之前**,先在主项目 chat 里跟 Claude 顾问说一声: + +> "我要开一个子 project 讨论 X 模块,目标是 Y。" + +主项目 Claude 会做两件事: + +- 检查 X 是否真的适合分出去(参照第一节三问) +- 把主项目跟 X 相关的红线、技术栈、宪法摘出来给你 + +**实操**:把这些"开局材料"打包好,作为子项目的 files 上传过去(至少包括 `.clinerules`、`project_plan.md`、`dev_plan.md`,必要时加相关的 phase log)。子项目 Claude 能读到这些,就能少犯错。 + +**这一步不能省**。子项目 Claude 看不到主项目宪法时,会本能地按自己的最佳实践设计——很可能违反主项目某条红线。 + +### 步骤 2:在子项目讨论、迭代、收敛 + +要点: + +- 子项目**不写主项目的代码**,只输出文档、demo、独立小工具 +- 子项目**不改主项目的 schema**,所有涉及主项目数据库结构的提议,回主项目让 Claude 顾问审 +- 子项目**遇到吃不准的事,回主项目问**——以提问列表的形式(参考秒级 chat 那份 PRD 第八节的 6 问) + +### 步骤 3:子项目凝结成"交付包" + +讨论完不能就这么散了。要凝结成可以跨 chat、跨 project、被未来任何人接手的产物。**详见下面第四节五份交付物**。 + +**关键认知**:Claude 的 chat 越长,判断力越下降(上下文太满);而且新 chat 一开就丢了。**md 文档才是真正的产物,chat 只是过程**。讨论一收敛,赶紧让子项目 Claude 凝结成 md。 + +### 步骤 4:回主项目整合 + +带着交付包回主项目: + +- 主项目 Claude 顾问审一遍交付包,看跟主项目红线有没有冲突 +- 没冲突 → 在主项目 workspace 里让 Cline 落代码 +- 有冲突 → 标出冲突点,回子项目修,循环 + +**主项目顾问对子项目交付物有否决权**。听起来霸道,但必要——子项目 Claude 不知道主项目全部红线。这一步省不掉。 + +--- + +## 三、规范:跨 project 文档怎么写 + +做对四件事,文档传递不会乱。 + +### 规范 1:文件名带版本号 + +❌ `分钟收视需求规格.md` +✅ `分钟收视需求规格_v1.md` + +下次改了就 v2。**绝对不要原地覆盖**——历史版本要留着,方便回看"我们当时为什么这么定"。 + +### 规范 2:文档顶部固定"元信息块" + +每份跨 project 文档第一段必须有: + +``` +> 版本:v1 +> 日期:2026-06-11 +> 作者:[谁写的] +> 状态:[草稿 / 待主项目审 / 已采纳 / 已作废] +> 上一版:[v0 或"无"] +> 主要变化:[v2 才需要写] +``` + +这块 6 行,写起来不累,但是救命。**没有这个块的跨 project 文档,主项目这边可以拒收**。 + +### 规范 3:一份文档只谈一件事 + +不要在"分钟收视需求规格"里顺带讨论"用户管理优化"。串了就乱。 + +### 规范 4:主项目这边定期回收 + +子项目讨论完、文档传过来、整合完成后,把最终采纳的那份 md 放到主项目的 `docs/cross_project/` 目录里。这是主项目的"对外接口档案库"。 + +--- + +## 四、最终交付物:子项目结束时该产出什么(五份) + +子项目结束时,告诉那边的 Claude: + +> "请把所有讨论凝结成最终交付包,包含以下五份产物。" + +### 产物 1:决策摘要 md + +记录子项目全程的关键决策。每条三句话: + +``` +决策 X:[一句话决策内容] + - 背景:为什么需要这个决策 + - 拍板理由:选这条不选那条的理由 + - 拍板人:[制片人 / 主项目顾问 / 子项目 Claude 建议+制片人采纳] +``` + +不需要"我们讨论了 47 轮"的过程,只要最终结论。10-20 条就把整个子项目的"为什么这么做"讲清。 + +### 产物 2:接口约定 md(最技术、最精确) + +把子板块与主项目接驳的所有"接口"白纸黑字写出来。"接口"是广义的,包括: + +- **数据接口**:要新建哪些表、哪些字段、字段类型、约束 +- **API 接口**:要新增哪些后端 endpoint、URL、方法、请求体、响应体、错误码 +- **UI 接口**:要在主项目哪个页面挂载这个模块、入口在哪、路由怎么走 +- **权限接口**:哪些角色可以做什么操作 +- **存储接口**:文件存到哪个目录、命名规则、URL 怎么拼 + +每一条都要具体到"主项目的 Cline 拿着这份就能写代码"的程度。**这份是子项目给主项目的"合同"**。 + +### 产物 3:实物交付(独立工具、demo、设计稿) + +子项目特有的产物。视模块性质不同: + +- 分钟收视回放子项目 → 本地切图工具 (py + exe + 使用说明) +- 视觉重设计子项目 → 设计稿(Figma / HTML demo) +- 数据分析子项目 → 离线分析脚本 + 示例输出 + +这些东西**与主项目零耦合**,自己能独立运行。 + +### 产物 4:未尽事项 backlog + +诚实写出"子项目讨论中提到但没做的事"。每条三行: + +- 是什么 +- 为什么没做(暂缓 / P1+ / 等条件成熟) +- 触发时机 + +放进主项目的 backlog 池子里,未来某个 Phase 收尾时回看,决定哪条捞进下个 Phase。 + +### 产物 5:给主项目 Claude 顾问的"接手提示词" + +一两段话,告诉主项目顾问"如果你是接手这件事的 Claude,最重要的三件事是 X、Y、Z"。 + +这段相当于一份"防止主项目这边犯傻"的备忘,往往是最有价值的一份。 + +--- + +## 五、操作过程中的实操注意点 + +### 注意 1:永远以 md 为准,不要口头转述 + +❌ "那边 Claude 说 XX",然后跟那边说"主项目这边说 YY" +✅ 所有跨项目沟通**以 md 文档为准** + +口头转述会丢细节、会失真,连续转两次就跟最初的意思差很远。 + +### 注意 2:chat 是过程,md 是产物 + +子项目 chat 长了之后,Claude 自己的判断力会下降(上下文太满),换新 chat 就丢了。**讨论一收敛,赶紧让子项目 Claude 凝结成 md。chat 可以扔,md 不能扔**。 + +### 注意 3:主项目顾问的"审查"环节不能省 + +子项目 Claude 不知道主项目的全部红线,可能输出违规方案。**拿到子项目交付包后,先来主项目让顾问审一遍,再让 Cline 落实施**。这一步省不掉。 + +### 注意 4:每个子项目最长不要超过 3-4 周 + +时间越长,跟主项目脱节越严重(主项目可能在这期间已经迭代)。如果一个子项目超过 4 周还没收敛,应该停下来重新评估:是不是分得太大?要不要切成更小的子子项目? + +### 注意 5:交付包归档到主项目仓库 + +交付完成后,五份交付物放到主项目的 `docs/cross_project/{子项目名}/` 目录里。**版本号文件全部保留**,未来回看决策史时会用到。 + +--- + +## 六、一句话总结 + +> **子项目专心做事不出主项目;主项目负责审查与整合,不掺合子项目讨论;md 文档是跨项目通信的唯一介质;版本号 + 元信息块永远不省。** + +--- + +## 七、复盘提示(每次子项目结束后回看一次) + +子项目结束,回过头来问自己: + +1. 这次分子项目是不是真的提高了效率?还是反而增加了沟通成本? +2. 主项目顾问审查时发现了多少个违规设计?说明子项目立项时给的"开局材料"够不够? +3. 五份交付物齐了吗?哪份最有用?哪份没人看? +4. 这次的经验,要不要加进本提示单的下一版? + +**本提示单本身也按版本管理**。每次复盘有沉淀就出 v2。 + +--- + +*v1 由主 project 顾问 (Claude Opus 4.7) 协助刘通于 2026-06-11 整理成稿。下次修订时机:第一次完整跑完一个子项目(分钟收视回放)之后。* diff --git a/docs/doco/Doco子项目_Brief.md b/docs/doco/Doco子项目_Brief.md new file mode 100644 index 0000000..b8ef565 --- /dev/null +++ b/docs/doco/Doco子项目_Brief.md @@ -0,0 +1,144 @@ +# Doco 文稿整理子项目 Brief + +> 主项目 → 子项目的"交接宪法":红线、技术栈、出入口接口 +> 起草日期:2026-06-12 +> 状态:主项目签发,子项目内部不修改 + +--- + +## 一、为什么做 + +**痛点**:《军事科技》每期节目播出后,产出一份贴近实际播出的终版文稿,过去靠人工对照 A 稿(编导定稿)+ 录音转写 + OCR 字幕反复核对,**单期 4-6 小时**,且容易遗漏错字、整段重写、编导笔误。 + +**升级目标**:把"三方文本 → 终版文稿 + 差异报告"做成可自动化的流水线模块。 + +**现状起点**:demo 已用《现代防空反导大对决》一期跑通,效果达标。栏目组改变了素材输出方式——直接产出"黑底白字+干净人声"的特殊视频——使物理输入从 3 路(A 稿+B 稿+ASR)收敛到 2 路(A 稿+视频),但**逻辑上仍然三方融合**(A 稿+B 路视频字幕 OCR+音轨 ASR)。 + +--- + +## 二、做什么(功能边界,只列名) + +| 模块 | 简述 | +|---|---| +| 视频双路拆分 | ffmpeg 抽帧+字幕变化检测+OCR → B 稿;ffmpeg 抽音轨 → 16k WAV | +| 讯飞 ASR 适配层 | 复用 demo 跑通的 `xfyun_asr_standard.py`,替换凭证 | +| 三方融合引擎 | 规则层(Python)+ AI 层(Claude Sonnet 4.6),demo 已锁 | +| 单期处理接口 | CLI + Python API,契约见主项目回复 §Q3 | +| Golden test | 用 demo 那期视频做零回归验证 | +| 23 期批量调度入口 | 单期接口的批量调用方式,具体编排不在本子项目 | + +**具体怎么做,子项目内部讨论,本 Brief 不预设方案。** + +--- + +## 三、怎么用(目标流程) + +**单期处理**: +1. 责编/编排层在 episodes 表落库该期,拿到 INT 主键 +2. 拼出 episode_id:`ep{NNN}_{YYYYMMDD}_{slug}` +3. 把视频和 A 稿放进 `programs/{episode_id}/source/` +4. 调 doco:`doco.process_episode(episode_id, video_path, a_draft_path, output_dir)` +5. 产物落 `programs/{episode_id}/output/`:终版 docx + 差异报告 + needs_review JSON +6. 编导/制片人审 needs_review 队列,决定接受 / 拒绝 / 编辑 + +**23 期批量**:用同一接口循环调用 23 次,失败重试 + 进度跟踪由调用方负责。 + +**降级回退**:若某期视频不符合"黑底白字+干净人声"条件,通过 feature flag 切换到旧流程(独立 mp3 + 上游 OCR)。 + +--- + +## 四、不做什么(红线) + +子项目设计任何方案,**绝不**触碰以下: + +- ❌ **不动 demo 已锁的算法层**(三方融合优先级 / 时间戳容忍 ±5s / 口语清理三档 / 改动确信度阈值 0.85/0.6 三段) +- ❌ **不引入 `ffmpeg-python` 等 wrapper**(用 subprocess 调系统 ffmpeg) +- ❌ **不替换 AI 融合层模型**(Claude Sonnet 4.6 已锁,不临时换 DeepSeek 等) +- ❌ **不复用主 project 那把 DeepSeek key**(Cline 工具用的 key 跟生产业务分开) +- ❌ **不把凭证写进主 project 的 `backend/.env`**(子模块自治,各自 .env) +- ❌ **不假设 episode_id 命名规则**(由调用方给定,doco 只当字符串用) +- ❌ **不引入主 project 没有的技术栈**(继续 Python 3.x + Claude API + 讯飞 API) +- ❌ **不自己实现批量调度**(失败重试 / 并发控制 / 进度跟踪属于编排层职责) +- ❌ **不在子项目里写中台密钥服务**(那不属于 doco 范围) + +--- + +## 五、技术栈约束(继承主 project) + +- **运行环境**:Python 3.x(版本对齐 backend),Windows / Linux 都可跑 +- **系统依赖**:ffmpeg ≥ 4.x(子模块文档明确列出) +- **AI 融合**:Anthropic Claude API,模型 `claude-sonnet-4-6` +- **OCR**:DeepSeek Vision API(主项目已批,Q1) +- **ASR**:讯飞开放平台 录音文件转写标准版(**不要用大模型版**——`language` 参数被阉割) +- **音频规格**:16kHz / 单声道 / 16bit WAV(讯飞规格) +- **数据格式**:句子级时间戳统一 `[Nm Ns] 句子` 格式 + +--- + +## 六、交付什么(出口接口) + +子项目最终交付物以下面形式回到主 project,**必须满足以下接口**: + +### 6.1 模块交付物 +- `doco/` Python 包,可被主 project 编排层 import +- CLI 入口:`doco process ...` +- 单元测试 + golden test(demo 那期零回归) +- `README.md`:系统依赖、安装、使用、配置 + +### 6.2 配置与凭证 +- doco 自己的 `.env`(讯飞 + DeepSeek + Claude 三套 key 各自管) +- 主项目仓库根目录的 `docs/api_credentials_inventory.md` 登记一行 doco 的凭证元信息(不存真实 key) + +### 6.3 数据资产沉淀(可入 TPS 中台共享) +- A 稿术语表(每期处理时从 A 稿提取,可入主 project 数据库的 terms 维度) +- OCR 错字映射表(demo 已整理,固定字形混淆对) + +### 6.4 不接受 +- 子项目自己改主 project 的 backend 代码、schema、迁移 +- 子项目自己写主 project 的前端 UI(编导确认 UI 属于上层,不在 doco 范围) +- 子项目自己定 episode_id 命名规则(由主项目给定) + +--- + +## 七、入口接口(子项目要知道的主 project 现状) + +- **主项目没有 OCR 子模块**(已确认,Q1) +- **主项目没有视频处理服务**(已确认,Q2) +- **主项目没有节目素材批量编排层**(已确认,Q3) +- **主项目没有中台密钥服务**(已确认,Q4) +- **主项目没有节目素材目录规约**(已确认,Q5,本子项目带头定 `programs/{episode_id}/...`) +- **主项目有 episodes 表**(INT 自增主键),doco 用 episode_id 时假定调用方已落库 + +--- + +## 八、未决项(归子项目自己拍板) + +以下不在本 Brief 内预设,**由子项目和制片人讨论决定**: + +- 视频抽帧的具体策略(关键帧检测算法 / 抽帧密度 / 字幕变化阈值) +- DeepSeek Vision 调用的具体 prompt 设计 +- 规则层 OCR 错字映射表的具体扩展机制 +- AI 融合层的具体提示词迭代 +- needs_review JSON 的具体字段(在 demo 基础上演化) +- 单元测试覆盖率目标 +- 子项目内部的 git 分支策略 / 版本号约定 + +--- + +## 九、决策史指向(不重复内容) + +子项目讨论前必读: +- `doco_project_design.md / .docx`(三方融合算法层,demo 沉淀,已锁) +- `doco_xfyun_integration_notes.md / .docx`(讯飞 ASR 接入 15 个坑) +- `doco_handoff_to_opus_chat.md / .docx`(子项目立项前的 opus 接手提示) +- `PRD_doco_文稿整理子项目_v2.md`(当前子项目的请求稿) +- `主project对Doco_PRDv2的回复.md`(主项目的批复) + +--- + +## 十、本 Brief 自身的修订规则 + +- 本 Brief 不在子项目内修改 +- 红线 / 技术栈如有变更,**主 project 这边发新版**,通过寄存条同步 +- 子项目可在自己的 chat 里讨论"建议主 project 调整某条红线",调整动作只能在主 project 发生 +- 子项目每次出新版 PRD,主项目顾问发新版回复;两者形成 PRD vN ↔ 回复 vN 的对照关系 diff --git a/docs/doco/PRD_doco_文稿整理子项目_v2.md b/docs/doco/PRD_doco_文稿整理子项目_v2.md new file mode 100644 index 0000000..c6ab926 --- /dev/null +++ b/docs/doco/PRD_doco_文稿整理子项目_v2.md @@ -0,0 +1,295 @@ +# PRD · Doco 文稿整理模块 · 视频源改造方案 + +> 版本:v2 +> 日期:2026-06-12 +> 作者:子 project Claude(Opus 4.7) +> 状态:草稿 / 待主项目审 +> 上一版:v1(2026-06-12 同日,更早一稿) +> 主要变化: +> 1. **子模块正式定名为「Doco 文稿整理模块」**(v1 沿用旧称"TPS 三方融合子模块",本版起全部改用 Doco;Q6 已由制片人拍板,不再列为待决问题) +> 2. **Q1(OCR 选型)方向更新**:制片人确认"软件离线刚需"已不成立,云端方案可接受。补充查清的关键事实:**讯飞 OCR 与 STT 共享鉴权凭证但套餐/余额各自独立**——按制片人原判据"如果能通用 token 订阅和余额就选讯飞"不成立。**新推荐方案:DeepSeek API**(制片人手上已有),并向主项目确认是否已有 OCR 能力或 LLM 视觉调用基础设施 +> 3. 其他 Q(Q2/Q3/Q4/Q5)保持不变 + +--- + +## 〇、一段话摘要(给主 project 顾问的最短摘要) + +Doco 文稿整理模块(前称"TPS 三方融合子模块")此前的物理输入是 A 稿 docx + B 稿 OCR txt + ASR txt(mp3→讯飞)。栏目组现在改了素材输出方式:责编一次性输出 23 期"特殊视频"——画面是黑底白字唱词字幕、声音是无 BGM/音效的干净人声(极少同期声杂音)。**B 稿与 ASR 现在同源派生于一个视频文件**,物理输入从 3 个收敛到 2 个(A 稿 + 视频)。 + +**核心判断**:下游"三方融合引擎"(规则层 + AI 层)算法**零侵入**——只要新增的"视频双路拆分"模块输出与旧版 B 稿/ASR txt 格式完全一致(`[Nm Ns] 句子`),下游所有逻辑不动。**逻辑上仍然是三方融合**——A 稿术语权威 + B 路视频字幕 OCR + 音轨 ASR,三路独立验证的关系没破。 + +子项目这边需要主 project 在开工前对 5 件影响接口/数据形态的事拍板。详见 §4。 + +--- + +## 一、变更前后对照 + +### 旧设计(demo 已验证) + +``` +[A 稿 docx] ──────────────────────┐ + │ +[上游既有 OCR 流程] ── B 稿 txt ──┤ + ├─► [三方融合引擎] ─► 终版.docx + 差异报告.docx +[节目纯净人声 mp3] │ + │ │ + └─► [讯飞 ASR] ── ASR txt ─┘ +``` + +### 新设计(本 PRD 提出) + +``` +[A 稿 docx] ─────────────────────────────────────┐ + │ +[节目特殊视频文件] │ + 画面:黑底白字字幕 │ + 声音:干净人声 │ + │ │ + ├─► [视频双路拆分子模块 · NEW] │ + │ │ │ + │ ├─► ffmpeg 抽帧+字幕变化检测 │ + │ │ │ │ + │ │ └─► [OCR] ── B 稿 txt ──────┤ + │ │ (待 Q1 拍板用 DeepSeek) ├─► [三方融合引擎] ─► 终版 + 差异 + │ └─► ffmpeg 抽音轨 → 16k/mono WAV │ (复用) + │ │ │ + │ └─► [讯飞 ASR · 复用] │ + │ └────── ASR txt ──────┘ + │ + └─ (后续接 23 期批量调度) +``` + +### 关键变化清单 + +| 项 | 旧 | 新 | +|---|---|---| +| 子模块名称 | TPS 三方融合子模块 | **Doco 文稿整理模块** | +| 物理输入 | A 稿 + B 稿 + ASR | A 稿 + 视频 | +| 逻辑融合方 | 三方 | **仍然三方**(A / B 路 / ASR 路) | +| B 稿来源 | 上游既有 OCR 流程 | 视频抽帧 → OCR | +| ASR 来源 | 节目 mp3 | 视频音轨 | +| 算法层 | 规则层 + AI 层 | **不变** | +| 新增模块 | — | 视频双路拆分(ffmpeg + OCR) | +| 处理粒度 | 单期 | 单期接口 + 23 期批量调度 | + +--- + +## 二、子项目这边已经拍板的事(不需要主 project 决策,仅告知) + +### 2.1 制片人已明确的决策 + +1. **子模块定名**:**Doco 文稿整理模块**("Doco" 取意"Documentation Consolidation"——文稿整合)。本 PRD 起所有引用旧称("TPS 三方融合子模块"、"三方融合")的地方都用新名替换。 +2. **离线不再是刚需**:原 v1 推荐 PaddleOCR 本地的核心理由(离线刚需)失效;OCR 选型转向云端。 + +### 2.2 demo 已验证或设计文档已定义的事 + +不变: + +1. **三方融合优先级**(A 稿术语权威 / ASR 口吻 / B 稿验证)—— 见 project_design.md §5.1 +2. **时间戳容忍度 ±5 秒** —— project_design.md §5.2 +3. **口语清理三档**(keep_all / medium / clean)—— project_design.md §5.3 +4. **改动确信度阈值**(0.85 自动 / 0.6–0.85 黄标 / <0.6 待确认)—— project_design.md §5.4 +5. **AI 融合层模型**:Claude Sonnet 4.6 起步 +6. **差异报告格式**:demo 黄金对照已落定 +7. **A 稿术语表数据结构**:project_design.md §9.1 +8. **OCR 错字映射表**:复用 demo 整理的字形混淆对 + +--- + +## 三、子项目这边的开发计划草案(待主 project 审) + +| Phase | 内容 | 产物 | 主依赖 | +|---|---|---|---| +| P1 | 视频双路拆分预处理(单期)| `video_split.py`:视频 → 抽帧+字幕变化检测+OCR → B稿.txt;视频 → 音轨 → 16k WAV | ffmpeg、OCR(待 Q1 拍板,倾向 DeepSeek API) | +| P2 | 讯飞 ASR 适配层 | 复用 `xfyun_asr_standard.py`,替换新凭证、做成可被 P1 流水线调用的模块 | 讯飞开发端密钥(待 Q4 拍板) | +| P3 | Doco 融合引擎 | 规则层 Python + AI 层 Claude API;输入 A/B/ASR 三方 txt,输出终版 docx + 差异报告 + needs_review JSON | Claude API | +| P4 | 单期端到端 golden test | 用 demo 那期《现代防空反导大对决》的视频跑一遍,与 demo 产物比对,确认零回归 | 上面三 phase | +| P5 | 23 期批量 | 单期模块包成可被批量调度调用的接口(CLI / Python API 二选一,待 Q3 拍板) | — | + +--- + +## 四、需要主项目决策的 5 个问题 + +> 每条都给了子项目这边的推荐答案 + 理由。主项目顾问可以照单批,也可以推翻。 + +### Q1. OCR 方案选型? + +**问题**:B 路 OCR 用什么?这是新引入的依赖,绕不开。 + +#### Q1.A 关键事实(更新自 v1) + +子项目这边查清了几件事,供主项目决策参考: + +1. **讯飞 OCR 与 STT 的共享情况**: + - 鉴权凭证(开发者账号、APPID、APIKey、APISecret)**可共享**,一组凭证可同时调用多个服务 + - 但**套餐/计费/余额各自独立**:STT 是"5 小时免费试用包"独立购买;OCR 是另一套计费体系(参考 SaaS 零售价 4.9 元/10 张、9.9 元/50 张)。**不存在用 STT 的余额跑 OCR 这种事** + - **按制片人原判据("如果能通用 token 订阅和余额就选讯飞")此条件不成立** + +2. **制片人手上已有的 API**: + - **DeepSeek**:有专门的 `DeepSeek-OCR` 模型(OCR 2.0 方案,对中文文档识别准确率行业领先)+ DeepSeek Vision 识图模式(官方 API endpoint)。**推荐** + - **MiniMax**:有 MiniMax-VL 视觉模型,理论上可 OCR,但 OCR 专项优化不如 DeepSeek-OCR + - **小米 MiMo**:主推推理模型,未见明确的视觉/OCR 能力 + +3. **本场景的 OCR 难度评估**: + - 输入图像是**黑底白字纯字幕画面**——OCR 最简单的子集(高对比度、印刷体、无图案干扰、无版面分析) + - LLM 视觉模型在此场景几乎不会出错;用 LLM 做 OCR 在这里不是杀鸡用牛刀,因为成本极低且无新增依赖 + +4. **成本估算(23 期总量)**: + - 单期约 300 条字幕(demo 数据),23 期 ≈ 6900 张图 + - DeepSeek Vision API 单张成本约几厘到一分,**总成本预估 50–150 元** + - 对比讯飞 OCR SaaS 零售价:6900 张 × 0.198 元/张 ≈ 1370 元 + - 对比 PaddleOCR 本地:0 元但需要维护本地环境(已不是刚需) + +#### Q1.B 选项与推荐 + +**选项**: +- A. **DeepSeek API(视觉模型)**——制片人已有 API,无新增订阅 +- B. **讯飞 OCR**——与 STT 同账号但余额独立 +- C. **PaddleOCR 本地**——零成本但需本地环境 +- D. **主 project 已有的 OCR 服务**——如果存在 + +**子项目推荐**:A(DeepSeek API) + +**理由**: +- 满足制片人"用现有 API 资源"的方向 +- 黑底白字字幕是 LLM 视觉模型的舒适区,识别质量有保障 +- 与讯飞 STT 解耦,单点故障范围小 +- 成本最低(除 PaddleOCR)且无本地环境维护成本 + +**请主项目确认**: +- 主 project 是否已有 OCR 子模块/能力?(制片人初步判断"主 project 应该没有 OCR 配置",请顾问最终确认) +- 主 project 的密钥管理体系是否已经接入 DeepSeek?还是需要 Doco 子模块自行管理 DeepSeek 凭证? +- 6900 张图调用 DeepSeek 是否会影响主 project 其他模块的 DeepSeek 配额/限流? + +--- + +### Q2. 视频处理依赖(ffmpeg)的入口? + +**问题**:抽帧与抽音轨都依赖 ffmpeg。 + +**选项**: +- A. Doco 子模块自带 ffmpeg 系统依赖 + Python 封装(`ffmpeg-python` 或 subprocess) +- B. 主 project 有统一的视频处理服务/适配层 + +**子项目推荐**:A,使用 subprocess 调用系统 ffmpeg + +**理由**:ffmpeg 是标准工具,独立部署足够简单。 + +**请主项目确认**:是否已经有视频处理子模块/服务在规划中?如有,应改走中台接口。 + +--- + +### Q3. 23 期批量 vs 单期接口? + +**问题**:本次实际场景是 23 期,Doco 子模块的接口应该长什么样? + +**选项**: +- A. 子模块只负责单期,输入 = 1 视频 + 1 A 稿;批量调度交给主 project 编排层 +- B. 子模块内部支持批量,输入 = 视频目录 + A 稿目录 +- C. 两者都提供 + +**子项目推荐**:A(子模块只对单期负责) + +**理由**: +- 单一职责原则。批量调度涉及失败重试、进度跟踪、并发控制——属于编排层职责 +- 单期接口在出错时定位简单(哪期失败、失败在哪个 phase 一目了然) +- 主 project 未来可能有节目档案库流水线、报题单流水线等,统一在编排层做并发更合理 + +**请主项目确认**: +- 主 project 是否计划做"节目素材批量处理编排层"?如有,Doco 的单期接口应满足什么样的契约(CLI?Python API?返回值结构?) +- 23 期这次是先单期跑通再批量,还是要求一次性 batch? + +--- + +### Q4. 讯飞密钥更新/续费策略? + +**问题**:demo 凭证可能已过期(制片人提示"讯飞试用可能也过了"),且需要区分**消费端**(讯飞听见 App)与**开发端**(开放平台)。 + +**选项**: +- A. Doco 子模块各自申请新凭证、各自管理 +- B. 接入中台统一密钥服务(如果有) +- C. 申请新凭证 + 写入"中台密钥资产文档"作为登记 + +**子项目推荐**:C + +**理由**:现阶段中台密钥服务可能未完成,但密钥归属、过期日期、所属子模块应该有统一登记入口。 + +**请主项目确认**: +- 中台是否已有密钥管理子模块? +- 新申请的讯飞开发端密钥(包括 APP_ID、SECRET_KEY、5 小时免费试用包激活状态)应该登记在哪里? +- 如果 Q1 拍板用 DeepSeek,DeepSeek API key 是否也按同样规则登记? + +--- + +### Q5. 目录结构与命名规约? + +**问题**:23 期素材、抽帧产物、wav、终版 docx 的存储路径需要规约,否则后期归档混乱。 + +**子项目草案**: + +``` +programs/ +└── {episode_id}/ # 例:20260612_防空反导 + ├── source/ + │ ├── video.mp4 # 原始特殊视频(黑底白字+干净人声) + │ └── a_draft.docx # A 稿(编导定稿) + ├── work/ # 中间产物(可清理) + │ ├── frames/ # 抽出的字幕关键帧 + │ ├── audio_16k.wav # 抽音轨标准化产物 + │ ├── b_draft.txt # OCR 产物(带 [Nm Ns] 时间戳) + │ ├── asr_result.txt # 讯飞 ASR 产物 + │ └── asr_result_raw.json # 讯飞原始返回 + └── output/ # 主产物(入档案库) + ├── final.docx # 终版文稿 + ├── diff_report.docx # 差异报告 + └── needs_review.json # 待编导确认队列 +``` + +**请主项目确认**: +- TPS 中台是否对节目素材的目录有统一规约? +- `episode_id` 命名规则是什么?(日期+栏目+期号?UUID?编导给定?) +- `work/` 中间产物保留多久?是否要自动清理? + +--- + +## 五、不向主项目提问、但需要告知的事 + +1. **demo 的 5 份 fixture 仍然有效**:A 稿 / B 稿 / ASR / 终版 / 差异报告 在新流程下都可作为单元测试与集成测试的黄金对照 +2. **讯飞 ASR 脚本仍然有效**:`xfyun_asr_standard.py` 只需替换凭证、把"音频文件路径"参数从"独立 mp3"改为"视频抽音轨产物 wav" +3. **23 期之后的常态化问题**:栏目组以后是否每期都按"黑底白字+干净人声"特殊视频出素材?还是只这一批 23 期是特例?这影响 Doco 子模块要不要保留旧的 mp3+独立 OCR 流程作为回退路径。**建议主项目顾问直接跟栏目组确认** + +--- + +## 六、给主项目顾问的"接手提示词" + +如果主 project 顾问要审这份 PRD,最重要的三件事: + +1. **算法层零侵入是 demo 验证过的硬保证**。任何改动如果会让 P3(Doco 融合引擎)必须改算法,需要警惕——大概率是输入数据形态没对齐。 +2. **OCR 选型(Q1)和目录规约(Q5)是会广泛影响其他子模块的事**,主项目顾问视野更大,应该是这两条的最终拍板人。如果主 project 有 OCR 能力或 DeepSeek 集成基础设施,Q1 的子项目推荐随时可被覆盖。 +3. **23 期是一次性还是常态化(§5 第 3 条)是个产品问题,不是技术问题**,建议主项目顾问直接跟栏目组确认后再批 PRD。 + +--- + +## 七、回复期望 + +子项目这边等以下确认才正式开干: +- Q1(OCR 选型)—— 必须先答,否则 P1 不能开始 +- Q4(讯飞密钥)—— 必须先答,否则 P2 不能开始 +- Q5(目录规约)—— 必须先答,否则 P1 输出无处可放 +- Q3(接口契约)—— P5 之前必须答 +- Q2 —— Doco 子模块可以先按推荐方案开干,主项目随后批 + +收到主项目 Claude 顾问的回复 md 后,Doco 子项目这边出 PRD v3(含元信息块标注"上一版:v2"),再启动 P1。 + +--- + +## 八、版本变更摘要 + +| 版本 | 日期 | 主要变化 | +|---|---|---| +| v1 | 2026-06-12 | 首版。6 个待决问题(含子模块命名 Q6)。OCR 选型推荐 PaddleOCR 本地 | +| **v2** | **2026-06-12** | 子模块定名"Doco 文稿整理模块";Q1 改推荐 DeepSeek API(基于讯飞 OCR/STT 余额独立的事实查清 + 制片人手上已有 API 资源);Q6 已拍板移出待决列表;剩余 5 个待决问题 | + +--- + +*v2 由 Doco 子 project Claude(Opus 4.7)于 2026-06-12 拟稿,遵照《跨 project 协作提示单 v1》§三的规范。* diff --git a/docs/doco/doco_handoff_to_opus_chat.md b/docs/doco/doco_handoff_to_opus_chat.md new file mode 100644 index 0000000..442e6dc --- /dev/null +++ b/docs/doco/doco_handoff_to_opus_chat.md @@ -0,0 +1,103 @@ +# Handoff to opus_chat · TPS三方融合子模块 + +> 这份是发给中台 opus_chat 的最短交接说明。完整设计见 `project_design.md`。 + +--- + +## 这是什么 + +《军事科技》TPS(终版文稿生成中台)下的一个子模块,叫"三方融合"。 + +**它做的事**:把三份资料合并成一份贴近实际播出的终版 docx 文稿,并生成一份差异报告。 + +三份资料是: +1. **A 稿** — 编导手写定稿(docx,有【主持人N】【解说N】【专家N】【动画N】结构标签) +2. **B 稿** — OCR 扒词(txt,带 `[Nm Ns]` 时间戳,有 OCR 错字) +3. **ASR** — 讯飞录音文件转写结果(txt,带 `[Nm Ns]` 时间戳,有同音误识) + +--- + +## 你需要记住的 5 件事 + +### 1. 三方权威优先级(**最重要,不要搞反**) + +| 看什么 | 信谁 | +|---|---| +| 术语 / 人名 / 装备型号 / 事实 | **A 稿** | +| 标点 / 语序 / 口吻 | **ASR** | +| OCR 字形错(肘/时、娈/变) | 用 **ASR 或 A 稿** 覆盖 B 稿 | +| 整段是否存在 | **B 稿 + ASR 联合**判定 | + +为什么 A 稿术语优先?demo 中 ASR 把"美以两国"识别成了"美伊两国"——句子通顺、语义荒谬。无 A 稿无法发现。 + +### 2. 架构是双层(不是单层 AI) + +``` +规则层(Python) AI 层(Claude API) +├ OCR 错字映射 ├ 段落对齐 +├ A 稿术语字典覆盖 ├ 改动类型判定 +├ 时间戳对齐 ├ 整段改写边界 +├ 数字 / 标点规范化 └ 编导笔误识别 +└ 口语词清理(可配置) +``` + +确定性的事走规则层,需要语义判断的事走 AI 层。**不要全塞给 AI**。 + +### 3. 输入有严格规范 + +- **A 稿**:自然段开头 `【…】` 是结构标签;`隔断:【…】` 是章节分隔 +- **B 稿 / ASR**:每行格式 `[Nm Ns] 句子内容` +- **音频**(如果走完整流程从音频开始):必须 **16kHz / 单声道 / 16bit WAV**,否则讯飞拒收 + +### 4. 讯飞 ASR 有坑(开发前必读) + +- 用"**录音文件转写(标准版)**",**不要**用"大模型版"(免费包阉割了 `language` 参数) +- 领域参数 `pd=mil`(军事节目专用) +- 顺滑参数 `eng_smoothproc=true` + `eng_colloqproc=true` +- **热词机制**是关键:每期从 A 稿提 200 字以内的专业术语作为 `hotWord` +- 讯飞**消费端**(讯飞听见 App)和**开发端**(开放平台)密钥**不通用** +- "5 小时免费试用"必须走 0 元购买流程激活 +- 签名:`signa = base64(HmacSHA1(MD5(appid + ts), secretKey))` + +详见 demo 中的 `xfyun_asr_standard.py`。 + +### 5. 输出有两份,不只一份 + +- **终版.docx** — 主产物,给档案库 +- **差异报告.docx** — 副产物,给编导回顾。**差异报告的长期价值可能比终版更高**(能反向分析编导删改偏好) + +--- + +## 我和这个模块的关系 + +- **你(opus_chat)**:中台对话入口,可能会被用户问到本模块的边界 / 接口 / 状态 +- **本模块**:被 TPS 主流程调用,输入三份文本,输出两份 docx + 一份 JSON +- **不归我管**:音频转码、OCR 识别本身、档案入库、编导确认 UI + +如果用户问以下内容,**统一口径**: + +| 问题 | 答 | +|---|---| +| "能不能不用 A 稿?" | 不能。会引入 ASR 的同音事实错误,且术语全乱。 | +| "能不能不用 B 稿?" | 可以,但失去独立交叉验证;不推荐。 | +| "能不能不用 ASR?" | demo 证明 A+B 也能跑,但效果显著下降;不推荐。 | +| "ASR 选讯飞还是别家?" | 当前讯飞。已踩坑、已跑通;阿里云是规划中的备份。 | +| "AI 用哪个模型?" | Claude Sonnet 4.6 起步,单期 26 分钟节目约 16k 字上下文。 | +| "处理一期要多久?" | 正式版预估 15–30 分钟(含人工确认);demo 实测 2 小时但近一半花在踩讯飞坑上。 | + +--- + +## demo 状态 + +- 已完整跑通一期《现代防空反导大对决》(26 分钟) +- 关键术语识别率接近 100%(开启 35 条热词后) +- 主要修复:OCR 错字 10+ 类、ASR 同音误识 4 类、编导笔误 1 段、整段删除 2 段 +- 复盘文档:`实测复盘.md` +- 设计文档:`project_design.md` + +--- + +## 不一致时怎么办 + +如果你(opus_chat)发现本备忘与 `project_design.md` 不一致,**以 project_design.md 为准**。 +如果你发现 project_design.md 本身需要更新,请同步刘统制片组。 diff --git a/docs/doco/doco_project_design.md b/docs/doco/doco_project_design.md new file mode 100644 index 0000000..07da4c7 --- /dev/null +++ b/docs/doco/doco_project_design.md @@ -0,0 +1,451 @@ +# TPS · 三方融合子模块 设计文档(project_design.md) + +> 归属:《军事科技》中台 TPS · 终版文稿生成(Three-source Pipeline Synthesis) +> 文档目的:把 demo 阶段的实测结论沉淀为可被中台其他子模块(含 opus_chat)调用的明确接口与约束 +> 当前状态:demo 已跑通一期完整节目(《现代防空反导大对决》),进入正式开发阶段 +> 文档版本:v0.1(2026-05-15) +> 维护:刘统制片组 / Claude + +--- + +## 0. TL;DR(给 opus_chat 的最短摘要) + +- 本子模块的输入是三份资料,输出是一份贴近实际播出的 docx 文稿 + 一份逐段差异报告。 +- **三份输入:** + 1. **A 稿**:编导手写定稿(docx,带【主持人N】【解说N】【专家N】【动画N】【隔断:…】结构标签) + 2. **B 稿**:OCR 扒词文档(txt,带 `[Nm Ns]` 句级时间戳,存在 OCR 错字) + 3. **ASR 结果**:讯飞录音文件转写(txt,带 `[Nm Ns]` 句级时间戳,存在同音误识) +- **核心信念**:三方各有短板,单源不可信;融合后才是"播出真相"。 + - A 稿 → 术语 / 人名 / 装备型号 / 事实 的**权威** + - ASR → 播出语序与口吻的**骨架** + - B 稿 → 独立**交叉验证**(同时验证 A 与 ASR) +- **架构两层:** + - **规则层**(Python):术语字典纠正、OCR 错字映射、时间戳对齐、口语词清理、数字规范化 + - **AI 层**(Claude API):段落对齐、改动类型判定、整段改写边界、编导笔误识别 +- **请 opus_chat 注意:** 本模块依赖讯飞 ASR 与 Claude API,**两套密钥**互不复用;调用本模块前应确认 A 稿术语表已入库。 + +--- + +## 1. 业务背景与定位 + +### 1.1 上游 / 下游 + +``` +[节目编导] ──A稿(docx)──┐ + │ +[OCR 服务(旧流程)]──B稿(txt+时间戳)──┐ + ├──► [本模块 三方融合] ──► [终版docx] ──► [节目档案库] + │ └► [差异报告docx] ──► [编导回顾 / 训练素材] +[节目纯净声音文件]──[讯飞 ASR]──ASR(txt+时间戳)─┘ +``` + +### 1.2 在 TPS 中台的位置 + +本子模块是 TPS(终版文稿生成中台)的**核心算法子模块**,位于上游"素材接收"和下游"档案入库 / 编导确认 UI"之间。 + +- 它**不**负责音频转码(由 ASR 适配层处理) +- 它**不**负责 OCR 识别(B 稿来自既有 OCR 流程) +- 它**不**负责最终入库(由档案子模块负责) +- 它**只**负责"三方文本 → 一份贴近播出的终版文稿 + 差异报告" + +### 1.3 为什么不能省略某一方? + +| 缺哪一方 | 后果 | 实例 | +|---|---|---| +| 缺 A 稿 | 术语 / 人名 / 装备型号易错;ASR 同音错难发现 | "美以两国"被 ASR 识别成"美伊两国"——句子通顺、语义荒谬,无 A 稿无法纠正 | +| 缺 ASR | 无法知道实际播出语序与口吻;专家口语词全丢 | A 稿用"观众朋友们,你们好",播出实际是"各位观众你们好" | +| 缺 B 稿 | 失去独立交叉验证;ASR/A 稿冲突时无第三方仲裁 | A 稿与 ASR 在某段不一致时,B 稿与谁一致就以谁为准 | + +**结论**:B 稿可以视为弱必需(demo 证明 A+ASR 二方融合也能跑),但建议保留 B 稿做 sanity check。 + +--- + +## 2. 输入规范 + +### 2.1 A 稿(编导定稿) + +- **格式**:`.docx`(实际为 markdown 风格的纯文本,也兼容真 docx) +- **结构标签**(出现在自然段开头,方括号包裹): + - `【导视】` `【主持人N】` `【解说N】` `【动画N】` `【专家N】` + - `隔断:【…】` 用于章节分隔 +- **特点**: + - 内容偏书面化;可能存在编导笔误(如本期【专家7】【专家8】内容字符完全相同 = 复制粘贴失误) + - 术语严格、人名 / 装备型号完整("爱国者-3"、"霍拉姆沙赫尔-4"、"见证者-136") + - 标点 / 顿号 / 引号规范 + +### 2.2 B 稿(OCR 扒词) + +- **格式**:`.txt` +- **行格式**:`[Nm Ns] 句子内容`,每行一句 +- **特点**: + - 句子时间戳精度到秒 + - **存在 OCR 错字**:字形相近字混淆(肘↔时、娈↔变、夭↔天、井↔并、末↔未、纺↔防、观↔现、忽↔您、岳↔越、改命↔致命) + - 标点弱(多为空白分隔,缺逗号 / 句号) + - 句子切分较碎(一句话常被切成 2–3 行) + +### 2.3 ASR(讯飞录音文件转写) + +- **格式**:`.txt` +- **行格式**:`[Nm Ns] 句子内容`,每行一句(与 B 稿对齐) +- **特点**: + - 标点合理(讯飞已自动加句号、逗号、问号) + - 经 `eng_smoothproc + eng_colloqproc` 处理,已**部分**清理"嗯/呃" + - **存在同音误识**:"中端↔中段"、"末端↔末段"、"中诚↔中程"、"美伊↔美以"、"高超声速↔高超音速" + - 数字 / 百分比识别准确 + - 句子级时间戳精确,可与 B 稿做交叉对齐 + +### 2.4 三方时间戳的对齐口径 + +A 稿无时间戳;B 稿与 ASR 都有 `[Nm Ns]` 但**不严格一致**(B 稿来自 OCR 字幕显示时点,ASR 来自语音波形起点;常相差 1–3 秒)。融合时**容忍 ±5 秒**的时间漂移作为同段判定的辅助条件。 + +--- + +## 3. 输出规范 + +### 3.1 终版文稿(主产物) + +- **格式**:`.docx` +- **结构**:保留 A 稿的段落标签(【导视】【主持人1】…) +- **内容来源策略**: + - 默认以 ASR 文本为骨架 + - A 稿术语 / 人名 / 装备型号回填 + - B 稿 OCR 错字修复(用 ASR / A 稿覆盖) + - 标点采用 ASR 的版本(最自然) + - 口语词处理强度由"清理档位"参数控制(见 §5.3) + +### 3.2 差异报告(副产物) + +- **格式**:`.docx` +- **内容**: + 1. 改动总览(段落数 / 改动类型分布) + 2. 逐段对照(A 稿原文 vs 终版,标注改动类型与依据) + 3. 关键差异专题:整段删除 / 整段改写 / 术语变化 / 编导笔误 / OCR 错字修复 / ASR 错字修复 / 口语词处理 + 4. 依据图例(三方一致 / ASR 为主 / A 稿权威 / …) +- **价值**:差异报告本身就是编导工作回顾,长期累积可分析编导删改偏好。 + +### 3.3 改动类型枚举 + +| 枚举值 | 含义 | 处置 | +|---|---|---| +| `unchanged` | 三方一致或语义等价 | 直接采用 A 稿 | +| `minor_edit` | 标点 / 顿号 / 简称差异 | 自动以 ASR 版本输出 | +| `term_normalize` | 术语 / 字形 / 同音修正 | 规则层处理 | +| `rewrite_large` | 整段重写(A 稿与播出版差异较大) | AI 层处理 + **建议编导确认** | +| `segment_delete` | A 稿有但播出无 | AI 层判定 + **建议编导确认** | +| `segment_add` | A 稿无但播出有 | AI 层判定 + **建议编导确认** | +| `editor_typo` | A 稿编导笔误(整段重复 / 明显错位) | AI 层提示 + **必须编导确认** | + +--- + +## 4. 模块架构 + +### 4.1 顶层流程 + +``` + ┌───────────────────────────────────────────────────┐ + │ 三方融合引擎(本子模块) │ + │ │ +A 稿 ──────►│ 解析层 ──► 段落对齐层 ──► 规则纠错层 ──► AI 融合 │──► 终版docx +B 稿 ──────►│ ↓ │──► 差异报告 +ASR ──────►│ [Claude API] │ + └───────────────────────────────────────────────────┘ + ▲ + │ + [A 稿术语表 / OCR 错字字典 / 口语词字典] +``` + +### 4.2 各层职责 + +#### 解析层(parser) +- A 稿:按 `【…】` 切段,识别隔断标签,输出 `[(label, text)]` +- B 稿 / ASR:按 `[Nm Ns]` 行切句,输出 `[(start_ms, end_ms, text)]` + +#### 段落对齐层(aligner) +- 目标:把 B 稿 / ASR 的句子聚合并归到 A 稿的段落标签下 +- 算法: + - **强信号**:通过 A 稿首末锚点句做语义匹配(demo 用了人工锚点列表,正式版应用 Claude API 做语义匹配) + - **弱信号**:时间戳的单调推进 +- 容错:允许 ±5 秒漂移、允许中间出现专家发言被识别为"解说" + +#### 规则纠错层(rule-based corrector) +- **A 稿术语字典**:从 A 稿提取专有名词,扫描 ASR / B 稿,发现字形不同但拼音相同的同音字 → 用 A 稿覆盖 +- **OCR 错字字典**:维护固定映射表(肘→时、娈→变、夭→天…),扫描 B 稿 +- **数字规范化**:`百%` → `100%`、`数10` → `数十`、`马赫数10` → `10马赫` +- **标点规范化**:去重逗号、补齐句号 + +#### AI 融合层(Claude API) +- 输入:经规则层处理后的三方对齐结果 +- 任务: + 1. 段落对齐的最终校验(解决规则层算不准的边界) + 2. 改动类型标记(`unchanged` / `minor_edit` / `rewrite_large` / `segment_delete` / `segment_add` / `editor_typo`) + 3. 高把握改动直接产出终版 + 4. 低把握改动标记原因 + 给编导待确认列表 +- 提示词要点:见 §6 + +### 4.3 双层划分的依据 + +| 任务 | 走哪层 | 理由 | +|---|---|---| +| OCR 错字纠正 | 规则层 | 字形错误是确定性映射 | +| 术语统一 | 规则层 | A 稿术语表是封闭集 | +| 时间戳对齐 | 规则层 | 数值比较 | +| 段落归属 | AI 层 | 需要语义判断("这句专家发言到底归【专家3】还是【解说5】") | +| 整段删除判定 | AI 层 | 需要判断"A 稿这一段,是否在 B 稿 + ASR 都找不到对应内容" | +| 编导笔误识别 | AI 层 | 需要"【专家7】【专家8】内容相同" + "ASR 第 N 句到第 M 句讲了完全不同的内容"的联合判断 | + +--- + +## 5. 关键决策与参数 + +### 5.1 三方冲突时的优先级 + +| 冲突类型 | 优先采用 | 例 | +|---|---|---| +| 术语 / 人名 / 装备型号 | **A 稿** | "美以两国"(ASR 错识"美伊") | +| 标点 / 句式 / 口吻 | **ASR** | "各位观众你们好"(A 稿"观众朋友们,你们好") | +| 字形错字 | **ASR / A 稿** 覆盖 B 稿 | "肘→时""纺空→防空" | +| 整段存在性 | **B 稿 + ASR 联合** 优先 | A 稿"雷达被誉为眼睛..."B 稿/ASR 都没有 → 删 | +| 数字 / 百分比 | **ASR**(已确认 ASR 100% 准确) | "5%"、"100%" | +| 同音 / 字形错 | **A 稿术语字典** | "中端→中段""高超声速→高超音速" | + +### 5.2 时间戳容忍度 + +- 同段判定:B 稿 / ASR 时间戳差 ≤ **5 秒** 视为同一播出位置 +- 锚点匹配:A 稿首句对应的 ASR 时间位置 ± **10 秒** 为搜索窗 + +### 5.3 口语词清理档位(可配置) + +| 档位 | 行为 | 适用场景 | +|---|---|---| +| `keep_all` | 完全保留"那么""呢""啊""这个" | 反映播出真相、用于事后复盘 | +| `medium`(**默认**) | 保留专家段口语词,清理解说段 | 平衡可读性与真实性 | +| `clean` | 全部清理,按 A 稿书面化 | 用于外部传播 / 文稿出版 | + +### 5.4 改动确信度阈值 + +- AI 判定结果带 `confidence ∈ [0,1]` +- `confidence ≥ 0.85`:自动应用,记入差异报告 +- `0.6 ≤ confidence < 0.85`:自动应用 + **黄色标记**,编导可在 UI 中翻看 +- `confidence < 0.6`:**不自动应用**,进入编导待确认队列 + +--- + +## 6. AI 融合层提示词设计纲要 + +提示词应包含以下要素(正式实现时按需扩展): + +``` +[系统角色] +你是《军事科技》节目终版文稿生成助手。已知: +- A 稿是编导手写定稿,术语 / 人名 / 装备型号权威 +- ASR 是讯飞录音转写,标点与口吻接近播出真相,但存在同音误识 +- B 稿是 OCR 扒词,存在字形错字,用作交叉验证 +三方冲突时按"§5.1 三方冲突优先级"裁决。 + +[输入] +A 稿全文(含 【…】 标签):{a_doc} +ASR 结果(带时间戳):{asr_sentences} +B 稿 OCR(带时间戳):{b_sentences} +A 稿术语表:{terms_dict} +OCR 错字字典:{ocr_typos} +口语清理档位:{level} + +[任务] +1. 把 ASR / B 稿的句子按时间顺序聚合并归到 A 稿的段落标签下 +2. 对每段标记改动类型(unchanged / minor_edit / rewrite_large / segment_delete / segment_add / editor_typo) +3. 对每段给出 confidence ∈ [0,1] +4. 对 confidence ≥ 0.85 的段落直接产出终版文本 +5. 对 confidence < 0.85 的段落产出"建议版本 + 待确认原因" +6. 识别 A 稿与 ASR 的术语 / 同音 / 字形差异,自动应用 A 稿权威 +7. 识别 A 稿的编导笔误(如整段复制粘贴)并标记 + +[输出] +JSON: +{ + "segments": [ + { + "label": "【主持人1】", + "change_type": "rewrite_large", + "confidence": 0.92, + "final_text": "...", + "evidence": {"asr_lines": [...], "b_lines": [...]}, + "reasons": ["A 稿首句被改写为口语化"] + } + ], + "needs_review": [...] +} +``` + +--- + +## 7. 外部依赖 + +### 7.1 讯飞 ASR(必需) + +- **服务**:讯飞开放平台「**录音文件转写(标准版)**」 +- **不要用**:讯飞「大模型版」——免费包阉割了 `language` 参数,会报误导性的 `language verify fail` +- **认证**:APP_ID + SECRET_KEY;本期 demo 已申请到一组测试凭证(见 `xfyun_asr_standard.py`,正式上线需替换) +- **音频规格**:**16kHz / 单声道 / 16bit WAV**;其他规格讯飞会拒收 +- **领域参数**:`pd=mil`(军事节目专用,提升术语识别率) +- **顺滑参数**:`eng_smoothproc=true` + `eng_colloqproc=true` +- **热词机制(关键)**: + - 每期节目从 A 稿提取专业术语(武器装备 / 技术概念 / 人名 / 军方机构),上限 200 个,每个 2–16 字 + - 用 `|` 分隔传入 `hotWord` 参数 + - demo 实测 35 个热词后,关键术语识别率接近 100% +- **计费**:0元购买"5 小时免费试用包"(注意:看到额度但未走 0 元购买流程**不会激活**),1 年有效期 +- **签名算法**:`signa = base64(HmacSHA1(MD5(appid + ts), secretKey))` + +详见 `xfyun_asr_standard.py`(demo 已跑通的本地脚本,可直接作为正式适配层的起点)。 + +### 7.2 Claude API(必需) + +- 用于 AI 融合层 +- 调用模型:建议 `claude-sonnet-4-6` 或更高(涉及长文本理解与语义对齐) +- 单期节目(26 分钟)的预估上下文:A 稿 ~6k 字 + ASR ~5k 字 + B 稿 ~5k 字 ≈ 16k 字,远在 Sonnet 上下文窗口内 +- 调用频次:每期节目 1–3 次(首次全量融合 + 若干次低确信段重判) + +### 7.3 OCR 服务(已有) + +- B 稿来自上游既有 OCR 流程 +- 本模块只消费 B 稿 txt,不调用 OCR 服务 + +### 7.4 密钥管理 + +> **opus_chat 注意**:以下是常见混淆点,请勿用错。 + +| 密钥 | 用途 | 来源 | +|---|---|---| +| 讯飞 **消费端** | 讯飞听见 App(人工录音转写) | 讯飞听见 App 内 | +| 讯飞 **开发端** | 录音文件转写 API(本模块用) | 讯飞**开放平台** console | +| Claude API | AI 融合层 | Anthropic console | + +三套密钥**互不相通**。 + +--- + +## 8. 编导确认 UI(属于上层 UI 子模块,本模块只提供数据) + +本模块按以下结构输出供 UI 子模块消费的 JSON: + +```json +{ + "program_id": "xxx", + "segments": [...], + "needs_review": [ + { + "segment_label": "【解说6】", + "reason": "整段改写边界不确定", + "candidates": [ + {"text": "...", "source": "A稿"}, + {"text": "...", "source": "ASR"} + ] + } + ], + "diff_report_path": "...", + "final_docx_path": "..." +} +``` + +UI 子模块应至少提供(参考 demo 复盘 §3.4): + +- **左中右三栏 diff 视图**:A 稿原文 | 终版 | ASR/B 稿(带时间戳,可点击播放对应音频) +- **改动类型颜色编码**:删除红 / 改写黄 / 术语修正蓝 / 无变化白 +- **逐段确认按钮**:接受 / 拒绝 / 编辑 / 标记疑问 +- **口语清理强度滑杆**:切换 `keep_all / medium / clean` +- **导出按钮**:终版 docx / 差异报告 / 复盘 CSV + +--- + +## 9. 数据资产 + +### 9.1 应入库的"中台共享资产" + +1. **A 稿术语表**(核心资产) + - 每期节目处理时从 A 稿提取后入库 + - 同时作为讯飞热词来源 + 规则层纠错字典 + - 字段:`term`, `domain`(武器 / 技术 / 人名 / 机构 / 栏目),`first_seen_episode`, `frequency` +2. **OCR 错字映射表** + - 固定字形混淆对(肘↔时、娈↔变、夭↔天…) + - 随版本演进可扩展 +3. **节目编导风格档案** + - 长期累积每位编导的删改偏好(口语词保留度、术语简称习惯…) + - 用于参数自适应 + +### 9.2 demo 阶段产物的处置建议 + +| 文件 | 处置 | +|---|---| +| `xfyun_asr_standard.py` | 作为 ASR 适配层的起点代码 | +| `asr_result_timed.txt` | 单元测试 fixture | +| `B稿_..._扒词.txt` | 单元测试 fixture(含典型 OCR 错字) | +| `A稿_..._定稿.docx` | 单元测试 fixture | +| `现代防空反导大对决_终版.docx` | 集成测试**期望输出**(黄金对照) | +| `差异报告.docx` | 集成测试**期望输出**(差异报告格式参考) | +| `实测复盘.md` | 设计文档背书 + 长期归档 | + +--- + +## 10. 性能与耗时基线(实测) + +来自 demo(26 分钟节目): + +| 阶段 | 耗时 | 占比 | +|---|---|---| +| 讯飞 ASR 转写 | ~5 分钟 | — | +| 三方解析 | ~5 分钟 | — | +| 段落对齐 | ~15 分钟(demo 手工) | 正式版预计 ≤2 分钟(AI 调用) | +| 术语规范化 + 口语清理 | ~5 分钟 | — | +| 终版 docx 生成 | ~5 分钟 | — | +| 差异报告生成 | ~15 分钟(demo 手工) | 正式版预计 ≤3 分钟 | +| **正式版预估单期** | **~15–30 分钟** | 取决于改动幅度与人工确认次数 | + +--- + +## 11. 已知风险与未决事项 + +| 项 | 当前态 | 建议 | +|---|---|---| +| ASR 第三方依赖 | 讯飞单源 | 接入阿里云 ASR 做备份 / 交叉验证 | +| 整段改写的边界 | demo 中默认取 ASR 短版 | 必须接入编导确认 UI,不能全自动 | +| 编导风格差异 | 硬编码"中度清理" | 需配置文件或编导画像 | +| 隔断标签的处置 | demo 直接保留 A 稿 | 待确认是否需要根据音频静音段重新切分 | +| A 稿与 ASR 都缺失的旁白 | 不处理 | 极小概率事件,靠 B 稿兜底;记录用例 | + +--- + +## 12. 给 opus_chat 的提示(重要) + +如果 opus_chat 在其他场景中被问到本模块,请按以下口径回答: + +1. **本模块的边界**:只做"三方文本 → 终版文稿 + 差异报告",不负责音频转码、不负责 OCR、不负责档案入库、不负责编导 UI。 +2. **依赖与约束**:依赖讯飞 ASR(标准版)和 Claude API;A 稿术语表必须先入库;音频规格必须 16kHz/单声道/16bit WAV。 +3. **三方权威优先级**:A 稿(术语)> ASR(口吻)> B 稿(验证);任何与此相反的处理都是 bug。 +4. **未来扩展**:编导风格画像、第二 ASR 供应商、口语清理档位是后续路标。 + +如遇到与本文档不一致的描述,**以本文档为准**;如发现本文档需要更新,请同步刘统制片组。 + +--- + +## 附录 A:项目文件清单(demo 阶段) + +``` +project/ +├── A稿_现代防空反导大对决_定稿.docx # 输入1:编导定稿 +├── B稿_现代防空反导大对决_扒词.txt # 输入2:OCR扒词 +├── asr_result_timed.txt # 输入3:讯飞ASR输出 +├── xfyun_asr_standard.py # ASR调用脚本 +├── 现代防空反导大对决_终版.docx # 输出1:终版文稿 +├── 差异报告.docx # 输出2:差异报告 +├── 实测复盘.md # demo复盘(设计文档原料) +└── project_design.md # 本文档 +``` + +## 附录 B:与"实测复盘.md"的对应关系 + +| 复盘章节 | 本文档对应位置 | +|---|---| +| 一、ASR环节实测数据 | §7.1 讯飞 ASR | +| 二、三方融合关键决策点 | §5 关键决策与参数 | +| 三、对正式开发的启示 | §4 模块架构 / §6 提示词设计 / §8 UI | +| 四、实测耗时分解 | §10 性能基线 | +| 五、给制片人的建议 | §9 数据资产 / §11 风险 | diff --git a/docs/doco/doco_xfyun_integration_notes.md b/docs/doco/doco_xfyun_integration_notes.md new file mode 100644 index 0000000..48a3b07 --- /dev/null +++ b/docs/doco/doco_xfyun_integration_notes.md @@ -0,0 +1,181 @@ +# 讯飞 ASR 集成踩坑笔记 + +> demo 期间累积的所有讯飞接入坑点。建议入 TPS 知识库,作为未来接入新 ASR 供应商时的对照。 + +--- + +## 选型坑 + +### 坑 1:不要用"大模型版" + +- 讯飞开放平台有两个录音转写产品: + - 「录音文件转写(**标准版**)」← **用这个** + - 「录音文件转写(**大模型版**)」← 不要用 +- **大模型版的免费包阉割了 `language` 参数**,调用时会报 `language verify fail` +- 这个错误信息**严重误导**:看上去是语种没设对,实际是免费包没开通该参数权限 +- 排查耗时:约 30 分钟 + +### 坑 2:消费端和开发端密钥不通 + +- 「讯飞听见 App」属于**消费端**,给最终用户做人工转写用 +- 「讯飞开放平台」属于**开发端**,给开发者调 API 用 +- **两套密钥互不相通**——开发端的 APP_ID 在消费端没用,反之亦然 +- 如果只在讯飞听见 App 注册了账号,**没有** APP_ID 和 SecretKey,必须再去开放平台注册一次 + +### 坑 3:免费额度不会自动激活 + +- 开放平台首页显示"5 小时免费试用包",但**只有走 0 元购买流程**才会激活 +- 看到额度但没下单 → 调用时会报余额不足 +- 流程:商品页 → 0 元下单 → 支付(实际免费)→ 额度到账 + +--- + +## 音频规格坑 + +### 坑 4:必须是 16kHz / 单声道 / 16bit WAV + +- 其他规格讯飞会报错(且错误信息可能误导成"language verify fail"或"audio decode error") +- MP3 在标准版**也支持**,但保险起见统一转 WAV +- 转码命令(ffmpeg): + ```bash + ffmpeg -i input.mp3 -ac 1 -ar 16000 -sample_fmt s16 output_16k_mono.wav + ``` + - `-ac 1` = 单声道 + - `-ar 16000` = 16kHz 采样率 + - `-sample_fmt s16` = 16bit 位深 + +### 坑 5:时长字段不严格校验但建议传准 + +- API 要求传 `duration`(毫秒) +- 实测哪怕传 0 也能上传成功,但官方文档建议传准确值 +- WAV 从文件头读:`n_frames / sample_rate * 1000` +- MP3 用 `mutagen.mp3.MP3` 读 + +--- + +## 接口坑 + +### 坑 6:签名算法是老式 HmacSHA1,不是常见的 HmacSHA256 + +```python +# signa = base64(HmacSHA1(MD5(appid + ts), secretKey)) +md5_str = hashlib.md5((appid + ts).encode("utf-8")).hexdigest() # 32 位小写 hex +mac = hmac.new(secret_key.encode("utf-8"), md5_str.encode("utf-8"), + digestmod=hashlib.sha1) +signa = base64.b64encode(mac.digest()).decode("utf-8") +``` + +注意: +- MD5 输出是**32 位小写 hex 字符串**,不是 16 字节 raw bytes +- HMAC 的 key 是 `secretKey`,data 是 MD5 字符串本身(不是其字节) +- 最后做 base64 编码 + +### 坑 7:参数全部走 URL query,不是 form-data 或 JSON body + +- 上传接口:`POST https://raasr.xfyun.cn/v2/api/upload?appId=...&signa=...&ts=...&...` +- `Content-Type: application/json`,但**请求体是音频原始字节流**(不是 JSON) +- 所有业务参数(`fileSize` `fileName` `duration` `language` `pd` `hotWord` …)都在 URL query 里 +- 中文热词必须做 URL encode:`quote(hot_word_str, safe='')` + +### 坑 8:热词用 `|` 分隔,不是逗号 + +```python +hot_word_str = "|".join(HOT_WORDS) # 萨德|爱国者|标准-6|... +params["hotWord"] = hot_word_str +``` + +限制: +- 最多 200 个热词 +- 每个热词 2–16 字 +- 整个 hotWord 参数 URL encode 后不能超过某个长度(实测 35 个常规军事术语没问题) + +--- + +## 异步查询坑 + +### 坑 9:轮询用 POST 不是 GET + +- 查询结果接口:`POST https://raasr.xfyun.cn/v2/api/getResult?...` +- 即便没有 body 也是 POST +- 用 GET 会报方法不允许 + +### 坑 10:status 状态码语义 + +| status | 含义 | +|---|---| +| 0 | 待处理 | +| 1 | 处理中 | +| 4 | **完成** | +| -1 | 失败 | + +完成是 `4`,不是 `2` 也不是 `200`。 + +### 坑 11:轮询间隔与超时 + +- 26 分钟音频实测转写耗时约 5 分钟 +- 推荐轮询间隔 30 秒(taskEstimateTime 返回的预估值仅供参考) +- 超时上限设 30 分钟比较保险 + +--- + +## 结果解析坑 + +### 坑 12:返回结果是双层嵌套 JSON 字符串 + +```python +# 外层 +data = response.json() +order_result_str = data["content"]["orderResult"] # 这是 JSON 字符串 + +# 中间还有一层反斜杠转义 +cleaned = re.sub(r"\\\\", r"\\", order_result_str) +outer = json.loads(cleaned) + +# 句子在 outer["lattice"] 里 +for item in outer["lattice"]: + inner_str = item["json_1best"] # 又是 JSON 字符串 + inner = json.loads(inner_str) + # 句子时间在 inner["st"]["bg"] / inner["st"]["ed"] + # 句子内容在 inner["st"]["rt"][..]["ws"][..]["cw"][..]["w"] +``` + +每个 `cw` 是一个字 / 词;要拼接所有 `cw["w"]`(跳过 `wp == "g"` 的空白标记)。 + +### 坑 13:时间戳单位是毫秒(不是秒、不是百分秒) + +- `bg` `ed` 都是毫秒(int) +- 与 B 稿的 `[Nm Ns]` 对齐时记得换算 + +--- + +## 业务参数坑 + +### 坑 14:`pd=mil` 对军事术语显著加分 + +- 不开 `pd`:默认通用领域,军事术语会被识别成同音常见词 +- 开 `pd=mil`:军事领域专用模型介入,配合热词效果叠加 + +### 坑 15:`eng_smoothproc` + `eng_colloqproc` 让 ASR 接近书面 + +- `eng_smoothproc=true`:去掉"嗯""那个""呃" +- `eng_colloqproc=true`:口语规整("咱们"→"我们"等) +- 两个都开后,输出已经非常接近书面文稿 +- 但**不会清理"那么""呢""啊""这个"**——这些保留与否需要在融合层决定 + +--- + +## 凭证与配额(demo 阶段使用) + +``` +APP_ID: 84eff996 +SECRET_KEY: d37fb0c77e7f4b4f4398e6a8834d1017 +免费包: 5 小时(已激活),有效期至 2027 年 5 月 +``` + +> ⚠️ **正式上线时替换为生产凭证**,并把 SECRET_KEY 从代码移到环境变量 / 密钥管理服务。 + +--- + +## 一句话总结 + +讯飞 ASR 标准版**能用、好用**,但接入文档稀少且错误信息误导性强;以上 15 个坑全部踩完后,单次调用的成功率接近 100%。后续接入新 ASR 供应商时,建议按本笔记的结构(选型 / 音频 / 接口 / 异步 / 解析 / 业务参数 / 凭证)做同样的整理。 diff --git a/docs/doco/golden test/现代防空反导大对决 定稿.docx b/docs/doco/golden test/现代防空反导大对决 定稿.docx new file mode 100644 index 0000000..cce8e45 Binary files /dev/null and b/docs/doco/golden test/现代防空反导大对决 定稿.docx differ diff --git a/docs/doco/golden test/现代防空反导大对决_终版.docx b/docs/doco/golden test/现代防空反导大对决_终版.docx new file mode 100644 index 0000000..9708fbf Binary files /dev/null and b/docs/doco/golden test/现代防空反导大对决_终版.docx differ diff --git a/docs/doco/xfyun_asr_standard.py b/docs/doco/xfyun_asr_standard.py new file mode 100644 index 0000000..cf85a96 --- /dev/null +++ b/docs/doco/xfyun_asr_standard.py @@ -0,0 +1,345 @@ +# -*- coding: utf-8 -*- +""" +讯飞 录音文件转写(标准版)- 本地运行脚本 +================================================= +用途:将节目音频转为带时间戳的文本,用于TPS中台三方融合demo。 + +接口:https://raasr.xfyun.cn/v2/api/upload / getResult +签名:signa = base64(HmacSHA1(MD5(appid + ts), secretKey)) + +特性: +- 支持热词列表(hotWord),提升专业术语识别率 +- 支持军事领域参数(pd=mil) +- 支持顺滑+口语规整(输出更接近书面语) +- 默认语种 cn(中文普通话),免费包标配,无需 autodialect + +依赖:pip install requests + +输出文件(与脚本同目录): + asr_result_raw.json - 讯飞原始返回 + asr_result_full.txt - 纯文本 + asr_result_timed.txt - 带时间戳的文本(格式同B稿) +""" + +import base64 +import hashlib +import hmac +import json +import os +import re +import time +import wave +from urllib.parse import quote + +import requests + +# ======================================================================== +# 配置区 —— 填写凭证 + 音频路径 +# ======================================================================== + +# 老版只用 APPID + SecretKey 两个字段 +APP_ID = "84eff996" +SECRET_KEY = "在此填入您的SecretKey" + +# 音频文件——可以用之前转好的WAV,也可以直接用mp3(讯飞标准版mp3也支持) +AUDIO_FILE = "现代防空反导大对决音频_16k_mono.wav" + +# 自动去除空白 +APP_ID = APP_ID.strip() +SECRET_KEY = SECRET_KEY.strip() + +# ======================================================================== +# 接口配置 +# ======================================================================== + +HOST = "https://raasr.xfyun.cn/v2/api" +UPLOAD_URL = HOST + "/upload" +RESULT_URL = HOST + "/getResult" + +# 业务参数 +LANGUAGE = "cn" # 中文普通话 +PD = "mil" # 军事领域优化 +ENG_SMOOTHPROC = "true" # 顺滑(去掉"嗯/那个") +ENG_COLLOQPROC = "true" # 口语规整 + +# 热词列表——节目里出现的关键专业术语(讯飞限制200个热词,每个2-16字) +# 我从A稿提取了下面这批,能显著提升识别准确率 +HOT_WORDS = [ + # 武器装备 + "萨德", "爱国者", "标准-6", "铁穹", "塔米尔", + "大卫投石索", "箭式", "箭-2", "箭-3", + "霍拉姆沙赫尔-4", "见证者-136", "卡桑", "泥石", + "C-17", "飞毛腿", "M270", + # 技术概念 + "高超音速", "弹道导弹", "巡航导弹", "无人机蜂群", + "中段反导", "饱和攻击", "动能撞击", "诱饵弹", + "相控阵雷达", "电子战", "外大气层", + # 事件军方 + "真实承诺-4", "伊斯兰革命卫队", "本·古里安", "拉斐尔", + "黎巴嫩真主党", "波斯湾", + # 节目栏目 + "军事科技", +] + +# 轮询配置 +POLL_INTERVAL_SECONDS = 30 +MAX_WAIT_MINUTES = 30 + + +# ======================================================================== +# 签名+工具 +# ======================================================================== + + +def make_signa(app_id, secret_key, ts): + """ + 讯飞老版签名:signa = base64(HmacSHA1(MD5(appid + ts), secretKey)) + """ + base_string = (app_id + ts).encode("utf-8") + md5_str = hashlib.md5(base_string).hexdigest() # 32位小写hex + mac = hmac.new( + secret_key.encode("utf-8"), + md5_str.encode("utf-8"), + digestmod=hashlib.sha1, + ) + signa = base64.b64encode(mac.digest()).decode("utf-8") + return signa + + +def get_audio_duration_ms(filepath): + """获取音频时长(毫秒)。WAV用内置,MP3用mutagen。""" + ext = os.path.splitext(filepath)[1].lower() + + if ext == ".wav": + with wave.open(filepath, "rb") as wf: + n_frames = wf.getnframes() + sample_rate = wf.getframerate() + duration_ms = int(round(n_frames / sample_rate * 1000)) + print(f"[info] WAV规格: {sample_rate}Hz, 声道={wf.getnchannels()}, 位深={wf.getsampwidth()*8}bit") + return duration_ms + + if ext == ".mp3": + try: + from mutagen.mp3 import MP3 + return int(MP3(filepath).info.length * 1000) + except ImportError: + print("[warn] mutagen未安装,时长按0传——讯飞文档说该字段不严格校验") + return 0 + + raise ValueError(f"不支持的音频格式: {ext}") + + +# ======================================================================== +# 上传 +# ======================================================================== + + +def upload_audio(filepath): + """上传音频,返回 orderId""" + if not os.path.exists(filepath): + raise FileNotFoundError(f"音频文件不存在: {filepath}") + + file_size = os.path.getsize(filepath) + file_name = os.path.basename(filepath) + duration_ms = get_audio_duration_ms(filepath) + ts = str(int(time.time())) + + signa = make_signa(APP_ID, SECRET_KEY, ts) + print(f"[info] ts={ts}, signa={signa}") + print(f"[info] 文件: {file_name}, {file_size/1024/1024:.2f}MB, {duration_ms/1000:.1f}秒") + + # 构建URL参数 + params = { + "appId": APP_ID, + "signa": signa, + "ts": ts, + "fileSize": str(file_size), + "fileName": file_name, + "duration": str(duration_ms), + "language": LANGUAGE, + "pd": PD, + "eng_smoothproc": ENG_SMOOTHPROC, + "eng_colloqproc": ENG_COLLOQPROC, + } + + # 热词,用 | 分隔 + if HOT_WORDS: + hot_word_str = "|".join(HOT_WORDS) + params["hotWord"] = hot_word_str + print(f"[info] 热词数量: {len(HOT_WORDS)} 个") + + url_parts = [f"{quote(k, safe='')}={quote(str(v), safe='')}" for k, v in params.items()] + url = f"{UPLOAD_URL}?{'&'.join(url_parts)}" + + headers = { + "Content-Type": "application/json", + } + + with open(filepath, "rb") as f: + audio_bytes = f.read() + + print(f"[info] 正在上传... ({file_size/1024/1024:.1f}MB)") + resp = requests.post(url, headers=headers, data=audio_bytes, timeout=300) + print(f"[info] HTTP状态: {resp.status_code}") + + data = resp.json() + print(f"[info] 响应: {json.dumps(data, ensure_ascii=False, indent=2)}") + + if data.get("code") != "000000": + raise RuntimeError(f"上传失败: code={data.get('code')}, desc={data.get('descInfo')}") + + order_id = data["content"]["orderId"] + estimate_ms = data["content"].get("taskEstimateTime", 0) + print(f"\n[ok] orderId = {order_id}") + print(f"[ok] 预估完成时间: {estimate_ms/1000:.1f}秒\n") + return order_id + + +# ======================================================================== +# 查询结果 +# ======================================================================== + + +def query_result(order_id): + """单次查询""" + ts = str(int(time.time())) + signa = make_signa(APP_ID, SECRET_KEY, ts) + + params = { + "appId": APP_ID, + "signa": signa, + "ts": ts, + "orderId": order_id, + "resultType": "transfer", + } + url_parts = [f"{quote(k, safe='')}={quote(str(v), safe='')}" for k, v in params.items()] + url = f"{RESULT_URL}?{'&'.join(url_parts)}" + + resp = requests.post(url, timeout=30) + return resp.json() + + +def poll_until_done(order_id): + """轮询直到完成""" + print(f"[info] 开始轮询(每 {POLL_INTERVAL_SECONDS} 秒一次)...") + start_time = time.time() + while True: + elapsed = time.time() - start_time + if elapsed > MAX_WAIT_MINUTES * 60: + raise TimeoutError(f"超过 {MAX_WAIT_MINUTES} 分钟未完成") + + data = query_result(order_id) + order_info = data.get("content", {}).get("orderInfo", {}) + status = order_info.get("status") + fail_type = order_info.get("failType", 0) + elapsed_min = elapsed / 60 + print(f"[poll] 已等 {elapsed_min:.1f} 分钟, status={status}, failType={fail_type}") + + if status == 4: + print(f"\n[ok] 转写完成!耗时 {elapsed_min:.1f} 分钟") + return data + if status == -1: + raise RuntimeError(f"转写失败: failType={fail_type}, 数据: {data}") + + time.sleep(POLL_INTERVAL_SECONDS) + + +# ======================================================================== +# 结果解析 +# ======================================================================== + + +def parse_order_result(order_result_str): + """ + 解析嵌套JSON,返回 [(sentence_start_ms, sentence_end_ms, text), ...] + """ + if not order_result_str: + return [] + + cleaned = re.sub(r"\\\\", r"\\", order_result_str) + outer = json.loads(cleaned) + + sentences = [] + for item in outer.get("lattice", []): + inner_str = item.get("json_1best", "") + if not inner_str: + continue + inner = json.loads(inner_str) + st = inner.get("st", {}) + bg = int(st.get("bg", 0)) + ed = int(st.get("ed", 0)) + + words = [] + for rt in st.get("rt", []): + for ws in rt.get("ws", []): + for cw in ws.get("cw", []): + w = cw.get("w", "").strip() + wp = cw.get("wp", "n") + if w and wp != "g": + words.append(w) + sentence = "".join(words).strip() + if sentence: + sentences.append((bg, ed, sentence)) + + return sentences + + +def format_timestamp(ms): + total_sec = ms // 1000 + return f"{total_sec // 60}m{total_sec % 60}s" + + +def write_outputs(sentences, raw_data): + with open("asr_result_raw.json", "w", encoding="utf-8") as f: + json.dump(raw_data, f, ensure_ascii=False, indent=2) + print(f"[ok] 已写 asr_result_raw.json") + + timed_lines = [f"[{format_timestamp(bg)}] {text}" for bg, _, text in sentences] + with open("asr_result_timed.txt", "w", encoding="utf-8") as f: + f.write("\n".join(timed_lines)) + print(f"[ok] 已写 asr_result_timed.txt ({len(timed_lines)} 句)") + + full_text = "".join(t for _, _, t in sentences) + with open("asr_result_full.txt", "w", encoding="utf-8") as f: + f.write(full_text) + print(f"[ok] 已写 asr_result_full.txt ({len(full_text)} 字)") + + +# ======================================================================== +# 入口 +# ======================================================================== + + +def main(): + print("=" * 60) + print("讯飞 录音文件转写(标准版) - 本地脚本") + print("=" * 60) + + if SECRET_KEY.startswith("在此填入"): + print("[error] 请先填写 SECRET_KEY") + return + + print(f"[diag] APP_ID = {APP_ID} (长度 {len(APP_ID)})") + print(f"[diag] SECRET_KEY 长度 {len(SECRET_KEY)}, 首4位={SECRET_KEY[:4]}, 末4位={SECRET_KEY[-4:]}") + print(f"[diag] AUDIO_FILE = {AUDIO_FILE}") + print() + + # 1. 上传 + order_id = upload_audio(AUDIO_FILE) + + # 2. 轮询 + final_data = poll_until_done(order_id) + + # 3. 解析+写文件 + order_result_str = final_data["content"]["orderResult"] + sentences = parse_order_result(order_result_str) + write_outputs(sentences, final_data) + + print("\n" + "=" * 60) + print(f"完成!共识别 {len(sentences)} 句") + print(f"请把 asr_result_timed.txt 发给 Claude 进行三方融合") + print("=" * 60) + + +if __name__ == "__main__": + main() diff --git a/docs/doco/主project对Doco_PRDv2的回复.md b/docs/doco/主project对Doco_PRDv2的回复.md new file mode 100644 index 0000000..cd6dd82 --- /dev/null +++ b/docs/doco/主project对Doco_PRDv2的回复.md @@ -0,0 +1,214 @@ +# 主 project 对 Doco PRD v2 的回复 + +> 来源:TPS 主 project 顾问(Claude Opus 4.7) +> 日期:2026-06-12 +> 针对:`PRD_doco_文稿整理子项目_v2.md` 第四章 5 个问题 +> 性质:正式批复,Doco 子项目据此出 v3 后启动 P1 + +--- + +## 总体意见 + +**5 个问题的子项目推荐**,**整体方向 4 个批准、1 个调整**: +- Q1 OCR 选型:**批准 DeepSeek API,但有附加条件**(见下) +- Q2 ffmpeg 入口:**批准,有补充约束** +- Q3 单期 vs 批量接口:**批准,加交付契约** +- Q4 密钥管理:**调整方案** — 走"自管 + 中台登记 inventory" +- Q5 目录规约:**批准草案,但 episode_id 命名规则需主项目定** + +5.3 §"23 期是否常态化":**这是一个产品问题,我代制片人答不了。子项目可以按"先按 23 期一次性做完、保留兜底回退路径"开干,常态化的事跟栏目组确认后再回头审。** + +--- + +## Q1. OCR 方案选型 — 批准 DeepSeek API + +### 主 project 现状 +- **主 project 没有 OCR 子模块/能力**(已确认)。旧设计里 B 稿来自"上游既有 OCR 流程",指的是栏目组那边人工跑的 OCR,不是 TPS 内部的服务。 +- 主 project `backend/.env` 里有 `DEEPSEEK_API_KEY`,但**只用作 Cline 工具的 Plan/Act 模型**——没有任何业务代码在调 DeepSeek。所以 doco 调 DeepSeek 视觉模型相当于**新增一条业务调用**,不是"复用现有基础设施"。 + +### 批复 + +**Doco 子模块新增 DeepSeek Vision 调用,自管 API key。** + +- API key 独立申请,**不复用 Cline 用的那把 key**。理由:Cline 的 key 是开发工具用的,doco 是生产服务,生命周期、配额、监控都该独立。 +- 6900 张图 × 几厘 / 张 ≈ 50-150 元,在制片人手上的 API 余额范围内,**不存在配额冲突问题**(主 project 业务代码侧没人在花)。 +- 黑底白字字幕场景对 LLM 视觉模型确实是舒适区,**实施前先在 demo 那期视频上跑 10 帧抽样,验证识别准确率达到目标后再扩到 23 期**。 +- **降级路径**:如果 DeepSeek Vision 在某些边角 case 上不达标(比如有同期声同步显示双行字幕、字号变化等),回退到 PaddleOCR 本地。**不要回退到讯飞 OCR**(余额独立 + 单期 ~13 元成本太高)。 + +--- + +## Q2. 视频处理依赖(ffmpeg)入口 — 批准方案 A + +### 主 project 现状 +- **没有视频处理子模块/服务**(已确认),dev_plan 也没规划。 + +### 批复 + +**Doco 自带 ffmpeg 系统依赖 + Python subprocess 调用。** + +附加约束: +- **不引入 `ffmpeg-python` wrapper**——subprocess 足够,不增加新依赖。 +- ffmpeg 命令封装在 `doco/video_split.py` 内,**对外只暴露 Python 函数接口**,不让上层调用方直接 shell 调 ffmpeg。 +- 在 doco 的 `README.md` 明确写"系统依赖:ffmpeg ≥ 4.x"——这是部署的前置条件。 +- 未来如果主 project 真做了统一的视频处理服务,**doco 的封装方式应该使迁移成本最低**(把 subprocess 调用换成 HTTP 调用即可,业务逻辑不动)。 + +--- + +## Q3. 23 期批量 vs 单期接口 — 批准方案 A,加契约 + +### 主 project 现状 +- **没有节目素材批量处理编排层**(已确认)。dev_plan 提到的"批量导入工具 v1/v2"是收视数据和报题单的批量,跟视频处理是两回事。 + +### 批复 + +**Doco 只对单期负责。同时提供 CLI 和 Python API 两套接口。** + +**接口契约(子项目正式实现时按这个出)**: + +```python +# Python API +def process_episode( + episode_id: str, # 调用方给定,doco 不管命名规则 + video_path: Path, # 输入视频 + a_draft_path: Path, # A 稿 docx + output_dir: Path, # 产物存放目录 + cleanup_level: str = "medium", # keep_all / medium / clean +) -> ProcessResult + +# ProcessResult 必含字段 +@dataclass +class ProcessResult: + episode_id: str + status: Literal["success", "partial", "failed"] + final_docx_path: Optional[Path] + diff_report_path: Optional[Path] + needs_review_json_path: Optional[Path] + errors: List[str] + stage_timings: Dict[str, float] # 哪个 phase 用了多久 +``` + +```bash +# CLI 等价形式 +doco process \ + --episode-id ep023 \ + --input-video /path/to/video.mp4 \ + --input-a-draft /path/to/a_draft.docx \ + --output-dir /path/to/output \ + --cleanup-level medium +``` + +**关于 23 期推进**:**先单期跑通再批量**——拿 demo 那期《现代防空反导大对决》视频做 golden test(P4),与 demo 已有产物比对零回归,再扩到 23 期。一次性 batch 23 期风险太大。 + +未来主 project 若开节目素材批量处理编排层,**会反过来调 doco 的单期接口**,不会改 doco。 + +--- + +## Q4. 讯飞密钥管理 — 调整方案:自管 + Inventory 登记 + +### 主 project 现状 +- **没有中台密钥管理子模块**(已确认),也不在 dev_plan 排期内。 +- 主 project 凭证都在 `backend/.env`,各模块走环境变量。 + +### 批复 + +不走子项目推荐的"申请新凭证 + 写入中台密钥资产文档"(因为中台密钥服务不存在,不能凭空捏一个)。改为: + +**1. Doco 自管凭证。** 讯飞、DeepSeek 各自的 API key 放 doco 自己的 `.env`,**不放进主 project 的 `backend/.env`**——保持子模块自治。 + +**2. 主 project 仓库根目录新增一份登记文档:`docs/api_credentials_inventory.md`** + +这份文档: +- **不存储真实凭证**(那些在各自子模块的 .env 里) +- 只存储**元信息**:每个外部 API 用了什么、所属子模块是谁、开通时间、激活状态、到期日、续费责任人 +- 子模块申请新 key、key 到期更换,都更新这份文档 +- 这是主 project 帮所有子模块做"凭证清单"的最小落地——比起"中台密钥服务",轻得多,但解决"忘了谁管哪把 key"的问题 + +**3. Inventory 文档的字段**(供子项目和未来其他子模块参考): + +```markdown +| 子模块 | API 服务 | Key 类型 | 开通日 | 激活状态 | 到期日 | 责任人 | 备注 | +|---|---|---|---|---|---|---|---| +| doco | 讯飞开放平台 - 录音文件转写 | APP_ID + SECRET_KEY | 2026-06-12 | 已激活 5h 试用包 | 2027-06-12 | 制片人 | demo 凭证已过期,新申请 | +| doco | DeepSeek Vision | API_KEY | 2026-06-12 | 已激活 | — | 制片人 | doco OCR 用 | +| (主) | Anthropic Claude API | API_KEY | ... | ... | ... | ... | AI 融合层用 | +``` + +**4. 制片人现在要做的事**(代答 Q4 里"新申请的讯飞开发端密钥应该登记在哪里"): +- 去讯飞开放平台 console 申请新的开发端凭证 +- 走 0 元购买流程激活 5 小时免费试用包 +- 把 APP_ID / SECRET_KEY 写到 doco 的 .env 里 +- 在 `docs/api_credentials_inventory.md` 登记一行 + +--- + +## Q5. 目录结构与命名规约 — 批准草案,episode_id 命名由主项目定 + +### 主 project 现状 +- **没有节目素材目录的统一规约**(已确认)。主 project 处理的是数据维度的 `episodes` 表,episode_id 是 INT 自增主键。 +- 但是,**素材文件名跟数据库 ID 是两层东西**,不能直接套。 + +### 批复 + +**子项目提的 `programs/{episode_id}/source|work|output/...` 结构批准。** + +**关于 episode_id 命名规则**——这是主项目要定的规约,定如下: + +**episode_id 格式:`ep{NNN}_{YYYYMMDD}_{slug}`** + +- `ep{NNN}` = episodes 表自增 INT 主键,零填充到 3 位(如 ep023) +- `{YYYYMMDD}` = 首播日期 +- `{slug}` = 节目名称的拼音缩写或简称中文(无空格、无特殊字符) + +举例: +- `ep023_20260612_haishang_xianfeng` +- `ep007_20260201_马年军事图鉴` + +**理由**: +- INT 主键稳定可关联到 episodes 表 +- 日期方便文件系统按时间排序 +- slug 让人眼可读 + +**约定**: +- episode_id **由调用方给定**(主项目编排层 / 责编 / CLI 调用者),doco 不生成 +- doco 只把它当一个字符串使用 +- 主项目责编/编排层在调 doco 前**先在 episodes 表落库该期、拿到 INT ID**,再拼出 episode_id + +**work/ 中间产物保留时长**: +- 节目入档案库后保留 **30 天**,然后可清理(由编排层负责,doco 不管) +- 出问题需要复查时,30 天窗口够定位 + +--- + +## §5 第 3 条:23 期是常态化吗? + +**这是产品问题,不是技术问题。我代制片人答不了。** + +**建议子项目的处理**: +- 按"23 期一次性"开干,先把这批做完 +- 算法层零侵入是硬保证,即使将来变常态化,流水线也能继续跑 +- **保留旧的 mp3+独立 OCR 流程作为回退路径**(代码不删,加 feature flag 或环境变量切换)。万一某期视频不符合"黑底白字+干净人声"特殊条件,降级到旧流程 +- 23 期完成 + 制片人跟栏目组确认后,再决定是否清理回退路径 + +--- + +## 子项目可以启动的部分 + +按 PRD v2 §七 的回复期望: +- ✅ **Q1 已答**(DeepSeek API + 附加条件) → P1 可开始 +- ✅ **Q2 已答**(subprocess + 不引入 wrapper)→ P1 可开始 +- ✅ **Q3 已答**(单期 + 契约) → P5 推进时按契约 +- ✅ **Q4 已答**(自管 + inventory 登记) → 制片人先申请讯飞新凭证 + 建 inventory,P2 可开始 +- ✅ **Q5 已答**(目录草案批准 + episode_id 规则) → P1 输出有处可放 + +**Doco 子项目现在可以出 PRD v3,启动 P1。** + +--- + +## 顺便给子项目的两条提醒 + +1. **demo 的 5 份 fixture 必须进 git**(transcripts / A 稿 / B 稿 / ASR / 终版 / 差异报告),作为单元测试 + golden test 黄金对照。这件事属于 Doco 内部自治,主项目不管,但提醒一下。 +2. **AI 融合层模型选 Sonnet 4.6**(PRD v2 §二 已锁),不要在子项目里临时换成别的模型。主项目这边也不会推翻这个选择。 + +--- + +*主 project 顾问(Claude Opus 4.7)签发,2026-06-12* diff --git a/docs/doco/实测复盘.md b/docs/doco/实测复盘.md new file mode 100644 index 0000000..69608ad --- /dev/null +++ b/docs/doco/实测复盘.md @@ -0,0 +1,151 @@ +# 《现代防空反导大对决》三方融合demo实测复盘 + +> 日期:2026年5月13日 | 报告人:Claude | 节目时长:26分钟 | 实施耗时:约2小时 + +--- + +## 一、ASR环节实测数据 + +### 1.1 服务选型最终结果 + +**最终采用:讯飞开放平台「录音文件转写(标准版)」** + +| 维度 | 实测结果 | +|---|---| +| 转写耗时 | 5分钟左右(26分钟音频) | +| 识别句子数 | 307句(含片尾彩蛋) | +| 主体节目识别 | 297句对齐节目主体 | +| 关键术语识别率 | **接近100%**(开启35条热词后) | +| 数字/百分比识别 | 100%准确 | +| 文档显示价格 | 5小时免费试用包,1年有效期 | + +### 1.2 ASR亮点 + +- 讯飞自动加入了合理的标点(句号、逗号、问号) +- 开启 `eng_smoothproc=true` 和 `eng_colloqproc=true` 后,已自动清理了大部分"嗯/那个/呃"等口语词 +- **热词机制效果显著**:`霍拉姆沙赫尔-4` `见证者-136` `塔米尔` `大卫投石索` `本古里安` `拉斐尔` 等生僻军事术语全部正确识别 +- 句子级时间戳精准,可直接与B稿做时间对齐 + +### 1.3 ASR短板(需要A稿术语表后处理修正) + +| 错误类型 | 实例 | 修复依据 | +|---|---|---| +| 同音误识 | "中端/末端" → 应为"中段/末段" | A稿术语 | +| 同音误识 | "中诚防御" → 应为"中程防御" | A稿术语 | +| 事实错误 | "美伊两国" → 应为"美以两国"(最严重) | A稿/语境 | +| 表述偏好 | "高超声速" → A稿用"高超音速" | A稿术语统一 | +| 百分比表达 | "百%" → 应为"100%" | 后处理规则 | +| 数字表达 | "数10" → 应为"数十" | 后处理规则 | +| 口语词残留 | 专家发言里仍有"啊呢这个" | 部分保留以反映播出状态 | + +### 1.4 关于'美伊→美以'这类事实错误的反思 + +ASR第18行把"美以两国"识别成了"美伊两国"。**这是最危险的一类错误**——拼音相同、字形不同,单独看ASR文本完全像是合法的事实陈述("美国和伊朗两国协同向伊朗发起军事打击"语义虽然荒谬但句子通顺),人工审校如果不熟悉上下文也可能漏过。 + +这印证了交接说明里的设计判断:**A稿的术语和事实必须作为权威源参与融合**,不能让ASR单独输出,否则会引入危险的事实错误。 + +--- + +## 二、三方融合环节关键决策点 + +### 2.1 把握大的判断(demo中AI判断高确信度) + +1. **整段删除的识别**:A稿【解说2】末尾'雷达被誉为中段反导体系的眼睛...'在B稿和ASR里完全找不到对应内容 → 信号非常明确,删除 +2. **整段重复笔误**:A稿【专家7】和【专家8】内容字符完全相同 → 编导笔误,按ASR的真实内容(讲效费比)替换【专家8】 +3. **术语事实错误的修复**:ASR'美伊→美以'类同音错误 → A稿权威覆盖 +4. **OCR错字的批量修复**:'肘→时''娈→变''夭→天'等字形混淆 → ASR提供正确版本 + +### 2.2 把握较小的判断(demo中AI判断中等确信度,未来需要编导确认) + +1. **解说6"整段改写"的边界**:A稿80字版本和ASR/B稿40字版本,**究竟保留哪个细节合并哪个细节**——目前demo直接采用了ASR的40字版本,但A稿那80字版本里有"信任危机""推迟采购方案"等A稿独有的内容,编导可能想保留。**未来应该让编导在UI上看diff后人工确认** +2. **专家发言的口语词处理**:'呢''啊'保留多少?太多影响阅读,太少违背播出真相。本次demo保留较多,倾向"播出真相"。**未来可做个可调档位("完全保留口语 / 中度清理 / 完全书面化"三档)** +3. **A稿首句被改写的情况**:A稿"观众朋友们,你们好!欢迎来到这一期的《军事科技》节目",播出时改为了"各位观众,你们好!欢迎收看《军事科技》"——句式接近但用词全变。demo靠手工锚点列表匹配上了,未来要让Claude做语义对齐而非字符匹配。 + +### 2.3 把握很小的判断(demo中AI暂时不处理,必须人工确认) + +1. **句子级的微小增删**:如A稿"在涉及远、中、近程"和ASR"在涉及远中近程"——只是顿号差异。这种差异融合时按ASR走、还是按A稿格式来?**未来UI应该展示句子级diff让编导决定** +2. **专有名词的简写问题**:A稿严格用"爱国者-3",播出时多数说"爱国者"。这是术语统一问题还是口语化问题?**取决于该期节目的风格定位** + +--- + +## 三、对正式开发TPS子模块的启示 + +### 3.1 模块架构建议 + +``` +[音频上传] → [ASR服务(讯飞)] → [OCR处理(B稿)] → [三方融合引擎] → [编导确认UI] → [终版docx] + ↓ + [大模型API(Claude)] +``` + +**核心是"三方融合引擎"应当分两层**: +- **规则层**:OCR错字纠正(固定映射表)、术语统一(A稿术语权威)、时间戳对齐 — 走Python代码 +- **AI层**:段落对齐、整段改写判定、'编导笔误'识别 — 走大模型API + +### 3.2 关于讯飞ASR的具体集成建议 + +**应该写进project_design.md【外部依赖】章节的内容**: + +1. 优先使用讯飞「录音文件转写(标准版)」API,**不要**用大模型版(免费包阉割了language参数) +2. 音频必须先转码为 **16kHz / 单声道 / 16bit WAV**,否则讯飞会报误导性的`language verify fail`错误 +3. **热词词库**是关键能力:每期节目从A稿提取专业术语作为热词上传给ASR +4. **领域参数** `pd=mil` 对军事节目有显著效果 +5. 开启 `eng_smoothproc=true` + `eng_colloqproc=true` 让ASR输出更接近书面文稿 +6. 讯飞密钥分两套:消费端(讯飞听见App)和开发端(讯飞开放平台),**互不相通** +7. "免费5小时"需要走0元购买流程才激活,不是看到额度就能用 + +### 3.3 关于大模型融合提示词的设计 + +未来正式开发时调Claude API做段落对齐,prompt应该包含: + +- **输入1**:A稿全文 + 标签序列 +- **输入2**:ASR结果(句子+时间戳) +- **输入3**:B稿OCR结果(句子+时间戳,作为交叉验证) +- **任务1**:把ASR句子按A稿标签序列归类 +- **任务2**:对每段标记改动类型(无变化/细微改写/整段改写/整段删除/整段新增) +- **任务3**:对'高把握'改动直接产出终版;对'低把握'改动标记原因,等编导确认 +- **任务4**:识别A稿术语和ASR结果的字形/同音差异,用A稿权威修正 + +### 3.4 关于编导确认UI的设计 + +借鉴本次demo发现的痛点,UI应该至少提供: + +- **左中右三栏diff视图**:A稿原文 | 终版 | ASR/B稿(带时间戳,可点击播放对应音频片段) +- **改动类型颜色编码**:删除红色 / 改写黄色 / 术语修正蓝色 / 无变化白色 +- **逐段确认按钮**:接受 / 拒绝 / 编辑 / 标记疑问 +- **口语清理强度滑杆**:让编导决定保留多少口语词 +- **导出按钮**:终版docx / 差异报告 / 复盘CSV + +--- + +## 四、实测耗时分解(用于未来效率评估) + +| 阶段 | 实测耗时 | 主要消耗 | +|---|---|---| +| 讯飞ASR申请+踩坑 | 约45分钟 | 大模型版语种权限问题、音频规格转码 | +| 老版讯飞ASR调通 | 约15分钟 | 申请+脚本+调用 | +| 三方解析 | 约5分钟 | A稿/B稿/ASR解析为统一结构 | +| 段落对齐 | 约15分钟 | 锚点匹配算法+单调推进 | +| 术语规范化+口语清理 | 约5分钟 | 字符级规则映射 | +| 终版docx生成 | 约5分钟 | python-docx写文档 | +| 差异报告+复盘 | 约15分钟 | 这份报告本身 | + +**总耗时约2小时**,其中近一半花在讯飞踩坑上——正式开发后这部分会清零,每期实际处理时间预计15-30分钟(取决于改动幅度)。 + +--- + +## 五、给您(刘统制片)的几点直接建议 + +1. **TPS正式开发时,不必把ASR作为强依赖**。本次demo证明,即便没有ASR,A稿+B稿做二方融合也能产出接近播出版的终版。ASR的价值在于"独立第三方仲裁"——值得做但不应阻塞主流程。 + +2. **A稿术语表应该入库管理**,作为TPS的核心知识资产之一。每期节目处理时都从该表查找"权威术语",自动覆盖ASR的同音错误。本次demo手工列出的35个热词清单是个起点。 + +3. **节目编导习惯的差异要预留可配置项**。比如有的编导喜欢保留口语词、有的喜欢全部规整化;有的喜欢保留专家发言的原始措辞、有的喜欢编辑过的书面版本。这些应该在配置文件里,而不是硬编码。 + +4. **差异报告的价值可能比终版docx更大**。每期节目处理完,差异报告其实是个"编导工作回顾"——能看到自己当初做了哪些删改、哪些是OCR错字。长期累积下来可以分析编导的删改偏好,作为节目优化的素材。 + +5. **本次踩的坑值得专门整理一个"讯飞集成踩坑笔记"文档**入TPS知识库。未来下次开发新供应商接入时(比如阿里云ASR),可以走更顺的路。 + +--- + +*本复盘为demo阶段产物,不代表正式开发的最终决策。所有结论以下次设计文档为准。* diff --git a/docs/跨子项目协作规则.md b/docs/跨子项目协作规则.md new file mode 100644 index 0000000..90e12aa --- /dev/null +++ b/docs/跨子项目协作规则.md @@ -0,0 +1,38 @@ +# 跨子项目协作规则 + +> 主项目维护的通用规则,所有外迁子项目都适用。 +> 起始日期:2026-06-12 + +--- + +## 规则 1:PRD 版本管理(立于 Doco 立项时) + +### 1.1 主 project 这边的规则 + +- **只保留最新版 PRD + 对应回复**,旧版本一律删 +- **PRD 与回复一一配对**:PRD v2 ↔ 回复 v2;PRD v3 ↔ 回复 v3 +- 任何时点,主 project 不允许同时存在同一子项目的两个 PRD 版本 + +### 1.2 子 project 那边的规则 + +- **保留所有版本**(包括 PRD v0 / v1 / v2 / v3...) +- 旧版本可移到 `archive/` 子目录或加 `_archived` 后缀,但不删 +- 每份新 PRD 在元信息块标注"上一版:vN" + +### 1.3 版本翻新的操作 + +子项目出 PRD vN+1 时: +1. 制片人在主 project 这边**先删** PRD vN + 回复 vN +2. **再传** PRD vN+1 + 主项目顾问写的回复 vN+1 +3. 一次性,不允许"先传再删"造成短暂双版本状态 + +### 1.4 适用范围 + +- 当前所有外迁子项目(看板升级 / Doco 等) +- 未来新立项的子项目沿用 + +--- + +## (未来其他通用规则在这里累加) + +> 后续规则按 `## 规则 2:xxx` `## 规则 3:xxx` 顺序追加。 diff --git a/note/续接快照_看板分析升级_设计讨论.md b/note/续接快照_看板分析升级_设计讨论_v1.md similarity index 100% rename from note/续接快照_看板分析升级_设计讨论.md rename to note/续接快照_看板分析升级_设计讨论_v1.md diff --git a/note/续接快照_看板分析升级_设计讨论_v4.md b/note/续接快照_看板分析升级_设计讨论_v4.md new file mode 100644 index 0000000..477b2fb --- /dev/null +++ b/note/续接快照_看板分析升级_设计讨论_v4.md @@ -0,0 +1,377 @@ +# 续接快照 — 看板分析升级 v4(AI 打标流水线落地 + 模型选型完成) + +> 用途:下次新 chat 接力用。承接 2026-06-09 v1 + 2026-06-10 v2 + 2026-06-11 上午 v3,包含 2026-06-11 一整天讨论。 +> 状态:AI 打标流水线跑通;Prompt 2 v0.2 锁定;ground-truth v0.2.1 锁定;模型选型完成 → **MiniMax M3 + Prompt v0.2 = 100% 命中率**;Git 已推 Gitea 落库。 +> 更新时间:2026-06-11(晚) +> 顾问:Claude Opus 4.7 | 制片人:刘通 + +--- + +## 零、本快照与 v1/v2/v3 的关系 + +v1/v2/v3 全部结论仍然有效,**v4 是增量,不替换**。今日新增 6 件大事: + +1. AI 打标流水线从纸面落到能跑(脚本 + 配置 + 文稿入库 + 汇总工具) +2. Prompt 2 升级到 v0.2(加"段内承接 ≠ 全片骨架"陷阱教学) +3. ground-truth 经两轮复议升级到 v0.2.1(三期改判) +4. 三家模型在同一份"试卷"上公平对比完成 +5. 模型选型拍板:**MiniMax M3** +6. Git 双 commit 推送 Gitea 落库(commit `38f3728` 是今天的里程碑) + +--- + +## 一、今天的时间线(2026-06-11 一日) + +| 阶段 | 关键动作 | 产出 | +|---|---|---| +| 上午 | 工作区目录搭建 + 10 期文稿导入 + ep04 单跑 | 9/10 自动导入成功,ep05 .doc 制片人手工另存补全 | +| 中段 | 发现 reasoning model 的 `` 标签 bug → 修 `extract_json_from_response` | JSON 解析链路稳定 | +| Prompt v0.1 全跑 | M3 跑 10 期 | **5/10 = 50%**,全部"高置信" | +| 复议 1 | ep05/13/14 维持并列,ep10/15 改主线演进 | ground-truth v0.2 | +| Prompt 升级 | 加"段内承接陷阱"+ `chapter_list` + `shuffle_test` 强制思考字段 | Prompt 2 v0.2 | +| M3 二跑 | 9/10 = 90%,唯一错 ep12 | 锁定 v0.2 不再调 | +| DeepSeek V4 Pro | 70%,错的全是"应主线判并列",偏保守 | — | +| MiMo v2.5 Pro | 60%,两向都错 | — | +| 复议 2 | ep12 三家独立都判并列 → ground-truth 改 | ground-truth v0.2.1 | +| 最终战绩 | **M3 100% / DeepSeek 80% / MiMo 70%** | 选 M3 | +| 收尾 | Git 双 commit 推 Gitea | commit 38f3728 + edfb298 | + +--- + +## 二、AI 打标流水线已落地资产 + +### 2.1 工作目录(`E:\tps-dashboard\ai-labeling\`) + +``` +ai-labeling/ +├── benchmark-set/ +│ ├── transcripts/ ← 10 期文稿 .md(基准卷子) +│ │ ├── ep03_硅基大脑.md +│ │ ├── ep04_潜艇仿生.md +│ │ ├── ep05_舰证不凡.md +│ │ ├── ep07_马年图鉴.md +│ │ ├── ep10_射速决定论.md +│ │ ├── ep11_空战颠覆者.md +│ │ ├── ep12_逆袭战局.md +│ │ ├── ep13_长短智慧.md +│ │ ├── ep14_X76飞机.md +│ │ └── ep15_空中坚盾.md +│ └── ground-truth.json ← 基准答案 v0.2.1 +├── prompts/ +│ └── prompt2_narrative.md ← 叙事结构判别 v0.2(5 示例,含两个陷阱反例) +├── experiments/ ← 跑批结果 .json(.gitignore 拦截,不入 git) +├── scripts/ +│ ├── import_transcripts.py ← docx/doc → md 解析 + 清洗 +│ ├── run_labeling.py ← 单期或批量调模型 + 写文件 +│ └── summarize.py ← 扫 experiments/ 汇总命中率 +├── .env.example ← 入 git 的 Key 占位模板 +├── .env ← 不入 git,真 Key +├── .gitignore ← 拦 .env / experiments / __pycache__ +└── README.md +``` + +### 2.2 三个关键脚本的分工 + +| 脚本 | 干什么 | 用法 | +|---|---|---| +| `import_transcripts.py` | 把源 docx/doc 拷+解析+清洗成 .md,落 transcripts/ | 已跑过一次,10 期都在;新文稿要扩源目录映射表 | +| `run_labeling.py` | 调模型,把 result + ground_truth 写进 experiments/ 一个 .json | `python scripts/run_labeling.py --ep N --model m3` | +| `summarize.py` | 扫 experiments/ 下指定 model 的最新 json,出 10 行命中表 + 汇总 | `python scripts/summarize.py --model m3` | + +PowerShell 批量套路(模型选型阶段用,以后可作为标准跑法): +```powershell +cd E:\tps-dashboard\ai-labeling +3, 4, 5, 7, 10, 11, 12, 13, 14, 15 | ForEach-Object { python scripts/run_labeling.py --ep $_ --model m3 } +python scripts/summarize.py --model m3 +``` + +### 2.3 MODEL_CONFIG 已配置的三家(`scripts/run_labeling.py`) + +```python +MODEL_CONFIG = { + "m3": { + "base_url": "https://api.minimaxi.com/v1", + "model_name": "MiniMax-M3", + "api_key_env": "MINIMAX_API_KEY", + }, + "deepseek-v4-pro": { + "base_url": "https://api.deepseek.com", # 注意:不带 /v1 + "model_name": "deepseek-v4-pro", + "api_key_env": "DEEPSEEK_API_KEY", + }, + "mimo-v2.5-pro": { + "base_url": "https://api.xiaomimimo.com/v1", + "model_name": "mimo-v2.5-pro", + "api_key_env": "MIMO_API_KEY", + }, +} +``` + +依赖锁定(`scripts/requirements.txt`): +``` +openai==1.55.0 # 不能升级,新版自动转 developer 角色,MiniMax 不支持 +python-dotenv>=1.0.0 +python-docx>=1.1.0 +``` + +--- + +## 三、Prompt 2 v0.2 核心设计 + +(完整文件见 `ai-labeling/prompts/prompt2_narrative.md`,以下是要点摘录) + +### 3.1 两档定义(收为 2 档,沿用 v3) + +- **主线演进**:全片由"贯穿主线"串起来。主线可以是 a) 内在概念 / b) 时间因果链 / c) 性能阶梯 +- **并列结构**:章节相互独立、可替换,共性只来自分类共性 + +### 3.2 关键边界(共 4 条 + 1 条核心新增) + +1. 命名共性不构成主线 +2. 装备域共性不构成主线 +3. 空间方位共性不构成主线 +4. **【v0.2 新增,最重要】段内承接 ≠ 全片骨架**——文稿里某段出现"递进""演进""阶梯""奠定基础"字样,**往往只是段内微观承接**,不是全片骨架。先识别全片大章节,再做章际打乱测试。 + +### 3.3 强制判断流程(v0.2 新增) + +模型必须先输出 `chapter_list`(全片 3-5 个大章节)+ `shuffle_test`(打乱测试结论),才能下判断。避免它一看到"递进"两字就秒判主线演进。 + +### 3.4 5 个示例(2 主线 + 3 并列,平衡分布) + +| 示例 | 类型 | 教学重点 | +|---|---|---| +| 潜艇仿生 | 主线演进-内在概念 | 同一命题贯穿全片 | +| 空战颠覆者 | 主线演进-时间线 | 严格按时间序推进 | +| 马年军事图鉴 | 并列结构-命名共性 | 高收视不靠结构,靠节点策划 | +| **舰证不凡** ⚠️ | **并列结构-警惕段内承接陷阱** | "递进式"字样在段内 ≠ 全片主线 | +| **X-76 飞行器** ⚠️ | **并列结构-警惕段内时间线陷阱** | 时间线只在"背景"段里 ≠ 全片骨架 | + +### 3.5 JSON 输出 schema(新增两个强制思考字段) + +```json +{ + "narrative_structure": "主线演进 或 并列结构", + "chapter_list": ["大章节1", "大章节2", ...], ← v0.2 新增 + "shuffle_test": "打乱后观众怎样的一句话", ← v0.2 新增 + "main_thread": "主线演进时点明主线,并列填 null", + "reasoning": "判断理由,如果文稿有'递进'等字样必须说明是段内还是全片", + "key_evidence": ["证据片段1", "证据片段2"], + "confidence": "高 或 中 或 低", + "confidence_reason": "为什么这个置信度" +} +``` + +--- + +## 四、ground-truth v0.2.1 锁定的 10 期分布 + +| ep | 节目 | share | 叙事结构(v0.2.1) | 开篇钩子 | v0.1 → v0.2.1 变迁 | +|---|---|---|---|---|---| +| 3 | 硅基大脑 | 0.85 | 并列结构 | 中 | 未变 | +| 4 | 潜艇仿生 | 0.92 | 主线演进 | 强 | 未变 | +| 5 | 舰证不凡 | 0.72 | 并列结构 | 中 | 未变(经讨论后维持) | +| 7 | 马年军事图鉴 | 0.95 | 并列结构 | 强 | 未变 | +| 10 | 射速决定论 | 0.703 | **主线演进** | 弱 | v0.1 并列 → v0.2 主线(性能阶梯) | +| 11 | 空战颠覆者 | 0.859 | 主线演进 | 中 | 未变 | +| 12 | 逆袭战局 | 0.85 | **并列结构** | 强 | v0.1 主线 → v0.2.1 并列(三家独立都判并列) | +| 13 | 长短智慧 | 0.533 | 并列结构 | 中 | 未变(经讨论后维持) | +| 14 | X-76 飞行器 | 0.873 | 并列结构 | 中 | 未变(经讨论后维持) | +| 15 | 空中坚盾 | 0.875 | **主线演进** | 强 | v0.1 并列 → v0.2 主线(层级承接) | + +**最终分布:5 主线 / 5 并列,平衡。** 此前 v0.1 是 3 主线 / 7 并列。 + +--- + +## 五、三家模型最终对比(基于 v0.2.1 修订版试卷) + +### 5.1 命中率总表 + +| 期次 | 修订后标准 | **M3** | **DeepSeek V4 Pro** | **MiMo v2.5 Pro** | +|---|---|---|---|---| +| ep03 | 并列 | ✓ | ✓ | ✓ | +| ep04 | 主线 | ✓ | **✗** | ✓ | +| ep05 | 并列 | ✓ | ✓ | **✗** | +| ep07 | 并列 | ✓ | ✓ | ✓ | +| ep10 | 主线 | ✓ | **✗** | **✗** | +| ep11 | 主线 | ✓ | ✓ | ✓ | +| ep12 | 并列 | ✓ | ✓ | ✓ | +| ep13 | 并列 | ✓ | ✓ | ✓ | +| ep14 | 并列 | ✓ | ✓ | ✓ | +| ep15 | 主线 | ✓ | ✓ | **✗** | +| **命中率** | | **10/10 = 100%** | 8/10 = 80% | 7/10 = 70% | +| **错的方向** | | 无 | 全部"应主线判并列",**偏保守** | 两个方向都错 | + +### 5.2 选型结论:MiniMax M3 完胜 + +理由不只在命中率,更在质量层: + +| 维度 | M3 | DeepSeek | MiMo | +|---|---|---|---| +| 命中率 | **100%** | 80% | 70% | +| 三种主线识别能力(内在概念/时间线/性能阶梯/层级承接) | **全识别** | 漏识别 ep04(示例 1 直接教过的潜艇仿生都没认出来) | 漏 2 期主线 | +| Few-shot 学习力 | 强 | **弱**(连示例 1 同型的 ep04 都漏) | 中 | +| reasoning 质量 | chapter_list + shuffle_test + 时序验证完整 | 一般 | 一般 | +| 系统偏差 | 无 | **偏保守** | 偏向不稳定 | + +**致命差距**:DeepSeek 连 Prompt 里"示例 1 直接教过的潜艇仿生"都没认出来——这说明它对 few-shot 示例的"听话度"较差,以后加再多反例也可能漏。 + +### 5.3 落地选型(冻结) + +- **生产模型**:MiniMax M3 +- **Prompt**:Prompt 2 v0.2(`ai-labeling/prompts/prompt2_narrative.md`) +- **基准卷子**:ground-truth v0.2.1(`ai-labeling/benchmark-set/ground-truth.json`) +- **回退方案**:如 M3 服务中断,DeepSeek V4 Pro 备选(虽然命中率较低,但稳定可用) + +--- + +## 六、关键经验教训(下次接力的我必读) + +### 6.1 reasoning model 的输出格式坑 + +MiniMax M3 是 reasoning model,输出格式是: +``` + +模型的内部推理过程(英文,几百字) + + +{真正的 JSON 输出} +``` + +直接 `json.loads(content)` 会失败。脚本里 `extract_json_from_response` 用正则剥掉 `...` 后再解析。**未来如果换其他 reasoning model(R1、o1 系列等)同样适用。** + +### 6.2 段内承接 vs 全片骨架(Prompt 2 v0.2 的灵魂) + +模型最容易栽的跟头是看到"递进""演进""阶梯"几个字就秒判主线演进。但这些字样常常**只在某一段内**(讲两件装备先后、某段背景的时间线等),不是全片骨架。 + +判别口诀(已写进 Prompt 2):**先看全片大章节(树干),再看段内细节(树叶)**。章节顺序能不能打乱才是主线判别的唯一依据。 + +### 6.3 ground-truth 是活的,不是写死的 + +v0.1 → v0.2(改两期)→ v0.2.1(改一期),共改三期。每次修改都因为发现 v0.1 标的判断与 v3 §1.1 自己定的判别规则有冲突,或者多家模型独立得出反向结论。 + +**纪律**:基准答案集每次升级,changelog 必须详细记录变更原因,不能"悄悄改"。未来用 pgvector 检索做动态示例集时,固化示例必须明确版本号 + 复议历史。 + +### 6.4 同一份卷子比三家 vs 优化单家 + +诱惑很大:M3 90% 后只差一题,继续调 Prompt 上 100% 应该不难。但**这样会过度适配 M3 的脾气**——同一个 Prompt 跑 DeepSeek/MiMo 反而下降。 + +实践证明:v0.2 Prompt 上 M3 100%,DeepSeek 也吃这套教学(从 70% 升 80%),MiMo 也吃(从 60% 升 70%)。**好的 Prompt 不是为某一家定制,而是把判别规则讲清楚,三家都受益。** + +### 6.5 MiniMax M2.7(Cline 的 Plan/Act 模型)写长文件不稳定 + +中段 Cline 改 run_labeling.py 时撞过: +- `write_to_file` 长内容截断 +- 改用辅助脚本生成主文件 +- 改用 base64 编码绕过 +- 触发 MiniMax 自己的 context 限制 + +**纪律**:涉及 ai-labeling/ 内文件改动,**老文件用 `replace_in_file` 局部改,新文件用 `write_to_file` 整体写**(<200 行才稳)。Prompt 和 ground-truth 这种长文件,**让制片人手工替换最稳**。 + +### 6.6 边界期是制片人 + 多家模型共审拍板 + +ep12 是个标志性案例:制片人 v0.1 标主线演进,M3/DeepSeek/MiMo 三家独立都判并列结构,经制片人复读稿后改并列。**这种"多家独立一致 + 人工复审"的双重证据机制,未来扩展示例集时是黄金流程。** + +--- + +## 七、待办池(追加到 `backlog.md`) + +继承 v3 §六的 4 条 + v4 新增 4 条: + +### 继承 v3 §六 + +- **F1. AI 打标示例集更新纪律【优先级:中,上线后启用】** + 示例集每月集中替换一次,不碎片化更新(吃 prompt 缓存红利) + +- **F2. Prompt 1(4 分类字段)+ Prompt 3(开篇钩子)撰写【优先级:中,Prompt 2 已验证通过,可启动】** + 按 Prompt 2 同样套路:Opus 写 → M3 跑基准 → 制片人审 → 锁定 + +- **F3. Decision 3 横轴量化方法落地【优先级:中】** + v2 §3 已基本定(栏目均值偏离),但还没真正算过 23 期具体数值 + +- **F4. 23 期回填确认(继承 v2 §5.5)** + ep15 空中坚盾原"空军防空"→确认改 `导弹与反导`? + ep16 启程远航装备域缺失,疑似 `海军舰船` + ep18 海上先锋·无人舰艇 → `海军舰船` + tech_tag=`无人作战` + +### v4 新增 + +- **F5. opening_hook 字段尚未跑过 AI 验证【优先级:中,等 Prompt 3】** + 10 期 ground-truth 里 opening_hook 是制片人读稿确认的,但还没让 AI 试着判过。Prompt 3 上线后跑一次,对答案看 M3 在开篇钩子上的命中率。 + +- **F6. 改 episodes schema 加 6 字段【优先级:高,但必须先切 Plan + Opus 审】** + 字段:`program_format / equipment_domain / scene_tags / tech_tags / narrative_structure / opening_hook` + 1 个 `confidence` 字段。**纪律**:Cline 不许直接 Act,必须先 Plan + 我审过迁移方案。回补方案包括 23 期已标注的回填脚本。 + +- **F7. UI 必须区分置信度三档【优先级:中,Phase 4a/4b 看板设计时落地】** + 特别警惕"AI 自评高置信但实际错判"的样本(模型不知道自己错了),UI 上要让制片人能一眼分辨"AI 草稿/制片人确认/标题推断"三档。 + +- **F8. prompt 缓存月度更新机制【优先级:低,上线后启用】** + v3 §3.7 已经写过纪律,执行时机是 AI 打标系统上线后第 1 个月起。 + +**追加方式**:你看完后告诉我,我给一段 Cline 指令把 F1-F8 这 8 条追加到 `backlog.md`(如果文件不存在就新建)。 + +--- + +## 八、纪律红线(沿用 v3 §七 + v4 增补) + +沿用: +- 改表须 Opus 审,Cline 不得自行加字段 +- AI 只出草稿、给方向,人拍板 +- 不做编导排名(团队视角走"能力地图") +- 未审核字段不上看板,编导只看已确认数据 +- AI 打标三个 prompt 独立,不合并 +- 示例集每月集中更新,不碎片化(吃缓存红利) +- Prompt 内容不让 Cline 创作——Cline 是执行者不是作者,Prompt 由 Opus 写、Cline 落文件 + +**v4 新增红线**: + +- **AI 打标实验工作区(`ai-labeling/`)与生产代码(`backend/`)严格隔离** +- **`ai-labeling/` 内改动允许 Cline 直接 Act**(沙盒,改坏重跑就是) +- **`backend/` 改动必须切 Plan + Opus 审**(生产代码,改 schema 加字段更要严) +- **长文件改动失败时,让制片人手工替换最稳**(避免 Cline 在 write_to_file 截断时套娃式 workaround) +- **改 ground-truth 必须留 changelog**(谁、何时、改了什么、为什么改) + +--- + +## 九、技术备忘(沿用 v3 §八 + 新增) + +沿用: +- 栈:React18 + Vite + AntD5 + Zustand | FastAPI + SQLModel + PG16 + pgvector +- 图表:ECharts / @ant-design/charts +- 配色固化:米色底 `#fbf9f1`、深绿主色 `#6b8e6b` +- 三色色板:红 `#c0584f` / 蓝 `#5b8db8` / 绿 `#7aa874` +- 基础线 0.6448 / 摸高线 0.8989(2026) + +v4 新增: +- AI 打标模型选型:**MiniMax M3** + `ai-labeling/prompts/prompt2_narrative.md` v0.2 +- `summarize.py` 是模型选型基准工具,未来切其他模型继续用 +- `experiments/*.json` 不进 git(.gitignore 拦截) +- `ground-truth.json` + `transcripts/*.md` 进 git(栏目核心资产) +- `requirements.txt` 锁 openai==1.55.0(不要升级) + +--- + +## 十、Git 状态 + +里程碑 commit(2026-06-11 晚): + +``` +edfb298 chore: TPS 主项目素材积累(海报 logo + 样本 md) +38f3728 feat(ai-labeling): AI 打标实验工作区初始化 + 模型选型完成 ← 今天的硬核成果 +ae04c7f chore: gitignore 忽略前端测试题图截图 +ae9581e docs: 新增 claude 协作原则文件,backlog 待办池入库 +b942907 docs: phase3_log 收尾,Task 3/4 记录归位 +``` + +`ai-labeling/` 已在 Gitea 落地,任意时点可回溯。`.env` / `experiments/` / `__pycache__/` 全部被 `.gitignore` 拦住,无敏感泄露。 + +--- + +## 十一、下次开局第一句 + +> "续接 v3 → v4。AI 打标流水线已跑通,**MiniMax M3 + Prompt 2 v0.2 在 ground-truth v0.2.1 上命中率 100%**,模型选型完成。下一步推 Prompt 1(4 分类字段)+ Prompt 3(开篇钩子),按 v4 同样的'Opus 写 Prompt → M3 跑 10 期基准 → 制片人审 → 锁定'三步走。**改 episodes schema 加 6 字段之前必须切 Plan + Opus 审**——这是宪法红线,不能直接 Act。" + +--- + +## 附:今日核心结论一句话总结 + +> AI 打标流水线从纸面落地;Prompt 2 v0.2 + ground-truth v0.2.1 经两轮复议锁定;三家模型公平对比(M3 100% / DeepSeek 80% / MiMo 70%)后选 MiniMax M3 为生产模型;Git 双 commit 推 Gitea 落库(里程碑 commit `38f3728`)。明天起可以推 Prompt 1 + Prompt 3,但改 episodes schema 必须先 Plan + Opus 审。