Spaces:
Sleeping
Sleeping
| """Prompt builders for the Gradio dashboard.""" | |
| import json | |
| import textwrap | |
| try: | |
| from .constants import MAX_EXPLORE_STEPS, MAX_REPAIR_STEPS | |
| except ImportError: # pragma: no cover | |
| from constants import MAX_EXPLORE_STEPS, MAX_REPAIR_STEPS | |
| SYSTEM_PROMPT = textwrap.dedent("""\ | |
| You are an expert educator that creates interactive explanations of technical topics. | |
| You interact with an environment in two phases: | |
| ## Phase 1: EXPLORE | |
| Search for relevant information. You'll be given a topic + tier (beginner/intermediate/advanced). | |
| - Start from `search_wikipedia` for the topic overview, terminology, equations, | |
| references, and branch keywords. | |
| - Then use what you learned from Wikipedia/top chunks to choose the next search | |
| avenue: arXiv/Scholar/HF papers for deeper sources, `fetch_docs` for | |
| Marimo/Manim/API/code patterns, and HF Hub for model/dataset/examples. | |
| - Decide search queries to gather relevant material | |
| - Choose one explicit research tool: | |
| - search_wikipedia: fundamentals and beginner explanations | |
| - search_hf_papers: ML/AI papers from Hugging Face Papers | |
| - search_arxiv: scientific/math/ML papers from arXiv | |
| - search_scholar: paper metadata, abstracts, citations | |
| - fetch_docs: library/API documentation for code, plots, Marimo, Manim | |
| - search_hf_hub: model cards, datasets, Spaces, examples | |
| - Explore for what the generated code needs: formulas, pseudocode, visual intuition, | |
| implementation examples, and Marimo/Manim/API patterns. | |
| - Use `fetch_docs` when you need code examples or interactive artifact patterns. | |
| Do not repeat broad Wikipedia/paper overview searches when code-oriented context is missing. | |
| - You have up to {MAX_EXPLORE_STEPS} explore steps. Stop early if you have enough info. | |
| ## Phase 2: GENERATE | |
| Produce a complete, runnable Python file in one of two formats: | |
| ### marimo notebook format (STRICT) | |
| First line: `import marimo` | |
| Second line: `app = marimo.App()` | |
| Use `@app.cell` functions, import shared libraries in the first cell, return shared | |
| variables explicitly, and use underscore-prefixed scratch variables by default to | |
| avoid MB002. Last line: `if __name__ == "__main__": app.run()`. | |
| ### manim animation format | |
| Use a Scene class with `construct()`, `self.play()`, and `self.wait()`. | |
| ## Phase 3: REPAIR | |
| If validation fails, submit a revised complete file using the exact error feedback. | |
| For EXPLORE actions, respond with a JSON object: | |
| ```json | |
| { | |
| "tool": "search_wikipedia | search_hf_papers | search_arxiv | search_scholar | fetch_docs | search_hf_hub", | |
| "query": "search query", | |
| "intent": "what you need from this source" | |
| } | |
| ``` | |
| For GENERATE actions, respond with a JSON object: | |
| ```json | |
| { | |
| "format": "marimo" or "manim", | |
| "code": "complete Python source code", | |
| "narration": "scene narration (manim only, empty string for marimo)" | |
| } | |
| ``` | |
| """).replace("{MAX_EXPLORE_STEPS}", str(MAX_EXPLORE_STEPS)).replace( | |
| "{MAX_REPAIR_STEPS}", | |
| str(MAX_REPAIR_STEPS), | |
| ) | |
| def build_explore_prompt( | |
| topic: str, | |
| content: str, | |
| tier: str, | |
| keywords: str, | |
| step: int, | |
| steps_left: int, | |
| explored_context: str, | |
| feedback: str, | |
| ) -> str: | |
| return textwrap.dedent(f"""\ | |
| TOPIC: {topic} | |
| TIER: {tier} | |
| KEYWORDS: {keywords} | |
| DESCRIPTION: {content} | |
| PHASE: EXPLORE (step {step}, {steps_left} steps left) | |
| PREVIOUS RESEARCH: | |
| {explored_context or "(none yet)"} | |
| FEEDBACK: {feedback} | |
| Provide a search query to find relevant information about this topic. | |
| If this is the first explore step, use `search_wikipedia` for the starting overview. | |
| On later explore steps, use prior research/top chunks to branch into papers, docs, | |
| examples, references, or APIs. Prefer queries/intents that will help write the final | |
| interactive code: equations, pseudocode, visual examples, implementation details, | |
| or Marimo/Manim docs. | |
| If you already have enough context, respond with just: SKIP | |
| Otherwise respond with the JSON object described in the system prompt. | |
| """) | |
| def build_generate_prompt( | |
| topic: str, | |
| content: str, | |
| tier: str, | |
| keywords: str, | |
| data_available: bool, | |
| explored_context: str, | |
| ) -> str: | |
| format_hint = "" | |
| if data_available: | |
| format_hint = "This topic has associated data - consider marimo with data visualizations." | |
| return textwrap.dedent(f"""\ | |
| TOPIC: {topic} | |
| TIER: {tier} | |
| KEYWORDS: {keywords} | |
| DESCRIPTION: {content} | |
| DATA AVAILABLE: {data_available} | |
| {format_hint} | |
| ACCUMULATED RESEARCH: | |
| {explored_context or "(no research done)"} | |
| PHASE: GENERATE | |
| Create a complete, runnable interactive explanation. Choose the best format (marimo or manim). | |
| Respond with a JSON object: | |
| ```json | |
| {{ | |
| "format": "marimo" or "manim", | |
| "code": "complete Python source code here", | |
| "narration": "scene-by-scene narration (manim only, empty for marimo)" | |
| }} | |
| ``` | |
| Requirements: | |
| - For marimo: first line `import marimo`, second line `app = marimo.App()`, | |
| every cell has an explicit return, scratch variables use underscore prefixes, | |
| and the file ends with `if __name__ == "__main__": app.run()`. | |
| - For manim: Scene class with construct(), self.play() animations, MathTex for math. | |
| - Cover the key concepts from the keywords. | |
| - Match the depth to the tier level ({tier}). | |
| - Incorporate findings from the research above. | |
| """) | |
| def build_repair_prompt( | |
| topic: str, | |
| tier: str, | |
| fmt: str, | |
| previous_code: str, | |
| last_errors: str, | |
| ) -> str: | |
| return textwrap.dedent(f"""\ | |
| TOPIC: {topic} | |
| TIER: {tier} | |
| FORMAT: {fmt} | |
| The previous generated artifact failed validation. | |
| ERROR FEEDBACK: | |
| {last_errors} | |
| PREVIOUS CODE: | |
| ```python | |
| {previous_code} | |
| ``` | |
| Submit a corrected complete Python file. Respond with the same JSON shape used | |
| for generation: format, code, narration. | |
| If the error is MB002, do a full-file variable audit before answering. Fix the | |
| assignment names and loop variable names, not just the return values. | |
| """) | |
| def parse_generate_response(response: str) -> tuple[str, str, str]: | |
| text = response.strip() | |
| if "```json" in text: | |
| text = text.split("```json", 1)[1].split("```", 1)[0].strip() | |
| elif "```" in text: | |
| text = text.split("```", 1)[1].split("```", 1)[0].strip() | |
| try: | |
| data = json.loads(text) | |
| return data.get("format", "marimo"), data.get("code", ""), data.get("narration", "") | |
| except json.JSONDecodeError: | |
| if "from manim" in response or ("class " in response and "Scene" in response): | |
| return "manim", response, "" | |
| return "marimo", response, "" | |
| def parse_explore_response(response: str, fallback_query: str) -> tuple[str, str, str]: | |
| text = response.strip() | |
| if "```json" in text: | |
| text = text.split("```json", 1)[1].split("```", 1)[0].strip() | |
| elif text.startswith("```"): | |
| text = text.split("```", 1)[1].split("```", 1)[0].strip() | |
| try: | |
| data = json.loads(text) | |
| return ( | |
| data.get("tool", "search_wikipedia"), | |
| data.get("query", fallback_query), | |
| data.get("intent", "gather background and examples"), | |
| ) | |
| except json.JSONDecodeError: | |
| return "search_wikipedia", fallback_query, "gather background and examples" | |