MySafeCode commited on
Commit
1b4d13d
·
verified ·
1 Parent(s): 0d5b97b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +268 -336
app.py CHANGED
@@ -1,7 +1,6 @@
1
  import gradio as gr
2
  import requests
3
  import os
4
- import time
5
  import json
6
 
7
  # Suno API key
@@ -9,133 +8,19 @@ SUNO_KEY = os.environ.get("SunoKey", "")
9
  if not SUNO_KEY:
10
  print("⚠️ SunoKey not set!")
11
 
12
- def get_task_info(task_id):
13
- """Manually check any Suno task status"""
14
- if not task_id:
15
- return "❌ Please enter a Task ID"
16
-
17
- try:
18
- resp = requests.get(
19
- "https://api.sunoapi.org/api/v1/generate/record-info",
20
- headers={"Authorization": f"Bearer {SUNO_KEY}"},
21
- params={"taskId": task_id},
22
- timeout=30
23
- )
24
-
25
- if resp.status_code != 200:
26
- return f"❌ HTTP Error {resp.status_code}\n\n{resp.text}"
27
-
28
- data = resp.json()
29
-
30
- # Format the response for display
31
- output = f"## 🔍 Task Status: `{task_id}`\n\n"
32
-
33
- if data.get("code") == 200:
34
- task_data = data.get("data", {})
35
- status = task_data.get("status", "UNKNOWN")
36
-
37
- output += f"**Status:** {status}\n"
38
- output += f"**Task ID:** `{task_data.get('taskId', 'N/A')}`\n"
39
- output += f"**Music ID:** `{task_data.get('musicId', 'N/A')}`\n"
40
- output += f"**Created:** {task_data.get('createTime', 'N/A')}\n"
41
-
42
- if status == "SUCCESS":
43
- response_data = task_data.get("response", {})
44
-
45
- # Try to parse response (could be string or dict)
46
- if isinstance(response_data, str):
47
- try:
48
- response_data = json.loads(response_data)
49
- except:
50
- output += f"\n**Raw Response:**\n```\n{response_data}\n```\n"
51
- response_data = {}
52
-
53
- # Check for song data
54
- songs = []
55
- if isinstance(response_data, dict):
56
- songs = response_data.get("sunoData", [])
57
- if not songs:
58
- songs = response_data.get("data", [])
59
- elif isinstance(response_data, list):
60
- songs = response_data
61
-
62
- if songs:
63
- output += f"\n## 🎵 Generated Songs ({len(songs)})\n\n"
64
-
65
- for i, song in enumerate(songs, 1):
66
- if isinstance(song, dict):
67
- output += f"### Song {i}\n"
68
- output += f"**Title:** {song.get('title', 'Untitled')}\n"
69
- output += f"**ID:** `{song.get('id', 'N/A')}`\n"
70
-
71
- # Audio URLs
72
- audio_url = song.get('audioUrl') or song.get('audio_url')
73
- stream_url = song.get('streamUrl') or song.get('stream_url')
74
- download_url = song.get('downloadUrl') or song.get('download_url')
75
-
76
- if audio_url:
77
- output += f"**Audio:** [Play]({audio_url}) | [Download]({audio_url})\n"
78
- elif stream_url:
79
- output += f"**Stream:** [Play]({stream_url})\n"
80
-
81
- if download_url:
82
- output += f"**Download:** [MP3]({download_url})\n"
83
-
84
- # Audio player
85
- play_url = audio_url or stream_url
86
- if play_url:
87
- output += f"""\n<audio controls style="width: 100%; margin: 10px 0;">
88
- <source src="{play_url}" type="audio/mpeg">
89
- Your browser does not support audio.
90
- </audio>\n"""
91
-
92
- output += f"**Prompt:** {song.get('prompt', 'N/A')[:100]}...\n"
93
- output += f"**Duration:** {song.get('duration', 'N/A')}s\n"
94
- output += f"**Created:** {song.get('createTime', 'N/A')}\n\n"
95
- output += "---\n\n"
96
- else:
97
- output += "\n**No song data found in response.**\n"
98
-
99
- elif status == "FAILED":
100
- error_msg = task_data.get("errorMessage", "Unknown error")
101
- output += f"\n**Error:** {error_msg}\n"
102
-
103
- elif status in ["PENDING", "PROCESSING", "RUNNING"]:
104
- output += f"\n**Task is still processing...**\n"
105
- output += f"Check again in 30 seconds.\n"
106
-
107
- else:
108
- output += f"\n**Unknown status:** {status}\n"
109
-
110
- else:
111
- output += f"**API Error:** {data.get('msg', 'Unknown')}\n"
112
-
113
- # Show raw JSON for debugging
114
- output += "\n## 📋 Raw Response\n"
115
- output += f"```json\n{json.dumps(data, indent=2)}\n```"
116
-
117
- return output
118
-
119
- except Exception as e:
120
- return f"❌ Error checking task: {str(e)}"
121
-
122
- def generate_song_from_text(lyrics_text, style, title, instrumental, model):
123
- """Generate a song from lyrics text"""
124
  if not SUNO_KEY:
