import streamlit as st import requests import base64 import numpy as np import matplotlib.pyplot as plt import librosa import librosa.display from io import BytesIO import soundfile as sf # Page configuration st.set_page_config( page_title="Moodify AI", page_icon="🎵", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS st.markdown(""" """, unsafe_allow_html=True) # API Base URL API_URL = "http://127.0.0.1:8000" # Timeout settings based on duration def get_timeout(duration): """Calculate appropriate timeout based on duration""" # CPU: ~6-10 seconds per 1 second of audio # Add 30s buffer for processing return max(duration * 10 + 30, 180) # Minimum 3 minutes # Check backend connection def check_backend(): """Check if backend is running""" try: response = requests.get(f"{API_URL}/", timeout=5) if response.status_code == 200: data = response.json() return True, data.get('device', 'unknown') return False, None except: return False, None # Header st.markdown("

Moodify AI

", unsafe_allow_html=True) st.markdown("

AI-Based Music Mood & Remix Generator

", unsafe_allow_html=True) # Backend status check backend_online, device_type = check_backend() if not backend_online: st.error("⚠️ Backend not running! Please start the backend server on port 8000.") st.info("Run in terminal: `cd backend && python main.py`") st.stop() else: # Show device info if device_type == 'cpu': st.warning("🐌 Running on CPU - Generation takes 30-120 seconds. Please be patient!") else: st.success(f"⚡ Running on {device_type.upper()} - Fast generation enabled!") # Sidebar with st.sidebar: st.header("Configuration") mode = st.radio( "Select Mode", ["Generate New Music", "Remix Existing Audio", "Analyze Audio"], help="Choose what you want to do with Moodify AI" ) # Performance tips with st.expander("⚡ Performance Tips"): st.markdown(""" **On CPU:** - Start with 5-8 second durations - Generation takes ~30-120 seconds - Be patient - it's working! **To Speed Up:** - Use shorter durations (5-10s) - Close other heavy applications - Use a GPU if available """) # Main content area if mode == "Generate New Music": st.header("Generate New Music") col1, col2 = st.columns(2) with col1: st.subheader("Select Mood") mood = st.selectbox( "Choose a mood for your music", ["", "Happy", "Calm", "Energetic", "Romantic", "Focused", "Party"] ) with col2: st.subheader("Select Genre") genre = st.selectbox( "Choose a genre", ["", "Pop", "Rock", "Electronic", "Classical", "Jazz", "Hip Hop", "Ambient", "Lo-fi"] ) st.subheader("Describe Your Music") prompt = st.text_area( "Describe your music", placeholder="e.g., 'A peaceful morning with birds chirping'", height=100 ) # Duration with warning duration = st.slider("Duration (seconds)", 5, 30, 8) if device_type == 'cpu' and duration > 15: st.warning(f"⚠️ {duration}s on CPU will take ~{duration * 6}-{duration * 10} seconds to generate") if st.button("Generate Music"): if not mood and not genre and not prompt: st.error("Please select a mood, genre, or enter a text prompt!") else: timeout = get_timeout(duration) # Show estimated time if device_type == 'cpu': estimated_time = duration * 8 st.info(f"⏱️ Estimated time: ~{estimated_time} seconds. Please wait...") with st.spinner(f"🎵 Generating {duration}s of music... This may take a while on CPU..."): try: response = requests.post( f"{API_URL}/generate", json={"mood": mood, "genre": genre, "prompt": prompt, "duration": duration}, timeout=timeout ) if response.status_code == 200: result = response.json() audio_bytes = base64.b64decode(result["audio_base64"]) st.success("✅ Music generated successfully!") st.audio(audio_bytes, format="audio/wav") col1, col2 = st.columns(2) with col1: st.download_button( "📥 Download Audio", audio_bytes, file_name="moodify_generated.wav", mime="audio/wav" ) with col2: st.metric("Duration", f"{result.get('duration', duration)}s") else: error_detail = response.json().get('detail', 'Unknown error') st.error(f"❌ Generation failed: {error_detail}") except requests.exceptions.ConnectionError: st.error("❌ Cannot connect to backend. Is it running on port 8000?") except requests.exceptions.Timeout: st.error(f"⏱️ Generation timed out after {timeout} seconds.") st.info(""" **Troubleshooting:** - Try a shorter duration (5-8 seconds) - Backend is still working - check terminal - On CPU, 10s takes ~60-90 seconds - Wait a bit and check if file appears """) except Exception as e: st.error(f"❌ Error: {str(e)}") elif mode == "Remix Existing Audio": st.header("Remix Existing Audio") uploaded_file = st.file_uploader( "Upload audio file (WAV, MP3, OGG)", type=["wav", "mp3", "ogg"] ) if uploaded_file: st.subheader("Original Audio") st.audio(uploaded_file) target_mood = st.selectbox( "Select Target Mood for Remix", ["Happy", "Calm", "Energetic", "Romantic", "Focused", "Party"] ) if st.button("Remix Audio"): with st.spinner("🎚️ Remixing your audio... This takes 10-30 seconds..."): try: audio_bytes = uploaded_file.read() audio_base64 = base64.b64encode(audio_bytes).decode() response = requests.post( f"{API_URL}/remix", json={"audio_base64": audio_base64, "target_mood": target_mood}, timeout=120 # 2 minutes for remix ) if response.status_code == 200: result = response.json() remixed_bytes = base64.b64decode(result["remixed_audio_base64"]) st.success("✅ Audio remixed successfully!") st.subheader("Remixed Audio") st.audio(remixed_bytes, format="audio/wav") # Show transformation details if available if "original_tempo" in result: col1, col2, col3 = st.columns(3) with col1: st.metric("Original Tempo", f"{result['original_tempo']:.1f} BPM") with col2: st.metric("Target Tempo", f"{result['target_tempo']:.1f} BPM") with col3: st.metric("Stretch Factor", f"{result['stretch_factor']:.2f}x") st.download_button( "📥 Download Remixed Audio", remixed_bytes, file_name=f"moodify_remix_{target_mood.lower()}.wav", mime="audio/wav" ) else: error_detail = response.json().get('detail', 'Unknown error') st.error(f"❌ Remix failed: {error_detail}") except requests.exceptions.ConnectionError: st.error("❌ Cannot connect to backend. Is it running on port 8000?") except requests.exceptions.Timeout: st.error("⏱️ Remix timed out. Try a shorter audio file (< 30 seconds).") except Exception as e: st.error(f"❌ Error: {str(e)}") elif mode == "Analyze Audio": st.header("Analyze Audio Features") uploaded_file = st.file_uploader( "Upload audio file for analysis", type=["wav", "mp3", "ogg"] ) if uploaded_file: st.subheader("Uploaded Audio") st.audio(uploaded_file) if st.button("Analyze Audio"): with st.spinner("🔍 Analyzing audio features..."): try: audio_bytes = uploaded_file.read() audio_base64 = base64.b64encode(audio_bytes).decode() response = requests.post( f"{API_URL}/analyze", json={"audio_base64": audio_base64}, timeout=60 ) if response.status_code == 200: result = response.json() st.success("✅ Analysis completed!") # Display results in a nice layout st.subheader("Audio Features") col1, col2, col3 = st.columns(3) with col1: st.metric("Tempo", f"{result.get('tempo', 0):.1f} BPM") st.metric("Duration", f"{result.get('duration', 0):.2f}s") with col2: st.metric("Energy", f"{result.get('energy', 0):.3f}") st.metric("Estimated Key", result.get('estimated_key', 'N/A')) with col3: st.metric("Spectral Centroid", f"{result.get('spectral_centroid', 0):.1f} Hz") st.metric("Zero Crossing Rate", f"{result.get('zero_crossing_rate', 0):.4f}") # Additional details in expander with st.expander("🔬 Technical Details"): st.json(result) else: error_detail = response.json().get('detail', 'Unknown error') st.error(f"❌ Analysis failed: {error_detail}") except requests.exceptions.ConnectionError: st.error("❌ Cannot connect to backend. Is it running on port 8000?") except requests.exceptions.Timeout: st.error("⏱️ Analysis timed out. Try a shorter audio file.") except Exception as e: st.error(f"❌ Error: {str(e)}") # Footer st.markdown("---") st.markdown(""" """, unsafe_allow_html=True) # Force layout refresh (prevents bottom notch) st.write("")