haraberget commited on
Commit
77c8e1c
·
verified ·
1 Parent(s): c3f6215

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +271 -121
app.py CHANGED
@@ -4,6 +4,7 @@ import os
4
  import json
5
  import uuid
6
  import time
 
7
  from datetime import datetime
8
  from typing import Dict, Optional
9
 
@@ -12,10 +13,64 @@ SUNO_KEY = os.environ.get("SunoKey", "")
12
  if not SUNO_KEY:
13
  print("⚠️ Warning: SunoKey environment variable not set!")
14
 
15
- # Task storage
16
  tasks_db = {}
 
17
 
18
- def generate_lyrics(prompt: str) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  """Submit lyrics generation task to Suno API"""
20
  if not SUNO_KEY:
21
  return "❌ Error: SunoKey environment variable not set. Please add it in Space Settings."
@@ -33,7 +88,7 @@ def generate_lyrics(prompt: str) -> str:
33
  "Content-Type": "application/json"
34
  }
35
 
36
- # Suno requires a callback URL, but we'll use a dummy one and rely on polling
37
  dummy_callback = "https://dummy.callback.url/not-used"
38
 
39
  payload = {
@@ -58,9 +113,23 @@ def generate_lyrics(prompt: str) -> str:
58
  "result": None,
59
  "error": None,
60
  "created_at": datetime.now().isoformat(),
61
- "last_checked": None
 
 
 
62
  }
63
 
 
 
 
 
 
 
 
 
 
 
 
64
  return f"""✅ **Task Submitted Successfully!**
65
 
66
  **Your Task ID:** `{task_id}`
@@ -68,13 +137,11 @@ def generate_lyrics(prompt: str) -> str:
68
 
69
  📝 **Prompt:** {prompt[:100]}{'...' if len(prompt) > 100 else ''}
70
 
71
- **Next Steps:**
72
- 1. Task is now processing with Suno AI
73
- 2. This usually takes 10-30 seconds
74
- 3. Click **"Check Status"** tab to check progress
75
- 4. Use your Task ID: `{task_id}`
76
 
77
- 💡 **Tip:** Save your Task ID to check results later!"""
 
 
78
 
79
  else:
80
  error_msg = data.get("msg", f"HTTP {response.status_code}")
@@ -91,13 +158,11 @@ def generate_lyrics(prompt: str) -> str:
91
  return "❌ Error: Request timeout - Suno API is not responding"
92
  except requests.exceptions.ConnectionError:
93
  return "❌ Error: Connection failed - Check your internet connection"
94
- except requests.exceptions.HTTPError as e:
95
- return f"❌ Error: HTTP {e.response.status_code if e.response else 'Unknown'}"
96
  except Exception as e:
97
  return f"❌ Error: {str(e)}"
98
 
99
- def check_task_status(task_id: str) -> str:
100
- """Check the status of a task using polling"""
101
  if not task_id or not task_id.strip():
102
  return "❌ Please enter a Task ID"
103
 
@@ -105,64 +170,71 @@ def check_task_status(task_id: str) -> str:
105
  return f"❌ Task ID `{task_id}` not found. Please submit a task first."
106
 
107
  task = tasks_db[task_id]
108
- api_task_id = task["api_task_id"]
109
 
110
- # Poll the Suno API
111
- url = f"https://api.sunoapi.org/api/v1/lyrics/details?taskId={api_task_id}"
112
- headers = {"Authorization": f"Bearer {SUNO_KEY}"}
113
-
114
- try:
115
- response = requests.get(url, headers=headers, timeout=30)
116
- data = response.json()
117
-
118
- if response.status_code == 200 and data.get("code") == 200:
119
- task_data = data["data"]
120
- status = task_data.get("status", "unknown")
121
 
122
- # Update task status
123
- tasks_db[task_id]["status"] = status
124
- tasks_db[task_id]["last_checked"] = datetime.now().isoformat()
125
 
126
- if status == "completed" and "data" in task_data:
127
- # Task completed successfully
128
- lyrics_data = task_data["data"]
129
- tasks_db[task_id]["result"] = lyrics_data
 
