Files
ocr_data/tools/seed_jobs.py
2026-09-28 16:09:31 +08:00

90 lines
3.9 KiB
Python

# -*- coding: utf-8 -*-
"""把一份/多份视频清单切成分片, 上传到 COS 的 todo/, 供常驻 worker 认领。
用法:
python tools/seed_jobs.py 清单1.txt [清单2.txt ...]
python tools/seed_jobs.py ./text2 # 目录: 取其中所有 *.txt
python tools/seed_jobs.py ./text2 --skip-processed # 灌之前先过滤掉全局已处理过的视频
分片大小取 config.dispatch.shard_size(默认2000)。分片名: shard_<起始序号>。
幂等性: 同名分片已存在(todo 里有)则跳过, 不覆盖。
--skip-processed: 聚合 30 台机器各自最新一天的 数据.jsonl 快照(dispatch.daily_backup_path),
合并成全局已处理视频集合再过滤清单 —— 避免同一视频被不同机器重复处理(本机 数据.jsonl 只能
挡住"这台机器"重复跑, 挡不住跨机器重复)。有最长约1天(daily_backup_hour)的数据延迟。
"""
import argparse
import glob
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config.config_utils import config # noqa: E402
from tool import job_cos # noqa: E402
def _collect_lines(paths):
lines = []
for p in paths:
files = glob.glob(os.path.join(p, "*.txt")) if os.path.isdir(p) else [p]
for fp in files:
with open(fp, encoding="utf-8") as f:
lines += [ln.strip() for ln in f if ln.strip()]
# 去重并保序
seen, out = set(), []
for ln in lines:
if ln not in seen:
seen.add(ln)
out.append(ln)
return out
def main():
ap = argparse.ArgumentParser(description="切片灌任务到 COS todo/")
ap.add_argument("paths", nargs="+", help="清单.txt 或目录(取其中所有 *.txt)")
ap.add_argument("--skip-processed", action="store_true",
help="灌之前先过滤掉全局(所有机器)已处理过的视频,见文件头说明")
ap.add_argument("--all-dates", action="store_true",
help="配合 --skip-processed: 不只取每台机器最新一天,把所有历史日期的已处理清单都拉下来合并判断"
"(机群已停机、想更保险地核对时用;正常灌任务不需要,只会多下载很多文件)")
args = ap.parse_args()
shard_size = int((config.get_dispatch_config() or {}).get("shard_size", 2000))
lines = _collect_lines(args.paths)
if not lines:
print("✗ 没有读到任何视频路径")
sys.exit(1)
if args.skip_processed:
if args.all_dates:
print("正在聚合所有机器【全部历史日期】的已处理清单(daily_backup_path)...")
else:
print("正在聚合各机器最新一天的已处理清单(daily_backup_path)...")
processed = job_cos.global_processed_set(verbose=True, all_dates=args.all_dates)
before = len(lines)
lines = [ln for ln in lines if ln not in processed]
print(f"全局已处理 {len(processed)} 条 -> 过滤掉 {before - len(lines)} 条,剩余 {len(lines)} 条待灌。")
if not lines:
print("✓ 全部已处理过,无需灌任务。")
return
existing = set(job_cos.list_todo())
n_shards = (len(lines) + shard_size - 1) // shard_size
print(f"共 {len(lines)} 条 -> {n_shards} 个分片(每片≤{shard_size})。已存在 {len(existing)} 个分片。")
added = skipped = 0
for i in range(0, len(lines), shard_size):
shard = f"shard_{i:08d}"
if shard in existing:
skipped += 1
continue
body = "\n".join(lines[i:i + shard_size]).encode("utf-8")
job_cos._put(job_cos._key("todo", shard), body) # 普通写(任务清单, 不需禁止覆盖)
added += 1
if added % 50 == 0:
print(f" 已上传 {added} 个分片...")
print(f"✓ 完成: 新增 {added} 个分片, 跳过已存在 {skipped} 个。worker 会自动认领。")
if __name__ == "__main__":
main()