haraberget commited on
Commit
1f1b856
·
verified ·
1 Parent(s): 6c0850c

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -659
app.py CHANGED
@@ -2,696 +2,155 @@ import gradio as gr
2
  import requests
3
  import os
4
  import json
5
- import uuid
6
- import time
7
- import threading
8
  from datetime import datetime
9
- from typing import Dict, Optional
10
 
11
  # Load Suno API key
12
  SUNO_KEY = os.environ.get("SunoKey", "")
13
  if not SUNO_KEY:
14
  print("⚠️ Warning: SunoKey environment variable not set!")
15
 
16
- # Debug mode
17
- DEBUG = True
18
-
19
- # Task storage with auto-polling
20
- tasks_db = {}
21
- polling_threads = {}
22
-
23
- def debug_log(message):
24
- """Debug logging"""
25
- if DEBUG:
26
- timestamp = datetime.now().strftime("%H:%M:%S")
27
- print(f"[{timestamp}] {message}")
28
-
29
- def make_api_request(method, url, **kwargs):
30
- """Make API request with detailed error logging"""
31
- try:
32
- debug_log(f"Making {method} request to {url}")
33
- response = requests.request(method, url, **kwargs)
34
- debug_log(f"Response status: {response.status_code}")
35
-
36
- if DEBUG and len(response.content) < 10000: # Don't log huge responses
37
- debug_log(f"Response: {response.text[:500]}")
38
-
39
- return response
40
- except Exception as e:
41
- debug_log(f"API request error: {str(e)}")
42
- raise
43
-
44
- def poll_task_status(task_id: str, max_attempts=120, interval=3):
45
- """Background thread to automatically poll task status"""
46
- if task_id not in tasks_db:
47
- debug_log(f"Task {task_id} not found in DB")
48
- return
49
 
50
- task = tasks_db[task_id]
51
- api_task_id = task["api_task_id"]
52
 
53
- debug_log(f"Starting auto-polling for task {task_id} (API ID: {api_task_id})")
 
 
 
 
 
54
 
55
- for attempt in range(max_attempts):
 
 
 
56
  try:
57
- debug_log(f"Poll attempt {attempt + 1} for task {task_id}")
58
-
59
- # Poll the API
60
- url = f"https://api.sunoapi.org/api/v1/lyrics/details?taskId={api_task_id}"
61
- headers = {"Authorization": f"Bearer {SUNO_KEY}"}
62
-
63
- response = make_api_request("GET", url, headers=headers, timeout=30)
64
- data = response.json()
65
-
66
- if response.status_code == 200 and data.get("code") == 200:
67
- task_data = data["data"]
68
- status = task_data.get("status", "unknown")
69
-
70
- debug_log(f"Task {task_id} status: {status}")
71
-
72
- # Update task status
73
- tasks_db[task_id]["status"] = status
74
- tasks_db[task_id]["last_checked"] = datetime.now().isoformat()
75
-
76
- if status == "completed" and "data" in task_data:
77
- # Task completed successfully
78
- lyrics_data = task_data["data"]
79
- tasks_db[task_id]["result"] = lyrics_data
80
- tasks_db[task_id]["completed_at"] = datetime.now().isoformat()
81
- debug_log(f"✅ Task {task_id} completed successfully!")
82
- break
83
-
84
- elif status == "failed":
85
- error_msg = task_data.get("error", "Unknown error")
86
- tasks_db[task_id]["error"] = error_msg
87
- tasks_db[task_id]["completed_at"] = datetime.now().isoformat()
88
- debug_log(f"❌ Task {task_id} failed: {error_msg}")
89
- break
90
- elif status == "processing":
91
- debug_log(f"🔄 Task {task_id} is processing...")
92
- else:
93
- debug_log(f"📊 Task {task_id} has unknown status: {status}")
94
-
95
  else:
96
- error_code = data.get("code", "unknown")
97
- error_msg = data.get("msg", "No error message")
98
- debug_log(f"❌ API error for task {task_id}: Code {error_code}, {error_msg}")
99
-
100
- # Update attempts
101
- tasks_db[task_id]["poll_attempts"] = attempt + 1
102
-
103
  except Exception as e:
