Spaces:
Sleeping
Sleeping
#!/usr/bin/env python3 | |
""" | |
Madverse Music - Hugging Face Spaces Version | |
Streamlit app for HF Spaces deployment | |
""" | |
import streamlit as st | |
import torch | |
import librosa | |
import tempfile | |
import os | |
import time | |
import numpy as np | |
# Import the sonics library for model loading | |
try: | |
from sonics import HFAudioClassifier | |
except ImportError: | |
st.error("Sonics library not found. Please install it first.") | |
st.stop() | |
# Global model variable | |
model = None | |
# Page configuration | |
st.set_page_config( | |
page_title="Madverse Music: AI Music Detector", | |
page_icon="🎵", | |
layout="wide", | |
initial_sidebar_state="expanded" | |
) | |
# Custom CSS | |
st.markdown(""" | |
<style> | |
.main-header { | |
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); | |
padding: 1rem; | |
border-radius: 10px; | |
color: white; | |
text-align: center; | |
margin-bottom: 2rem; | |
} | |
.result-box { | |
padding: 1rem; | |
border-radius: 10px; | |
margin: 1rem 0; | |
border-left: 5px solid; | |
} | |
.real-music { | |
background-color: #d4edda; | |
border-left-color: #28a745; | |
} | |
.fake-music { | |
background-color: #f8d7da; | |
border-left-color: #dc3545; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
def load_model(): | |
"""Load the model with caching for HF Spaces""" | |
try: | |
with st.spinner("Loading AI model... This may take a moment..."): | |
# Use the same loading method as the working API | |
model = HFAudioClassifier.from_pretrained("awsaf49/sonics-spectttra-alpha-120s") | |
model.eval() | |
return model | |
except Exception as e: | |
st.error(f"Failed to load model: {str(e)}") | |
return None | |
def process_audio(audio_file, model): | |
"""Process audio file and return classification""" | |
try: | |
# Save uploaded file temporarily | |
with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as tmp_file: | |
tmp_file.write(audio_file.read()) | |
tmp_path = tmp_file.name | |
# Load audio (model uses 16kHz sample rate) | |
audio, sr = librosa.load(tmp_path, sr=16000) | |
# Convert to tensor and add batch dimension | |
audio_tensor = torch.FloatTensor(audio).unsqueeze(0) | |
# Get prediction using the same pattern as working API | |
with torch.no_grad(): | |
output = model(audio_tensor) | |
# Convert logit to probability using sigmoid | |
probability = torch.sigmoid(output).item() | |
# Classify: prob < 0.5 = Real, prob >= 0.5 = Fake | |
if probability < 0.5: | |
classification = "Real" | |
confidence = (1 - probability) * 2 # Convert to 0-1 scale | |
else: | |
classification = "Fake" | |
confidence = (probability - 0.5) * 2 # Convert to 0-1 scale | |
# Calculate duration | |
duration = len(audio) / sr | |
# Clean up | |
os.unlink(tmp_path) | |
return { | |
'classification': classification, | |
'confidence': min(confidence, 1.0), # Cap at 1.0 | |
'probability': probability, | |
'raw_score': output.item(), | |
'duration': duration, | |
'success': True | |
} | |
except Exception as e: | |
# Clean up on error | |
if 'tmp_path' in locals(): | |
try: | |
os.unlink(tmp_path) | |
except: | |
pass | |
return { | |
'success': False, | |
'error': str(e) | |
} | |
def main(): | |
# Header | |
st.markdown(""" | |
<div class="main-header"> | |
<h1>Madverse Music: AI Music Detector</h1> | |
<p>Detect AI-generated music vs human-created music using advanced AI technology</p> | |
</div> | |
""", unsafe_allow_html=True) | |
# Sidebar | |
with st.sidebar: | |
st.markdown("### About") | |
st.markdown(""" | |
This AI model can detect whether music is: | |
- **Real**: Human-created music | |
- **Fake**: AI-generated music (Suno, Udio, etc.) | |
**Model**: SpecTTTra-α (120s) | |
**Accuracy**: 97% F1 score | |
**Max Duration**: 120 seconds | |
""") | |
st.markdown("### Supported Formats") | |
st.markdown("- WAV (.wav)") | |
st.markdown("- MP3 (.mp3)") | |
st.markdown("- FLAC (.flac)") | |
st.markdown("- M4A (.m4a)") | |
st.markdown("- OGG (.ogg)") | |
st.markdown("### Links") | |
st.markdown("- [Madverse Website](https://madverse.co)") | |
st.markdown("- [GitHub Repository](#)") | |
# Load model | |
model = load_model() | |
if model is None: | |
st.error("Model failed to load. Please refresh the page.") | |
return | |
st.success("AI model loaded successfully!") | |
# File upload | |
st.markdown("### Upload Audio File") | |
uploaded_file = st.file_uploader( | |
"Choose an audio file", | |
type=['wav', 'mp3', 'flac', 'm4a', 'ogg'], | |
help="Upload an audio file to analyze (max 120 seconds)" | |
) | |
if uploaded_file is not None: | |
# Display file info | |
st.markdown("### File Information") | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
st.metric("Filename", uploaded_file.name) | |
with col2: | |
st.metric("File Size", f"{uploaded_file.size / 1024:.1f} KB") | |
with col3: | |
st.metric("Format", uploaded_file.type) | |
# Audio player | |
st.markdown("### Preview") | |
st.audio(uploaded_file) | |
# Analysis button | |
if st.button("Analyze Audio", type="primary", use_container_width=True): | |
try: | |
with st.spinner("Analyzing audio... This may take a few seconds..."): | |
# Reset file pointer | |
uploaded_file.seek(0) | |
# Process audio | |
start_time = time.time() | |
result = process_audio(uploaded_file, model) | |
processing_time = time.time() - start_time | |
if not result['success']: | |
st.error(f"Error processing audio: {result['error']}") | |
return | |
# Display results | |
st.markdown("### Analysis Results") | |
classification = result['classification'] | |
confidence = result['confidence'] | |
# Result box | |
if classification == "Real": | |
st.markdown(f""" | |
<div class="result-box real-music"> | |
<h3>Result: Human-Created Music</h3> | |
<p><strong>Classification:</strong> {classification}</p> | |
<p><strong>Confidence:</strong> {confidence:.1%}</p> | |
<p><strong>Message:</strong> This appears to be human-created music!</p> | |
</div> | |
""", unsafe_allow_html=True) | |
else: | |
st.markdown(f""" | |
<div class="result-box fake-music"> | |
<h3>Result: AI-Generated Music</h3> | |
<p><strong>Classification:</strong> {classification}</p> | |
<p><strong>Confidence:</strong> {confidence:.1%}</p> | |
<p><strong>Message:</strong> This appears to be AI-generated music!</p> | |
</div> | |
""", unsafe_allow_html=True) | |
# Detailed metrics | |
with st.expander("Detailed Metrics"): | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
st.metric("Confidence", f"{confidence:.1%}") | |
with col2: | |
st.metric("Probability", f"{result['probability']:.3f}") | |
with col3: | |
st.metric("Processing Time", f"{processing_time:.2f}s") | |
if result['duration'] > 0: | |
st.metric("Duration", f"{result['duration']:.1f}s") | |
st.markdown("**Interpretation:**") | |
st.markdown(""" | |
- **Probability < 0.5**: Classified as Real (human-created) | |
- **Probability ≥ 0.5**: Classified as Fake (AI-generated) | |
- **Confidence**: How certain the model is about its prediction | |
""") | |
except Exception as e: | |
st.error(f"Error processing audio: {str(e)}") | |
# Footer | |
st.markdown("---") | |
st.markdown(""" | |
<div style="text-align: center; color: #666;"> | |
<p>Powered by <strong>Madverse Music</strong> | Built with Streamlit & PyTorch</p> | |
<p>This tool is for research and educational purposes. Results may vary depending on audio quality.</p> | |
</div> | |
""", unsafe_allow_html=True) | |
if __name__ == "__main__": | |
main() |