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 |