Initial commit: audio2text 双语字幕生成服务
- 音频/视频转双语(英/中)SRT 字幕,Docker 容器化,CPU 开发/GPU 生产同一份代码 - faster-whisper ASR(词级时间戳) + 断句时间戳重算 + NLLB 翻译(模型不共驻) - 分片上传(断点续传) + SQLite 持久化 + 主页/历史/日志页面 - 历史页文件名搜索;缓存定时清理(默认保留7天,可配置) - 双 Dockerfile(cpu/gpu) + setup/start/stop 脚本
This commit is contained in:
65
app/services/asr_service.py
Normal file
65
app/services/asr_service.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""语音识别服务:faster-whisper,输出带词级时间戳的 segments。
|
||||
|
||||
CPU dev: tiny.en + int8;GPU prod: large-v3-turbo + float16。同一份代码。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from ..config import get_settings
|
||||
from .model_manager import get_model_manager
|
||||
from .types import Segment, Word
|
||||
|
||||
logger = logging.getLogger("audio2text.asr")
|
||||
|
||||
|
||||
def transcribe(wav_path: Path) -> list[Segment]:
|
||||
"""转写 wav,返回 segments(含词级时间戳)。
|
||||
|
||||
Args:
|
||||
wav_path: 16kHz mono PCM wav
|
||||
|
||||
Returns:
|
||||
list[Segment],每个 Segment 带词级 words(若 word_timestamps 启用)。
|
||||
"""
|
||||
s = get_settings().asr
|
||||
if not wav_path.is_file():
|
||||
raise FileNotFoundError(f"音频不存在:{wav_path}")
|
||||
|
||||
model = get_model_manager().get_asr()
|
||||
logger.debug("开始转写 %s(model=%s language=%s)", wav_path.name, s.model, s.language)
|
||||
|
||||
segments_gen, info = model.transcribe(
|
||||
str(wav_path),
|
||||
language=s.language,
|
||||
word_timestamps=s.word_timestamps,
|
||||
vad_filter=s.vad_filter,
|
||||
beam_size=5,
|
||||
)
|
||||
logger.debug(
|
||||
"音频时长 %.1fs,检测语言=%s(置信度 %.2f)",
|
||||
info.duration, info.language, info.language_probability,
|
||||
)
|
||||
|
||||
segments: list[Segment] = []
|
||||
for seg in segments_gen:
|
||||
words: list[Word] = []
|
||||
if s.word_timestamps and getattr(seg, "words", None):
|
||||
for w in seg.words:
|
||||
words.append(Word(
|
||||
text=w.word.strip(),
|
||||
start=float(w.start),
|
||||
end=float(w.end),
|
||||
probability=float(getattr(w, "probability", 1.0)),
|
||||
))
|
||||
segments.append(Segment(
|
||||
text=seg.text.strip(),
|
||||
start=float(seg.start),
|
||||
end=float(seg.end),
|
||||
words=words,
|
||||
))
|
||||
logger.debug("转写完成:%d 段,%d 词。",
|
||||
len(segments), sum(len(s.words) for s in segments))
|
||||
return segments
|
||||
Reference in New Issue
Block a user