Spaces:
Sleeping
Sleeping
File size: 6,557 Bytes
ebae6ab | 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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | #!/usr/bin/env python3
"""
Build curriculum tiers from existing test scripts + synthetic scripts.
Generates:
- easy_tier.jsonl (20 configs)
- medium_tier.jsonl (15 configs)
- hard_tier.jsonl (10 configs)
Usage: python data/curriculum/build_curriculum.py
(Run generate_synthetic_scripts.py first if synthetic_scripts.json is missing)
"""
import json
import sys
from pathlib import Path
BASE_DIR = Path(__file__).parent.parent.parent
DATA_DIR = BASE_DIR / "data"
CURRICULUM_DIR = DATA_DIR / "curriculum"
SCRIPTS_PATH = DATA_DIR / "test_scripts" / "scripts.json"
SYNTHETIC_PATH = CURRICULUM_DIR / "synthetic_scripts.json"
sys.path.insert(0, str(BASE_DIR.parent))
_FLAW_TO_CRITIQUE_CLASS = {
"buried_hook": "hook_weakness",
"no_cta": "cta_weakness",
"pacing_issue": "coherence_issue",
"coherence_break": "coherence_issue",
"cultural_mismatch": "cultural_misalignment",
"conflicting_advice":"coherence_issue",
"retention_risk": "hook_weakness",
"cta_buried": "cta_weakness",
}
_FLAW_TO_ACTION = {
"buried_hook": "hook_rewrite",
"no_cta": "cta_placement",
"pacing_issue": "section_reorder",
"coherence_break": "section_reorder",
"cultural_mismatch": "cultural_ref_sub",
"conflicting_advice":"section_reorder",
"retention_risk": "hook_rewrite",
"cta_buried": "cta_placement",
}
_EASY_NOTES = "One obvious flaw. Critic should win immediately. Strong reward signal on step 1."
_MEDIUM_NOTES = "Trade-off scenario. Critic and Defender both have valid points. Reward signal emerges over 2–3 steps."
_HARD_NOTES = "Fixing the top critique risks damaging R3 cultural alignment. Explicit reward conflict."
def _load_json(path: Path) -> list:
with open(path, encoding="utf-8") as f:
return json.load(f)
def _make_config(
config_id: str,
difficulty: str,
script: dict,
notes: str,
) -> dict:
flaws = script.get("known_flaws", script.get("dominant_flaw", ["buried_hook"]))
if isinstance(flaws, str):
flaws = [flaws]
dominant = flaws[0] if flaws else "buried_hook"
return {
"episode_config_id": config_id,
"difficulty": difficulty,
"script_id": script["script_id"],
"script_text": script["script_text"],
"region": script["region"],
"platform": script["platform"],
"niche": script["niche"],
"dominant_flaw": dominant,
"expected_critique_class": _FLAW_TO_CRITIQUE_CLASS.get(dominant, "hook_weakness"),
"expected_action": _FLAW_TO_ACTION.get(dominant, "hook_rewrite"),
"curriculum_notes": notes,
}
def build_easy_tier(existing: list, synthetic: list) -> list:
"""
20 configs: 10 from existing easy scripts (S01–S04) + 10 from synthetic easy.
Existing scripts are used with slight context variations (platform/region cycling).
"""
easy_existing = [s for s in existing if s["script_id"] in ("S01", "S02", "S03", "S04")]
easy_synthetic = [s for s in synthetic if s["difficulty"] == "easy"]
configs = []
idx = 1
region_variants = ["Mumbai Gen Z", "Pan-India English", "Tier-2 Hindi belt"]
platform_variants = ["Reels", "Shorts", "Reels"]
for i, script in enumerate(easy_existing * 3):
if len(configs) >= 10:
break
variant = i % len(region_variants)
patched = dict(script)
patched["region"] = region_variants[variant]
patched["platform"] = platform_variants[variant]
cfg = _make_config(f"easy_{idx:03d}", "easy", patched, _EASY_NOTES)
configs.append(cfg)
idx += 1
for script in easy_synthetic[:10]:
cfg = _make_config(f"easy_{idx:03d}", "easy", script, _EASY_NOTES)
configs.append(cfg)
idx += 1
return configs[:20]
def build_medium_tier(existing: list, synthetic: list) -> list:
"""
15 configs: 10 from medium scripts (S05–S07) + 5 from synthetic medium.
"""
med_existing = [s for s in existing if s["script_id"] in ("S05", "S06", "S07")]
med_synthetic = [s for s in synthetic if s["difficulty"] == "medium"]
configs = []
idx = 1
for i, script in enumerate(med_existing * 5):
if len(configs) >= 10:
break
cfg = _make_config(f"medium_{idx:03d}", "medium", script, _MEDIUM_NOTES)
configs.append(cfg)
idx += 1
for script in med_synthetic[:5]:
cfg = _make_config(f"medium_{idx:03d}", "medium", script, _MEDIUM_NOTES)
configs.append(cfg)
idx += 1
return configs[:15]
def build_hard_tier(existing: list, synthetic: list) -> list:
"""
10 configs: 5 from hard scripts (S08–S10) + 5 from synthetic hard.
"""
hard_existing = [s for s in existing if s["script_id"] in ("S08", "S09", "S10")]
hard_synthetic = [s for s in synthetic if s["difficulty"] == "hard"]
configs = []
idx = 1
for i, script in enumerate(hard_existing * 4):
if len(configs) >= 5:
break
cfg = _make_config(f"hard_{idx:03d}", "hard", script, _HARD_NOTES)
configs.append(cfg)
idx += 1
for script in hard_synthetic[:5]:
cfg = _make_config(f"hard_{idx:03d}", "hard", script, _HARD_NOTES)
configs.append(cfg)
idx += 1
return configs[:10]
def write_jsonl(configs: list, path: Path):
path.parent.mkdir(parents=True, exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
for cfg in configs:
f.write(json.dumps(cfg, ensure_ascii=False) + "\n")
print(f" Wrote {len(configs)} configs -> {path.name}")
def main():
existing = _load_json(SCRIPTS_PATH)
print(f"Loaded {len(existing)} existing scripts.")
if SYNTHETIC_PATH.exists():
synthetic = _load_json(SYNTHETIC_PATH)
print(f"Loaded {len(synthetic)} synthetic scripts.")
else:
print(f"WARNING: {SYNTHETIC_PATH} not found — using empty list.")
print("Run generate_synthetic_scripts.py first for full curriculum.")
synthetic = []
easy = build_easy_tier(existing, synthetic)
medium = build_medium_tier(existing, synthetic)
hard = build_hard_tier(existing, synthetic)
write_jsonl(easy, CURRICULUM_DIR / "easy_tier.jsonl")
write_jsonl(medium, CURRICULUM_DIR / "medium_tier.jsonl")
write_jsonl(hard, CURRICULUM_DIR / "hard_tier.jsonl")
print(f"\nCurriculum built: easy={len(easy)}, medium={len(medium)}, hard={len(hard)}")
if __name__ == "__main__":
main()
|