130
 
131
- # Format the output
132
- return format_lyrics_output(lyrics_data, task_id)
133
-
134
- elif status == "failed":
135
- error_msg = task_data.get("error", "Unknown error")
136
- tasks_db[task_id]["error"] = error_msg
137
- return f"""❌ **Task Failed**
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
  **Task ID:** `{task_id}`
140
  **Error:** {error_msg}
 
141
 
142
  💡 Please try generating again with a different prompt."""
143
-
144
- else:
145
- # Still processing
146
- elapsed = time_since(task["created_at"])
147
- return f"""⏳ **Task Processing...**
 
 
 
 
 
 
 
148
 
149
  **Task ID:** `{task_id}`
150
  **Status:** {status}
151
- **Elapsed:** {elapsed}
 
152
 
153
- ⏰ **Estimated time:** 10-30 seconds
154
- 🔄 **Auto-refresh recommended**
155
 
156
- 💡 Check back in a few seconds!"""
157
-
158
- else:
159
- error_msg = data.get("msg", f"HTTP {response.status_code}")
160
- return f"❌ Error checking status: {error_msg}"
161
-
162
- except Exception as e:
163
- return f"❌ Error: {str(e)}"
164
 
165
- def format_lyrics_output(lyrics_data, task_id):
166
  """Format the lyrics for display"""
167
  if not lyrics_data:
168
  return "✅ Task completed but no lyrics data received"
@@ -170,7 +242,8 @@ def format_lyrics_output(lyrics_data, task_id):
170
  output_lines = [
171
  f"# 🎵 Generated Lyrics (Task: {task_id})",
172
  "",
173
- f"**Generated at:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
 
174
  ""
175
  ]
176
 
@@ -190,24 +263,6 @@ def format_lyrics_output(lyrics_data, task_id):
190
 
191
  return "\n".join(output_lines)
192
 
193
- def time_since(iso_timestamp: str) -> str:
194
- """Calculate time elapsed since timestamp"""
195
- try:
196
- created = datetime.fromisoformat(iso_timestamp)
197
- elapsed = datetime.now() - created
198
- seconds = int(elapsed.total_seconds())
199
-
200
- if seconds < 60:
201
- return f"{seconds} seconds"
202
- elif seconds < 3600:
203
- minutes = seconds // 60
204
- return f"{minutes} minutes"
205
- else:
206
- hours = seconds // 3600
207
- return f"{hours} hours"
208
- except:
209
- return "Unknown"
210
-
211
  def list_all_tasks():
212
  """List all submitted tasks"""
213
  if not tasks_db:
@@ -215,42 +270,49 @@ def list_all_tasks():
215
 
216
  output_lines = ["# 📋 All Submitted Tasks", ""]
217
 
218
- for task_id, task in tasks_db.items():
219
  status = task.get("status", "unknown")
220
  prompt_preview = task.get("prompt", "")[:50]
221
  created = task.get("created_at", "")[:19]
222
 
223
- # Status icon
224
  if status == "completed":
225
  icon = "✅"
 
226
  elif status in ["failed", "error"]:
227
  icon = "❌"
 
228
  else:
229
  icon = "⏳"
 
230
 
231
- output_lines.append(f"{icon} **{task_id}** - {status}")
232
  output_lines.append(f" Prompt: {prompt_preview}...")
233
  output_lines.append(f" Created: {created}")
234
 
235
- if task.get("last_checked"):
236
- last_checked = task["last_checked"][:19]
237
- output_lines.append(f" Last checked: {last_checked}")
 
 
 
238
 
239
  output_lines.append("")
240
 
241
  # Add summary
242
  completed = sum(1 for t in tasks_db.values() if t.get("status") == "completed")
 
243
  total = len(tasks_db)
244
- output_lines.append(f"**Summary:** {completed}/{total} tasks completed")
245
 
246
  return "\n".join(output_lines)
247
 
