Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Generate synthetic scripts for curriculum tiers using the Anthropic API. | |
| Run once to populate data/curriculum/synthetic_scripts.json. | |
| Usage: python data/curriculum/generate_synthetic_scripts.py | |
| """ | |
| import json | |
| import os | |
| import sys | |
| from pathlib import Path | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent)) | |
| from viral_script_engine.agents.llm_backend import LLMBackend | |
| OUTPUT_PATH = Path(__file__).parent / "synthetic_scripts.json" | |
| FLAW_DIFFICULTY_MAP = { | |
| "easy": ["buried_hook", "no_cta", "buried_hook", "no_cta", "buried_hook", | |
| "no_cta", "buried_hook", "no_cta", "buried_hook", "no_cta"], | |
| "medium": ["pacing_issue", "coherence_break", "cultural_mismatch", "pacing_issue", "coherence_break"], | |
| "hard": ["conflicting_advice", "retention_risk", "cta_buried", "conflicting_advice", "retention_risk"], | |
| } | |
| NICHE_REGION_COMBOS = [ | |
| ("personal finance", "Mumbai Gen Z", "Reels"), | |
| ("fashion", "Mumbai Gen Z", "Reels"), | |
| ("tech", "Pan-India English", "Shorts"), | |
| ("agriculture", "Tier-2 Hindi belt", "Reels"), | |
| ("small business", "Tier-2 Hindi belt", "Reels"), | |
| ("local culture", "Hinglish", "Reels"), | |
| ("startup advice", "Pan-India English", "Shorts"), | |
| ("productivity", "Pan-India English", "Reels"), | |
| ("fitness", "Mumbai Gen Z", "Reels"), | |
| ("cooking", "Tier-2 Hindi belt", "Reels"), | |
| ] | |
| SYSTEM_PROMPT = ( | |
| "You are a short-form video scriptwriter for Indian social media creators. " | |
| "Write realistic scripts that feel authentic β not like AI-generated content. " | |
| "Respond ONLY with the script text, no preamble or labels." | |
| ) | |
| _FLAW_DESCRIPTIONS = { | |
| "buried_hook": "the hook (opening line) appears only after 10β15 seconds of backstory", | |
| "no_cta": "the script ends abruptly with no call-to-action or next step for viewers", | |
| "pacing_issue": "the script rushes through key points and has an uneven tempo", | |
| "coherence_break": "the script jumps between unrelated ideas mid-way, breaking narrative flow", | |
| "cultural_mismatch": "the script uses references or language that feel foreign to the target region", | |
| "conflicting_advice":"the script gives two pieces of advice that contradict each other", | |
| "retention_risk": "the middle third of the script drops energy and is likely to cause drop-off", | |
| "cta_buried": "there is a call-to-action but it is buried mid-script instead of at the end", | |
| } | |
| def _build_user_prompt(niche: str, region: str, platform: str, flaw: str, difficulty: str) -> str: | |
| flaw_desc = _FLAW_DESCRIPTIONS.get(flaw, flaw) | |
| return ( | |
| f"Generate a realistic 60β90 second {platform} script for [{niche}] targeting [{region}].\n" | |
| f"Intentionally include [{flaw}] as the dominant flaw: {flaw_desc}.\n" | |
| f"The flaw should be [{difficulty}] to diagnose.\n" | |
| f"Write naturally β use the local language style for the region. Do not label the flaw." | |
| ) | |
| def generate_scripts() -> list: | |
| llm = LLMBackend(backend="anthropic", model_name="claude-haiku-4-5-20251001") | |
| results = [] | |
| script_counter = {"easy": 0, "medium": 0, "hard": 0} | |
| for difficulty, flaws in FLAW_DIFFICULTY_MAP.items(): | |
| for i, flaw in enumerate(flaws): | |
| combo = NICHE_REGION_COMBOS[i % len(NICHE_REGION_COMBOS)] | |
| niche, region, platform = combo | |
| script_counter[difficulty] += 1 | |
| script_id = f"SYN_{difficulty[0].upper()}{script_counter[difficulty]:02d}" | |
| print(f" Generating {script_id} ({difficulty}, {flaw}, {niche}/{region})...") | |
| user_prompt = _build_user_prompt(niche, region, platform, flaw, difficulty) | |
| try: | |
| script_text = llm.generate(SYSTEM_PROMPT, user_prompt, max_tokens=600) | |
| except Exception as e: | |
| print(f" ERROR: {e} β using placeholder") | |
| script_text = f"[Synthetic {difficulty} script for {niche}/{region} with {flaw} β generation failed]" | |
| results.append({ | |
| "script_id": script_id, | |
| "difficulty": difficulty, | |
| "region": region, | |
| "platform": platform, | |
| "niche": niche, | |
| "dominant_flaw": flaw, | |
| "script_text": script_text, | |
| "is_synthetic": True, | |
| }) | |
| return results | |
| def main(): | |
| print("Generating synthetic scripts via Anthropic API...") | |
| print(f"Target: 10 easy + 5 medium + 5 hard = 20 total") | |
| scripts = generate_scripts() | |
| OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True) | |
| with open(OUTPUT_PATH, "w", encoding="utf-8") as f: | |
| json.dump(scripts, f, indent=2, ensure_ascii=False) | |
| counts = {} | |
| for s in scripts: | |
| counts[s["difficulty"]] = counts.get(s["difficulty"], 0) + 1 | |
| print(f"\nSaved {len(scripts)} scripts -> {OUTPUT_PATH}") | |
| for diff, count in sorted(counts.items()): | |
| print(f" {diff}: {count}") | |
| if __name__ == "__main__": | |
| main() | |