"""翻译服务:NLLB-200,英译中。 通过 model_manager 加载,确保 ASR 已卸载、翻译器独占显存,从而可用大 batch_size。 按字幕条目批量翻译,保留索引对应。 """ from __future__ import annotations import logging from ..config import get_settings from .model_manager import get_model_manager from .types import Subtitle logger = logging.getLogger("audio2text.translate") def translate(subtitles: list[Subtitle]) -> list[str]: """批量翻译英文字幕为中文。 Args: subtitles: 断句后的英文字幕条目 Returns: list[str],与 subtitles 等长、顺序对应的中文译文。 单条翻译失败时该位置回退为原英文。 """ if not subtitles: return [] s = get_settings().translation pipe = get_model_manager().get_translator() batch = s.batch_size max_len = s.max_length # 取纯文本(去掉折行),避免翻译把换行符当语义 texts = [sub.text.replace("\n", " ").strip() for sub in subtitles] logger.debug("开始翻译 %d 条字幕(batch_size=%d)...", len(texts), batch) results: list[str] = [] for i in range(0, len(texts), batch): chunk = texts[i:i + batch] try: out = pipe(chunk, max_length=max_len) for item in out: # pipeline 返回 [{"translation_text": "..."}] results.append(item.get("translation_text", "").strip()) except Exception as exc: # pragma: no cover logger.warning("第 %d-%d 批翻译失败,逐条重试:%s", i, i + len(chunk), exc) for t in chunk: try: out = pipe([t], max_length=max_len) results.append(out[0].get("translation_text", "").strip()) except Exception: results.append(t) # 回退原文 if (i // batch + 1) % 5 == 0: logger.debug("已翻译 %d/%d 条。", min(i + len(chunk), len(texts)), len(texts)) logger.debug("翻译完成:%d 条。", len(results)) return results