248
- def auto_refresh_status(task_id: str):
249
- """Auto-refresh status with loading animation"""
250
  if not task_id or task_id not in tasks_db:
251
  return task_id, "❌ Invalid Task ID"
252
 
253
- result = check_task_status(task_id)
254
  return task_id, result
255
 
256
  # Create the Gradio interface
@@ -258,6 +320,9 @@ with gr.Blocks(title="Suno Lyrics Generator", theme=gr.themes.Soft()) as app:
258
  gr.Markdown("# 🎵 Suno AI Lyrics Generator")
259
  gr.Markdown("Generate song lyrics using Suno's AI API")
260
 
 
 
 
261
  with gr.Tabs():
262
  # Tab 1: Generate Lyrics
263
  with gr.TabItem("✨ Generate"):
@@ -270,14 +335,20 @@ with gr.Blocks(title="Suno Lyrics Generator", theme=gr.themes.Soft()) as app:
270
  lines=4
271
  )
272
 
 
 
 
 
 
 
273
  submit_btn = gr.Button("🚀 Generate Lyrics", variant="primary", size="lg")
274
 
275
  gr.Markdown("### 📝 Tips:")
276
  gr.Markdown("""
277
  • Be descriptive in your prompt
278
  • Include genre, mood, or theme
279
- • Specify if you want verses, chorus, bridge
280
  • Typical processing time: 10-30 seconds
 
281
  """)
282
 
283
  with gr.Column(scale=3):
@@ -286,10 +357,23 @@ with gr.Blocks(title="Suno Lyrics Generator", theme=gr.themes.Soft()) as app:
286
  value="Your task submission result will appear here..."
287
  )
288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  submit_btn.click(
290
- fn=generate_lyrics,
291
- inputs=prompt_input,
292
- outputs=output_area
293
  )
294
 
295
  # Tab 2: Check Status
@@ -299,13 +383,24 @@ with gr.Blocks(title="Suno Lyrics Generator", theme=gr.themes.Soft()) as app:
299
  gr.Markdown("### Enter your Task ID")
300
  task_id_input = gr.Textbox(
301
  label="Task ID",
302
- placeholder="Paste your Task ID here (e.g., a1b2c3d4)",
303
  scale=1
304
  )
305
 
 
 
 
 
 
 
 
 
 
 
306
  with gr.Row():
307
  check_btn = gr.Button("🔍 Check Status", variant="primary")
308
  auto_refresh_btn = gr.Button("🔄 Auto-refresh", variant="secondary")
 
309
 
310
  gr.Markdown("---")
311
  refresh_all_btn = gr.Button("📋 List All Tasks")
@@ -317,27 +412,64 @@ with gr.Blocks(title="Suno Lyrics Generator", theme=gr.themes.Soft()) as app:
317
  value="Enter a Task ID above and click Check Status"
318
  )
319
 
320
- # Connect buttons to functions
321
  check_btn.click(
322
  fn=check_task_status,
323
  inputs=task_id_input,
324
  outputs=status_output
325
  )
326
 
327
- auto_refresh_btn.click(
328
- fn=auto_refresh_status,
329
- inputs=task_id_input,
330
- outputs=[task_id_input, status_output]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  ).then(
332
- fn=lambda: time.sleep(3),
333
  inputs=None,
334
  outputs=None
335
  ).then(
336
- fn=auto_refresh_status,
337
  inputs=task_id_input,
338
  outputs=[task_id_input, status_output]
339
  )
340
 
 
 
 
 
 
 
 
 