104
- debug_log(f"⚠️ Polling error for task {task_id}: {str(e)}")
105
-
106
- # Wait before next poll
107
- time.sleep(interval)
108
-
109
- debug_log(f"Finished polling for task {task_id} after {max_attempts} attempts")
110
 
111
- # Clean up polling thread
112
- if task_id in polling_threads:
113
- del polling_threads[task_id]
114
 
115
- def generate_lyrics(prompt: str, auto_poll: bool = True) -> str:
116
- """Submit lyrics generation task to Suno API"""
117
- if not SUNO_KEY:
118
- return "❌ Error: SunoKey environment variable not set. Please add it in Space Settings."
119
-
120
- if not prompt or not prompt.strip():
121
- return "❌ Please enter a lyrics prompt"
122
 
123
- # Generate task ID
124
- task_id = str(uuid.uuid4())[:8]
125
 
126
- debug_log(f"Starting generation for task {task_id} with prompt: {prompt[:50]}...")
127
 
128
- # Prepare API request
129
- url = "https://api.sunoapi.org/api/v1/lyrics"
130
- headers = {
131
- "Authorization": f"Bearer {SUNO_KEY}",
132
- "Content-Type": "application/json"
133
- }
134
-
135
- # Suno requires a callback URL
136
- dummy_callback = "https://dummy.callback.url/not-used"
137
 
138
  payload = {
139
- "prompt": prompt,
140
- "callBackUrl": dummy_callback
141
  }
142
 
143
  try:
144
- debug_log(f"Submitting to Suno API: {json.dumps(payload, indent=2)}")
145
-
146
- # Submit task
147
- response = make_api_request("POST", url, headers=headers, json=payload, timeout=30)
148
- data = response.json()
149
-
150
- debug_log(f"Submission response: {json.dumps(data, indent=2)[:500]}...")
151
 
152
- if response.status_code == 200 and data.get("code") == 200:
153
- api_task_id = data["data"]["taskId"]
154
-
155
- debug_log(f"✅ Submission successful! Task ID: {task_id}, API Task ID: {api_task_id}")
156
-
157
- # Store task information
158
- tasks_db[task_id] = {
159
- "id": task_id,
160
- "api_task_id": api_task_id,
161
- "prompt": prompt,
162
- "status": "submitted",
163
- "result": None,
164
- "error": None,
165
- "created_at": datetime.now().isoformat(),
166
- "last_checked": None,
167
- "poll_attempts": 0,
168
- "completed_at": None,
169
- "auto_poll": auto_poll,
170
- "raw_response": data # Store for debugging
171
- }
172
-
173
- # Start auto-polling if enabled
174
- if auto_poll:
175
- poll_thread = threading.Thread(
176
- target=poll_task_status,
177
- args=(task_id,),
178
- daemon=True
179
- )
180
- polling_threads[task_id] = poll_thread
181
- poll_thread.start()
182
- debug_log(f"🚀 Started auto-polling thread for task {task_id}")
183
-
184
- return f"""✅ **Task Submitted Successfully!**
185
-
186
- **Your Task ID:** `{task_id}`
187
- **API Task ID:** `{api_task_id}`
188
-
189
- 📝 **Prompt:** {prompt[:100]}{'...' if len(prompt) > 100 else ''}
190
-
191
- 🔄 **Auto-polling enabled** - Results will appear automatically!
192
-
193
- ⏳ **Estimated time:** Usually 10-60 seconds
194
-
195
- 📊 **Check Status tab** to monitor progress
196
-
197
- 💡 **Save your Task ID:** `{task_id}`"""
198
-
199
- else:
200
- error_msg = data.get("msg", f"HTTP {response.status_code}")
201
- debug_log(f"❌ Submission failed: {error_msg}")
202
-
203
- return f"""❌ **Submission Failed**
204
-
205
- **Error:** {error_msg}
206
-
207
- **Response:** {json.dumps(data, indent=2)[:500]}
208
-
209
- 💡 **Possible solutions:**
210
- • Check if your SunoKey is valid
211
- • Ensure API has available credits
212
- • Try a different prompt
213
- • Wait a few minutes and retry"""
214
-
215
- except requests.exceptions.Timeout:
216
- debug_log("❌ Request timeout")
217
- return "❌ Error: Request timeout - Suno API is not responding"
218
- except requests.exceptions.ConnectionError:
219
- debug_log("❌ Connection error")
220
- return "❌ Error: Connection failed - Check your internet connection"
221
- except Exception as e:
222
- debug_log(f"❌ Unexpected error: {str(e)}")
223
- return f"❌ Error: {str(e)}"
224
-
225
- def check_task_status(task_id: str, force_check: bool = False) -> str:
226
- """Check the status of a task with detailed debugging"""
227
- if not task_id or not task_id.strip():
228
- return "❌ Please enter a Task ID"
229
-
230
- if task_id not in tasks_db:
231
- return f"❌ Task ID `{task_id}` not found. Please submit a task first."
232
-
233
- task = tasks_db[task_id]
234
- api_task_id = task.get("api_task_id", "unknown")
235
-
236
- debug_log(f"Checking status for task {task_id} (API: {api_task_id})")
237
-
238
- # Force an immediate API check if requested
239
- if force_check:
240
- try:
241
- debug_log(f"Forcing API check for task {task_id}")
242
- url = f"https://api.sunoapi.org/api/v1/lyrics/details?taskId={api_task_id}"
243
- headers = {"Authorization": f"Bearer {SUNO_KEY}"}
244
-
245
- response = make_api_request("GET", url, headers=headers, timeout=30)
246
  data = response.json()
 
 
