Spaces:
Running
Running
| import os | |
| import requests | |
| import gradio as gr | |
| from dotenv import load_dotenv | |
| import json | |
| import uuid | |
| import tempfile | |
| from datetime import datetime | |
| # Load environment variables from .env file | |
| load_dotenv() | |
| # Get Suno API key from environment variable (loaded from secrets) | |
| SUNO_API_KEY = os.environ.get("SunoKey") | |
| # Fixed callback URL | |
| FIXED_CALLBACK_URL = "https://1hit.no/cover/cb.php" | |
| # API endpoint | |
| SUNO_API_URL = "https://api.sunoapi.org/api/v1/generate/upload-cover" | |
| def generate_suno_music( | |
| prompt, | |
| title, | |
| style, | |
| upload_url_type, | |
| custom_upload_url, | |
| instrumental=True, | |
| model="V4_5ALL", | |
| persona_id="", | |
| negative_tags="", | |
| vocal_gender="m", | |
| style_weight=0.65, | |
| weirdness_constraint=0.65, | |
| audio_weight=0.65, | |
| custom_mode=True | |
| ): | |
| """ | |
| Generate music using Suno API with fixed callback URL | |
| """ | |
| # Check if API key is available | |
| if not SUNO_API_KEY: | |
| return f"Error: Suno API key not found. Please set the 'SunoKey' environment variable or secret." | |
| # Determine upload URL based on selection | |
| if upload_url_type == "auto": | |
| # Generate a temporary upload URL (simulated - in practice this would be your storage service) | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| unique_id = str(uuid.uuid4())[:8] | |
| upload_url = f"https://storage.temp.example.com/uploads/{timestamp}_{unique_id}.mp3" | |
| else: | |
| # Use custom URL provided by user | |
| upload_url = custom_upload_url.strip() | |
| if not upload_url: | |
| return "Error: Please provide a custom upload URL or select 'Auto-generate temporary URL'" | |
| # Prepare payload with fixed callback URL | |
| payload = { | |
| "uploadUrl": upload_url, | |
| "customMode": custom_mode, | |
| "instrumental": instrumental, | |
| "model": model, | |
| "callBackUrl": FIXED_CALLBACK_URL, # Always use fixed callback URL | |
| "prompt": prompt, | |
| "style": style, | |
| "title": title, | |
| "personaId": persona_id, | |
| "negativeTags": negative_tags, | |
| "vocalGender": vocal_gender, | |
| "styleWeight": style_weight, | |
| "weirdnessConstraint": weirdness_constraint, | |
| "audioWeight": audio_weight | |
| } | |
| # Remove empty fields | |
| payload = {k: v for k, v in payload.items() if v not in ["", None]} | |
| # Prepare headers | |
| headers = { | |
| "Authorization": f"Bearer {SUNO_API_KEY}", | |
| "Content-Type": "application/json" | |
| } | |
| try: | |
| # Make API request | |
| response = requests.post(SUNO_API_URL, json=payload, headers=headers) | |
| # Check response status | |
| if response.status_code == 200: | |
| result = response.json() | |
| if result.get("code") == 200: | |
| task_id = result.get("data", {}).get("taskId", "Unknown") | |
| generated_url = upload_url if upload_url_type == "auto" else "Custom URL provided" | |
| return f"""✅ Success! | |
| Task ID: {task_id} | |
| Upload URL: {generated_url} | |
| Callback URL: {FIXED_CALLBACK_URL} | |
| 📋 Full API Response: | |
| {json.dumps(result, indent=2)}""" | |
| else: | |
| return f"""❌ API Error: {result.get('msg', 'Unknown error')} | |
| 📋 Full API Response: | |
| {json.dumps(result, indent=2)}""" | |
| else: | |
| return f"""❌ HTTP Error {response.status_code} | |
| Response: | |
| {response.text}""" | |
| except requests.exceptions.RequestException as e: | |
| return f"❌ Request failed: {str(e)}" | |
| except json.JSONDecodeError as e: | |
| return f"❌ Failed to parse response: {str(e)}\n\nResponse text: {response.text}" | |
| except Exception as e: | |
| return f"❌ Unexpected error: {str(e)}" | |
| # Create Gradio interface | |
| with gr.Blocks(title="Suno Music Generator") as app: | |
| gr.Markdown("# 🎵 Suno Music Generator") | |
| gr.Markdown(f"Generate music using Suno API. Callback URL is fixed to: `{FIXED_CALLBACK_URL}`") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### API Status") | |
| api_status = gr.Textbox( | |
| label="API Key Status", | |
| value=f"API Key: {'✅ Loaded' if SUNO_API_KEY else '❌ Not found'}" | |
| if SUNO_API_KEY else "❌ API Key not found. Please set 'SunoKey' environment variable.", | |
| interactive=False | |
| ) | |
| with gr.Column(scale=2): | |
| gr.Markdown("### About") | |
| gr.Markdown(f""" | |
| This app generates music using the Suno API. | |
| **Fixed Callback URL:** `{FIXED_CALLBACK_URL}` | |
| **Required setup:** | |
| 1. The basis for song generation is an mp3 url. | |
| 2. The setup here is weird. You click the automatic - not working button. | |
| 3. Then the other button. | |
| 4. Add URL. Typically from suno, udio or soundcloud download from other libraries. | |
| """) | |
| with gr.Tabs(): | |
| with gr.TabItem("Basic Settings"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| prompt = gr.Textbox( | |
| label="Music Prompt", | |
| value="A calm and relaxing piano track with soft melodies", | |
| placeholder="Describe the music you want to generate...", | |
| lines=3 | |
| ) | |
| title = gr.Textbox( | |
| label="Title", | |
| value="Peaceful Piano Meditation", | |
| placeholder="Title for your music track" | |
| ) | |
| style = gr.Textbox( | |
| label="Style", | |
| value="Classical", | |
| placeholder="Music style (e.g., Classical, Pop, Rock, Jazz)" | |
| ) | |
| with gr.Column(): | |
| gr.Markdown("### Upload URL Settings") | |
| upload_url_type = gr.Radio( | |
| label="Upload URL Type", | |
| choices=[ | |
| ("Auto - not working", "auto"), | |
| ("Use custom URL", "custom") | |
| ], | |
| value="custom", | |
| info="Auto-generate creates a temporary URL, or provide your own" | |
| ) | |
| custom_upload_url = gr.Textbox( | |
| label="Custom Upload URL", | |
| value="https://storage.example.com/upload", | |
| placeholder="Enter your custom upload URL here", | |
| visible=False | |
| ) | |
| # Show/hide custom URL field based on radio selection | |
| def toggle_upload_url(selection): | |
| return gr.update(visible=selection == "custom") | |
| upload_url_type.change( | |
| toggle_upload_url, | |
| inputs=upload_url_type, | |
| outputs=custom_upload_url | |
| ) | |
| with gr.TabItem("Advanced Settings"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| model = gr.Dropdown( | |
| label="Model", | |
| choices=["V5", "V4_5ALL", "V4", "V3", "V2"], | |
| value="V4_5ALL" | |
| ) | |
| instrumental = gr.Checkbox( | |
| label="Instrumental", | |
| value=True | |
| ) | |
| custom_mode = gr.Checkbox( | |
| label="Custom Mode", | |
| value=True | |
| ) | |
| with gr.Column(): | |
| persona_id = gr.Textbox( | |
| label="Persona ID (Optional)", | |
| value="persona_123", | |
| placeholder="Leave empty for no persona" | |
| ) | |
| negative_tags = gr.Textbox( | |
| label="Negative Tags (Optional)", | |
| value="Heavy Metal, Upbeat Drums", | |
| placeholder="Tags to avoid in the music" | |
| ) | |
| vocal_gender = gr.Dropdown( | |
| label="Vocal Gender", | |
| choices=["m", "f", "none"], | |
| value="m" | |
| ) | |
| with gr.TabItem("Weight Settings"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| style_weight = gr.Slider( | |
| label="Style Weight", | |
| minimum=0.0, | |
| maximum=1.0, | |
| value=0.65, | |
| step=0.05 | |
| ) | |
| weirdness_constraint = gr.Slider( | |
| label="Weirdness Constraint", | |
| minimum=0.0, | |
| maximum=1.0, | |
| value=0.65, | |
| step=0.05 | |
| ) | |
| audio_weight = gr.Slider( | |
| label="Audio Weight", | |
| minimum=0.0, | |
| maximum=1.0, | |
| value=0.65, | |
| step=0.05 | |
| ) | |
| # Submit button | |
| submit_btn = gr.Button("🎶 Generate Music", variant="primary", size="lg") | |
| # Output | |
| output = gr.Textbox( | |
| label="Generation Result", | |
| lines=12, | |
| interactive=False | |
| ) | |
| # Example button | |
| example_btn = gr.Button("📋 Load Example", variant="secondary") | |
| # Define button actions | |
| def load_example(): | |
| return { | |
| prompt: "A calm and relaxing piano track with soft melodies", | |
| title: "Peaceful Piano Meditation", | |
| style: "Classical", | |
| upload_url_type: "auto", | |
| custom_upload_url: "https://storage.example.com/upload", | |
| model: "V4_5ALL", | |
| instrumental: True, | |
| custom_mode: True, | |
| persona_id: "persona_123", | |
| negative_tags: "Heavy Metal, Upbeat Drums", | |
| vocal_gender: "m", | |
| style_weight: 0.65, | |
| weirdness_constraint: 0.65, | |
| audio_weight: 0.65 | |
| } | |
| # Connect buttons | |
| example_btn.click( | |
| load_example, | |
| outputs=[ | |
| prompt, title, style, upload_url_type, custom_upload_url, | |
| model, instrumental, custom_mode, persona_id, | |
| negative_tags, vocal_gender, style_weight, | |
| weirdness_constraint, audio_weight | |
| ] | |
| ) | |
| submit_btn.click( | |
| generate_suno_music, | |
| inputs=[ | |
| prompt, title, style, upload_url_type, custom_upload_url, | |
| instrumental, model, persona_id, negative_tags, | |
| vocal_gender, style_weight, weirdness_constraint, | |
| audio_weight, custom_mode | |
| ], | |
| outputs=output | |
| ) | |
| # Footer | |
| gr.Markdown("---") | |
| # Launch the app | |
| if __name__ == "__main__": | |
| # Check if API key is available | |
| if not SUNO_API_KEY: | |
| print("⚠️ Warning: Suno API key not found.") | |
| print("Please set the 'SunoKey' environment variable:") | |
| print(" - For Hugging Face Spaces: Add as Repository Secret") | |
| print(" - For local development: Create a .env file with SunoKey=your_key") | |
| print(" - Or set it directly: export SunoKey=your_key") | |
| app.launch( | |
| server_name="0.0.0.0" if os.environ.get("GRADIO_SERVER_NAME") else None, | |
| server_port=int(os.environ.get("GRADIO_SERVER_PORT", 7860)), | |
| share=os.environ.get("GRADIO_SHARE", "False").lower() == "true", | |
| theme=gr.themes.Soft() | |
| ) |