341
  refresh_all_btn.click(
342
  fn=list_all_tasks,
343
  inputs=None,
@@ -354,45 +486,63 @@ with gr.Blocks(title="Suno Lyrics Generator", theme=gr.themes.Soft()) as app:
354
  api_status = "✅ Configured" if SUNO_KEY else "❌ Not configured"
355
  gr.Markdown(f"**SunoKey:** {api_status}")
356
 
357
- gr.Markdown("### 📋 How to Use:")
358
  gr.Markdown("""
359
- 1. **Generate Tab:** Enter a lyrics prompt and submit
360
- 2. **Save your Task ID** from the result
361
- 3. **Check Status Tab:** Paste your Task ID to check progress
362
- 4. **Results:** Lyrics will appear when processing is complete
 
 
 
 
 
 
 
 
 
 
 
 
363
  """)
364
 
365
  with gr.Column():
366
- gr.Markdown("### 🚨 Troubleshooting")
367
  gr.Markdown("""
368
- **Common Issues:**
 
 
 
369
 
370
- **"SunoKey not set":** Add your API key in Space Settings → Repository secrets
371
- **"Task ID not found":** Submit a new task and save the ID
372
- **Long processing time:** Suno API can take 10-30 seconds
373
- **API errors:** Check if your API key is valid and has credits
374
 
375
- **For best results:**
376
- - Use descriptive prompts
377
- - Check status after 15-20 seconds
378
- - Save your Task IDs
379
  """)
380
 
381
- gr.Markdown("### 📞 Support")
382
  gr.Markdown("""
383
- If you continue to have issues:
 
 
 
 
384
 
385
- 1. **Check your SunoKey** is correct and has available credits
386
- 2. **Try a simpler prompt** to test the API
387
- 3. **Wait a few minutes** if the API seems busy
388
- 4. **Contact Suno API support** for API-specific issues
389
  """)
390
 
391
  # Launch the app
392
  if __name__ == "__main__":
393
  print(f"🔑 SunoKey status: {'Configured' if SUNO_KEY else 'NOT SET'}")
394
- print(f"📊 Tasks in memory: {len(tasks_db)}")
395
- print("🚀 Starting Suno Lyrics Generator...")
396
 
397
  app.launch(
398
  server_name="0.0.0.0",
 
4
  import json
5
  import uuid
6
  import time
7
+ import threading
8
  from datetime import datetime
9
  from typing import Dict, Optional
10
 
 
13
  if not SUNO_KEY:
14
  print("⚠️ Warning: SunoKey environment variable not set!")
15
 
16
+ # Task storage with auto-polling
17
  tasks_db = {}
18
+ polling_threads = {}
19
 
20
+ def poll_task_status(task_id: str, max_attempts=60, interval=2):
21
+ """Background thread to automatically poll task status"""
22
+ if task_id not in tasks_db:
23
+ return
24
+
25
+ task = tasks_db[task_id]
26
+ api_task_id = task["api_task_id"]
27
+
28
+ for attempt in range(max_attempts):
29
+ try:
30
+ # Poll the API
31
+ url = f"https://api.sunoapi.org/api/v1/lyrics/details?taskId={api_task_id}"
32
+ headers = {"Authorization": f"Bearer {SUNO_KEY}"}
33
+
34
+ response = requests.get(url, headers=headers, timeout=30)
35
+ data = response.json()
36
+
37
+ if response.status_code == 200 and data.get("code") == 200:
38
+ task_data = data["data"]
39
+ status = task_data.get("status", "unknown")
40
+
41
+ # Update task status
42
+ tasks_db[task_id]["status"] = status
43
+ tasks_db[task_id]["last_checked"] = datetime.now().isoformat()
44
+
45
+ if status == "completed" and "data" in task_data:
46
+ # Task completed successfully
47
+ lyrics_data = task_data["data"]
48
+ tasks_db[task_id]["result"] = lyrics_data
49
+ tasks_db[task_id]["completed_at"] = datetime.now().isoformat()
50
+ print(f"✅ Task {task_id} completed via auto-polling")
51
+ break
52
+
53
+ elif status == "failed":
54
+ error_msg = task_data.get("error", "Unknown error")
55
+ tasks_db[task_id]["error"] = error_msg
56
+ tasks_db[task_id]["completed_at"] = datetime.now().isoformat()
57
+ print(f"❌ Task {task_id} failed: {error_msg}")
58
+ break
59
+
60
+ # Update attempts
61
+ tasks_db[task_id]["poll_attempts"] = attempt + 1
62
+
63
+ except Exception as e:
64
+ print(f"⚠️ Polling error for task {task_id}: {str(e)}")
65
+
66
+ # Wait before next poll
67
+ time.sleep(interval)
68
+
69
+ # Clean up polling thread
70
+ if task_id in polling_threads:
71
+ del polling_threads[task_id]
72
+
73
+ def generate_lyrics(prompt: str, auto_poll: bool = True) -> str:
74
  """Submit lyrics generation task to Suno API"""
75
  if not SUNO_KEY:
76
  return "❌ Error: SunoKey environment variable not set. Please add it in Space Settings."
 
88
  "Content-Type": "application/json"
89
  }
90
 
91
+ # Suno requires a callback URL, but we'll use a dummy one
92
  dummy_callback = "https://dummy.callback.url/not-used"
93
 
94
  payload = {
 
113
  "result": None,
114
  "error": None,
115
  "created_at": datetime.now().isoformat(),
116
+ "last_checked": None,
117
+ "poll_attempts": 0,
118
+ "completed_at": None,
119
+ "auto_poll": auto_poll
120
  }
121
 
122
+ # Start auto-polling if enabled
123
+ if auto_poll:
124
+ poll_thread = threading.Thread(
125
+ target=poll_task_status,
126
+ args=(task_id,),
127
+ daemon=True
128
+ )
129
+ polling_threads[task_id] = poll_thread
130
+ poll_thread.start()
131
+ print(f"🚀 Started auto-polling for task {task_id}")
132
+
133
  return f"""✅ **Task Submitted Successfully!**
134
 
135
  **Your Task ID:** `{task_id}`
 
137
 
138
  📝 **Prompt:** {prompt[:100]}{'...' if len(prompt) > 100 else ''}
139
 
140
+ {'🔄 **Auto-polling enabled** - Results will appear automatically!' if auto_poll else '📊 **Auto-polling disabled** - Check status manually'}
 
 
 
 
141
 
142
+ **Estimated time:** 10-30 seconds
143
+
144
+ 💡 **Tip:** Save your Task ID: `{task_id}`"""
145
 
146
  else:
147
  error_msg = data.get("msg", f"HTTP {response.status_code}")
 
158
  return "❌ Error: Request timeout - Suno API is not responding"
159
  except requests.exceptions.ConnectionError:
160
  return "❌ Error: Connection failed - Check your internet connection"
 
 
161
  except Exception as e:
162
  return f"❌ Error: {str(e)}"
163
 
164
+ def check_task_status(task_id: str, auto_refresh: bool = False) -> str:
165
+ """Check the status of a task"""
166
  if not task_id or not task_id.strip():
167
  return "❌ Please enter a Task ID"
168
 
 
170
  return f"❌ Task ID `{task_id}` not found. Please submit a task first."
171
 
172
  task = tasks_db[task_id]
 
173
 
174
+ # If auto_refresh is True, force an immediate API check
175
+ if auto_refresh:
176
+ try:
177
+ url = f"https://api.sunoapi.org/api/v1/lyrics/details?taskId={task['api_task_id']}"
178
+ headers = {"Authorization": f"Bearer {SUNO_KEY}"}
 
 
 
 
 
 
179
 
180
+ response = requests.get(url, headers=headers, timeout=30)
181
+ data = response.json()
 
182
 
183
+ if response.status_code == 200 and data.get("code") == 200:
184
+ task_data = data["data"]
185
+ status = task_data.get("status", "unknown")
186
+ tasks_db[task_id]["status"] = status
187
+ tasks_db[task_id]["last_checked"] = datetime.now().isoformat()
188
 
189
+ if status == "completed" and "data" in task_data:
190
+ lyrics_data = task_data["data"]
191
+ tasks_db[task_id]["result"] = lyrics_data
192
+ tasks_db[task_id]["completed_at"] = datetime.now().isoformat()
193
+
194
+ except Exception:
195
+ pass # Keep existing status if API check fails
196
+
197
+ status = task.get("status", "unknown")
198
+ created_time = datetime.fromisoformat(task["created_at"])
199
+ elapsed = int((datetime.now() - created_time).total_seconds())
200
+
201
+ if status == "completed" and task.get("result"):
202
+ # Format completed lyrics
203
+ return format_lyrics_output(task["result"], task_id, elapsed)
204
+
205
+ elif status == "failed":
206
+ error_msg = task.get("error", "Unknown error")
207
+ return f"""❌ **Task Failed**
208
 
209
  **Task ID:** `{task_id}`
210
  **Error:** {error_msg}
211
+ **Elapsed time:** {elapsed} seconds
212
 
213
  💡 Please try generating again with a different prompt."""
214
+
215
+ else:
216
+ # Still processing
217
+ attempts = task.get("poll_attempts", 0)
218
+ last_checked = task.get("last_checked")
219
+ last_checked_str = ""
220
+
221
+ if last_checked:
222
+ last_time = datetime.fromisoformat(last_checked)
223
+ last_checked_str = f"\n**Last checked:** {last_time.strftime('%H:%M:%S')}"
224
+
225
+ return f"""⏳ **Task Processing...**
226
 
227
  **Task ID:** `{task_id}`
228
  **Status:** {status}
229
+ **Elapsed:** {elapsed} seconds
230
+ **Poll attempts:** {attempts}{last_checked_str}
231
 
232
+ ⏰ **Estimated completion:** 10-30 seconds
233
+ 🔄 {'Auto-polling active' if task.get('auto_poll') else 'Auto-polling disabled'}
234
 
235
+ {'✅ Results will appear automatically when ready!' if task.get('auto_poll') else '📊 Click "Check Status" again to refresh'}"""
 
 
 
 
 
 
 
236
 
237
+ def format_lyrics_output(lyrics_data, task_id, elapsed_time):
238
  """Format the lyrics for display"""
239
  if not lyrics_data:
240
  return "✅ Task completed but no lyrics data received"
 
242
  output_lines = [
243
  f"# 🎵 Generated Lyrics (Task: {task_id})",
244
  "",
245
+ f"**Generated in:** {elapsed_time} seconds",
246
+ f"**Completed at:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
247
  ""
248
  ]
249
 
 
263
 
264
  return "\n".join(output_lines)
265
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  def list_all_tasks():
267
  """List all submitted tasks"""
268
  if not tasks_db:
 
270
 
271
  output_lines = ["# 📋 All Submitted Tasks", ""]
272
 
273
+ for task_id, task in sorted(tasks_db.items(), key=lambda x: x[1]["created_at"], reverse=True):
274
  status = task.get("status", "unknown")
275
  prompt_preview = task.get("prompt", "")[:50]
276
  created = task.get("created_at", "")[:19]
277
 
278
+ # Status icon and color
279
  if status == "completed":
280
  icon = "✅"
281
+ color = "green"
282
  elif status in ["failed", "error"]:
283
  icon = "❌"
284
+ color = "red"
285
  else:
286
  icon = "⏳"
287
+ color = "orange"
288
 
289
+ output_lines.append(f"<span style='color:{color}'>{icon} **{task_id}** - {status}</span>")
290
  output_lines.append(f" Prompt: {prompt_preview}...")
291
  output_lines.append(f" Created: {created}")
292
 
293
+ if task.get("completed_at"):
294
+ completed = task["completed_at"][:19]
295
+ output_lines.append(f" Completed: {completed}")
296
+
297
+ if task.get("auto_poll"):
298
+ output_lines.append(f" Auto-polling: ✅ Enabled")
299
 
300
  output_lines.append("")
301
 
302
  # Add summary
303
  completed = sum(1 for t in tasks_db.values() if t.get("status") == "completed")
304
+ processing = sum(1 for t in tasks_db.values() if t.get("status") not in ["completed", "failed", "error"])
305
  total = len(tasks_db)
306
+ output_lines.append(f"**Summary:** {completed} completed, {processing} processing, {total} total")
307
 
308
  return "\n".join(output_lines)
309
 
310
+ def auto_refresh_display(task_id: str):
311
+ """Auto-refresh the status display"""
312
  if not task_id or task_id not in tasks_db:
313
  return task_id, "❌ Invalid Task ID"
314
 
315
+ result = check_task_status(task_id, auto_refresh=True)
316
  return task_id, result
317
 
318
  # Create the Gradio interface
 
320
  gr.Markdown("# 🎵 Suno AI Lyrics Generator")
321
  gr.Markdown("Generate song lyrics using Suno's AI API")
322
 
323
+ # Store the current task ID in a hidden state
324
+ current_task_id = gr.State("")
325
+
326
  with gr.Tabs():
327
  # Tab 1: Generate Lyrics
328
  with gr.TabItem("✨ Generate"):
 
335
  lines=4
336
  )
