feat: subtitle-ocr 进度日志增加预计剩余时间 ETA
- 进度日志追加"预计剩余 X分Y秒"(剩余帧/当前速度,速度未知时不显示)
This commit is contained in:
+27
-3
@@ -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-ocr:10s 窗口内平均响应 < 0.3s 则加 1 线程(上限
|
||||
|
||||
Reference in New Issue
Block a user