Skip to content

zeayii/suba-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Suba Python

Suba 是一个面向本地媒体库的字幕生成与翻译 CLI 工具。

它用于把电影、剧集、动画、课程等本地视频/音频文件自动处理成可用字幕: 先从媒体中提取音频,再通过 VAD/说话重叠检测/可选人声分离进行预处理,随后使用 Whisper 系列模型转写原文字幕,最后通过 OpenAI 或本地 Ollama 模型翻译并输出目标语言字幕文件。

简单来说,Suba 解决的是这个问题:

我有一批没有字幕、字幕质量很差、或只有外语音轨的视频,想批量生成可用的中文字幕,而不是一个文件一个文件手动处理。

主要能力

  • 扫描本地媒体目录,自动生成待处理任务。
  • 支持视频、音频输入,自动提取或复用 16kHz ASR 音频。
  • 使用 Silero VAD 切分语音片段,减少无声区干扰。
  • 支持 pyannote OSD 检测重叠说话,并可按规则启用 Sepformer 人声分离。
  • 使用 faster-whisper / Kotoba Whisper 进行语音转写。
  • 支持 OpenAI 标准请求、OpenAI Batch、Ollama 本地模型翻译。
  • 支持批量任务、缓存复用、失败重试、运行日志与终端进度面板。
  • 输出常见字幕格式,适合配合 Jellyfin、播放器或本地媒体库使用。

典型流程

本地视频/音频
  ↓
扫描目录生成 tasks.toml
  ↓
提取/复用 16kHz 音频
  ↓
VAD 切分语音
  ↓
OSD 重叠说话检测
  ↓
可选 Sepformer 人声分离
  ↓
Whisper 转写原文字幕
  ↓
OpenAI / Ollama 翻译
  ↓
写出目标字幕文件

适合谁使用

Suba 更适合以下场景:

  • 本地媒体库中有大量外语视频,需要批量生成中文字幕。
  • 希望字幕处理过程可配置、可恢复、可重复执行。
  • 希望本地完成转写,再用 OpenAI Batch 降低大批量翻译成本。
  • 希望用本地 Ollama 模型进行离线或半离线翻译实验。
  • 不满足于简单“音频转文字”,而是希望处理 VAD、重叠说话、缓存、批量任务、字幕格式输出等完整流程。

不适合的场景

  • 想要一个开箱即用的图形界面软件。
  • 只想临时转写一个短音频,不需要批量任务和配置文件。
  • 完全不想配置 Python、CUDA、ffmpeg、模型路径或翻译服务。
  • 需要商业级字幕质量保证而不做人工校对。

快速开始

推荐先生成本地配置模板和任务模板:

suba init config --output config.local.toml
suba init tasks --output tasks.local.toml

扫描媒体目录并生成任务:

suba scan --config config.local.toml --tasks-file tasks.local.toml --input-dir /path/to/media

先做配置校验和输入探测:

suba run --config config.local.toml --tasks-file tasks.local.toml --validate-only

正式执行:

suba run --config config.local.toml --tasks-file tasks.local.toml

如果使用 OpenAI Batch,可按三步执行:

suba batch-submit --config config.local.toml --tasks-file tasks.local.toml
suba batch-poll --config config.local.toml --tasks-file tasks.local.toml
suba batch-apply --config config.local.toml --tasks-file tasks.local.toml

安装

先创建并激活虚拟环境,然后安装依赖。 要求:Python 3.12.x(版本已锁定,不支持 3.13+)。

推荐(Windows 一键):

.\scripts\bootstrap.ps1

或:

.\scripts\bootstrap.bat

可选参数示例:

.\scripts\bootstrap.ps1 -Profile cu129 -ProxyUrl "http://127.0.0.1:10809"
.\scripts\bootstrap.ps1 -Profile cpu -ProxyUrl ""

本地配置建议:

  • 使用 suba init config --output config.local.toml 生成本地主配置模板。
  • 使用 suba init tasks --output tasks.local.toml 生成本地任务模板。
  • 这些文件已被 .gitignore 忽略,可安全填写本地提示词与测试任务。

Windows + CUDA:

pip install -U pip
pip install -r requirements/base.txt -r requirements/windows-cu129.txt
pip install -e .