125
- yield "❌ Error: SunoKey not configured in environment variables"
126
- return
127
 
128
  if not lyrics_text.strip() and not instrumental:
129
- yield "❌ Error: Please provide lyrics or select instrumental"
130
- return
131
 
132
  if not style.strip():
133
- yield "❌ Error: Please provide a music style"
134
- return
135
 
136
  if not title.strip():
137
- yield "❌ Error: Please provide a song title"
138
- return
139
 
140
  try:
141
  # Prepare request data
@@ -152,305 +37,352 @@ def generate_song_from_text(lyrics_text, style, title, instrumental, model):
152
  # Apply character limits
153
  if model == "V4" and len(lyrics_text) > 3000:
154
  lyrics_text = lyrics_text[:3000]
155
- yield f"⚠️ Lyrics truncated to 3000 characters for V4 model\n\n"
156
  elif model in ["V4_5", "V4_5PLUS", "V4_5ALL", "V5"] and len(lyrics_text) > 5000:
157
  lyrics_text = lyrics_text[:5000]
158
- yield f"⚠️ Lyrics truncated to 5000 characters for {model} model\n\n"
159
 
160
  request_data["prompt"] = lyrics_text
161
  else:
162
  request_data["prompt"] = ""
163
 
164
- # Apply style length limits
165
- if model == "V4" and len(style) > 200:
166
- style = style[:200]
167
- yield f"⚠️ Style truncated to 200 characters for V4 model\n\n"
168
- elif model in ["V4_5", "V4_5PLUS", "V4_5ALL", "V5"] and len(style) > 1000:
169
- style = style[:1000]
170
- yield f"⚠️ Style truncated to 1000 characters for {model} model\n\n"
 
 
 
171
 
172
- # Apply title length limits
173
- if model in ["V4", "V4_5ALL"] and len(title) > 80:
174
- title = title[:80]
175
- yield f"⚠️ Title truncated to 80 characters for {model} model\n\n"
176
- elif model in ["V4_5", "V4_5PLUS", "V5"] and len(title) > 100:
177
- title = title[:100]
178
- yield f"⚠️ Title truncated to 100 characters for {model} model\n\n"
179
 
180
- request_data["style"] = style
181
- request_data["title"] = title
182
 
183
- yield f"## 🚀 Submitting Song Request\n\n"
184
- yield f"**Title:** {title}\n"
185
- yield f"**Style:** {style}\n"
186
- yield f"**Model:** {model}\n"
187
- yield f"**Instrumental:** {'Yes' if instrumental else 'No'}\n"
188
- if not instrumental:
189
- yield f"**Lyrics length:** {len(lyrics_text)} characters\n\n"
190
- yield f"**Callback URL:** https://1hit.no/callback.php\n\n"
191
 
192
- # Submit generation request
193
- try:
194
- resp = requests.post(
195
- "https://api.sunoapi.org/api/v1/generate",
196
- json=request_data,
197
- headers={
198
- "Authorization": f"Bearer {SUNO_KEY}",
199
- "Content-Type": "application/json"
200
- },
201
- timeout=30
202
- )
203
-
204
- if resp.status_code != 200:
205
- yield f" Submission failed: HTTP {resp.status_code}"
206
- yield f"\n**Response:**\n```\n{resp.text}\n```"
207
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
 
209
- data = resp.json()
210
- print(f"Submission response: {json.dumps(data, indent=2)}")
 
 
211
 
