Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -101,12 +101,13 @@ def generate_song_from_text(lyrics_text, style, title, instrumental, model, cust
|
|
| 101 |
task_id = data["data"]["taskId"]
|
| 102 |
yield f"✅ **Request submitted!**\nTask ID: `{task_id}`\n\n⏳ Waiting for song generation...\n"
|
| 103 |
|
| 104 |
-
# Poll for results
|
| 105 |
-
|
| 106 |
-
|
|
|
|
| 107 |
|
| 108 |
try:
|
| 109 |
-
#
|
| 110 |
check = requests.get(
|
| 111 |
f"https://api.sunoapi.org/api/v1/generate/record-info?taskId={task_id}",
|
| 112 |
headers={"Authorization": f"Bearer {SUNO_KEY}"},
|
|
@@ -116,53 +117,96 @@ def generate_song_from_text(lyrics_text, style, title, instrumental, model, cust
|
|
| 116 |
if check.status_code == 200:
|
| 117 |
check_data = check.json()
|
| 118 |
|
| 119 |
-
# Check if the response structure is valid
|
| 120 |
if check_data.get("code") != 200:
|
| 121 |
-
|
| 122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
data_info = check_data.get("data", {})
|
| 125 |
status = data_info.get("status", "PENDING")
|
| 126 |
|
| 127 |
if status == "COMPLETE":
|
| 128 |
-
#
|
| 129 |
response_data = data_info.get("response", {})
|
| 130 |
|
| 131 |
-
#
|
| 132 |
if isinstance(response_data, str):
|
| 133 |
try:
|
| 134 |
response_data = json.loads(response_data)
|
| 135 |
except:
|
| 136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
|
|
|
|
| 138 |
songs = response_data.get("data", [])
|
| 139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
if songs:
|
| 141 |
output = "🎶 **Song Generation Complete!**\n\n"
|
|
|
|
|
|
|
| 142 |
for i, song in enumerate(songs, 1):
|
| 143 |
song_title = song.get('title', f'Song {i}')
|
| 144 |
-
stream_url = song.get('streamUrl'
|
| 145 |
-
download_url = song.get('downloadUrl'
|
| 146 |
|
| 147 |
output += f"## Song {i}: {song_title}\n"
|
| 148 |
-
output += f"**Stream URL:** {stream_url}\n\n"
|
| 149 |
-
output += f"**Download URL:** {download_url}\n\n"
|
| 150 |
-
output += f"**Listen Now:** [Click to Stream]({stream_url})\n\n"
|
| 151 |
|
| 152 |
-
|
| 153 |
-
|
|
|
|
|
|
|
|
|
|
| 154 |
output += f"""<audio controls style="width: 100%; margin: 10px 0;">
|
| 155 |
<source src="{stream_url}" type="audio/mpeg">
|
| 156 |
Your browser does not support the audio element.
|
| 157 |
</audio>\n\n"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
|
| 159 |
output += "---\n\n"
|
| 160 |
|
| 161 |
-
output += f"⏱️ Generated in about {(attempt + 1) *
|
| 162 |
-
output += "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
yield output
|
| 164 |
else:
|
| 165 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
return
|
| 167 |
|
| 168 |
elif status == "FAILED":
|
|
@@ -172,15 +216,22 @@ def generate_song_from_text(lyrics_text, style, title, instrumental, model, cust
|
|
| 172 |
|
| 173 |
else:
|
| 174 |
# Still processing (PENDING or PROCESSING)
|
| 175 |
-
if attempt %
|
| 176 |
-
yield f"⏳ Status: {status}\
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
else:
|
| 178 |
-
yield f"⚠️ Check error: HTTP {check.status_code}"
|
| 179 |
|
| 180 |
except Exception as e:
|
| 181 |
-
yield f"⚠️ Error checking status: {str(e)}"
|
| 182 |
|
| 183 |
-
yield "⏰ Timeout after
|
| 184 |
|
| 185 |
except Exception as e:
|
| 186 |
yield f"❌ Error: {str(e)}"
|
|
@@ -304,6 +355,7 @@ with gr.Blocks(title="Suno Song Generator", theme="soft") as app:
|
|
| 304 |
**Generation time:**
|
| 305 |
- 30-40s: Stream URL ready
|
| 306 |
- 2-3 min: Download URL ready
|
|
|
|
| 307 |
""")
|
| 308 |
|
| 309 |
with gr.Column(scale=2):
|
|
|
|
| 101 |
task_id = data["data"]["taskId"]
|
| 102 |
yield f"✅ **Request submitted!**\nTask ID: `{task_id}`\n\n⏳ Waiting for song generation...\n"
|
| 103 |
|
| 104 |
+
# Poll for results
|
| 105 |
+
max_attempts = 90 # 90 attempts * 10 seconds = 900 seconds (15 minutes)
|
| 106 |
+
for attempt in range(max_attempts):
|
| 107 |
+
time.sleep(10) # Check every 10 seconds
|
| 108 |
|
| 109 |
try:
|
| 110 |
+
# Check task status
|
| 111 |
check = requests.get(
|
| 112 |
f"https://api.sunoapi.org/api/v1/generate/record-info?taskId={task_id}",
|
| 113 |
headers={"Authorization": f"Bearer {SUNO_KEY}"},
|
|
|
|
| 117 |
if check.status_code == 200:
|
| 118 |
check_data = check.json()
|
| 119 |
|
|
|
|
| 120 |
if check_data.get("code") != 200:
|
| 121 |
+
# If we get an error, check if task might still be processing
|
| 122 |
+
if attempt < max_attempts - 1:
|
| 123 |
+
continue
|
| 124 |
+
else:
|
| 125 |
+
yield f"⚠️ API returned error: {check_data.get('msg', 'Unknown')}"
|
| 126 |
+
continue
|
| 127 |
|
| 128 |
data_info = check_data.get("data", {})
|
| 129 |
status = data_info.get("status", "PENDING")
|
| 130 |
|
| 131 |
if status == "COMPLETE":
|
| 132 |
+
# Try to get the response data
|
| 133 |
response_data = data_info.get("response", {})
|
| 134 |
|
| 135 |
+
# The response might be a JSON string or already parsed
|
| 136 |
if isinstance(response_data, str):
|
| 137 |
try:
|
| 138 |
response_data = json.loads(response_data)
|
| 139 |
except:
|
| 140 |
+
# Try to extract URLs directly if it's not JSON
|
| 141 |
+
yield f"🎵 **Generation Complete!**\n\n"
|
| 142 |
+
yield f"Task ID: `{task_id}`\nStatus: {status}\n\n"
|
| 143 |
+
yield "However, we couldn't parse the song URLs from the response.\n\n"
|
| 144 |
+
yield "**Try this:**\n"
|
| 145 |
+
yield "1. Go to https://sunoapi.org\n"
|
| 146 |
+
yield "2. Log in to your account\n"
|
| 147 |
+
yield f"3. Check your generation history for task ID: {task_id}\n"
|
| 148 |
+
yield "4. You should find your songs there with download links\n"
|
| 149 |
+
return
|
| 150 |
|
| 151 |
+
# Extract songs from response
|
| 152 |
songs = response_data.get("data", [])
|
| 153 |
|
| 154 |
+
if not songs:
|
| 155 |
+
# Try alternative structure
|
| 156 |
+
songs = response_data.get("songs", [])
|
| 157 |
+
|
| 158 |
if songs:
|
| 159 |
output = "🎶 **Song Generation Complete!**\n\n"
|
| 160 |
+
output += f"Generated {len(songs)} song(s)\n\n"
|
| 161 |
+
|
| 162 |
for i, song in enumerate(songs, 1):
|
| 163 |
song_title = song.get('title', f'Song {i}')
|
| 164 |
+
stream_url = song.get('streamUrl') or song.get('stream_url')
|
| 165 |
+
download_url = song.get('downloadUrl') or song.get('download_url')
|
| 166 |
|
| 167 |
output += f"## Song {i}: {song_title}\n"
|
|
|
|
|
|
|
|
|
|
| 168 |
|
| 169 |
+
if stream_url:
|
| 170 |
+
output += f"**Stream URL:** {stream_url}\n\n"
|
| 171 |
+
output += f"**Listen Now:** [Click to Stream]({stream_url})\n\n"
|
| 172 |
+
|
| 173 |
+
# Add audio player for streaming
|
| 174 |
output += f"""<audio controls style="width: 100%; margin: 10px 0;">
|
| 175 |
<source src="{stream_url}" type="audio/mpeg">
|
| 176 |
Your browser does not support the audio element.
|
| 177 |
</audio>\n\n"""
|
| 178 |
+
else:
|
| 179 |
+
output += "⚠️ Stream URL not available yet\n\n"
|
| 180 |
+
|
| 181 |
+
if download_url:
|
| 182 |
+
output += f"**Download URL:** {download_url}\n\n"
|
| 183 |
+
output += f"**Download:** [Click to Download]({download_url})\n\n"
|
| 184 |
+
else:
|
| 185 |
+
output += "⚠️ Download URL not available yet (check back in 2-3 minutes)\n\n"
|
| 186 |
|
| 187 |
output += "---\n\n"
|
| 188 |
|
| 189 |
+
output += f"⏱️ Generated in about {(attempt + 1) * 10} seconds\n\n"
|
| 190 |
+
output += "**Tips:**\n"
|
| 191 |
+
output += "- Stream URLs work immediately\n"
|
| 192 |
+
output += "- Download URLs may take 2-3 minutes to become available\n"
|
| 193 |
+
output += "- Files are retained for 15 days\n\n"
|
| 194 |
+
output += "**If URLs don't work:**\n"
|
| 195 |
+
output += f"1. Visit https://sunoapi.org\n"
|
| 196 |
+
output += f"2. Log in and check your generation history\n"
|
| 197 |
+
output += f"3. Look for task ID: `{task_id}`\n"
|
| 198 |
+
|
| 199 |
yield output
|
| 200 |
else:
|
| 201 |
+
# No songs found in response
|
| 202 |
+
yield f"🎵 **Generation Complete!**\n\n"
|
| 203 |
+
yield f"Task ID: `{task_id}`\nStatus: {status}\n\n"
|
| 204 |
+
yield "**To access your songs:**\n"
|
| 205 |
+
yield "1. Go to https://sunoapi.org\n"
|
| 206 |
+
yield "2. Log in to your account\n"
|
| 207 |
+
yield "3. Check your generation history\n"
|
| 208 |
+
yield f"4. Look for task ID: `{task_id}`\n"
|
| 209 |
+
yield "\nThe songs should be available there with download links."
|
| 210 |
return
|
| 211 |
|
| 212 |
elif status == "FAILED":
|
|
|
|
| 216 |
|
| 217 |
else:
|
| 218 |
# Still processing (PENDING or PROCESSING)
|
| 219 |
+
if attempt % 3 == 0: # Update every 30 seconds
|
| 220 |
+
yield f"⏳ Status: {status}\n"
|
| 221 |
+
yield f"Attempt: {attempt + 1}/{max_attempts}\n"
|
| 222 |
+
yield f"Task ID: `{task_id}`\n\n"
|
| 223 |
+
yield "Still processing...\n\n"
|
| 224 |
+
yield "**Typical timing:**\n"
|
| 225 |
+
yield "- 30-40 seconds: Stream URL ready\n"
|
| 226 |
+
yield "- 2-3 minutes: Download URL ready\n"
|
| 227 |
+
yield "- Up to 5 minutes for longer songs\n"
|
| 228 |
else:
|
| 229 |
+
yield f"⚠️ Check error: HTTP {check.status_code} - Task might still be processing"
|
| 230 |
|
| 231 |
except Exception as e:
|
| 232 |
+
yield f"⚠️ Error checking status: {str(e)} - Will try again..."
|
| 233 |
|
| 234 |
+
yield "⏰ Timeout after 15 minutes. Try checking your Suno API dashboard for results."
|
| 235 |
|
| 236 |
except Exception as e:
|
| 237 |
yield f"❌ Error: {str(e)}"
|
|
|
|
| 355 |
**Generation time:**
|
| 356 |
- 30-40s: Stream URL ready
|
| 357 |
- 2-3 min: Download URL ready
|
| 358 |
+
- Up to 5 min for longer songs
|
| 359 |
""")
|
| 360 |
|
| 361 |
with gr.Column(scale=2):
|