feat: subtitle-ocr 进度日志增加预计剩余时间 ETA

- 进度日志追加"预计剩余 X分Y秒"(剩余帧/当前速度,速度未知时不显示)
This commit is contained in:
2026-08-23 16:25:18 +08:00
parent 5688f38d62
commit 87abde33d4
2 changed files with 53 additions and 3 deletions
+27 -3
View File
@@ -59,6 +59,28 @@ def _load_partial(output_dir: Path) -> dict[int, str]:
result[int(item["frame"])] = str(item["text"])
return result
def _format_eta(seconds: float) -> str:
"""把剩余秒数格式化为可读的预计完成时间(如 34分13秒 / 2小时05分)。"""
total = max(0, int(seconds))
hours, remainder = divmod(total, 3600)
minutes, secs = divmod(remainder, 60)
if hours:
return f"{hours}小时{minutes:02d}"
if minutes:
return f"{minutes}{secs:02d}"
return f"{secs}"
def _eta_suffix(done: int, total: int, rate: float) -> str:
"""根据当前处理速度计算剩余时间后缀(供进度日志追加)。
剩余时间 = 剩余帧数 / 当前速度;速度为 0(刚开始或耗时不可测)时
返回空串,进度提示不显示 ETA。
"""
if rate <= 0:
return ""
return f", 预计剩余 {_format_eta((total - done) / rate)}"
# 默认垃圾词:无文字帧的模型输出可能反复出现这些词。
def _sampling_interval(manifest: list[dict], default: float) -> float:
"""从帧清单时间轴推导采样间隔(相邻帧时间差的中位数)。
@@ -206,12 +228,14 @@ def invoke(request: InvokeRequest) -> InvokeResponse:
if pending:
# 进度日志:打印已识别帧数、总数、平均处理速度(帧/s)、最近窗口平均
# 单帧耗时当前线程数——便于判断多线程是否因单帧处理过慢而未启用
# (窗口平均响应 ≥ fast_threshold 时自适应池不会扩容)。
# 单帧耗时当前线程数与**预计剩余完成时间**(剩余帧/当前速度)——
# 便于判断多线程是否因单帧处理过慢而未启用(窗口平均响应 ≥
# fast_threshold 时自适应池不会扩容)以及整体还需要多久。
def log_progress(done: int, total: int, rate: float, avg_time: float, workers: int) -> None:
logger.info(
"OCR 进度 %d/%d 帧 (%.1f 帧/s, 平均 %.2fs/帧, 线程 %d/%d)",
"OCR 进度 %d/%d 帧 (%.1f 帧/s, 平均 %.2fs/帧, 线程 %d/%d%s)",
done, total, rate, avg_time, workers, pool.max_workers,
_eta_suffix(done, total, rate),
)
# 自适应并发调用 vlm-ocr10s 窗口内平均响应 < 0.3s 则加 1 线程(上限