337
 
338
+ auto_poll_checkbox = gr.Checkbox(
339
+ label="🔁 Enable auto-polling",
340
+ value=True,
341
+ info="Automatically check for results (recommended)"
342
+ )
343
+
344
  submit_btn = gr.Button("🚀 Generate Lyrics", variant="primary", size="lg")
345
 
346
  gr.Markdown("### 📝 Tips:")
347
  gr.Markdown("""
348
  • Be descriptive in your prompt
349
  • Include genre, mood, or theme
 
350
  • Typical processing time: 10-30 seconds
351
+ • Auto-polling will show results automatically
352
  """)
353
 
354
  with gr.Column(scale=3):
 
357
  value="Your task submission result will appear here..."
358
  )
359
 
360
+ def handle_generation(prompt, auto_poll):
361
+ result = generate_lyrics(prompt, auto_poll)
362
+ # Extract task ID from result
363
+ task_id = ""
364
+ if "Task ID:" in result:
365
+ for line in result.split('\n'):
366
+ if 'Task ID:' in line:
367
+ parts = line.split('`')
368
+ if len(parts) > 1:
369
+ task_id = parts[1]
370
+ break
371
+ return result, task_id
372
+
373
  submit_btn.click(
374
+ fn=handle_generation,
375
+ inputs=[prompt_input, auto_poll_checkbox],
376
+ outputs=[output_area, current_task_id]
377
  )
