File size: 4,442 Bytes
babffc8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from __future__ import annotations

import argparse
import sys
from pathlib import Path

import pandas as pd

sys.path.append(str(Path(__file__).resolve().parents[1]))
from src.io_utils import load_config, resolve_path, write_jsonl
from src.label_utils import normalize_label


VIDEO_COLUMNS = ["video_path", "path", "file", "filename", "video"]
LABEL_COLUMNS = ["label", "gloss", "sign", "sign_label", "text"]
SPLIT_COLUMNS = ["split", "subset"]
ID_COLUMNS = ["id", "sign_id"]


def pick_column(columns: list[str], candidates: list[str], name: str) -> str:
    lower = {c.lower(): c for c in columns}
    for cand in candidates:
        if cand.lower() in lower:
            return lower[cand.lower()]
    raise ValueError(f"Missing {name} column. Tried: {', '.join(candidates)}")


def read_metadata(path: Path) -> pd.DataFrame:
    suffix = path.suffix.lower()
    if suffix == ".csv":
        return pd.read_csv(path)
    if suffix in {".jsonl", ".ndjson"}:
        return pd.read_json(path, lines=True)
    if suffix == ".json":
        return pd.read_json(path)
    raise ValueError(f"Unsupported metadata format: {path.suffix}. Use CSV, JSON, or JSONL.")


def normalize_split(value: str) -> str:
    value = str(value).strip().lower()
    if value in {"train", "training"}:
        return "train"
    if value in {"val", "valid", "validation", "dev"}:
        return "val"
    if value in {"test", "testing"}:
        return "test"
    return value


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--config", default=None)
    parser.add_argument("--metadata", required=True)
    parser.add_argument("--video_root", required=True)
    parser.add_argument("--out_train", default=None)
    parser.add_argument("--out_val", default=None)
    parser.add_argument("--skip_missing_check", action="store_true")
    parser.add_argument("--val_fraction", type=float, default=0.1)
    args = parser.parse_args()

    cfg = load_config(args.config) if args.config else {}
    out_train = args.out_train or cfg.get("train_jsonl", "data/asl_citizen_train.jsonl")
    out_val = args.out_val or cfg.get("val_jsonl", "data/asl_citizen_val.jsonl")

    metadata_path = resolve_path(args.metadata, Path.cwd())
    video_root = resolve_path(args.video_root, Path.cwd())
    if not metadata_path.exists():
        raise FileNotFoundError(f"Metadata file not found: {metadata_path}")
    if not video_root.exists():
        raise FileNotFoundError(f"Video root not found: {video_root}")

    df = read_metadata(metadata_path)
    columns = list(df.columns)
    video_col = pick_column(columns, VIDEO_COLUMNS, "video path")
    label_col = pick_column(columns, LABEL_COLUMNS, "label")
    id_col = next((c for c in ID_COLUMNS if c in columns), None)
    split_col = next((c for c in SPLIT_COLUMNS if c in columns), None)

    rows = []
    for idx, row in df.iterrows():
        label = normalize_label(row[label_col])
        if not label:
            raise ValueError(f"Missing label in metadata row {idx}")
        raw_video = Path(str(row[video_col]))
        video_path = raw_video if raw_video.is_absolute() else video_root / raw_video
        if not args.skip_missing_check and not video_path.exists():
            raise FileNotFoundError(f"Missing video at metadata row {idx}: {video_path}")
        split = normalize_split(row[split_col]) if split_col else None
        rows.append(
            {
                "id": str(row[id_col]) if id_col else str(idx),
                "video_path": str(video_path),
                "label": label,
                "split": split,
            }
        )

    if split_col:
        train_rows = [r for r in rows if r["split"] == "train"]
        val_rows = [r for r in rows if r["split"] in {"val", "validation", "dev"}]
        if not train_rows or not val_rows:
            raise ValueError("Found a split column, but could not find both train and val rows.")
    else:
        split_at = max(1, int(len(rows) * (1 - args.val_fraction)))
        train_rows = rows[:split_at]
        val_rows = rows[split_at:]
        for r in train_rows:
            r["split"] = "train"
        for r in val_rows:
            r["split"] = "val"

    write_jsonl(out_train, train_rows)
    write_jsonl(out_val, val_rows)
    print(f"Wrote {len(train_rows)} train rows to {out_train}")
    print(f"Wrote {len(val_rows)} val rows to {out_val}")


if __name__ == "__main__":
    main()