212
- if data.get("code") != 200:
213
- yield f"❌ API error: {data.get('msg', 'Unknown')}"
214
- return
215
 
216
- # Extract task ID from response
217
- task_id = None
218
- if "taskId" in data:
219
- task_id = data["taskId"]
220
- elif "data" in data and "taskId" in data["data"]:
221
- task_id = data["data"]["taskId"]
222
- elif data.get("data") and "taskId" in data.get("data", {}):
223
- task_id = data["data"]["taskId"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
- if not task_id:
226
- yield f" Could not extract Task ID from response"
227
- yield f"\n**Raw Response:**\n```json\n{json.dumps(data, indent=2)}\n```"
228
- return
 
 
229
 
230
- yield f"## Request Submitted Successfully!\n\n"
231
- yield f"**🎯 Task ID:** `{task_id}`\n\n"
232
- yield f"**⏳ Status:** Generation started\n"
233
- yield f"**📞 Callback:** https://1hit.no/callback.php\n\n"
234
- yield "**What happens now:**\n"
235
- yield "1. Suno AI generates your song (1-3 minutes)\n"
236
- yield "2. You'll get a callback notification\n"
237
- yield "3. Use the Task ID above to check status manually\n\n"
238
- yield "---\n\n"
239
- yield f"## 🔍 Check Status Manually\n\n"
240
- yield f"Use this Task ID: `{task_id}`\n\n"
241
- yield "**To check status:**\n"
242
- yield "1. Copy the Task ID above\n"
243
- yield "2. Go to 'Check Any Task' tab\n"
244
- yield "3. Paste and click 'Check Status'\n"
245
- yield "4. Or wait for callback notification\n\n"
246
- yield "**Generation time:**\n"
247
- yield "- 30-60 seconds for stream URL\n"
248
- yield "- 2-3 minutes for download URL\n"
249
 
250
- # Simple one-time check after 30 seconds
251
- yield "\n**⏰ Will check once in 30 seconds...**\n"
252
- time.sleep(30)
253
 
254
- # Single status check
255
- status_result = get_task_info(task_id)
256
- yield "\n## 📊 Status Check (30s)\n\n"
257
- yield status_result
258
 
259
- except Exception as e:
260
- yield f" Error submitting request: {str(e)}"
261
- return
262
-
 
 
 
 
 
 
 
263
  except Exception as e:
264
- yield f"❌ **Unexpected Error:** {str(e)}"
265
 
266
  # Create the app
267
  with gr.Blocks() as app:
268
  gr.Markdown("# 🎵 Suno Song Generator")
269
- gr.Markdown("Create songs from lyrics and style using Suno AI")
 
 
270
 
271
  with gr.Tab("🎶 Generate Song"):
272
  with gr.Row():
273
  with gr.Column(scale=1):
274
- # Lyrics Input
275
- gr.Markdown("### Step 1: Enter Lyrics")
276
-
277
  lyrics_text = gr.Textbox(
278
- label="Lyrics",
279
- placeholder="Paste your lyrics here...\n\nExample:\n(Verse 1)\nSun is shining, sky is blue\nBirds are singing, just for you...",
280
- lines=10,
281
- interactive=True
282
  )
283
 
284
- # Song Settings
285
- gr.Markdown("### Step 2: Song Settings")
286
-
287
  style = gr.Textbox(
288
  label="Music Style",
289
- placeholder="Example: Pop, Rock, Jazz, Classical, Electronic, Hip Hop, Country",
290
  value="Pop",
291
- interactive=True
292
  )
293
 
294
  title = gr.Textbox(
295
  label="Song Title",
296
- placeholder="My Awesome Song",
297
- value="Generated Song",
298
- interactive=True
299
  )
300
 
301
  with gr.Row():
302
- instrumental = gr.Checkbox(
303
- label="Instrumental (No Vocals)",
304
- value=False,
305
- interactive=True
306
- )
307
  model = gr.Dropdown(
308
- label="Model",
309
  choices=["V5", "V4_5PLUS", "V4_5ALL", "V4_5", "V4"],
310
  value="V4_5ALL",
311
- interactive=True
312
  )
313
 
314
- # Action Buttons
315
- generate_btn = gr.Button("🚀 Generate Song", variant="primary")
316
- clear_btn = gr.Button("🗑️ Clear All", variant="secondary")
317
 
318
- # Instructions
319
  gr.Markdown("""
320
- **How to use:**
321
- 1. Paste lyrics (or leave empty for instrumental)
322
- 2. Set music style
323
- 3. Enter song title
324
- 4. Choose model
325
- 5. Click Generate!
326
-
327
- **Tips:**
328
- - V4_5ALL: Best overall quality
329
- - V5: Latest model
330
- - Instrumental: No vocals, just music
331
  """)
332
 
333
  with gr.Column(scale=2):
334
- # Output Area
335
- output = gr.Markdown(
336
- value="### Ready to generate!\n\nEnter lyrics and settings, then click 'Generate Song'"
337
  )
338
 
339
- with gr.Tab("🔍 Check Any Task"):
340
  with gr.Row():
341
  with gr.Column(scale=1):
342
- gr.Markdown("### Check Task Status")
343
- gr.Markdown("Enter any Suno Task ID to check its status")
344
 
345
- check_task_id = gr.Textbox(
 
346
  label="Task ID",
347
- placeholder="Enter Task ID from generation or separation",
348
- info="From Song Generator or Vocal Separator"
349
  )
350
 
351
- check_btn = gr.Button("🔍 Check Status", variant="primary")
352
- check_clear_btn = gr.Button("🗑️ Clear", variant="secondary")
 
 
 
 
 
 
 
353
 
354
  with gr.Column(scale=2):
355
- check_output = gr.Markdown(
356
- value="### Enter a Task ID above\n\nPaste any Suno Task ID to check its current status and results."
 
357
  )
 
 
 
 
 
 
358
 
359
- with gr.Tab("📚 Instructions"):
360
  gr.Markdown("""
361
- ## 📖 How to Use This App
362
-
363
- ### 🎶 Generate Song Tab
364
- 1. **Enter Lyrics** (or leave empty for instrumental)
365
- 2. **Set Music Style** (e.g., "Pop", "Rock", "Jazz")
366
- 3. **Enter Song Title**
367
- 4. **Choose Model** (V4_5ALL recommended)
368
- 5. **Click "Generate Song"**
369
-
370
- ### 🔍 Check Any Task Tab
371
- 1. **Paste any Suno Task ID**
372
- 2. **Click "Check Status"**
373
- 3. **View results and download links**
374
-
375
- ### ⏱️ What to Expect
376
-
377
- **After generating:**
378
- - You'll get a **Task ID** immediately
379
- - Generation takes **1-3 minutes**
380
- - **Callback** sent to https://1hit.no/callback.php
381
- - Use Task ID to **check status manually**
382
 
383
- **Task IDs come from:**
384
- - Song Generator (this app)
385
- - Vocal Separator (other app)
386
- - Any Suno API request
 
387
 
388
- ### 🎵 Getting Your Songs
 
 
 
 
389
 
390
- 1. **Stream URL:** Ready in 30-60 seconds
391
- 2. **Download URL:** Ready in 2-3 minutes
392
- 3. **Both appear in status check**
393
- 4. **Audio player** included for streaming
 
 
394
 
395
- ### 🔧 Troubleshooting
 
 
 
 
396
 
397
- **Task not found?**
398
- - Wait a few minutes
399
- - Check callback logs at https://1hit.no/viewer.php
400
- - Ensure Task ID is correct
 
401
 
402
- **No audio links?**
403
- - Wait 2-3 minutes
404
- - Check status again
405
- - Generation may have failed
406
  """)
407
 
408
- gr.Markdown("---")
409
- gr.Markdown(
410
- """
411
- <div style="text-align: center; padding: 20px;">
412
- <p>Powered by <a href="https://suno.ai" target="_blank">Suno AI</a> •
413
- <a href="https://sunoapi.org" target="_blank">Suno API Docs</a></p>
414
- <p><small>Create custom songs by providing lyrics and music style</small></p>
415
- </div>
416
- """,
417
- elem_id="footer"
418
- )
419
-
420
- # Event handlers for Generate Song tab
421
- def clear_all():
422
- return "", "Pop", "Generated Song", False, "V4_5ALL", "### Ready to generate!\n\nEnter lyrics and settings, then click 'Generate Song'"
423
 
424
- clear_btn.click(
425
- clear_all,
426
- outputs=[lyrics_text, style, title, instrumental, model, output]
 
427
  )
428
 
429
- generate_btn.click(
430
- generate_song_from_text,
 
 
 
 
 
 
 
431
  inputs=[lyrics_text, style, title, instrumental, model],
432
- outputs=output
433
  )
434
 
435
- # Event handlers for Check Any Task tab
436
- def clear_check():
437
- return "", "### Enter a Task ID above\n\nPaste any Suno Task ID to check its current status and results."
438
-
439
- check_clear_btn.click(
440
- clear_check,
441
- outputs=[check_task_id, check_output]
442
- )
443
 
444
  check_btn.click(
445
- get_task_info,
446
- inputs=[check_task_id],
447
- outputs=check_output
448
  )
449
 
450
- # Launch the app
451
  if __name__ == "__main__":
452
  print("🚀 Starting Suno Song Generator")
453
  print(f"🔑 SunoKey: {'✅ Set' if SUNO_KEY else '❌ Not set'}")
454
  print("🌐 Open your browser to: http://localhost:7860")
455
-
456
  app.launch(server_name="0.0.0.0", server_port=7860, share=False)
 
1
  import gradio as gr
2
  import requests
3
  import os
 
4
  import json
5
 
6
  # Suno API key
 
8
  if not SUNO_KEY:
9
  print("⚠️ SunoKey not set!")
10
 
11
+ def submit_song_generation(lyrics_text, style, title, instrumental, model):
12
+ """Submit song generation request - IMMEDIATE RESPONSE WITH TASK ID"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  if not SUNO_KEY:
14
+ return "❌ Error: SunoKey not configured", ""
 
15
 
16
  if not lyrics_text.strip() and not instrumental:
17
+ return "❌ Error: Please provide lyrics or select instrumental", ""
 
18
 
19
  if not style.strip():
20
+ return "❌ Error: Please provide a music style", ""
 
21
 
22
  if not title.strip():
23
+ return "❌ Error: Please provide a song title", ""
 
24
 
25
  try:
26
  # Prepare request data
 
37
  # Apply character limits
38
  if model == "V4" and len(lyrics_text) > 3000:
39
  lyrics_text = lyrics_text[:3000]
 
40
  elif model in ["V4_5", "V4_5PLUS", "V4_5ALL", "V5"] and len(lyrics_text) > 5000:
41
  lyrics_text = lyrics_text[:5000]
 
42
 
43
  request_data["prompt"] = lyrics_text
44
  else:
45
  request_data["prompt"] = ""
46
 
47
+ # Submit generation request
48
+ resp = requests.post(
49
+ "https://api.sunoapi.org/api/v1/generate",
50
+ json=request_data,
51
+ headers={
52
+ "Authorization": f"Bearer {SUNO_KEY}",
53
+ "Content-Type": "application/json"
54
+ },
55
+ timeout=30
56
+ )
57
 
58
+ if resp.status_code != 200:
59
+ return f"❌ Submission failed: HTTP {resp.status_code}\n\n{resp.text}", ""
 
 
 
 
 
60
 
61
+ data = resp.json()
 
62
 
63
+ # Extract task ID - IMMEDIATELY
64
+ task_id = None
 
 
 
 
 
 
65
 
66
+ # Try different response formats
67
+ if "taskId" in data:
68
+ task_id = data["taskId"]
69
+ elif "data" in data and "taskId" in data["data"]:
70
+ task_id = data["data"]["taskId"]
71
+ elif data.get("data") and "taskId" in data.get("data", {}):
72
+ task_id = data["data"]["taskId"]
73
+
74
+ if not task_id:
75
+ return f"❌ Could not extract Task ID\n\n**Raw:**\n```json\n{json.dumps(data, indent=2)}\n```", ""
76
+
77
+ # RETURN TASK ID IMMEDIATELY
78
+ output = f"## ✅ TASK SUBMITTED!\n\n"
79
+ output += f"**🎯 YOUR TASK ID:** `{task_id}`\n\n"
80
+ output += f"**📋 Details:**\n"
81
+ output += f"- **Title:** {title}\n"
82
+ output += f"- **Style:** {style}\n"
83
+ output += f"- **Model:** {model}\n"
84
+ output += f"- **Instrumental:** {'Yes' if instrumental else 'No'}\n\n"
85
+
86
+ output += f"**🚀 Next Steps:**\n"
87
+ output += f"1. **Copy this Task ID:** `{task_id}`\n"
88
+ output += f"2. **Switch to 'Check Status' tab**\n"
89
+ output += f"3. **Paste the Task ID**\n"
90
+ output += f"4. **Click 'Check Status'** for results\n\n"
91
+
92
+ output += f"**⏱️ Processing time:** 1-3 minutes\n"
93
+ output += f"**📞 Callback URL:** https://1hit.no/callback.php\n"
94
+
95
+ return output, task_id
96
+
97
+ except Exception as e:
98
+ return f"❌ Error: {str(e)}", ""
99
+
100
+ def check_song_status(task_id, show_raw=False):
101
+ """Check song generation status - RETURNS DOWNLOAD LINKS"""
102
+ if not task_id:
103
+ return "❌ Please enter a Task ID", ""
104
+
105
+ try:
106
+ resp = requests.get(
107
+ "https://api.sunoapi.org/api/v1/generate/record-info",
108
+ headers={"Authorization": f"Bearer {SUNO_KEY}"},
109
+ params={"taskId": task_id},
110
+ timeout=30
111
+ )
112
+
113
+ if resp.status_code != 200:
114
+ return f"❌ HTTP Error {resp.status_code}\n\n{resp.text}", ""
115
+
116
+ data = resp.json()
117
+
118
+ # RAW JSON for debugging (always stored, shown if requested)
119
+ raw_json = f"```json\n{json.dumps(data, indent=2)}\n```"
120
+
121
+ if data.get("code") != 200:
122
+ return f"❌ API Error: {data.get('msg', 'Unknown')}", raw_json
123
+
124
+ task_data = data.get("data", {})
125
+ status = task_data.get("status", "UNKNOWN")
126
+
127
+ # Format main output
128
+ output = f"## 🔍 Status Check: `{task_id}`\n\n"
129
+ output += f"**Status:** {status}\n"
130
+
131
+ if status == "TEXT_SUCCESS":
132
+ # This is the key status! Songs are ready!
133
+ response_data = task_data.get("response", {})
134
+ songs = response_data.get("sunoData", [])
135
 
136
+ if not songs:
137
+ output += f"\n**⚠️ Status TEXT_SUCCESS but no songs found**\n"
138
+ output += f"Raw data available in dropdown below\n"
139
+ return output, raw_json
140
 
141
+ output += f"## 🎵 SONGS READY! ({len(songs)} tracks)\n\n"
 
 
142
 
143
+ for i, song in enumerate(songs, 1):
144
+ output += f"### Track {i}\n"
145
+ output += f"**Title:** {song.get('title', 'Untitled')}\n"
146
+
147
+ # Get all possible URLs
148
+ audio_url = song.get('audioUrl')
149
+ stream_url = song.get('streamAudioUrl') or song.get('streamAudioURL') or song.get('stream_url')
150
+ source_stream = song.get('sourceStreamAudioUrl')
151
+ source_audio = song.get('sourceAudioUrl')
152
+
153
+ # Image URL
154
+ image_url = song.get('imageUrl') or song.get('sourceImageUrl')
155
+
156
+ # Best URL for listening
157
+ best_url = audio_url or stream_url or source_stream or source_audio
158
+
159
+ if best_url:
160
+ output += f"**🎧 Listen Now:** [Click to Play]({best_url})\n"
161
+ # Audio player
162
+ output += f"""<audio controls style="width: 100%; margin: 10px 0;">
163
+ <source src="{best_url}" type="audio/mpeg">
164
+ Your browser does not support audio.
165
+ </audio>\n"""
166
+
167
+ # Download button
168
+ if audio_url:
169
+ output += f"**💾 Download:** [MP3 File]({audio_url})\n"
170
+ elif stream_url:
171
+ output += f"**💾 Download:** [Stream MP3]({stream_url})\n"
172
+
173
+ if image_url:
174
+ output += f"**🖼️ Cover Art:** [View Image]({image_url})\n"
175
+
176
+ output += f"**ID:** `{song.get('id', 'N/A')}`\n"
177
+ output += f"**Model:** {song.get('modelName', 'N/A')}\n"
178
+ output += f"**Tags:** {song.get('tags', 'N/A')}\n"
179
+ if song.get('duration'):
180
+ output += f"**Duration:** {song.get('duration')}s\n"
181
+
182
+ # Show first 200 chars of prompt
183
+ prompt = song.get('prompt', '')
184
+ if prompt:
185
+ output += f"**Preview:** {prompt[:200]}...\n"
186
+
187
+ output += "\n---\n\n"
188
 
189
+ # Summary
190
+ output += f"**✅ Generation complete!**\n\n"
191
+ output += "**To save your songs:**\n"
192
+ output += "1. Right-click 'Listen Now' links → 'Save link as...'\n"
193
+ output += "2. Or use the download links above\n"
194
+ output += "3. Note the Track IDs for reference\n"
195
 
196
+ elif status in ["PENDING", "PROCESSING", "RUNNING"]:
197
+ output += f"\n**⏳ Song is still being generated...**\n"
198
+ output += "Check again in 30-60 seconds\n"
199
+ output += f"This usually takes 1-3 minutes total\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
 
201
+ elif status == "SUCCESS":
202
+ output += f"\n**✅ Generation succeeded!**\n"
203
+ output += "Check raw data below for song URLs\n"
204
 
205
+ elif status == "FAILED":
206
+ error_msg = task_data.get("errorMessage", "Unknown error")
207
+ output += f"\n**❌ Generation failed:** {error_msg}\n"
 
208
 
209
+ else:
210
+ output += f"\n**⚠️ Unknown status:** {status}\n"
211
+ output += "Check raw data below\n"
212
+
213
+ # Always show premium info
214
+ output += f"\n**💡 Tip:** Songs may take 2-3 minutes to fully process\n"
215
+ output += f"**📞 Callback sent to:** https://1hit.no/callback.php\n"
216
+ output += f"**🔗 Viewer:** [https://1hit.no/viewer.php?task_id={task_id}](https://1hit.no/viewer.php?task_id={task_id})\n"
217
+
218
+ return output, raw_json
219
+
220
  except Exception as e:
221
+ return f"❌ Error checking task: {str(e)}", ""
222
 
223
  # Create the app
224
  with gr.Blocks() as app:
225
  gr.Markdown("# 🎵 Suno Song Generator")
226
+
227
+ # Store current task ID
228
+ current_task_id = gr.State(value="")
229
 
230
  with gr.Tab("🎶 Generate Song"):
231
  with gr.Row():
232
  with gr.Column(scale=1):
233
+ # Inputs
 
 
234
  lyrics_text = gr.Textbox(
235
+ label="Lyrics (leave empty for instrumental)",
236
+ placeholder="[Verse 1]\nType your lyrics here...",
237
+ lines=8
 
238
  )
239
 
 
 
 
240
  style = gr.Textbox(
241
  label="Music Style",
 
242
  value="Pop",
243
+ placeholder="e.g., Rock, Jazz, Electronic"
244
  )
245
 
246
  title = gr.Textbox(
247
  label="Song Title",
248
+ value="My Song"
 
 
249
  )
250
 
251
  with gr.Row():
252
+ instrumental = gr.Checkbox(label="Instrumental Only")
 
 
 
 
253
  model = gr.Dropdown(
 
254
  choices=["V5", "V4_5PLUS", "V4_5ALL", "V4_5", "V4"],
255
  value="V4_5ALL",
256
+ label="Model"
257
  )
258
 
259
+ submit_btn = gr.Button("🚀 Generate Song", variant="primary")
 
 
260
 
 
261
  gr.Markdown("""
262
+ **Instructions:**
263
+ 1. Enter lyrics (or blank for instrumental)
264
+ 2. Set style & title
265
+ 3. Click Generate
266
+ 4. **Copy the Task ID**
267
+ 5. Check status in next tab
 
 
 
 
 
268
  """)
269
 
270
  with gr.Column(scale=2):
271
+ # Submission output
272
+ submission_output = gr.Markdown(
273
+ value="### Ready to generate!\n\nFill in the form and click 'Generate Song'"
274
  )
275
 
276
+ with gr.Tab("🔍 Check Status"):
277
  with gr.Row():
278
  with gr.Column(scale=1):
279
+ gr.Markdown("### Check Song Status")
 
280
 
281
+ # Task ID input (auto-fills from generation)
282
+ status_task_id = gr.Textbox(
283
  label="Task ID",
284
+ placeholder="Paste your Task ID here",
285
+ info="Will auto-fill from generated task"
286
  )
287
 
288
+ check_btn = gr.Button("🔍 Check Status Now", variant="primary")
289
+ auto_check = gr.Checkbox(label="Auto-check every 30s", value=False)
290
+
291
+ gr.Markdown("""
292
+ **What to expect:**
293
+ - **TEXT_SUCCESS**: Songs ready! Listen/download
294
+ - **PENDING/PROCESSING**: Still generating
295
+ - Check every 30s until ready
296
+ """)
297
 
298
  with gr.Column(scale=2):
299
+ # Status output
300
+ status_output = gr.Markdown(
301
+ value="### Enter a Task ID to check status"
302
  )
303
+
304
+ # Raw data in accordion
305
+ with gr.Accordion("📊 Raw API Response (Debug)", open=False):
306
+ raw_output = gr.Markdown(
307
+ value="*Raw JSON will appear here when you check status*"
308
+ )
309
 
310
+ with gr.Tab("📋 Instructions"):
311
  gr.Markdown("""
312
+ ## 🎵 Complete Workflow
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
 
314
+ ### 1. Generate Song
315
+ - Enter lyrics & settings
316
+ - Click **Generate Song**
317
+ - **IMMEDIATELY get a Task ID**
318
+ - Copy the Task ID
319
 
320
+ ### 2. Check Status
321
+ - Switch to **Check Status** tab
322
+ - Task ID auto-fills
323
+ - Click **Check Status Now**
324
+ - Wait for **TEXT_SUCCESS** status
325
 
326
+ ### 3. Download Songs
327
+ - When **TEXT_SUCCESS** appears:
328
+ - **Listen Now** links with audio players
329
+ - **Download** links for MP3 files
330
+ - Cover art images
331
+ - Track IDs for reference
332
 
333
+ ### 4. Tips
334
+ - Processing: **1-3 minutes**
335
+ - Check every **30 seconds**
336
+ - Use **Auto-check** for convenience
337
+ - Raw data available for debugging
338
 
339
+ ### 5. Status Meanings
340
+ - **TEXT_SUCCESS**: Songs ready!
341
+ - **PENDING/PROCESSING**: Still working
342
+ - **SUCCESS**: Check raw data
343
+ - **FAILED**: Try again
344
 
345
+ ### 6. Callback System
346
+ - Results also sent to: https://1hit.no/callback.php
347
+ - View all results: https://1hit.no/viewer.php
 
348
  """)
349
 
350
+ # Auto-fill status tab with task ID
351
+ def update_status_field(task_id):
352
+ return task_id
 
 
 
 
 
 
 
 
 
 
 
 
353
 
354
+ current_task_id.change(
355
+ fn=update_status_field,
356
+ inputs=[current_task_id],
357
+ outputs=[status_task_id]
358
  )
359
 
360
+ # Generate song
361
+ def on_generate(lyrics, style, title, instrumental, model):
362
+ output, task_id = submit_song_generation(lyrics, style, title, instrumental, model)
363
+ if task_id:
364
+ return output, task_id, task_id # Also updates status_task_id
365
+ return output, "", "" # Clear if error
366
+
367
+ submit_btn.click(
368
+ fn=on_generate,
369
  inputs=[lyrics_text, style, title, instrumental, model],
370
+ outputs=[submission_output, current_task_id, status_task_id]
371
  )
372
 
373
+ # Check status
374
+ def on_check(task_id, show_raw):
375
+ output, raw = check_song_status(task_id, show_raw)
376
+ return output, raw
 
 
 
 
377
 
378
  check_btn.click(
379
+ fn=on_check,
380
+ inputs=[status_task_id, gr.State(True)], # Always show raw
381
+ outputs=[status_output, raw_output]
382
  )
383
 
 
384
  if __name__ == "__main__":
385
  print("🚀 Starting Suno Song Generator")
386
  print(f"🔑 SunoKey: {'✅ Set' if SUNO_KEY else '❌ Not set'}")
387
  print("🌐 Open your browser to: http://localhost:7860")
 
388
  app.launch(server_name="0.0.0.0", server_port=7860, share=False)