import os import subprocess import uuid import shutil import glob from pathlib import Path # Get the directory of the current script (backend/) BASE_DIR = os.path.dirname(os.path.abspath(__file__)) MEDIA_DIR = os.path.join(BASE_DIR, "media") def cleanup_old_files(): """Clean up old scene files and media to free memory""" try: # Remove old scene files (keep only last 2) scene_files = sorted(glob.glob(os.path.join(BASE_DIR, "scene_*.py")), key=os.path.getmtime) for old_file in scene_files[:-2]: try: os.remove(old_file) print(f"🗑️ Cleaned up old scene file: {old_file}") except Exception as e: print(f"⚠️ Could not remove {old_file}: {e}") # Remove old video folders (keep only last 3) videos_dir = os.path.join(MEDIA_DIR, "videos") if os.path.exists(videos_dir): video_folders = sorted( [f for f in Path(videos_dir).iterdir() if f.is_dir()], key=os.path.getmtime ) for old_folder in video_folders[:-3]: try: shutil.rmtree(old_folder) print(f"🗑️ Cleaned up old video folder: {old_folder}") except Exception as e: print(f"⚠️ Could not remove {old_folder}: {e}") # Remove old step audio files (keep only last 5) audio_files = sorted(glob.glob(os.path.join(BASE_DIR, "step_*_narration.mp3")), key=os.path.getmtime) for old_audio in audio_files[:-5]: try: os.remove(old_audio) print(f"🗑️ Cleaned up old audio file: {old_audio}") except Exception as e: print(f"⚠️ Could not remove {old_audio}: {e}") # Remove old combined audio files (keep only last 2) combined_files = sorted(glob.glob(os.path.join(BASE_DIR, "combined_narration*.mp3")), key=os.path.getmtime) for old_combined in combined_files[:-2]: try: os.remove(old_combined) print(f"🗑️ Cleaned up old combined audio: {old_combined}") except Exception as e: print(f"⚠️ Could not remove {old_combined}: {e}") except Exception as e: print(f"⚠️ Cleanup error: {e}") async def render_scene(code: str): # Clean up old files before rendering cleanup_old_files() # Create a unique ID for this run run_id = str(uuid.uuid4()) filename = f"scene_{run_id}.py" # Save code to file in the backend directory filepath = os.path.join(BASE_DIR, filename) with open(filepath, "w", encoding='utf-8') as f: f.write(code) # Run Manim with LOW quality (-ql) for better memory usage # -ql = 480p15, much lighter than -qm (720p30) cmd = ["manim", "-ql", "--media_dir", MEDIA_DIR, filepath, "GenScene"] try: result = subprocess.run(cmd, capture_output=True, text=True, check=True) print("✓ Manim render completed") except subprocess.CalledProcessError as e: print("❌ Manim Error:", e.stderr) # Clean up failed scene file try: os.remove(filepath) except: pass raise Exception(f"Manim failed: {e.stderr}") # Construct expected output path # Low quality: {MEDIA_DIR}/videos/{filename_without_extension}/480p15/GenScene.mp4 video_folder = filename.replace(".py", "") video_path = os.path.join(MEDIA_DIR, "videos", video_folder, "480p15", "GenScene.mp4") if not os.path.exists(video_path): # Clean up scene file try: os.remove(filepath) except: pass raise Exception(f"Video file not found at {video_path}") print(f"✓ Video created: {video_path}") # Clean up the scene file immediately after successful render try: os.remove(filepath) print(f"🗑️ Cleaned up scene file: {filepath}") except Exception as e: print(f"⚠️ Could not remove scene file: {e}") return video_path