media-gen-api / app /services /video_service.py
osnarayana's picture
Fix video_service.py
2c3ea7b
import os, uuid, requests
from gtts import gTTS
from mutagen.mp3 import MP3
from moviepy.editor import ImageClip, concatenate_videoclips, AudioFileClip
from moviepy.config import change_settings
# βœ… Force MoviePy temp directory to /tmp
change_settings({"FFMPEG_BINARY": "ffmpeg"})
os.environ["TMPDIR"] = "/tmp"
def generate_video_file(script: str, duration: int = None) -> str:
base_tmp = "/tmp/video"
audio_tmp = "/tmp/audio"
tmp_images = "/tmp/video_tmp"
os.makedirs(base_tmp, exist_ok=True)
os.makedirs(audio_tmp, exist_ok=True)
os.makedirs(tmp_images, exist_ok=True)
video_filename = f"video_{uuid.uuid4().hex}.mp4"
video_path = os.path.join(base_tmp, video_filename)
audio_path = os.path.join(audio_tmp, f"audio_{uuid.uuid4().hex}.mp3")
# Step 1: Generate TTS audio
tts = gTTS(text=script, lang='en')
tts.save(audio_path)
# Step 2: Get audio duration
audio = MP3(audio_path)
audio_duration = max(audio.info.length, 3.0)
# Step 3: Fetch Unsplash images
images = fetch_unsplash_images(script, count=3)
if not images:
raise Exception("No images found from Unsplash for the prompt")
clips, tmp_files = [], []
per_image_duration = audio_duration / len(images)
for url in images:
img_data = requests.get(url).content
tmp_file = os.path.join(tmp_images, f"tmp_{uuid.uuid4().hex}.jpg")
tmp_files.append(tmp_file)
with open(tmp_file, "wb") as f:
f.write(img_data)
clip = ImageClip(tmp_file).resize(height=720).set_duration(per_image_duration)
clips.append(clip)
# Step 4: Build final video
final_clip = concatenate_videoclips(clips, method="compose").set_duration(audio_duration)
final_clip = final_clip.set_audio(AudioFileClip(audio_path))
# βœ… Step 5: Export video with all temp files in /tmp
final_clip.write_videofile(
video_path,
fps=24,
codec="libx264",
audio_codec="aac",
threads=4,
preset="ultrafast",
temp_audiofile="/tmp/temp-audio.m4a",
remove_temp=True,
ffmpeg_params=["-avoid_negative_ts", "make_zero"]
)
# Cleanup images
for file in tmp_files:
try:
os.remove(file)
except:
pass
return video_filename