首次提交
This commit is contained in:
89
tools/seed_jobs.py
Normal file
89
tools/seed_jobs.py
Normal file
@@ -0,0 +1,89 @@
|
||||
# -*- 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()
|
||||
Reference in New Issue
Block a user