EduVid-LLM / src /generation /code_generator.py
gokul00060's picture
AI debugger finally working
e5644ac
# src/generation/code_generator.py
import json
import tempfile
from src.core.ai_helpers import generate_with_ai
from src.utils.helpers import fix_invalid_colors
from src.utils.smart_logger import logger
def generate_scene_code(project_config: dict, gemini_client, temp_dir_name: str):
"""Workflow Step 2: Generate Manim code and save to a temporary file."""
logger.start_operation("code_gen", "Generating scene code")
if not project_config.get("video_plan"):
logger.end_operation("code_gen", "No video plan found")
return
plan = project_config["video_plan"]
scenes_count = len(plan.get('scenes', []))
logger.quick_log("info", f"Generating code for {scenes_count} scenes")
plan_str = json.dumps(project_config["video_plan"], indent=2)
code_gen_prompt = f"""
Generate a single Python file containing all Manim scene classes based on this video plan:
{plan_str}
Requirements:
1. Create ONE Python file with all necessary Manim scene classes.
2. Use modern Manim syntax (e.g., `from manim import *`).
3. Each class name must exactly match a `scene_name` from the plan.
4. Implement the `construct` method for each scene based on its `description`.
5. Set the background color for every scene to WHITE.
6. Add comments to explain the code.
7. At the end, add: `SCENE_ORDER = ["IntroScene", "MainConceptScene", ...]`
8. Return ONLY the Python code, inside a single markdown block.
CRITICAL CONSTRAINTS:
- NEVER use ImageMobject, SVGMobject, or any file references.
- NEVER use MathTex, Tex, or any LaTeX-dependent objects (LaTeX not installed).
- Use Text() for all text including mathematical formulas.
- Create all visuals using Manim's built-in shapes and functions ONLY.
- ONLY use these colors: RED, BLUE, GREEN, YELLOW, WHITE, BLACK, GRAY, ORANGE, PURPLE, PINK.
- To position objects, call .to_edge(), .move_to(), or .shift() DIRECTLY on the Mobject.
- For math formulas, use Text() with simple strings like "x² + y² = z²".
"""
response_text = generate_with_ai(gemini_client, code_gen_prompt, is_json=False)
if not response_text:
logger.end_operation("code_gen", "No AI response received")
return
if "```python" in response_text:
all_scenes_code = response_text.split("```python")[1].split("```")[0].strip()
else:
all_scenes_code = response_text.strip()
all_scenes_code = fix_invalid_colors(all_scenes_code)
with tempfile.NamedTemporaryFile(mode='w+', suffix='.py', delete=False, dir=temp_dir_name) as temp_code_file:
temp_code_file.write(all_scenes_code)
temp_code_file_path = temp_code_file.name
for scene_name in project_config["scenes"]:
project_config["scenes"][scene_name]["code_file"] = temp_code_file_path
code_size = len(all_scenes_code)
logger.end_operation("code_gen", "Scene code generated", f"{code_size} chars → {temp_code_file_path}")
def regenerate_single_scene_code(project_config: dict, gemini_client, temp_dir_name: str, scene_name: str) -> bool:
"""Regenerate code for a single scene when debugging fails."""
logger.start_operation("regen_scene", f"Regenerating code for {scene_name}")
if not project_config.get("video_plan"):
logger.end_operation("regen_scene", "No video plan found")
return False
# Find the specific scene in the plan
scenes = project_config["video_plan"].get("scenes", [])
target_scene = None
for scene in scenes:
if scene.get("scene_name") == scene_name:
target_scene = scene
break
if not target_scene:
logger.end_operation("regen_scene", f"Scene {scene_name} not found in plan")
return False
scene_prompt = f"""
Generate a single Manim scene class for this specific scene:
Scene Name: {scene_name}
Description: {target_scene.get('description', '')}
Narration: {target_scene.get('narration', '')}
Requirements:
1. Create ONE Python file with the complete scene class.
2. Use modern Manim syntax (e.g., `from manim import *`).
3. Class name must be exactly: {scene_name}
4. Implement the `construct` method based on the description.
5. Set background color to WHITE.
6. Add detailed comments.
7. Return ONLY the Python code, inside a single markdown block.
CRITICAL CONSTRAINTS:
- NEVER use ImageMobject, SVGMobject, or any file references.
- NEVER use MathTex, Tex, or any LaTeX-dependent objects (LaTeX not installed).
- Use Text() for all text including mathematical formulas.
- Create all visuals using Manim's built-in shapes and functions ONLY.
- ONLY use these colors: RED, BLUE, GREEN, YELLOW, WHITE, BLACK, GRAY, ORANGE, PURPLE, PINK.
- To position objects, call .to_edge(), .move_to(), or .shift() DIRECTLY on the Mobject.
- For math formulas, use Text() with simple strings like "x² + y² = z²".
- Make the animation clear and educational.
"""
response_text = generate_with_ai(gemini_client, scene_prompt, is_json=False)
if not response_text:
logger.end_operation("regen_scene", "No AI response received")
return False
if "```python" in response_text:
scene_code = response_text.split("```python")[1].split("```")[0].strip()
else:
scene_code = response_text.strip()
scene_code = fix_invalid_colors(scene_code)
# Create a new temporary file for this regenerated scene
with tempfile.NamedTemporaryFile(mode='w+', suffix='.py', delete=False, dir=temp_dir_name) as temp_code_file:
temp_code_file.write(scene_code)
temp_code_file_path = temp_code_file.name
# Update the project config for this specific scene
if scene_name in project_config["scenes"]:
project_config["scenes"][scene_name]["code_file"] = temp_code_file_path
project_config["scenes"][scene_name]["status"] = "code_regenerated"
code_size = len(scene_code)
logger.end_operation("regen_scene", f"Scene code regenerated", f"{code_size} chars → {temp_code_file_path}")
return True