247
 
248
- if response.status_code == 200 and data.get("code") == 200:
249
- task_data = data["data"]
250
- status = task_data.get("status", "unknown")
251
- debug_log(f"Forced check result: {status}")
252
 
253
- tasks_db[task_id]["status"] = status
254
- tasks_db[task_id]["last_checked"] = datetime.now().isoformat()
 
255
 
256
- if status == "completed" and "data" in task_data:
257
- lyrics_data = task_data["data"]
258
- tasks_db[task_id]["result"] = lyrics_data
259
- tasks_db[task_id]["completed_at"] = datetime.now().isoformat()
260
- elif status == "failed":
261
- error_msg = task_data.get("error", "Unknown error")
262
- tasks_db[task_id]["error"] = error_msg
263
- tasks_db[task_id]["completed_at"] = datetime.now().isoformat()
264
-
265
- except Exception as e:
266
- debug_log(f"Force check error: {str(e)}")
267
-
268
- status = task.get("status", "unknown")
269
- created_time = datetime.fromisoformat(task["created_at"])
270
- elapsed = int((datetime.now() - created_time).total_seconds())
271
-
272
- debug_log(f"Task {task_id} - Status: {status}, Elapsed: {elapsed}s")
273
-
274
- # Display based on status
275
- if status == "completed" and task.get("result"):
276
- debug_log(f"Task {task_id} has completed results")
277
- return format_lyrics_output(task["result"], task_id, elapsed)
278
-
279
- elif status == "failed":
280
- error_msg = task.get("error", "Unknown error")
281
- debug_log(f"Task {task_id} failed: {error_msg}")
282
- return f"""❌ **Task Failed**
283
-
284
- **Task ID:** `{task_id}`
285
- **API Task ID:** `{api_task_id}`
286
- **Error:** {error_msg}
287
- **Elapsed time:** {elapsed} seconds
288
-
289
- 💡 Please try generating again with a different prompt."""
290
-
291
- else:
292
- # Still processing or unknown status
293
- attempts = task.get("poll_attempts", 0)
294
- last_checked = task.get("last_checked")
295
- last_checked_str = ""
296
-
297
- if last_checked:
298
- last_time = datetime.fromisoformat(last_checked)
299
- last_checked_str = f"\n**Last checked:** {last_time.strftime('%H:%M:%S')}"
300
-
301
- debug_info = ""
302
- if DEBUG and "raw_response" in task:
303
- debug_info = f"\n\n**Debug Info:**\n```json\n{json.dumps(task.get('raw_response', {}), indent=2)[:300]}...\n```"
304
-
305
- return f"""⏳ **Task Processing...**
306
-
307
- **Task ID:** `{task_id}`
308
- **API Task ID:** `{api_task_id}`
309
- **Status:** {status}
310
- **Elapsed:** {elapsed} seconds
311
- **Poll attempts:** {attempts}{last_checked_str}
312
-
313
- ⏰ **Status Guide:**
314
- - **submitted:** Task accepted by API
315
- - **processing:** AI is generating lyrics
316
- - **completed:** Ready! Check auto-refresh
317
- - **failed:** Error occurred
318
-
319
- 🔄 **Auto-polling:** {'✅ Active' if task.get('auto_poll') else '❌ Disabled'}
320
-
321
- 💡 **What to do:**
322
- 1. Wait 30-60 seconds for processing
323
- 2. Click "Force Check" for immediate update
324
- 3. Results appear automatically when ready{debug_info}"""
325
-
326
- def force_check_task(task_id: str):
327
- """Force an immediate API check"""
328
- return check_task_status(task_id, force_check=True)
329
-
330
- def format_lyrics_output(lyrics_data, task_id, elapsed_time):
331
- """Format the lyrics for display"""
332
- if not lyrics_data:
333
- return "✅ Task completed but no lyrics data received"
334
-
335
- output_lines = [
336
- f"# 🎵 Generated Lyrics (Task: {task_id})",
337
- "",
338
- f"**Generated in:** {elapsed_time} seconds",
339
- f"**Completed at:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
340
- ""
341
- ]
342
-
343
- for i, item in enumerate(lyrics_data, 1):
344
- title = item.get('title', f'Variant {i}')
345
- lyrics = item.get('text', 'No lyrics generated')
346
-
347
- output_lines.append(f"## Variant {i}: {title}")
348
- output_lines.append("```")
349
- output_lines.append(lyrics)
350
- output_lines.append("```")
351
- output_lines.append("---")
352
- output_lines.append("")
353
-
354
- output_lines.append("### 🎉 All done!")
355
- output_lines.append("You can generate more lyrics or try different prompts.")
356
-
357
- return "\n".join(output_lines)
358
-
359
- def list_all_tasks():
360
- """List all submitted tasks with detailed info"""
361
- if not tasks_db:
362
- return "📭 No tasks found. Generate some lyrics first!"
363
-
364
- output_lines = ["# 📋 All Submitted Tasks", ""]
365
-
366
- for task_id, task in sorted(tasks_db.items(), key=lambda x: x[1]["created_at"], reverse=True):
367
- status = task.get("status", "unknown")
368
- api_task_id = task.get("api_task_id", "unknown")
369
- prompt_preview = task.get("prompt", "")[:50]
370
- created = task.get("created_at", "")[:19]
371
-
372
- # Status icon and color
373
- if status == "completed":
374
- icon = "✅"
375
- color = "green"
376
- elif status in ["failed", "error"]:
377
- icon = "❌"
378
- color = "red"
379
  else:
