freeai-app's picture
Update app.py
13263d1 verified
raw
history blame
4.86 kB
import gradio as gr
import os
import re
import glob
import requests
from moviepy.editor import ImageClip, AudioFileClip, CompositeAudioClip
# ================================
# Config
# ================================
HF_TOKEN = os.getenv("HF_API_TOKEN") # Hugging Face API token
OWNER_TOKEN = os.getenv("OWNER_TOKEN") # Your private owner token
SD_MODEL = "runwayml/stable-diffusion-v1-5"
# ================================
# Utility Functions
# ================================
def slugify(text):
"""Convert text into safe lowercase filename parts."""
text = text.lower()
text = re.sub(r'[^a-z0-9]+', '_', text)
return text.strip("_")
def get_next_file(base_name):
"""Increment file names: journal_001.mp4, 002, etc."""
existing = glob.glob(f"{base_name}_*.mp4")
if not existing:
return f"{base_name}_001.mp4"
nums = [int(re.search(r'(\d+).mp4', f).group(1)) for f in existing if re.search(r'(\d+).mp4', f)]
next_num = max(nums) + 1 if nums else 1
return f"{base_name}_{next_num:03d}.mp4"
def generate_image(prompt):
"""Call Hugging Face API to generate an image."""
headers = {"Authorization": f"Bearer {HF_TOKEN}"}
payload = {"inputs": prompt}
response = requests.post(
f"https://api-inference.huggingface.co/models/{SD_MODEL}",
headers=headers,
json=payload
)
if response.status_code == 200:
out_path = "generated.png"
with open(out_path, "wb") as f:
f.write(response.content)
return out_path
else:
raise RuntimeError(f"Image generation failed: {response.text}")
# ================================
# Main Video Creation
# ================================
def create_video(prompt, journal_text, duration, bg_music, user_music, add_voice, owner_token):
status = "πŸš€ Starting video generation..."
# -------- Access Rules --------
if owner_token != OWNER_TOKEN:
journal_text = "" # hide journal for public
if duration > 10:
return None, None, "⚠️ Free users can only make videos up to 10s."
else:
if duration > 600:
return None, None, "⚠️ Owner limit is 600s (10 minutes). Reduce duration."
try:
# -------- Generate image --------
status = "πŸ–ΌοΈ Generating image..."
image_path = generate_image(prompt)
# -------- Create video clip --------
status = "🎬 Creating video clip..."
clip = ImageClip(image_path, duration=duration)
# Force 1080p, 30fps
clip = clip.resize(height=1080).set_fps(30)
# -------- Background music --------
audio_clips = []
if user_music is not None:
audio_clips.append(AudioFileClip(user_music))
if bg_music != "none":
try:
audio_clips.append(AudioFileClip(f"music/{bg_music}.mp3"))
except:
pass
if audio_clips:
final_audio = CompositeAudioClip(audio_clips).set_duration(clip.duration)
clip = clip.set_audio(final_audio)
# -------- Save video --------
out_file = get_next_file("journal")
clip.write_videofile(out_file, codec="libx264", audio_codec="aac")
return out_file, image_path, "βœ… Video generation complete!"
except Exception as e:
return None, None, f"❌ Error: {str(e)}"
# ================================
# Gradio Interface
# ================================
def gradio_interface(prompt, journal_text, duration, bg_music, user_music, add_voice, owner_token):
return create_video(prompt, journal_text, duration, bg_music, user_music, add_voice, owner_token)
with gr.Blocks() as demo:
gr.Markdown("# πŸŽ₯ EchoHeart Video Generator")
gr.Markdown("Generate AI-powered videos with EchoHeart. ✨")
with gr.Row():
prompt = gr.Textbox(label="Prompt", placeholder="Describe your scene...")
journal_text = gr.Textbox(label="Journal (owner only)", type="text")
duration = gr.Slider(1, 600, value=5, step=1, label="Duration (seconds)")
bg_music = gr.Dropdown(choices=["none", "lofi", "cinematic", "happy"], value="none", label="Background Music")
user_music = gr.File(label="Upload Your Own Music (optional)", type="file")
add_voice = gr.Checkbox(label="Add Voice (owner only)")
owner_token = gr.Textbox(label="Owner Token (if you have one)", type="password")
generate_btn = gr.Button("πŸš€ Generate Video")
video_out = gr.Video(label="Generated Video")
image_out = gr.Image(label="Generated Image")
status_out = gr.Textbox(label="Status")
generate_btn.click(
fn=gradio_interface,
inputs=[prompt, journal_text, duration, bg_music, user_music, add_voice, owner_token],
outputs=[video_out, image_out, status_out]
)
demo.launch()