# Doco - TPS 工作台 · 终版文稿生成子模块

> 央视《军事科技》栏目 - 终版文稿自动融合流水线

## 项目状态

**✅ 20期全部出稿完成，流水线验证通过。** 16/16批量跑零失败（847分钟）。下一步：制片人逐期核验分段标签 → 带成品回归 TPS 主项目知识库。

---

## 功能概述

《军事科技》每期节目播出后，需要产出一份最接近实际播出的终版文稿。过去靠人工核对，**单期 4-6 小时**。

Doco 把**同一期节目**的三个文本来源自动融合，产出终版文稿：

| 文本来源 | 说明 | 权威范围 |
|---|---|---|
| **A稿**（编导定稿） | 编导剧本的书面结构与分段 | 段落骨架、专业术语规范写法 |
| **B稿v2**（屏幕字幕 OCR） | 视频画面中"黑底白字"字幕的OCR识别结果 | 屏幕术语/型号/番号（≈A稿并列权威） |
| **ASR**（口语转写） | 音轨经讯飞转写的口语实录 | 实际语音、语气、临场措辞 |

**铁律**：正文**汉字零改**——所有正文内容100%来自B稿v2，AI只负责纠错OCR错字、语义对齐分段、按语义插入标点，绝不改任何一个汉字。

最终产出两个**内容一致、形态不同**的交付物：

| 交付物 | 给谁 | 形态 |
|---|---|---|
| **融合B稿** | 爱德华（字幕/片段定位） | 碎句 + 密集字幕级时间戳 `[XmYs] 文本` |
| **融合A稿** | 编导存档 | 公文格式 docx，保留【导视】【主持人N】【解说N】【专家N】【隔断】分段 |

一致性约束：融合A稿**由融合B稿生成**（按A稿分段归拢 + 套格式），不是事后比对硬凑。

---

## 六阶段流水线架构

```
A稿 docx ──► ① 术语提取(C1) ──► 本期热词表
                                      │
视频 mp4 ──► ② 音频分离 ──► 讯飞ASR(C2) ──► ASR文本（带时间戳）
（黑底白字+         │                      │
 干净人声）     抽帧+OCR(P1)──► 文本去重(P2)──► B稿v2（碎句+时间戳）
                                                       │
                                         B稿v2 ⊕ ASR ──► ③ 交叉复审(C3) ──► 融合B稿
                                                                                      │
                                         融合B稿 + A稿骨架 ──► ④ 语义对齐(C4) ──► 融合A稿.docx
```

| 阶段 | 子命令 | 做什么 | 产物 |
|---|---|---|---|
| **P1** | `doco split` | ffmpeg抽帧 + OCR识别屏幕字幕 | 关键帧、音频WAV |
| **P2** | （模板脚本自动） | 字幕文本去重、格式化 | B稿v2.txt（约700-870行） |
| **C1** | `doco terms` | 从A稿提取专有名词 → 累积词典 → 热词表 | 本期热词表（给ASR用） |
| **C2** | `doco asr` | 音频分离 → 讯飞ASR转写 | asr_v2_timed.txt |
| **C3** | `doco fuse` | B稿⊕ASR 交叉复审，AI纠错 | 融合B稿.txt + fusion_review.csv |
| **C4** | `doco compose` | 按A稿分段骨架语义对齐 → 套公文格式 | 融合A稿.docx + c4_alignment.csv |

---

## 系统依赖

### ffmpeg（必须）

**Windows 用户：**
1. 从 https://www.gyan.dev/ffmpeg/builds/ 下载 ffmpeg（建议用 essentials 版本）
2. 解压到本地目录（如 `C:\ffmpeg`）
3. 把 `C:\ffmpeg\bin` 加入系统 PATH
4. 打开 cmd，验证：`ffmpeg -version`

**Mac / Linux 用户：**
```bash
# Mac
brew install ffmpeg

# Linux
apt install ffmpeg
```

### Python >= 3.12

---

## 安装

```bash
# 1. 进入 doco 目录
cd doco

# 2. 安装（可编辑模式）
pip install -e .

# 3. 配置凭证（见下节）
cp .env.example .env
```

## 凭证配置

在 `doco/.env` 中配置以下变量（**已在 .gitignore 中，不会入库**）：

| 变量名 | 用途 |
|---|---|
| `LLM_API_KEY` | LLM融合层API密钥（当前用小米 MiMo 2.5 Pro） |
| `LLM_BASE_URL` | LLM API地址（OpenAI兼容端点） |
| `LLM_MODEL` | 模型名称（如 `mimo-v2.5-pro`） |
| `XFYUN_APP_ID` | 讯飞开放平台 APP ID |
| `XFYUN_SECRET_KEY` | 讯飞开放平台 SECRET KEY |

> ⚠️ 讯飞要用「录音文件转写**标准版**」，不要用"大模型版"（免费包阉割 `language` 参数，会报误导性错误）。

---

## 使用方式

### 一键全流程（推荐）

