feat: 进度条颗粒度优化 — ASR/翻译按批次细分进度
原来进度只在阶段结束时跳一次(ASR 5%→55%、翻译 60%→98%),长视频时 进度条卡住不动。现在每完成一个批次就更新进度。 ASR(asr_service.py): - 用 info.duration_after_vad 算总 chunk 数(ceil(时长/30s)) - 消费生成器时按 seg.end 跨 30s chunk 边界回调 on_progress - 30s 粒度自然节流,长视频约几十次更新 翻译(translate_service.py): - _translate_sorted / _translate_sequential 每批完成后回调 on_progress(done, total) - 批数循环前已知(len(batches)),每批都回调 pipeline.py: - asr_phase / translate_phase 定义闭包回调,把 (current,total) 占比映射到 对应进度区间(ASR 5%→55%、翻译 60%→98%),调 _set_status 写 DB(DEBUG 级) 验证(test/55.mp4, 640 条字幕): - ASR: 5%→19.9%→23.8%→33.7%→48.6%→55% 平滑增长 ✅ - 翻译: 20 批,65.3%→68.9%→74.2%→79.6%→84.9%→90.2%→93.8%→98% ✅ - 翻译卡在 60% 的 ~50s 是模型加载时间(卸载ASR+加载NLLB),属调度器层面
This commit is contained in:
@@ -14,6 +14,7 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Callable
|
||||
|
||||
from ..config import get_settings
|
||||
from .model_manager import get_model_manager
|
||||
@@ -25,11 +26,15 @@ logger = logging.getLogger("audio2text.translate")
|
||||
_TOKENS_PER_WORD = 1.2
|
||||
|
||||
|
||||
def translate(subtitles: list[Subtitle]) -> list[str]:
|
||||
def translate(
|
||||
subtitles: list[Subtitle],
|
||||
on_progress: Callable[[int, int], None] | None = None,
|
||||
) -> list[str]:
|
||||
"""批量翻译英文字幕为中文。
|
||||
|
||||
Args:
|
||||
subtitles: 断句后的英文字幕条目(按时间顺序)
|
||||
on_progress: 可选进度回调 (done_count, total_count),每批完成时调一次。
|
||||
|
||||
Returns:
|
||||
list[str],与 subtitles 等长、顺序对应的中文译文。
|
||||
@@ -52,9 +57,9 @@ def translate(subtitles: list[Subtitle]) -> list[str]:
|
||||
sort_by_length = False
|
||||
|
||||
if sort_by_length:
|
||||
results = _translate_sorted(pipe, texts, batch_size, max_len)
|
||||
results = _translate_sorted(pipe, texts, batch_size, max_len, on_progress)
|
||||
else:
|
||||
results = _translate_sequential(pipe, texts, batch_size, max_len)
|
||||
results = _translate_sequential(pipe, texts, batch_size, max_len, on_progress)
|
||||
|
||||
logger.debug("翻译完成:%d 条。", len(results))
|
||||
return results
|
||||
@@ -64,6 +69,7 @@ def translate(subtitles: list[Subtitle]) -> list[str]:
|
||||
|
||||
def _translate_sorted(
|
||||
pipe, texts: list[str], batch_size: int, max_len: int,
|
||||
on_progress: Callable[[int, int], None] | None = None,
|
||||
) -> list[str]:
|
||||
"""按长度排序后分批翻译,翻译完按原序散回。
|
||||
|
||||
@@ -120,7 +126,9 @@ def _translate_sorted(
|
||||
for idx, zh in zip(orig_indices, translated):
|
||||
results[idx] = zh
|
||||
done += len(batch)
|
||||
if (done // batch_size + 1) % 5 == 0:
|
||||
if on_progress is not None:
|
||||
on_progress(done, n)
|
||||
elif (done // batch_size + 1) % 5 == 0:
|
||||
logger.debug("已翻译 %d/%d 条。", done, n)
|
||||
|
||||
# None(理论不会发生,_translate_batch 保证返回等长)→ 回退原文
|
||||
@@ -142,15 +150,20 @@ def _estimate_sequential_padding(texts: list[str], batch_size: int) -> int:
|
||||
|
||||
def _translate_sequential(
|
||||
pipe, texts: list[str], batch_size: int, max_len: int,
|
||||
on_progress: Callable[[int, int], None] | None = None,
|
||||
) -> list[str]:
|
||||
"""按原序分批翻译(旧行为,便于 A/B 对比)。"""
|
||||
results: list[str] = []
|
||||
for i in range(0, len(texts), batch_size):
|
||||
n = len(texts)
|
||||
for i in range(0, n, batch_size):
|
||||
chunk = texts[i:i + batch_size]
|
||||
translated = _translate_batch(pipe, chunk, max_len)
|
||||
results.extend(translated)
|
||||
if (i // batch_size + 1) % 5 == 0:
|
||||
logger.debug("已翻译 %d/%d 条。", min(i + len(chunk), len(texts)), len(texts))
|
||||
done = min(i + len(chunk), n)
|
||||
if on_progress is not None:
|
||||
on_progress(done, n)
|
||||
elif (i // batch_size + 1) % 5 == 0:
|
||||
logger.debug("已翻译 %d/%d 条。", done, n)
|
||||
return results
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user