Spaces:
Sleeping
Sleeping
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 |