90 lines
3.9 KiB
Python
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()
|