```bash
doco run \
  --episode-id ep001_20260612_fangkong_fandao \
  --a-script programs/ep001_20260612_fangkong_fandao/source/a_draft.docx \
  --input-video programs/ep001_20260612_fangkong_fandao/source/video.mp4
```

串联 P1→P2→C1→C2→C3→C4 六个阶段，中间产物自动落盘，各阶段可断点续跑（已有产物自动跳过）。

**可选参数：**
- `--skip-p1`：跳过P1/P2（已有B稿v2时使用）
- `--batch-size 25`：C4对齐每批行数（默认25，可调）

> ⚠️ C4 开始前要求骨架文件已存在，需**先手动**运行 `doco skeleton` 并人工核验：
> ```bash
> doco skeleton --episode-id <id> --a-script <a_draft.docx>
> # 检查输出的骨架预览表，确认无误后再跑 doco run
> ```

### 各子命令（可单独运行）

```bash
# P1: 视频拆分（抽帧 + OCR + 音频分离）
doco split --episode-id <id> --input-video <mp4> --output-dir <dir>

# C1: 术语提取
doco terms --episode-id <id> --a-script <docx>

# C2: 讯飞ASR转写
doco asr --episode-id <id> --input-video <mp4> --output-dir <dir>

# C3: 交叉复审融合
doco fuse --episode-id <id> [--batch-size 35]

# C4: 对齐出稿
doco compose --episode-id <id> [--batch-size 25]
```

> ⚠️ `--output-dir` 务必传**绝对路径**，否则产物会落到当前工作目录，与 doco 产物分家。

---

## 目录结构

```
doco/
├── src/doco/
│   ├── __init__.py
│   ├── cli.py              # CLI 入口（doco run/split/terms/asr/fuse/skeleton/compose）
│   ├── video_split.py      # P1: 抽帧 + 音频分离（ffmpeg）
│   ├── llm.py              # LLM 统一客户端（OpenAI兼容）
│   ├── term_extract.py     # C1: 规则层+AI层术语提取
│   ├── asr_adapter.py      # C2: 讯飞ASR适配层
│   ├── fusion_review.py    # C3: B稿⊕ASR交叉复审
│   ├── fusion_align.py     # C4: A稿骨架抽取+语义对齐+出稿
│   └── templates/          # P1/P2 模板脚本
│       ├── stage_a_extract_ocr.py   # P1 抽帧+OCR
│       └── stage_b_dedup_output.py  # P2 文本去重
├── programs/               # 每期节目产物（按 episode_id 分目录）
│   └── <episode_id>/
│       ├── source/         # 输入（video.mp4 + a_draft.docx）
│       ├── B稿_v2.txt      # P2 产出的OCR字幕文本
│       ├── audio_16k.wav   # 分离的音频（16kHz/单声道/16bit）
│       ├── asr_v2_timed.txt     # ASR转写结果（带时间戳）
│       ├── <id>_a_skeleton.json # A稿分段骨架
│       ├── 融合B稿.txt          # C3 产出
│       ├── fusion_review.csv    # C3 复审留痕
│       ├── 融合A稿.docx         # C4 最终交付物
│       └── c4_alignment.csv     # C4 对齐留痕
├── data/
│   └── term_dict.json      # 累积术语词典（逐期更新）
├── deliverables/           # 已完成的融合A稿展示
├── note/                   # 设计文档、PRD、决策记录
├── tests/                  # 测试
├── CLAUDE.md               # 项目协作主控文件（交接、决策、状态）
├── pyproject.toml
└── .env.example            # 凭证模板
```

---

## 设计原则

- **汉字零改**：正文100%来自B稿v2，AI只做OCR纠错+语义对齐+标点插入，绝不改任何一个汉字。`strip_punct()`硬校验守门。
- **有序无阻塞**：全自动产出，拿不准的地方全部进 `fusion_review.csv` 留痕，绝不卡出稿。
- **各阶段解耦**：中间产物落缓存，可断点续跑，可单独重跑，失败不影响已完成阶段。
- **专名铁律**：厂名/型号/番号/国名/人名/机构名，B稿与ASR同音异写时**一律以B稿为准**，零容忍采ASR。
- **OCR漏字不补**：缺的字是真实信息丢失，不让LLM补词（LLM补词=猜词=破红线）。

---

## 相关文档

- **项目协作主控文件**：`CLAUDE.md`（状态、交接、关键决策，新接手者首选阅读）
- **子项目Brief**：`note/Doco子项目_Brief.md`（红线、技术栈、出入口接口）
- **PRD**：`note/PRD_doco_文稿整理子项目_v2.md`（需求规格、方案选型）
- **P3设计稿**：`note/doco_P3_设计稿.md`（三方融合架构设计）
- **快照与决策记录**：`note/` 目录下其他文件

---

## 技术栈

- **语言**：Python ≥ 3.12
- **LLM**：小米 MiMo 2.5 Pro（OpenAI兼容端点，`openai` SDK）
- **OCR**：本地 Ollama + DeepSeek-OCR 模型
- **ASR**：讯飞开放平台 录音文件转写（标准版）
- **视频处理**：ffmpeg（subprocess调用）
- **文档生成**：python-docx
- **CLI框架**：Click