"""Regenerate only the specific missions that failed validation with thin content. Cheaper than re-running a whole chapter: reuses the same skeleton (title/hook/ source_pages/focus_notes already on disk) and only calls the model for the flagged mission_ids, with an extra reminder about the minimum note count. """ from __future__ import annotations import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT / "backend" / "scripts")) import importlib.util spec = importlib.util.spec_from_file_location("blueprints", ROOT / "backend/scripts/generate_source_backed_science_blueprints.py") mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) TARGETS = { "bio-p1-c5": ["M2", "M10"], "chem-p1-c2": ["M5"], "chem-p1-c4": ["M4", "M7"], "chem-p2-c6": ["M8"], } def main() -> int: groq_key = mod.env_value("GROQ_API_KEY") model = "meta-llama/llama-4-scout-17b-16e-instruct" generate = lambda prompt: mod.call_groq(prompt, groq_key, model) # noqa: E731 chapters_by_id = {chapter[0]: chapter for chapter in mod.CHAPTERS} for chapter_id, mission_ids in TARGETS.items(): chapter_id_, subject, title, markdown_file, first_page, last_page = chapters_by_id[chapter_id] path = mod.OUTPUT / f"{chapter_id}.json" data = json.loads(path.read_text(encoding="utf-8")) markdown_path = mod.MARKDOWN / markdown_file for mission in data["missions"]: if mission["mission_id"] not in mission_ids: continue excerpt = mod.mission_excerpt(markdown_path, mission.get("source_pages") or [], first_page, last_page) skeleton_like = { "mission_id": mission["mission_id"], "title": mission["title"], "source_pages": mission.get("source_pages") or [first_page], "hook": mission.get("hook", ""), "focus_notes": "IMPORTANT: notebook_notes must contain at least 4 concise, distinct notes. " + mission.get("title", ""), } prompt = mod.mission_prompt_for(chapter_id, subject, title, first_page, last_page, markdown_file, excerpt, skeleton_like) new_mission = mod.generate_with_retries(generate, prompt, chapter_id, f"patch {mission['mission_id']}") mission.clear() mission.update(new_mission) print(f"[{chapter_id}] patched {skeleton_like['mission_id']}", flush=True) path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") issues = mod.validate(data, chapter_id, subject, title, first_page, last_page) print(json.dumps({"chapter_id": chapter_id, "passed": not issues, "issues": issues}), flush=True) return 0 if __name__ == "__main__": sys.exit(main())