Manimator / src /services /manim_service.py
MostlyK
Manimator in HF
d970572
raw
history blame
3.73 kB
import re
import subprocess
import os
import glob
import logging
def get_scene_name(manim_code):
match = re.search(r'class\s+(\w+)\s*\(\s*Scene\s*\)', manim_code)
if match:
return match.group(1)
raise ValueError("No Scene class found in generated code")
def create_manim_video(video_data, manim_code, audio_file=None):
logging.info("Starting to create Manim video")
with open("generated_video.py", "w") as f:
manim_code_clean = re.sub(r"```python", "", manim_code)
manim_code_clean = manim_code_clean.replace("```", "").strip()
f.write(manim_code_clean)
scene_name = get_scene_name(manim_code_clean)
logging.info(f"Identified scene name: {scene_name}")
command = ["manim", "-qh", "generated_video.py", scene_name]
logging.info(f"Running Manim with command: {' '.join(command)}")
subprocess.run(command, check=True)
search_pattern = os.path.join("media", "videos", "generated_video", "1080p60", f"{scene_name}.mp4")
if not os.path.exists(search_pattern):
logging.error(f"No rendered video found at: {search_pattern}")
raise Exception(f"No rendered video found for scene {scene_name}")
output_video = search_pattern
final_output = "final_output.mp4"
if audio_file and os.path.exists(audio_file):
logging.info(f"Merging video with audio file: {audio_file}")
video_duration_cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1", output_video]
audio_duration_cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1", audio_file]
video_duration = float(subprocess.check_output(video_duration_cmd).decode('utf-8').strip())
audio_duration = float(subprocess.check_output(audio_duration_cmd).decode('utf-8').strip())
logging.info(f"Video duration: {video_duration}s, Audio duration: {audio_duration}s")
if audio_duration > video_duration:
logging.info("Audio is longer than video, extending video duration")
extended_video = "extended_video.mp4"
padding_time = audio_duration - video_duration
extend_cmd = [
"ffmpeg", "-y",
"-i", output_video,
"-f", "lavfi", "-i", "color=black:s=1920x1080:r=60",
"-filter_complex", f"[0:v][1:v]concat=n=2:v=1:a=0[outv]",
"-map", "[outv]",
"-c:v", "libx264",
"-t", str(audio_duration),
extended_video
]
logging.info(f"Extending video with command: {' '.join(extend_cmd)}")
subprocess.run(extend_cmd, check=True)
output_video = extended_video
merge_cmd = [
"ffmpeg", "-y",
"-i", output_video,
"-i", audio_file,
"-c:v", "copy",
"-c:a", "aac",
"-map", "0:v:0",
"-map", "1:a:0",
final_output
]
logging.info(f"Merging with command: {' '.join(merge_cmd)}")
subprocess.run(merge_cmd, check=True)
output_video = final_output
if os.path.exists("extended_video.mp4"):
os.remove("extended_video.mp4")
logging.info("Removed temporary extended video file")
if os.path.exists("generated_video.py"):
os.remove("generated_video.py")
logging.info("Removed generated_video.py")
logging.info(f"Final video created at: {output_video}")
return output_video