SUNO-API / app.py
haraberget's picture
Update app.py
c3f6215 verified
raw
history blame
14.2 kB
import gradio as gr
import requests
import os
import json
import uuid
import time
from datetime import datetime
from typing import Dict, Optional
# Load Suno API key
SUNO_KEY = os.environ.get("SunoKey", "")
if not SUNO_KEY:
print("⚠️ Warning: SunoKey environment variable not set!")
# Task storage
tasks_db = {}
def generate_lyrics(prompt: str) -> str:
"""Submit lyrics generation task to Suno API"""
if not SUNO_KEY:
return "❌ Error: SunoKey environment variable not set. Please add it in Space Settings."
if not prompt or not prompt.strip():
return "❌ Please enter a lyrics prompt"
# Generate task ID
task_id = str(uuid.uuid4())[:8]
# Prepare API request
url = "https://api.sunoapi.org/api/v1/lyrics"
headers = {
"Authorization": f"Bearer {SUNO_KEY}",
"Content-Type": "application/json"
}
# Suno requires a callback URL, but we'll use a dummy one and rely on polling
dummy_callback = "https://dummy.callback.url/not-used"
payload = {
"prompt": prompt,
"callBackUrl": dummy_callback
}
try:
# Submit task
response = requests.post(url, headers=headers, json=payload, timeout=30)
data = response.json()
if response.status_code == 200 and data.get("code") == 200:
api_task_id = data["data"]["taskId"]
# Store task information
tasks_db[task_id] = {
"id": task_id,
"api_task_id": api_task_id,
"prompt": prompt,
"status": "submitted",
"result": None,
"error": None,
"created_at": datetime.now().isoformat(),
"last_checked": None
}
return f"""✅ **Task Submitted Successfully!**
**Your Task ID:** `{task_id}`
**API Task ID:** `{api_task_id}`
📝 **Prompt:** {prompt[:100]}{'...' if len(prompt) > 100 else ''}
⏳ **Next Steps:**
1. Task is now processing with Suno AI
2. This usually takes 10-30 seconds
3. Click **"Check Status"** tab to check progress
4. Use your Task ID: `{task_id}`
💡 **Tip:** Save your Task ID to check results later!"""
else:
error_msg = data.get("msg", f"HTTP {response.status_code}")
return f"""❌ **Submission Failed**
**Error:** {error_msg}
💡 **Possible solutions:**
• Check if your SunoKey is valid
• Try a different prompt
• Wait a few minutes and retry"""
except requests.exceptions.Timeout:
return "❌ Error: Request timeout - Suno API is not responding"
except requests.exceptions.ConnectionError:
return "❌ Error: Connection failed - Check your internet connection"
except requests.exceptions.HTTPError as e:
return f"❌ Error: HTTP {e.response.status_code if e.response else 'Unknown'}"
except Exception as e:
return f"❌ Error: {str(e)}"
def check_task_status(task_id: str) -> str:
"""Check the status of a task using polling"""
if not task_id or not task_id.strip():
return "❌ Please enter a Task ID"
if task_id not in tasks_db:
return f"❌ Task ID `{task_id}` not found. Please submit a task first."
task = tasks_db[task_id]
api_task_id = task["api_task_id"]
# Poll the Suno API
url = f"https://api.sunoapi.org/api/v1/lyrics/details?taskId={api_task_id}"
headers = {"Authorization": f"Bearer {SUNO_KEY}"}
try:
response = requests.get(url, headers=headers, timeout=30)
data = response.json()
if response.status_code == 200 and data.get("code") == 200:
task_data = data["data"]
status = task_data.get("status", "unknown")
# Update task status
tasks_db[task_id]["status"] = status
tasks_db[task_id]["last_checked"] = datetime.now().isoformat()
if status == "completed" and "data" in task_data:
# Task completed successfully
lyrics_data = task_data["data"]
tasks_db[task_id]["result"] = lyrics_data
# Format the output
return format_lyrics_output(lyrics_data, task_id)
elif status == "failed":
error_msg = task_data.get("error", "Unknown error")
tasks_db[task_id]["error"] = error_msg
return f"""❌ **Task Failed**
**Task ID:** `{task_id}`
**Error:** {error_msg}
💡 Please try generating again with a different prompt."""
else:
# Still processing
elapsed = time_since(task["created_at"])
return f"""⏳ **Task Processing...**
**Task ID:** `{task_id}`
**Status:** {status}
**Elapsed:** {elapsed}
⏰ **Estimated time:** 10-30 seconds
🔄 **Auto-refresh recommended**
💡 Check back in a few seconds!"""
else:
error_msg = data.get("msg", f"HTTP {response.status_code}")
return f"❌ Error checking status: {error_msg}"
except Exception as e:
return f"❌ Error: {str(e)}"
def format_lyrics_output(lyrics_data, task_id):
"""Format the lyrics for display"""
if not lyrics_data:
return "✅ Task completed but no lyrics data received"
output_lines = [
f"# 🎵 Generated Lyrics (Task: {task_id})",
"",
f"**Generated at:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
""
]
for i, item in enumerate(lyrics_data, 1):
title = item.get('title', f'Variant {i}')
lyrics = item.get('text', 'No lyrics generated')
output_lines.append(f"## Variant {i}: {title}")
output_lines.append("```")
output_lines.append(lyrics)
output_lines.append("```")
output_lines.append("---")
output_lines.append("")
output_lines.append("### 🎉 All done!")
output_lines.append("You can generate more lyrics or try different prompts.")
return "\n".join(output_lines)
def time_since(iso_timestamp: str) -> str:
"""Calculate time elapsed since timestamp"""
try:
created = datetime.fromisoformat(iso_timestamp)
elapsed = datetime.now() - created
seconds = int(elapsed.total_seconds())
if seconds < 60:
return f"{seconds} seconds"
elif seconds < 3600:
minutes = seconds // 60
return f"{minutes} minutes"
else:
hours = seconds // 3600
return f"{hours} hours"
except:
return "Unknown"
def list_all_tasks():
"""List all submitted tasks"""
if not tasks_db:
return "📭 No tasks found. Generate some lyrics first!"
output_lines = ["# 📋 All Submitted Tasks", ""]
for task_id, task in tasks_db.items():
status = task.get("status", "unknown")
prompt_preview = task.get("prompt", "")[:50]
created = task.get("created_at", "")[:19]
# Status icon
if status == "completed":
icon = "✅"
elif status in ["failed", "error"]:
icon = "❌"
else:
icon = "⏳"
output_lines.append(f"{icon} **{task_id}** - {status}")
output_lines.append(f" Prompt: {prompt_preview}...")
output_lines.append(f" Created: {created}")
if task.get("last_checked"):
last_checked = task["last_checked"][:19]
output_lines.append(f" Last checked: {last_checked}")
output_lines.append("")
# Add summary
completed = sum(1 for t in tasks_db.values() if t.get("status") == "completed")
total = len(tasks_db)
output_lines.append(f"**Summary:** {completed}/{total} tasks completed")
return "\n".join(output_lines)
def auto_refresh_status(task_id: str):
"""Auto-refresh status with loading animation"""
if not task_id or task_id not in tasks_db:
return task_id, "❌ Invalid Task ID"
result = check_task_status(task_id)
return task_id, result
# Create the Gradio interface
with gr.Blocks(title="Suno Lyrics Generator", theme=gr.themes.Soft()) as app:
gr.Markdown("# 🎵 Suno AI Lyrics Generator")
gr.Markdown("Generate song lyrics using Suno's AI API")
with gr.Tabs():
# Tab 1: Generate Lyrics
with gr.TabItem("✨ Generate"):
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### Enter your lyrics idea")
prompt_input = gr.Textbox(
label="Lyrics Prompt",
placeholder="Example: A romantic ballad about stargazing on a summer night...",
lines=4
)
submit_btn = gr.Button("🚀 Generate Lyrics", variant="primary", size="lg")
gr.Markdown("### 📝 Tips:")
gr.Markdown("""
• Be descriptive in your prompt
• Include genre, mood, or theme
• Specify if you want verses, chorus, bridge
• Typical processing time: 10-30 seconds
""")
with gr.Column(scale=3):
output_area = gr.Markdown(
label="Result",
value="Your task submission result will appear here..."
)
submit_btn.click(
fn=generate_lyrics,
inputs=prompt_input,
outputs=output_area
)
# Tab 2: Check Status
with gr.TabItem("🔍 Check Status"):
with gr.Row():
with gr.Column():
gr.Markdown("### Enter your Task ID")
task_id_input = gr.Textbox(
label="Task ID",
placeholder="Paste your Task ID here (e.g., a1b2c3d4)",
scale=1
)
with gr.Row():
check_btn = gr.Button("🔍 Check Status", variant="primary")
auto_refresh_btn = gr.Button("🔄 Auto-refresh", variant="secondary")
gr.Markdown("---")
refresh_all_btn = gr.Button("📋 List All Tasks")
tasks_list = gr.Markdown(label="All Tasks")
with gr.Column():
status_output = gr.Markdown(
label="Status",
value="Enter a Task ID above and click Check Status"
)
# Connect buttons to functions
check_btn.click(
fn=check_task_status,
inputs=task_id_input,
outputs=status_output
)
auto_refresh_btn.click(
fn=auto_refresh_status,
inputs=task_id_input,
outputs=[task_id_input, status_output]
).then(
fn=lambda: time.sleep(3),
inputs=None,
outputs=None
).then(
fn=auto_refresh_status,
inputs=task_id_input,
outputs=[task_id_input, status_output]
)
refresh_all_btn.click(
fn=list_all_tasks,
inputs=None,
outputs=tasks_list
)
# Tab 3: Help & Info
with gr.TabItem("ℹ️ Help"):
gr.Markdown("# Help & Information")
with gr.Row():
with gr.Column():
gr.Markdown("### 🔑 API Status")
api_status = "✅ Configured" if SUNO_KEY else "❌ Not configured"
gr.Markdown(f"**SunoKey:** {api_status}")
gr.Markdown("### 📋 How to Use:")
gr.Markdown("""
1. **Generate Tab:** Enter a lyrics prompt and submit
2. **Save your Task ID** from the result
3. **Check Status Tab:** Paste your Task ID to check progress
4. **Results:** Lyrics will appear when processing is complete
""")
with gr.Column():
gr.Markdown("### 🚨 Troubleshooting")
gr.Markdown("""
**Common Issues:**
• **"SunoKey not set":** Add your API key in Space Settings → Repository secrets
• **"Task ID not found":** Submit a new task and save the ID
• **Long processing time:** Suno API can take 10-30 seconds
• **API errors:** Check if your API key is valid and has credits
**For best results:**
- Use descriptive prompts
- Check status after 15-20 seconds
- Save your Task IDs
""")
gr.Markdown("### 📞 Support")
gr.Markdown("""
If you continue to have issues:
1. **Check your SunoKey** is correct and has available credits
2. **Try a simpler prompt** to test the API
3. **Wait a few minutes** if the API seems busy
4. **Contact Suno API support** for API-specific issues
""")
# Launch the app
if __name__ == "__main__":
print(f"🔑 SunoKey status: {'Configured' if SUNO_KEY else 'NOT SET'}")
print(f"📊 Tasks in memory: {len(tasks_db)}")
print("🚀 Starting Suno Lyrics Generator...")
app.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
debug=False,
show_error=True
)