378
 
379
  # Tab 2: Check Status
 
383
  gr.Markdown("### Enter your Task ID")
384
  task_id_input = gr.Textbox(
385
  label="Task ID",
386
+ placeholder="Paste your Task ID here (e.g., 7d3b63c4)",
387
  scale=1
388
  )
389
 
390
+ # Auto-populate if we have a current task ID
391
+ def update_task_id_input(current_id):
392
+ return current_id if current_id else ""
393
+
394
+ current_task_id.change(
395
+ fn=update_task_id_input,
396
+ inputs=current_task_id,
397
+ outputs=task_id_input
398
+ )
399
+
400
  with gr.Row():
401
  check_btn = gr.Button("🔍 Check Status", variant="primary")
402
  auto_refresh_btn = gr.Button("🔄 Auto-refresh", variant="secondary")
403
+ stop_refresh_btn = gr.Button("⏹️ Stop", variant="stop", visible=False)
404
 
405
  gr.Markdown("---")
406
  refresh_all_btn = gr.Button("📋 List All Tasks")
 
412
  value="Enter a Task ID above and click Check Status"
413
  )
414
 
415
+ # Regular check
416
  check_btn.click(
417
  fn=check_task_status,
418
  inputs=task_id_input,
419
  outputs=status_output
420
  )
