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