media-gen-api / backend /media_gen.py
osnarayana's picture
updated folder structure
a2bddb3
# βœ… Updated media_gen.py with file logging + UI debug toggle
import os
import re
import logging
import streamlit as st
import requests
from PIL import Image, UnidentifiedImageError
from io import BytesIO
from dotenv import load_dotenv
from moviepy.editor import ImageClip, AudioFileClip
from elevenlabs import generate, save, set_api_key
from googletrans import Translator
from PIL import ImageEnhance, Image
import tempfile
# Load env vars
load_dotenv()
# Logging setup
logging.basicConfig(
filename="app.log",
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
)
# Constants
OUTPUT_DIR = "outputs"
DEFAULT_IMAGE = "assets/fallback.jpg"
WATERMARK_PATH = "assets/logo_watermark.png"
UNSPLASH_ACCESS_KEY = os.getenv("UNSPLASH_ACCESS_KEY")
os.makedirs("outputs/audio", exist_ok=True)
os.makedirs("outputs/images", exist_ok=True)
os.makedirs("outputs/videos", exist_ok=True)
def translate_text(text, target_lang):
return Translator().translate(text, dest=target_lang).text
def sanitize_filename(text):
return re.sub(r'\W+', '_', text).lower()[:50]
def apply_watermark(image_path, watermark_path=WATERMARK_PATH):
try:
base = Image.open(image_path).convert("RGBA")
watermark = Image.open(watermark_path).convert("RGBA").resize((100, 100))
base.paste(watermark, (base.width - 110, base.height - 110), watermark)
base.convert("RGB").save(image_path)
except Exception as e:
logging.error(f"Watermarking failed: {e}")
st.write(f"❌ Watermarking failed: {e}")
def use_fallback_image(prompt, add_watermark=False):
try:
fallback_path = DEFAULT_IMAGE
output_path = f"outputs/images/{sanitize_filename(prompt)}.jpg"
with Image.open(fallback_path) as img:
img.save(output_path)
if add_watermark:
apply_watermark(output_path)
return output_path
except UnidentifiedImageError:
logging.error("Could not open fallback image.")
st.write("❌ Could not open fallback image.")
return None
def generate_gtts_fallback(prompt, output_path, lang="en", debug_mode=False):
try:
from gtts import gTTS
tts = gTTS(text=prompt, lang=lang)
tts.save(output_path)
logging.info(f"gTTS fallback audio saved to {output_path}")
if debug_mode:
st.write(f"βœ… Fallback audio (gTTS) saved to {output_path}")
return output_path
except Exception as e:
logging.error(f"gTTS fallback failed: {e}")
st.write(f"❌ gTTS fallback failed: {str(e)}")
return None
def generate_image(prompt, file_tag, add_watermark=False, dark_mode=False, debug_mode=False):
try:
# Enhance prompt if dark mode is enabled
if dark_mode:
prompt += " at night, dark theme, low light, moody lighting"
url = f"https://api.unsplash.com/photos/random?query={requests.utils.quote(prompt)}&client_id={UNSPLASH_ACCESS_KEY}"
response = requests.get(url, timeout=10)
response.raise_for_status()
image_url = response.json()["urls"]["regular"]
image_response = requests.get(image_url, timeout=10)
image_response.raise_for_status()
output_path = f"outputs/images/{sanitize_filename(prompt)}.jpg"
img = Image.open(BytesIO(image_response.content))
img.convert("RGB").save(output_path)
if add_watermark:
apply_watermark(output_path)
return output_path
except Exception as e:
logging.error(f"Image generation failed: {e}")
st.write("πŸ” Unsplash failed. Using fallback.")
st.write(f"❌ Image generation failed: {e}")
return use_fallback_image(prompt, add_watermark=add_watermark)
# βœ… Updated generate_audio with proper language handling
def generate_audio(prompt, output_path, debug_mode=False, lang="en"):
try:
api_key = os.getenv("ELEVEN_API_KEY") or st.secrets.get("ELEVEN_API_KEY", None)
# Use gTTS for non-English languages
if lang != "en":
if debug_mode:
st.write(f"🌐 Non-English language selected: {lang}. Using gTTS.")
return generate_gtts_fallback(prompt, output_path, lang=lang, debug_mode=debug_mode)
if api_key:
if debug_mode:
st.write(f"βœ… ELEVEN_API_KEY loaded: {api_key[:4]}...****")
set_api_key(api_key)
if debug_mode:
st.write(f"🎧 Generating audio for prompt: {prompt}")
try:
audio = generate(text=prompt, voice="Aria", model="eleven_monolingual_v1")
save(audio, output_path)
logging.info(f"Audio saved successfully to {output_path}")
if debug_mode:
st.write(f"πŸ” File exists after save? {os.path.exists(output_path)}")
st.write(f"βœ… Audio saved successfully to {output_path}")
return output_path
except Exception as e:
logging.warning(f"ElevenLabs failed: {e}")
if debug_mode:
st.write(f"⚠️ ElevenLabs failed: {str(e)}")
st.write("πŸ” Falling back to gTTS...")
return generate_gtts_fallback(prompt, output_path, lang=lang, debug_mode=debug_mode)
else:
logging.warning("ELEVEN_API_KEY not found")
if debug_mode:
st.write("❌ ELEVEN_API_KEY not found. Falling back to gTTS.")
return generate_gtts_fallback(prompt, output_path, lang=lang, debug_mode=debug_mode)
except Exception as e:
logging.error(f"Exception during audio generation setup: {e}")
if debug_mode:
st.write(f"❌ Exception during audio generation setup: {str(e)}")
st.write("πŸ” Falling back to gTTS...")
return generate_gtts_fallback(prompt, output_path, lang=lang, debug_mode=debug_mode)
def generate_video(prompt, image_path, audio_path, output_path, add_watermark=False, dark_mode=False):
try:
# If dark_mode, darken the image temporarily
if dark_mode:
with Image.open(image_path) as img:
enhancer = ImageEnhance.Brightness(img)
darker_img = enhancer.enhance(0.5) # Reduce brightness to 50%
# Save to a temporary file
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as tmp:
temp_image_path = tmp.name
darker_img.save(temp_image_path)
image_path = temp_image_path
audio_clip = AudioFileClip(audio_path)
image_clip = ImageClip(image_path).set_duration(audio_clip.duration).resize(height=720)
video = image_clip.set_audio(audio_clip)
output_path = f"outputs/videos/{sanitize_filename(prompt)}.mp4"
video.write_videofile(output_path, fps=24, codec="libx264", audio_codec="aac", verbose=False, logger=None)
return output_path
except Exception as e:
logging.error(f"Video generation failed: {e}")
st.write(f"❌ Video generation failed: {e}")
return None