380
- icon = "⏳"
381
- color = "orange"
382
-
383
- # Age calculation
384
- created_time = datetime.fromisoformat(task["created_at"])
385
- age_seconds = int((datetime.now() - created_time).total_seconds())
386
-
387
- output_lines.append(f"<span style='color:{color}'>{icon} **{task_id}** - {status} ({age_seconds}s)</span>")
388
- output_lines.append(f" API ID: `{api_task_id}`")
389
- output_lines.append(f" Prompt: {prompt_preview}...")
390
- output_lines.append(f" Created: {created}")
391
- output_lines.append(f" Poll attempts: {task.get('poll_attempts', 0)}")
392
-
393
- if task.get("last_checked"):
394
- last_checked = task["last_checked"][:19]
395
- output_lines.append(f" Last checked: {last_checked}")
396
-
397
- if task.get("completed_at"):
398
- completed = task["completed_at"][:19]
399
- output_lines.append(f" Completed: {completed}")
400
-
401
- output_lines.append("")
402
-
403
- # Add summary
404
- completed = sum(1 for t in tasks_db.values() if t.get("status") == "completed")
405
- processing = sum(1 for t in tasks_db.values() if t.get("status") not in ["completed", "failed", "error"])
406
- failed = sum(1 for t in tasks_db.values() if t.get("status") in ["failed", "error"])
407
- total = len(tasks_db)
408
-
409
- output_lines.append(f"**Summary:** {completed} ✅, {processing} ⏳, {failed} ❌, {total} total")
410
- output_lines.append(f"**Active poll threads:** {len(polling_threads)}")
411
-
412
- return "\n".join(output_lines)
413
-
414
- def get_diagnostic_info():
415
- """Get diagnostic information about the system"""
416
- info_lines = ["# 🩺 Diagnostic Information", ""]
417
-
418
- # API Key status
419
- api_status = "✅ Configured" if SUNO_KEY else "❌ NOT SET"
420
- api_preview = SUNO_KEY[:10] + "..." if SUNO_KEY and len(SUNO_KEY) > 10 else SUNO_KEY or "None"
421
- info_lines.append(f"**SunoKey:** {api_status} ({api_preview})")
422
-
423
- # Tasks summary
424
- info_lines.append(f"\n**Tasks in memory:** {len(tasks_db)}")
425
- info_lines.append(f"**Active poll threads:** {len(polling_threads)}")
426
-
427
- # Recent tasks
428
- if tasks_db:
429
- info_lines.append("\n**Recent Tasks:**")
430
- for task_id, task in sorted(tasks_db.items(), key=lambda x: x[1]["created_at"], reverse=True)[:5]:
431
- status = task.get("status", "unknown")
432
- age = int((datetime.now() - datetime.fromisoformat(task["created_at"])).total_seconds())
433
- info_lines.append(f"- `{task_id}`: {status} ({age}s ago)")
434
 