421
 
422
+ # Auto-refresh function
423
+ def start_auto_refresh(task_id, stop_flag):
424
+ if not task_id:
425
+ return task_id, "❌ Please enter a Task ID first", gr.update(visible=False), gr.update(visible=True)
426
+
427
+ # Update button states
428
+ return task_id, "🔄 Starting auto-refresh...", gr.update(visible=True), gr.update(visible=False)
429
+
430
+ def do_auto_refresh(task_id, iterations=10):
431
+ results = []
432
+ for i in range(iterations):
433
+ if not task_id or task_id not in tasks_db:
434
+ break
435
+
436
+ result = check_task_status(task_id, auto_refresh=True)
437
+ results.append(result)
438
+
439
+ # If completed, stop early
440
+ task = tasks_db.get(task_id, {})
441
+ if task.get("status") in ["completed", "failed"]:
442
+ break
443
+
444
+ # Wait between refreshes
445
+ if i < iterations - 1:
446
+ time.sleep(3)
447
+
448
+ return task_id, results[-1] if results else "Auto-refresh stopped"
449
+
450
+ # Connect auto-refresh button
451
+ auto_refresh_click = auto_refresh_btn.click(
452
+ fn=start_auto_refresh,
453
+ inputs=[task_id_input, gr.State(False)],
454
+ outputs=[task_id_input, status_output, stop_refresh_btn, auto_refresh_btn]
455
  ).then(
456
+ fn=lambda: time.sleep(1),
457
  inputs=None,
458
  outputs=None
459
  ).then(
460
+ fn=do_auto_refresh,
461
  inputs=task_id_input,
462
  outputs=[task_id_input, status_output]
463
  )
