# 本地视频语音转写 4 小时长视频优化编码方案 V001 创建人员:`dev.developer.project` 文件职责:冻结长视频有界分块、时间轴合并、资源验收和失败清理的最小实现方案。 管理规范/模板:`../../../dev-doc/编码规范.md`;`../../../dev-doc/开发审计规范.md`;`../../../../common/dev-doc/编码规范.md`。 引用文件:`../../../ai-media-processor/draft/本地视频语音转写_4小时长视频性能与资源优化需求_v0.1.md`;`../../../dev/project-dev/transcribe_media.py`;`../../../dev/project-dev/test/test_transcribe_media.py`;`../本地视频语音转写工具.md`。 记录方式:重型性能优化编码方案;方案审核通过后按本版本实现,变化另建后继版本。 ## 1. 事项与边界 - 事项:`DEV-PROJECT-INFO-LOCAL-MEDIA-TRANSCRIBE-LONG-VIDEO-OPT-20260801-001`。 - 目标:保持命令、模型和四文件合同不变,使约 4 小时视频不再把完整波形、VAD 拼接结果和频谱一次装入 Python 内存。 - 只修改 `dev/project-dev/transcribe_media.py`、对应测试和使用说明;不新增模型、CPU 降级、批处理、断点续跑、服务或数据库。 - 原视频只读;完整 FLAC 仍为正式候选输出;失败统一删除暂存目录,四个正式文件只在全部成功后提交。 ## 2. 模块和接口 现有公开 CLI 与 `transcribe_video(video_path, output_dir, language, ...)` 不变,只增加内部函数: 1. `_probe_audio_duration`:对已生成的完整 FLAC 获取有限、正数时长。 2. `_plan_audio_chunks`:当时长大于 `1200 s` 时生成顺序核心区间;核心长度 `1200 s`,两侧重叠 `5 s`,首尾裁到 `[0,duration]`。 3. `_extract_audio_chunk`:从完整 FLAC 生成唯一临时块;固定 16 kHz、单声道 FLAC、`-n`,失败显式停止。 4. `_collect_chunked_transcript`:复用同一模型逐块转写;每块结束后在 `finally` 删除临时块。 5. `_project_chunk_segments`:块内时间加音频块全局起点;按分段中点落入对应核心 `[core_start, core_end)`,仅末块允许中点等于总时长;排序后输出全局分段。 短视频 `duration <= 1200 s` 继续调用现有 `_collect_transcript(model, full_flac, language)`,不创建音频块。 ## 3. 语言与模型合同 - `large-v3`、`device=cuda`、`compute_type=float16`、`vad_filter=True` 不变。 - 模型在完整 FLAC 生成后只加载一次。 - 显式语言传给所有块;未指定语言时首块不传语言,保存其检测语言和概率,后续块固定复用检测语言。 - 任一块失败不走 CPU、其他模型或参数降级。 ## 4. 时间轴与去重 对第 `i` 块: - `core_start = i * 1200` - `core_end = min(duration, core_start + 1200)` - `audio_start = max(0, core_start - 5)` - `audio_end = min(duration, core_end + 5)` - `global_start/end = audio_start + local_start/end` - `midpoint = (global_start + global_end) / 2` 只保留中点属于本块核心区间的分段;这是一条唯一归属规则,不增加模糊文本去重或重写识别结果。最终分段按 `(start,end,text)` 升序,TXT/SRT/JSON 继续由同一个结果对象生成。 ## 5. 资源与失败安全 - 暂存目录同时包含完整 FLAC 和最多一个固定名临时块;临时块写完、转写后立即删除。 - 进度输出 `正在转写分块 i/n` 并立即刷新,便于资源采样关联块号。 - 中断、FFmpeg 或 GPU 失败由现有外层 `finally` 清理整个暂存目录;块函数另有局部 `finally`,确保当前块先删除。 - 不在 Python 中读取完整 FLAC 字节,不保存完整波形或频谱。 - 正式输出冲突检查、相邻暂存、四文件提交和回滚逻辑不变。 ## 6. 测试与验收 ### 6.1 离线测试 - 20 分钟阈值两侧;4 小时生成 12 个核心块。 - 首块、内部块、末块的 5 秒重叠和裁边。 - 边界中点唯一归属、全局偏移、排序和无重复序号。 - 模型只加载一次;未指定语言时首块检测、后续复用。 - 任意块失败时临时块和暂存目录清理。 - 现有无音轨、FFmpeg 失败、输出冲突和禁止 CPU 降级回归。 ### 6.2 真实回归 1. 使用原 `1193.64 s` 视频走未分块路径,核对 `705` 段、四文件对应、源哈希不变。 2. 在专属临时目录用只读源循环复用生成约 `14400 s` 测试副本。 3. 完整运行采样 Python 与 FFmpeg 合计工作集、RTX 3090 显存、当前块号和临时块大小。 4. 验证 exit `0`、耗时 `<=100 min`、RAM `<=12 GB`、GPU `<10 GB`、临时块 `<500 MB`、前后三块峰值差、FLAC 时长、文本非空、SRT/JSON 可解析和全部 20 分钟边界。 5. 保留 4 小时媒体与输出供 `case_analysis.media_processor` 只读复核。 ## 7. 重跑与恢复 - 不实现断点续跑;失败后换新输出目录整任务重跑。 - 已存在任一正式输出即拒绝,不复用半成品。 - 4 小时验收副本和结果只位于 `dev/project-dev/tmp/DEV-PROJECT-INFO-LOCAL-MEDIA-TRANSCRIBE-LONG-VIDEO-OPT-20260801-001/`。 ## 8. 高风险点与门禁 - 边界中点比较错误会导致重复或漏段,必须由合成分段单元测试冻结。 - 若未在每块 `finally` 删除临时块,会违反 500 MB 和单块上限。 - 若后续块仍传 `language=None`,会造成语言漂移;测试必须检查调用参数。 - 若短视频错误进入分块,19:54 基线会漂移;真实回归必须证明仍走单次路径。 - 方案审核未通过前不修改代码;实现后按需求执行完整资源验收,再提交实现审核或请求方验收。 ## 9. 当前状态 `PENDING_INDEPENDENT_DESIGN_REVIEW`