435
- # Test API connection
436
- info_lines.append("\n**API Connection Test:**")
437
- try:
438
- test_response = requests.get("https://api.sunoapi.org", timeout=5)
439
- info_lines.append(f"✅ Suno API reachable (HTTP {test_response.status_code})")
440
  except Exception as e:
441
- info_lines.append(f"❌ Cannot reach Suno API: {str(e)}")
442
-
443
- # Debug info
444
- info_lines.append(f"\n**Debug Mode:** {'✅ Enabled' if DEBUG else '❌ Disabled'}")
445
- info_lines.append(f"**Current Time:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
446
 
447
- return "\n".join(info_lines)
448
 
449
- # Create the Gradio interface
450
- with gr.Blocks(title="Suno Lyrics Generator", theme=gr.themes.Soft()) as app:
451
- gr.Markdown("# 🎵 Suno AI Lyrics Generator")
452
- gr.Markdown("Generate song lyrics using Suno's AI API")
453
-
454
- # Store the current task ID in a hidden state
455
- current_task_id = gr.State("")
456
-
457
- with gr.Tabs():
458
- # Tab 1: Generate Lyrics
459
- with gr.TabItem("✨ Generate"):
460
- with gr.Row():
461
- with gr.Column(scale=2):
462
- gr.Markdown("### Enter your lyrics idea")
463
- prompt_input = gr.Textbox(
464
- label="Lyrics Prompt",
465
- placeholder="Example: A romantic ballad about stargazing on a summer night...",
466
- lines=3
467
- )
468
-
469
- auto_poll_checkbox = gr.Checkbox(
470
- label="🔁 Enable auto-polling",
471
- value=True,
472
- info="Automatically check for results (recommended)"
473
- )
474
-
475
- submit_btn = gr.Button("🚀 Generate Lyrics", variant="primary", size="lg")
476
-
477
- gr.Markdown("### ⚠️ Current Issue:")
478
- gr.Markdown("""
479
- Tasks are getting stuck in "submitted" status.
480
- This version includes **debugging tools** to diagnose the issue.
481
-
482
- **What to try:**
483
- 1. Submit a simple prompt
484
- 2. Check "Diagnostic" tab
485
- 3. Use "Force Check" button
486
- 4. Monitor debug logs
487
- """)
488
-
489
- with gr.Column(scale=3):
490
- output_area = gr.Markdown(
491
- label="Result",
492
- value="Your task submission result will appear here..."
493
- )
494
-
495
- def handle_generation(prompt, auto_poll):
496
- result = generate_lyrics(prompt, auto_poll)
497
- # Extract task ID from result
498
- task_id = ""
499
- if "Task ID:" in result:
500
- for line in result.split('\n'):
501
- if 'Task ID:' in line:
502
- parts = line.split('`')
503
- if len(parts) > 1:
504
- task_id = parts[1]
505
- break
506
- return result, task_id
507
-
508
- submit_btn.click(
509
- fn=handle_generation,
510
- inputs=[prompt_input, auto_poll_checkbox],
511
- outputs=[output_area, current_task_id]
512
- )
513
-
514
- # Tab 2: Check Status
515
- with gr.TabItem("🔍 Check Status"):
516
- with gr.Row():
517
- with gr.Column():
518
- gr.Markdown("### Enter your Task ID")
519
- task_id_input = gr.Textbox(
520
- label="Task ID",
521
- placeholder="Paste your Task ID here (e.g., 0f015fcb)",
522
- scale=1
523
- )
524
-
525
- # Auto-populate if we have a current task ID
526
- def update_task_id_input(current_id):
527
- return current_id if current_id else ""
528
-
529
- current_task_id.change(
530
- fn=update_task_id_input,
531
- inputs=current_task_id,
532
- outputs=task_id_input
533
- )
534
-
535
- with gr.Row():
536
- check_btn = gr.Button("🔍 Check Status", variant="primary")
537
- force_check_btn = gr.Button("⚡ Force Check", variant="secondary")
538
- auto_refresh_btn = gr.Button("🔄 Auto-refresh", variant="secondary")
539
-
540
- gr.Markdown("---")
541
- refresh_all_btn = gr.Button("📋 List All Tasks")
542
- tasks_list = gr.Markdown(label="All Tasks")
543
-
544
- with gr.Column():
545
- status_output = gr.Markdown(
546
- label="Status",
547
- value="Enter a Task ID above and click Check Status"
548
- )
549
-
550
- # Regular check
551
- check_btn.click(
552
- fn=check_task_status,
553
- inputs=task_id_input,
554
- outputs=status_output
555
- )
556
-
557
- # Force check (immediate API call)
558
- force_check_btn.click(
559
- fn=force_check_task,
560
- inputs=task_id_input,
561
- outputs=status_output
562
- )
563
-
564
- # List all tasks
565
- refresh_all_btn.click(
566
- fn=list_all_tasks,
567
- inputs=None,
568
- outputs=tasks_list
569
- )
570
-
571
- # Tab 3: Diagnostic
572
- with gr.TabItem("🩺 Diagnostic"):
573
- gr.Markdown("# System Diagnostics")
574
- gr.Markdown("Use this tab to diagnose why tasks are getting stuck")
575
-
576
- with gr.Row():
577
- with gr.Column():
578
- diagnostic_btn = gr.Button("🔄 Refresh Diagnostics", variant="primary")
579
- diagnostic_output = gr.Markdown(label="Diagnostic Info")
580
-
581
- with gr.Column():
582
- gr.Markdown("### 🚨 Common Issues:")
583
- gr.Markdown("""
584
- **1. API Key Issues:**
585
- - Invalid or expired SunoKey
586
- - No API credits remaining
587
- - Incorrect environment variable name
588
-
589
- **2. API Response Issues:**
590
- - Suno API returning errors
591
- - Tasks stuck in queue
592
- - Rate limiting
593
-
594
- **3. Network Issues:**
595
- - Cannot reach api.sunoapi.org
596
- - Timeout errors
597
- - Connection refused
598
-
599
- **4. Task Processing:**
600
- - Suno AI taking longer than expected
601
- - Tasks stuck in "submitted" state
602
- - Server-side delays
603
- """)
604
-
605
- diagnostic_btn.click(
606
- fn=get_diagnostic_info,
607
- inputs=None,
608
- outputs=diagnostic_output
609
- )
610
-
611
- # Auto-refresh diagnostics every 10 seconds
612
- diagnostic_btn.click(
613
- fn=lambda: time.sleep(10),
614
- inputs=None,
615
- outputs=None
616
- ).then(
617
- fn=get_diagnostic_info,
618
- inputs=None,
619
- outputs=diagnostic_output
620
- )
621
-
622
- # Tab 4: Help
623
- with gr.TabItem("ℹ️ Help"):
624
- gr.Markdown("# Help & Troubleshooting")
625
-
626
- with gr.Row():
627
- with gr.Column():
628
- gr.Markdown("### 🐛 Debugging Stuck Tasks")
629
- gr.Markdown("""
630
- **If tasks are stuck in "submitted":**
631
-
632
- 1. **Check Diagnostic Tab:**
633
- - Verify API key is set
634
- - Test API connection
635
- - View recent task status
636
-
637
- 2. **Use Force Check:**
638
- - Makes immediate API call
639
- - Bypasses cached status
640
- - Shows raw API response
641
-
642
- 3. **Monitor Debug Logs:**
643
- - Check Space logs (bottom of page)
644
- - Look for API errors
645
- - Note timeout messages
646
-
647
- 4. **Try Simple Test:**
648
- - Use a very simple prompt
649
- - Disable auto-polling
650
- - Check after 60 seconds
651
- """)
652
-
653
- with gr.Column():
654
- gr.Markdown("### 📞 Support")
655
- gr.Markdown("""
656
- **If issues persist:**
657
-
658
- 1. **Check SunoKey:**
659
- - Ensure it's valid
660
- - Check credit balance
661
- - Try in Suno's own interface
662
-
663
- 2. **API Status:**
664
- - Suno API may be down
665
- - Check Suno status page
666
- - Wait and try later
667
-
668
- 3. **Contact Support:**
669
- - Suno API support
670
- - Provide your Task IDs
671
- - Share debug logs
672
-
673
- 4. **Alternative:**
674
- - Try a different prompt
675
- - Wait 5 minutes
676
- - Restart the Space
677
- """)
678
 
679
- # Launch the app
680
- if __name__ == "__main__":
681
- print("=" * 60)
682
- print("🚀 Starting Suno Lyrics Generator - DEBUG MODE")
683
- print("=" * 60)
684
- print(f"🔑 SunoKey: {'✅ Configured' if SUNO_KEY else '❌ NOT SET'}")
685
- if SUNO_KEY:
686
- print(f"🔑 Preview: {SUNO_KEY[:10]}...")
687
- print(f"🐛 Debug Mode: {'✅ Enabled' if DEBUG else '❌ Disabled'}")
688
- print(f"📊 Pre-existing tasks: {len(tasks_db)}")
689
- print("=" * 60)
690
-
691
- app.launch(
692
- server_name="0.0.0.0",
693
- server_port=7860,
694
- share=False,
695
- debug=False,
696
- show_error=True
697
- )
 
2
  import requests
3
  import os
4
  import json
 
 
 
5
  from datetime import datetime
 
6
 
7
  # Load Suno API key
8
  SUNO_KEY = os.environ.get("SunoKey", "")
9
  if not SUNO_KEY:
10
  print("⚠️ Warning: SunoKey environment variable not set!")
11
 
12
+ def test_all_endpoints():
13
+ """Test all possible Suno API endpoints to find the right one"""
14
+ results = ["# 🔍 Testing All Suno API Endpoints", ""]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
+ headers = {"Authorization": f"Bearer {SUNO_KEY}"}
 
17
 
18
+ endpoints = [
19
+ ("GET", "https://api.sunoapi.org/api/v1/lyrics", "Base lyrics endpoint"),
20
+ ("GET", "https://api.sunoapi.org/api/v1/lyrics/record-info", "Record info endpoint"),
21
+ ("GET", "https://api.sunoapi.org/api/v1/lyrics/details", "Details endpoint"),
22
+ ("POST", "https://api.sunoapi.org/api/v1/lyrics", "Submit lyrics"),
23
+ ]
24
 
25
+ for method, url, description in endpoints:
26
+ results.append(f"\n## 🔗 {method} {url.split('/')[-1]}")
27
+ results.append(f"**Description:** {description}")
28
+
29
  try:
30
+ if method == "GET":
31
+ response = requests.get(url, headers=headers, timeout=10)
32
+ else: # POST
33
+ # Try POST with minimal payload
34
+ post_headers = headers.copy()
35
+ post_headers["Content-Type"] = "application/json"
36
+ payload = {
37
+ "prompt": "Test endpoint",
38
+ "callBackUrl": "http://test.com/callback"
39
+ }
40
+ response = requests.post(url, json=payload, headers=post_headers, timeout=10)
41
+
42
+ results.append(f"**HTTP Status:** {response.status_code}")
43
+
44
+ if response.status_code == 200:
45
+ try:
46
+ data = response.json()
47
+ results.append(f"**Response:** ```json\n{json.dumps(data, indent=2)[:500]}...\n```")
48
+ except:
49
+ results.append(f"**Response:** {response.text[:200]}...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  else:
51
+ results.append(f"**Error:** {response.text[:200]}...")
52
+
 
 
 
 
 
53
  except Exception as e:
54
+ results.append(f"**Exception:** {str(e)}")
 
 
 
 
 
55
 
56
+ return "\n".join(results)
 
 
57
 
58
+ def test_correct_workflow():
59
+ """Test what SHOULD be the correct workflow based on your code"""
60
+ results = ["# 🎯 Testing Correct Workflow", ""]
 
 
 
 
61
 
62
+ if not SUNO_KEY:
63
+ return "❌ No SunoKey configured"
64
 
65
+ headers = {"Authorization": f"Bearer {SUNO_KEY}"}
66
 
67
+ # Step 1: Submit lyrics (as per your original working code)
68
+ results.append("## 1️⃣ Submit Lyrics")
69
+ submit_url = "https://api.sunoapi.org/api/v1/lyrics"
70
+ submit_headers = headers.copy()
71
+ submit_headers["Content-Type"] = "application/json"
 
 
 
 
72
 
73
  payload = {
74
+ "prompt": "Correct workflow test song",
75
+ "callBackUrl": "http://correct-test.com/callback"
76
  }
77
 
78
  try:
79
+ response = requests.post(submit_url, json=payload, headers=submit_headers, timeout=30)
80
+ results.append(f"**Status:** {response.status_code}")
 
 
 
 
 
81
 
82
+ if response.status_code == 200:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  data = response.json()
84
+ results.append(f"**Code:** {data.get('code')}")
85
+ results.append(f"**Message:** {data.get('msg', 'No message')}")
86
 
87
+ if data.get("code") == 200 and "data" in data:
88
+ task_id = data["data"]["taskId"]
89
+ results.append(f"**Task ID:** `{task_id}`")
 
90
 
91
+ # Step 2: Check using record-info endpoint (from your example)
92
+ results.append("\n## 2️⃣ Check with /record-info")
93
+ record_url = "https://api.sunoapi.org/api/v1/lyrics/record-info"
94
 
95
+ # Try different query parameters
96
+ test_params = [
97
+ {"taskId": task_id},
98
+ {"id": task_id},
99
+ {"record_id": task_id},
100
+ {}, # No params
101
+ ]
102
+
103
+ for params in test_params:
104
+ results.append(f"\n**Trying params:** {params}")
105
+ try:
106
+ record_response = requests.get(
107
+ record_url,
108
+ headers=headers,
109
+ params=params,
110
+ timeout=30
111
+ )
112
+ results.append(f"Status: {record_response.status_code}")
113
+
114
+ if record_response.status_code == 200:
115
+ record_data = record_response.json()
116
+ results.append(f"Response: ```json\n{json.dumps(record_data, indent=2)[:300]}...\n```")
117
+ else:
118
+ results.append(f"Error: {record_response.text[:100]}")
119
+ except Exception as e:
120
+ results.append(f"Exception: {str(e)}")
121
+
122
+ # Step 3: Also try details endpoint for comparison
123
+ results.append("\n## 3️⃣ Check with /details (for comparison)")
124
+ details_url = f"https://api.sunoapi.org/api/v1/lyrics/details?taskId={task_id}"
125
+ try:
126
+ details_response = requests.get(details_url, headers=headers, timeout=30)
127
+ results.append(f"Status: {details_response.status_code}")
128
+ if details_response.status_code == 200:
129
+ details_data = details_response.json()
130
+ results.append(f"Response: ```json\n{json.dumps(details_data, indent=2)[:300]}...\n```")
131
+ except Exception as e:
132
+ results.append(f"Exception: {str(e)}")
133
+
134
+ else:
135
+ results.append("❌ No task ID in response")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  else:
137
+ results.append(f"❌ Submission failed: {response.text[:200]}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
 
 
 
 
 
139
  except Exception as e:
140
+ results.append(f"❌ Exception: {str(e)}")
 
 
 
 
141
 
142
+ return "\n".join(results)
143
 
144
+ def check_api_documentation():
145
+ """Show what we know about Suno API"""
146
+ return """# 📚 Suno API Documentation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
+ ## 🔍 What We Know:
149
+
150
+ ### **Endpoints Found:**
151
+ 1. `POST /api/v1/lyrics` - Submit lyrics generation
152
+ ```json
153
+ {
154
+ "prompt": "song about...",
155
+ "callBackUrl": "https://your-webhook.com/callback"
156
+ }