chore: track claude skills, tools, templates, reference code and research-wiki
- Add all claude skills (brainstorming, commit, debugging, TDD, etc.) - Add claude hooks (pre-commit-guard, post-edit-quality) - Add research templates (experiment plan, research brief, etc.) - Add claude tools (arxiv/semantic_scholar/openalex fetch, wiki, exa) - Add TRM4 reference implementation as algorithm fidelity baseline - Add research-wiki content (plans, index, graph, query_pack) - Update .gitignore to exclude .graphify_version runtime state
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
"""
|
||||
_download_meta.py — VideoMME 元数据下载与长视频列表提取
|
||||
==========================================================
|
||||
从 HuggingFace `lmms-lab/Video-MME` 下载数据集元数据,
|
||||
过滤 duration_category == "long"(30-60 分钟)的视频,
|
||||
输出两个文件:
|
||||
- {meta_dir}/long_videos.jsonl 每行一条唯一长视频记录
|
||||
- {meta_dir}/long_videos_qa.jsonl 每行一条 QA 对(含 video_id)
|
||||
|
||||
使用方式(由 build_videomme_trees.sh 调用):
|
||||
python _download_meta.py --meta-dir /data/videomme/metadata
|
||||
|
||||
依赖(在脚本中已安装): datasets, huggingface_hub
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
p = argparse.ArgumentParser(description="下载 VideoMME 元数据并提取长视频列表")
|
||||
p.add_argument("--meta-dir", required=True, help="元数据输出目录")
|
||||
p.add_argument(
|
||||
"--min-duration",
|
||||
type=int,
|
||||
default=1800,
|
||||
help="最短视频时长(秒),默认 1800(30 分钟)",
|
||||
)
|
||||
p.add_argument(
|
||||
"--max-duration",
|
||||
type=int,
|
||||
default=3600,
|
||||
help="最长视频时长(秒),默认 3600(60 分钟)",
|
||||
)
|
||||
return p.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
meta_dir = Path(args.meta_dir)
|
||||
meta_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Phase 1: 尝试加载 HuggingFace 数据集
|
||||
print("[meta] 正在从 HuggingFace 加载 lmms-lab/Video-MME ...")
|
||||
try:
|
||||
from datasets import load_dataset # type: ignore
|
||||
except ImportError:
|
||||
print("[meta][ERROR] 未安装 datasets 库,请先运行: pip install datasets", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
# VideoMME 数据集,test split
|
||||
ds = load_dataset("lmms-lab/Video-MME", split="test")
|
||||
except Exception as e:
|
||||
print(f"[meta][ERROR] 数据集加载失败: {e}", file=sys.stderr)
|
||||
print("[meta] 请确认 HuggingFace 可访问,或配置 HF_ENDPOINT 镜像", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"[meta] 数据集总条目数: {len(ds)}")
|
||||
|
||||
# Phase 2: 过滤长视频
|
||||
# VideoMME 字段: video_id, youtube_id, url, duration, duration_category,
|
||||
# domain, sub_category, question, answer, options
|
||||
seen_video_ids: set[str] = set()
|
||||
long_videos: list[dict] = []
|
||||
long_qa: list[dict] = []
|
||||
|
||||
for row in ds:
|
||||
# 实际字段结构(lmms-lab/Video-MME 真实格式):
|
||||
# video_id : "001", "002", ... (数据集内部序号)
|
||||
# videoID : YouTube 视频 ID(如 "fFjv93ACGo8")
|
||||
# url : YouTube 完整链接
|
||||
# duration : "short" | "medium" | "long"(字符串类别,非秒数)
|
||||
# domain : 领域
|
||||
# sub_category : 细分类别
|
||||
# question_id : 问题序号
|
||||
# question : 问题文本
|
||||
# options : 选项列表(字符串)
|
||||
# answer : 正确选项字母
|
||||
duration_category = str(row.get("duration", "")).strip().lower()
|
||||
if duration_category != "long":
|
||||
continue
|
||||
|
||||
youtube_id = row.get("videoID") or row.get("video_id", "")
|
||||
url = row.get("url", f"https://www.youtube.com/watch?v={youtube_id}")
|
||||
|
||||
# 唯一视频记录(以 youtube_id 去重)
|
||||
if youtube_id not in seen_video_ids:
|
||||
seen_video_ids.add(youtube_id)
|
||||
long_videos.append(
|
||||
{
|
||||
"video_id": row.get("video_id", ""),
|
||||
"youtube_id": youtube_id,
|
||||
"url": url,
|
||||
"duration_category": duration_category,
|
||||
"domain": row.get("domain", ""),
|
||||
"sub_category": row.get("sub_category", ""),
|
||||
}
|
||||
)
|
||||
|
||||
# QA 对记录
|
||||
long_qa.append(
|
||||
{
|
||||
"video_id": row.get("video_id", ""),
|
||||
"youtube_id": youtube_id,
|
||||
"question_id": row.get("question_id", ""),
|
||||
"question": row.get("question", ""),
|
||||
"answer": row.get("answer", ""),
|
||||
"options": row.get("options", []),
|
||||
"duration_category": duration_category,
|
||||
}
|
||||
)
|
||||
|
||||
# Phase 3: 写出文件
|
||||
videos_path = meta_dir / "long_videos.jsonl"
|
||||
qa_path = meta_dir / "long_videos_qa.jsonl"
|
||||
|
||||
with open(videos_path, "w", encoding="utf-8") as f:
|
||||
for v in long_videos:
|
||||
f.write(json.dumps(v, ensure_ascii=False) + "\n")
|
||||
|
||||
with open(qa_path, "w", encoding="utf-8") as f:
|
||||
for q in long_qa:
|
||||
f.write(json.dumps(q, ensure_ascii=False) + "\n")
|
||||
|
||||
print(f"[meta] 长视频唯一数量: {len(long_videos)}")
|
||||
print(f"[meta] 长视频 QA 对数: {len(long_qa)}")
|
||||
print(f"[meta] 视频列表已保存: {videos_path}")
|
||||
print(f"[meta] QA 列表已保存: {qa_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user