Animetrix_AI / backend /runner.py
SayedZahur786's picture
Fix visual clutter and audio sync: enhanced layout zones, audio concatenation, proper timing
ee6d55e
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