Linux + CUDA:

pip install -r requirements/base.txt -r requirements/linux-cu129.txt
pip install -e .

CPU:

pip install -r requirements/base.txt -r requirements/cpu.txt
pip install -e .

命令

suba init config --output config.toml
suba init tasks --output tasks.toml
suba scan --config config.toml --tasks-file tasks.toml --input-dir /path/to/media
suba run --config config.toml --tasks-file tasks.toml --validate-only
suba run --config config.toml --tasks-file tasks.toml
suba batch-submit --config config.toml --tasks-file tasks.toml
suba batch-poll --config config.toml --tasks-file tasks.toml
suba batch-apply --config config.toml --tasks-file tasks.toml
suba batch-clean --config config.toml --tasks-file tasks.toml

配置设计原则

  • stages.*.typed:强校验区,未知 key 会报错。
  • stages.*.extra:扩展区,允许任意 key。
  • prompts.prompt / prompts.refinement_prompt:模板默认留空,不在仓库内置提示词;请本地填写(兼容旧字段 fix_prompt)。
  • stages.transcribe.typed.save_source_subtitle:是否保存原文字幕,默认 false
  • stages.transcribe.typed.model_profilekotoba-whisper-v2.2(默认)或 kotoba-whisper-v2.0
  • stages.transcribe.typed.without_timestamps:默认 false(建议保持,避免时间戳缺失)。
  • stages.translate.typed.api_modebatch|standard,默认 batch
  • stages.translate.provider_options.proxy_url:OpenAI 请求代理(可选,如 http://127.0.0.1:10809)。
  • context.title / context.description / context.genres:可选元数据,仅用于翻译消歧,不会改变时间戳流程。
  • process.paths.batch_work_dir:Batch 工件目录(可选)。为空时优先当前目录 suba/batch,失败回退 cache_dir/batch
  • process.batch_artifacts_policykeep|completed,默认 keepcompleted 表示成功回写后清理 Batch 中间工件。
  • process.batch_split_max_requests:Batch JSONL 拆分的最大请求数(默认 30000)。
  • process.batch_split_max_bytes_mb:Batch JSONL 拆分的最大大小 MB(默认 150)。
  • runtime 根目录规则:优先 process.paths.batch_work_dir 的上级目录;否则优先当前目录 suba,失败回退 cache_dir/suba
  • 模型目录优先级:--models-root > SUBA_MODELS_ROOT > process.paths.models_root

扫描规则(已实现)

  • 先收集视频,再按规则过滤并生成任务(视频是任务锚点)。
  • 同目录同 base 若存在 *.{任意lang}.asr.16khz.wav,优先使用该 ASR 音频作为任务输入;lang 仅用于命名,不作为可信语言来源。
  • process.overwrite_policy = "skip" 时:若同目录已存在 {base}.{target_primary}*.{format}(如目标 zh-CN 时匹配 zh*),扫描直接跳过,不写入任务。
  • 目标语言主语言为 zh 时,视频文件命中以下规则会跳过:
    • 文件名主干尾部 -C / -C1 / -UC / -UC1 ...
    • 文件名主干包含 .zh.zh-*
  • scan 默认仅扫描主视频(--scan-main-only),会过滤文件名包含 .sample. / .trailer. 的条目;可通过 --no-scan-main-only 关闭。
  • scan 仅更新任务文件(--tasks-file),不会改写主配置文件。

运行流程(当前版本)

  • 本地实时(ollamaopenai+standard): 提取 -> VAD -> OSD 门控 -> 可选 Sepformer 分离 -> 转写 -> 文件级翻译 -> 字幕写出。
    • openai+standard 默认按“整份字幕文件一次请求”翻译(不是逐句请求)。
    • ollama 支持 stages.translate.extra.mode = sentence|file:默认 sentence,可切到 file
    • ollamasentence 模式支持 stages.translate.extra.context_window(默认 5,即前 5 句上下文)。
    • openai+standard 会自动强制使用 staged 分阶段执行(忽略 process.execution_mode=per_task)。
    • ollama 优先使用 JSON Schema 约束返回结构;若服务版本不支持会自动降级为 format=json 并继续校验重试。
  • OpenAI Batch(openai+batch): 本地转写并落地 meta -> 生成 JSONL -> 提交 Batch -> 轮询 -> 回写目标字幕。
  • 视频输入:始终提取 16kHz wav 到 cache_dir
  • 音频输入:
    • .wav 只读取文件头判断采样率。
    • 其他音频通过 ffprobe 仅读元数据判断采样率。
  • 16kHz 音频直接跳过提取,否则提取到 cache_dir
  • 字幕直接写入 tasks.output_dir,不执行跨盘移动。
  • 提取并 read_audio 之后,后续 VAD/OSD/分离/转写都基于内存音频张量处理,不重复触发媒体文件 IO。

Batch 恢复与缓存

  • 路径指纹:仅使用输入路径生成指纹(不使用 size/mtime)。
  • 每个任务 meta:<cache_dir>/jobs/<fingerprint>/<media_name>.meta.json
  • Batch 状态:<batch_work_dir>/batches.json
  • meta 中会保存 cue id/t 与可选 o=1(重叠说话弱提示),用于 Batch 映射与回写。
  • standard/batch 共用 transcribe meta 复用逻辑:若指纹与转写参数签名匹配,会复用已转写结果并跳过重复转写。
  • 命令日志:<runtime_root>/logs/<timestamp>-<command>.log(控制台输出会同步写入日志文件)。
  • 日志内容包含异常堆栈(traceback)与任务耗时统计。
  • 每个任务在汇总里会输出一行阶段耗时(各阶段 + total)。
  • 终端呈现层(TTY 自动启用):顶部总览 + 中部两列(左任务列表固定宽度、右日志自适应)+ 底部按键提示。
  • UI 刷新频率固定为 250ms(4Hz),通过事件队列异步消费,不阻塞主流程执行。

OSD 门控默认参数(写在 stages.vad.extra

[stages.vad.extra]
overlap_gate_enabled = true
enable_sepformer = true
overlap_min_count = 3
overlap_min_total_ms = 3000
overlap_min_ratio = 0.03
osd_onset = 0.8104268538848918
osd_offset = 0.4806866463041527
osd_min_duration_on = 0.05537587440407595
osd_min_duration_off = 0.09791355693027545

并发与资源策略(已实现)

  • 任务级并发由 process.max_workers 控制。
  • process.execution_mode
    • per_task:按任务完整执行(默认)。
    • staged:按 preprocess -> transcribe -> translate/export 分阶段队列执行。
  • 失败重试与超时策略:
    • process.retry_count:任务失败后重试次数(默认 0)。
    • process.retry_backoff_seconds:重试退避基数秒数(默认 1.0)。
    • process.task_timeout_seconds:任务软超时阈值(默认 0 表示关闭)。
  • GPU 阶段采用互斥保护:
    • 转写阶段默认串行(避免显存竞争)。
    • 本地 Ollama 翻译默认与转写互斥(共享 GPU 门)。
    • Sepformer 分离可配置 stages.vad.extra.separation_device=cpu|gpu|auto
  • OpenAI 翻译默认不占本机 GPU,可与其他任务并发。
  • 可选设备参数(均在 extra):
    • stages.transcribe.extra.device = "auto|cpu|gpu"
    • stages.translate.extra.device = "auto|cpu|gpu"
    • stages.vad.extra.separation_device = "auto|cpu|gpu"
  • 转写透传参数(在 stages.transcribe.extra):
    • model_options:透传给 WhisperModel(...)
    • transcribe_options:透传给 model.transcribe(...)
  • 润色触发参数(在 stages.translate.extra):
    • request_timeout_seconds:翻译请求超时秒数(默认 3600
    • enable_refinement:是否启用润色逻辑(默认 true
    • refinement_max_len:超过该长度触发润色(默认 60
    • refinement_length_ratio:翻译长度超过原文长度倍数触发(默认 2.2
    • refinement_trigger_patterns:命中任一正则触发润色
    • json_retry_count:文件级 JSON 解析失败时的额外重试次数(默认 2
  • staged 模式可选并发参数(均在 extra):
    • stages.vad.extra.preprocess_parallelism
    • stages.transcribe.extra.parallelism
    • stages.translate.extra.parallelism