Files
subtitle-studio/ARCHITECTURE.md
T
hmo 7de5ab3902 subtitle-studio: 字幕生成系统
- 选择文件夹/单文件 → SenseVoice 转录 → LLM 修正 → 多路线翻译 → 双语 SRT
- 路线:直译中文 / 英转中 / 仅转录
- 并发流水线:转录(可调) + LLM 并发(可调),降噪拆锁并发
- 断点续跑:.subtitle-work/ 中间产物,三阶段独立续跑 + 翻译段级续跑
- 去重:history 跟随视频文件夹,防重复任务保护
- 实时进度:SSE 推送 + 耗时显示 + 子任务状态 + 重新生成按钮
- 时间戳调优:VAD silence_schedule + noisereduce 降噪 + 完整性校验
2026-08-16 20:17:14 +08:00

125 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 字幕生成系统 subtitle-studio — 架构设计
> 设计日期:2026-08-15 架构:纯 Windows 本地,自包含 | 目标:文件夹/单文件 → 多路线字幕
## 1. 总体架构
```
┌─────────────────────────── Windows 本机 ───────────────────────────┐
│ │
│ [Web 前端] 浏览器页面 │
│ - 选择文件夹 / 单个文件 │
│ - 选择翻译路线(直译 / 英转中 / 仅转录) │
│ - 实时查看任务进度(SSE 推送) │
│ - 已完成视频列表 + 字幕文件下载/打开 │
│ │ HTTP/SSE │
│ [FastAPI 后端] :8788 │
│ - 任务管理器(队列 + 并发控制,默认 1 任务串行防 GPU 争抢) │
│ - 进度状态机:pending → transcribing → fixing → translating → srt → done │
│ │ │
│ [管道核心] subsudio.pipeline │
│ - transcribe.py SenseVoice + fsmn-vadGPU16kHz wav
│ - fix.py LLM 分块并发修正日文/韩文转录 │
│ - translate.py LLM 全文翻译(路线1 直译 / 路线2 英转中) │
│ - srt.py 生成 .ja.zh.srt / .zh.srt / .zh.en.srt │
│ │ │
│ [运行时] py312_cudaconda + OCG Router (192.168.1.246:19878) │
└─────────────────────────────────────────────────────────────────────┘
```
## 2. 设计决策
### D1. 复用 py312_cuda 环境,不新建 venv
- 转录需要 faster-whisper/funasr/torch-CUDA,已全部就绪于 `D:\ProgramData\anaconda3\envs\py312_cuda`
- 后端 FastAPI/uvicorn 也装这个环境(检查缺包再补)
- 避免重复装 CUDA 依赖(虚拟环境铁律:不污染系统,但可复用专用环境)
### D2. LLM 走 OCG Router(本地中转,自动选 key)
- base_url `http://192.168.1.246:19878/v1`apiKey `ocg-router-local`
- 模型 `deepseek-v4-flash`1M 上下文,全文一次请求)
- 关键经验:**不指定 max_tokens**(推理模型会烧光截断);全文翻译 1746 段 105 秒
### D3. 翻译路线(用户可选)
| 路线 | 流程 | 产物 |
|------|------|------|
| direct (默认) | 转录 → LLM修正 → 直译中文 | .ja.zh.srt + .zh.srt |
| via_en | 转录 → LLM修正 → 英转中 | .r2.zh.en.srt + .r2.zh.srt |
| transcribe_only | 只转录,不翻译 | _transcript.json |
### D4. 任务队列串行执行
- GPU 转录是重资源操作,一次只跑 1 个任务
- 翻译阶段可并发分块(fix 用 4 worker
- 进度通过 SSE 实时推送到前端
### D5. 输出目录
- 默认:字幕文件生成到**视频同目录**(PotPlayer 自动加载)
- 同时复制一份到 `output/<task_id>/` 便于管理/下载
## 3. 目录布局
```
subtitle-studio/
├── src/substudio/
│ ├── __init__.py
│ ├── main.py # FastAPI 入口(uvicorn
│ ├── taskmanager.py # 任务队列 + 状态机 + SSE 广播
│ ├── pipeline/
│ │ ├── __init__.py
│ │ ├── transcribe.py # SenseVoice 转录(复用技能逻辑)
│ │ ├── fix.py # LLM 分块并发修正
│ │ ├── translate.py # LLM 全文翻译(路线选择)
│ │ └── srt.py # SRT 生成
│ ├── config.py # 路径/模型/API 配置
│ └── llm.py # OCG Router 客户端(流式兼容)
├── templates/index.html # 前端页面
├── static/app.js # 前端逻辑
├── output/ # 任务输出
├── scripts/start.bat # 启动脚本
└── README.md
```
## 4. 进度状态机
```
pending → transcribing → fixing → translating → srt → done
└────── error(失败即停,可重试)
```
每阶段有 `progress`0-100)和 `message`(如 "转录中 320/1746 段"
SSE 事件:`task_update` 推送 `{task_id, status, progress, message}`
## 5. 关键技术点
### 5.1 转录(复用已验证逻辑)
- ffmpeg 提取 16kHz 单声道 wav
- **降噪(默认开启)**noisereduce 频谱门控,prop_decrease=0.70.9 过度会字间隙),实测 RMS 降 64%,句子边界更清晰
- **fsmn-vad 切段(时间戳精准关键)**:
- `max_single_segment_time` 参数**无效**(实测)
- 必须传自定义 `silence_schedule``[(8000,500),(12000,300),(20000,200),(inf,100)]`
- 效果:段长从默认 15.67s → 4.64s 上限,平均 1.59s,时间戳严重错位修复
- 根因:默认 schedule 产生长段 → 只能按字符比例估算句内时间 → 字幕与说话时间对不上
- SenseVoiceSmall 逐段转录,rich_transcription_postprocess 清理
- 输出句子级时间戳 JSON
### 5.2 修正(分块并发)
- 按字符量分块(块边界=段边界,不切断句子)
- 每块一个 worker 进程并发(4 worker
- prompt:结合上下文修正 ASR 错误,保留 [idx]
### 5.3 翻译(全文一次请求)
- **不指定 max_tokens**1M 上下文)
- 全文 30K 字符一次请求,1746 段 105 秒
- 输出 [idx] 行式解析
### 5.4 OCG Router 兼容
- 兼容 SSE 流式返回(data: {...} 解析)
- 有限重试(3 次退避,不疯狂重试)
- 失败即停 + 进度保存(断点续传)
## 6. 安全与资源
- 无 Docker 操作,纯本地文件处理
- 只读视频,写入同目录 SRT + output/
- 一次一个任务(GPU 转录),翻译并发仅限 LLM API
- 不碰系统环境(复用 py312_cuda 专用环境)