464
 
465
+ # Stop button
466
+ stop_refresh_btn.click(
467
+ fn=lambda: ("", "⏹️ Auto-refresh stopped", gr.update(visible=False), gr.update(visible=True)),
468
+ inputs=None,
469
+ outputs=[task_id_input, status_output, stop_refresh_btn, auto_refresh_btn]
470
+ )
471
+
472
+ # List all tasks
473
  refresh_all_btn.click(
474
  fn=list_all_tasks,
475
  inputs=None,
 
486
  api_status = "✅ Configured" if SUNO_KEY else "❌ Not configured"
487
  gr.Markdown(f"**SunoKey:** {api_status}")
488
 
489
+ gr.Markdown("### 🚀 How to Use:")
490
  gr.Markdown("""
491
+ 1. **Generate Tab:**
492
+ - Enter lyrics prompt
493
+ - Enable auto-polling (recommended)
494
+ - Click Generate
495
+ - Save your Task ID
496
+
497
+ 2. **Check Status Tab:**
498
+ - Paste your Task ID
499
+ - Click "Check Status" for manual check
500
+ - Click "Auto-refresh" for automatic updates
501
+ - Results appear automatically with auto-polling
502
+
503
+ 3. **Results:**
504
+ - Appear automatically if auto-polling enabled
505
+ - Can take 10-30 seconds
506
+ - Multiple lyric variants provided
507
  """)
508
 
509
  with gr.Column():
510
+ gr.Markdown("### 🔧 Features")
511
  gr.Markdown("""
512
+ **Auto-polling:**
513
+ - Background thread checks status every 2 seconds
514
+ - Results appear automatically
515
+ - Stops after completion or 2 minutes
516
 
517
+ **Manual checking:**
518
+ - Check specific Task ID status
519
+ - Auto-refresh button for continuous updates
520
+ - List all submitted tasks
521
 
522
+ **Task management:**
523
+ - All tasks stored in memory
524
+ - Status tracking
525
+ - Error handling
526
  """)
527
 
528
+ gr.Markdown("### ⚠️ Troubleshooting")
529
  gr.Markdown("""
530
+ **If tasks aren't completing:**
531
+ 1. Check your SunoKey has available credits
532
+ 2. Try simpler prompts
533
+ 3. Wait 30+ seconds for processing
534
+ 4. Use the "Auto-refresh" button
535
 
536
+ **Common errors:**
537
+ - "Task ID not found": Submit a new task
538
+ - "SunoKey not set": Add API key in Space Settings
539
+ - "Timeout": Suno API may be busy
540
  """)
541
 
542
  # Launch the app
543
  if __name__ == "__main__":
544
  print(f"🔑 SunoKey status: {'Configured' if SUNO_KEY else 'NOT SET'}")
545
+ print("🚀 Starting Suno Lyrics Generator with auto-polling...")
 
546
 
547
  app.launch(
548
  server_name="0.0.0.0",