MySafeCode commited on
Commit
a71bf4d
·
verified ·
1 Parent(s): f949695

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +154 -279
app.py CHANGED
@@ -10,169 +10,72 @@ SUNO_KEY = os.environ.get("SunoKey", "")
10
  if not SUNO_KEY:
11
  print("⚠️ SunoKey not set!")
12
 
13
- def generate_lyrics(prompt):
14
- """Final working lyrics generator - UNCHANGED"""
15
- if not SUNO_KEY:
16
- yield "❌ Error: SunoKey not configured in environment variables"
17
- return
18
-
19
- if not prompt.strip():
20
- yield "❌ Error: Please enter a prompt"
21
- return
22
-
23
- # Submit task
24
- try:
25
- resp = requests.post(
26
- "https://api.sunoapi.org/api/v1/lyrics",
27
- json={
28
- "prompt": prompt,
29
- "callBackUrl": "http://dummy.com/callback" # Required but not used
30
- },
31
- headers={
32
- "Authorization": f"Bearer {SUNO_KEY}",
33
- "Content-Type": "application/json"
34
- },
35
- timeout=30
36
- )
37
-
38
- if resp.status_code != 200:
39
- yield f"❌ Submission failed: HTTP {resp.status_code}"
40
- return
41
-
42
- data = resp.json()
43
- if data.get("code") != 200:
44
- yield f"❌ API error: {data.get('msg', 'Unknown')}"
45
- return
46
-
47
- task_id = data["data"]["taskId"]
48
- yield f"✅ **Submitted!**\nTask ID: `{task_id}`\n\n⏳ Waiting for lyrics...\n"
49
-
50
- # Poll for results
51
- for attempt in range(30): # 30 attempts * 5 seconds = 150 seconds max
52
- time.sleep(5)
53
-
54
- try:
55
- check = requests.get(
56
- "https://api.sunoapi.org/api/v1/lyrics/record-info",
57
- headers={"Authorization": f"Bearer {SUNO_KEY}"},
58
- params={"taskId": task_id},
59
- timeout=30
60
- )
61
-
62
- if check.status_code == 200:
63
- check_data = check.json()
64
- status = check_data["data"].get("status", "PENDING")
65
-
66
- if status == "SUCCESS":
67
- # Success! Extract lyrics
68
- response_data = check_data["data"].get("response", {})
69
-
70
- if isinstance(response_data, str):
71
- # Sometimes response is a JSON string
72
- try:
73
- response_data = json.loads(response_data.replace('null', 'None'))
74
- except:
75
- response_data = {"data": []}
76
-
77
- lyrics_list = response_data.get("data", [])
78
-
79
- if lyrics_list:
80
- output = "🎵 **Lyrics Generated Successfully!**\n\n"
81
-
82
- for i, lyric in enumerate(lyrics_list, 1):
83
- title = lyric.get('title', f'Variant {i}')
84
- text = lyric.get('text', 'No lyrics')
85
-
86
- output += f"## Variant {i}: {title}\n"
87
- output += "```\n"
88
- output += text
89
- output += "\n```\n"
90
- output += "---\n\n"
91
-
92
- output += f"⏱️ Generated in about {(attempt + 1) * 5} seconds"
93
-
94
- # NEW: Store lyrics for later use
95
- lyrics_data = {
96
- "variants": lyrics_list,
97
- "original_prompt": prompt
98
- }
99
-
100
- # NEW: Prepare variant choices for dropdown
101
- variant_choices = [f"{i+1}: {lyric.get('title', f'Variant {i+1}')}"
102
- for i, lyric in enumerate(lyrics_list)]
103
-
104
- # NEW: Get first variant text
105
- first_text = lyrics_list[0].get('text', '') if lyrics_list else ""
106
-
107
- yield output, lyrics_data, variant_choices, first_text
108
- else:
109
- yield "✅ Completed but no lyrics found in response", None, [], ""
110
- return
111
-
112
- elif status == "FAILED":
113
- error = check_data["data"].get("errorMessage", "Unknown error")
114
- yield f"❌ Task failed: {error}", None, [], ""
115
- return
116
-
117
- else:
118
- # PENDING or PROCESSING
119
- yield (f"⏳ Status: {status}\n"
120
- f"Attempt: {attempt + 1}/30\n"
121
- f"Task ID: `{task_id}`\n\n"
122
- f"Still processing... (Usually takes 30-90 seconds)"), None, [], ""
123
- else:
124
- yield f"⚠️ Check error: HTTP {check.status_code}", None, [], ""
125
-
126
- except Exception as e:
127
- yield f"⚠️ Error checking status: {str(e)}", None, [], ""
128
-
129
- yield "⏰ Timeout after 150 seconds. Try checking again later.", None, [], ""
130
-
131
- except Exception as e:
132
- yield f"❌ Error: {str(e)}", None, [], ""
133
-
134
- def generate_song_from_text(lyrics_text, style, title, instrumental, model, custom_mode):
135
- """NEW: Generate a song from lyrics text"""
136
  if not SUNO_KEY:
137
  return "❌ Error: SunoKey not configured in environment variables"
138
 
139
  if not lyrics_text.strip():
140
- return "❌ Error: Please provide lyrics text"
 
 
 
 
 
 
141
 
142
  try:
143
- # Prepare request data based on custom mode
144
  request_data = {
145
- "customMode": custom_mode,
146
  "instrumental": instrumental,
147
  "model": model,
148
- "callBackUrl": "http://dummy.com/callback", # Required but not used
 
 
149
  }
150
 
151
- if custom_mode:
152
- # Custom mode requires style and title
153
- if not style.strip():
154
- return "❌ Error: Style is required in Custom Mode"
155
- if not title.strip():
156
- return " Error: Title is required in Custom Mode"
 
 
 
157
 
158
- request_data["style"] = style
159
- request_data["title"] = title
160
-
161
- if not instrumental:
162
- # Non-instrumental requires lyrics as prompt
163
- if len(lyrics_text) > 5000 and model in ["V4_5", "V4_5PLUS", "V4_5ALL", "V5"]:
164
- lyrics_text = lyrics_text[:5000]
165
- elif len(lyrics_text) > 3000 and model == "V4":
166
- lyrics_text = lyrics_text[:3000]
167
- request_data["prompt"] = lyrics_text
168
- else:
169
- # Non-custom mode only requires prompt (max 500 chars)
170
- if len(lyrics_text) > 500:
171
- lyrics_text = lyrics_text[:497] + "..."
172
  request_data["prompt"] = lyrics_text
173
- # Clear other fields for non-custom mode
174
- request_data["style"] = ""
175
- request_data["title"] = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
  # Submit generation request
178
  resp = requests.post(
@@ -186,13 +89,16 @@ def generate_song_from_text(lyrics_text, style, title, instrumental, model, cust
186
  )
187
 
188
  if resp.status_code != 200:
189
- return f"❌ Submission failed: HTTP {resp.status_code}"
 
190
 
191
  data = resp.json()
192
  if data.get("code") != 200:
193
- return f"❌ API error: {data.get('msg', 'Unknown')}"
 
194
 
195
  task_id = data["data"]["taskId"]
 
196
 
197
  # Poll for results
198
  for attempt in range(60): # 60 attempts * 5 seconds = 300 seconds max (5 minutes)
@@ -224,54 +130,49 @@ def generate_song_from_text(lyrics_text, style, title, instrumental, model, cust
224
  output += f"**Stream URL:** {stream_url}\n\n"
225
  output += f"**Download URL:** {download_url}\n\n"
226
  output += f"**Listen Now:** [Click to Stream]({stream_url})\n\n"
 
 
 
 
 
 
 
 
227
  output += "---\n\n"
228
 
229
  output += f"⏱️ Generated in about {(attempt + 1) * 5} seconds\n\n"
230
  output += "⚠️ **Note:** Files are retained for 15 days"
231
- return output
232
  else:
233
- return "✅ Completed but no songs found in response"
 
234
 
235
  elif status == "FAILED":
236
  error = check_data["data"].get("errorMessage", "Unknown error")
237
- return f"❌ Task failed: {error}"
 
238
 
239
  else:
240
  # Still processing
241
  if attempt % 6 == 0: # Update every 30 seconds
242
- yield f"⏳ Status: {status}\nAttempt: {attempt + 1}/60\nTask ID: `{task_id}`\n\nStill processing... (Usually takes 30-180 seconds)"
243
  else:
244
  yield f"⚠️ Check error: HTTP {check.status_code}"
245
 
246
  except Exception as e:
247
  yield f"⚠️ Error checking status: {str(e)}"
248
 
249
- return "⏰ Timeout after 300 seconds. Try checking again later."
250
 
251
  except Exception as e:
252
- return f"❌ Error: {str(e)}"
253
-
254
- # NEW: Helper functions for text handling
255
- def update_text_from_variant(lyrics_data, variant_choice):
256
- """Update text area when variant is selected"""
257
- if lyrics_data and lyrics_data.get("variants") and variant_choice:
258
- try:
259
- variant_idx = int(variant_choice.split(":")[0].strip()) - 1
260
- variants = lyrics_data["variants"]
261
-
262
- if 0 <= variant_idx < len(variants):
263
- text = variants[variant_idx].get('text', '')
264
- return text
265
- except:
266
- pass
267
- return ""
268
 
269
  def download_text_file(text):
270
  """Create downloadable text file"""
271
  if not text.strip():
272
  return None
273
 
274
- with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
275
  f.write(text)
276
  temp_path = f.name
277
 
@@ -294,118 +195,107 @@ def upload_text_file(file):
294
  except Exception as e:
295
  return f"❌ Error reading file: {str(e)}"
296
 
 
 
 
 
297
  # Create the app
298
- with gr.Blocks(title="Suno Lyrics Generator", theme="soft") as app:
299
- gr.Markdown("# 🎵 Suno Lyrics Generator")
300
- gr.Markdown("Generate song lyrics and turn them into full songs using Suno AI")
301
-
302
- # Store lyrics data
303
- lyrics_state = gr.State()
304
 
305
  with gr.Row():
306
  with gr.Column(scale=1):
307
- # Step 1: Generate Lyrics (original layout preserved)
308
- gr.Markdown("### Step 1: Generate Lyrics")
309
 
310
- prompt = gr.Textbox(
311
- label="Lyrics Prompt",
312
- placeholder="Example: A happy song about sunshine and rainbows",
313
- lines=3
314
- )
315
- lyrics_btn = gr.Button("🎵 Generate Lyrics", variant="primary")
316
-
317
- # NEW: Text Management Section
318
- gr.Markdown("### Text Management")
319
 
320
- with gr.Tab("Upload Text"):
321
  file_upload = gr.File(
322
  label="Upload Text File (.txt)",
323
  file_types=[".txt"],
324
  type="filepath"
325
  )
326
- upload_btn = gr.Button("📁 Load Text", variant="secondary")
327
-
328
- with gr.Tab("Select from Generated"):
329
- variant_choice = gr.Dropdown(
330
- label="Select Generated Variant",
331
- choices=[],
332
- interactive=True
333
- )
334
-
335
- # Step 2: Edit Lyrics
336
- gr.Markdown("### Step 2: Edit Lyrics (Optional)")
337
 
338
- lyrics_text = gr.Textbox(
339
- label="Lyrics Text",
340
- placeholder="Your lyrics will appear here. You can edit them or paste your own.",
341
- lines=15,
342
- interactive=True
343
- )
344
-
345
- with gr.Row():
346
- download_btn = gr.Button("💾 Download Text", variant="secondary")
347
- clear_btn = gr.Button("🗑️ Clear", variant="secondary")
348
-
349
- # Step 3: Generate Song (NEW)
350
- gr.Markdown("### Step 3: Generate Song")
351
-
352
- with gr.Row():
353
- custom_mode = gr.Checkbox(
354
- label="Custom Mode",
355
- value=False,
356
- info="Enable for advanced settings"
357
- )
358
- instrumental = gr.Checkbox(
359
- label="Instrumental",
360
- value=False,
361
- info="No vocals"
362
- )
363
 
364
  with gr.Row():
365
  style = gr.Textbox(
366
  label="Music Style",
367
- placeholder="Pop, Rock, Jazz",
368
  value="Pop",
369
- interactive=True
 
370
  )
 
 
371
  title = gr.Textbox(
372
  label="Song Title",
373
- placeholder="My Song",
374
  value="Generated Song",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
  interactive=True
376
  )
377
 
378
- model = gr.Dropdown(
379
- label="Model Version",
380
- choices=["V5", "V4_5PLUS", "V4_5ALL", "V4_5", "V4"],
381
- value="V4_5ALL",
382
- interactive=True
383
- )
384
 
385
- song_btn = gr.Button("🎶 Generate Song", variant="primary")
 
386
 
387
  # Instructions
388
  gr.Markdown("""
389
- **How it works:**
390
- 1. Generate lyrics or upload your own
391
- 2. Edit the text if needed
392
- 3. Set song parameters
393
- 4. Generate music!
 
 
 
 
 
 
 
 
394
 
395
- **Song Generation:**
396
- - Custom Mode: Requires style & title
397
- - Non-custom: Simple mode with prompt only
398
- - Instrumental: Music only, no singing
399
  """)
400
 
401
  with gr.Column(scale=2):
402
- # Main output (unchanged)
403
  output = gr.Markdown(
404
- label="Results",
405
- value="Your generated lyrics and songs will appear here..."
406
  )
407
 
408
- # NEW: Hidden download component
409
  file_output = gr.File(label="Download Lyrics", visible=False)
410
 
411
  gr.Markdown("---")
@@ -413,9 +303,8 @@ with gr.Blocks(title="Suno Lyrics Generator", theme="soft") as app:
413
  """
414
  <div style="text-align: center; padding: 20px;">
415
  <p>Powered by <a href="https://suno.ai" target="_blank">Suno AI</a> •
416
- <a href="https://sunoapi.org" target="_blank">Suno API Docs</a>
417
- <a href="https://github.com" target="_blank">GitHub</a></p>
418
- <p><small>This app uses the Suno API to generate AI-powered lyrics and music.</small></p>
419
  </div>
420
  """,
421
  elem_id="footer"
@@ -423,54 +312,40 @@ with gr.Blocks(title="Suno Lyrics Generator", theme="soft") as app:
423
 
424
  # Event handlers
425
 
426
- # Original lyrics generation (unchanged except outputs)
427
- lyrics_btn.click(
428
- generate_lyrics,
429
- inputs=prompt,
430
- outputs=[output, lyrics_state, variant_choice, lyrics_text]
431
- )
432
-
433
- # NEW: Upload text
434
  upload_btn.click(
435
  upload_text_file,
436
  inputs=file_upload,
437
  outputs=lyrics_text
438
  ).then(
439
- lambda: "📁 **Text loaded from file!**\n\nYou can now edit the text and generate a song.",
440
  outputs=output
441
  )
442
 
443
- # NEW: Update text when variant selected
444
- variant_choice.change(
445
- update_text_from_variant,
446
- inputs=[lyrics_state, variant_choice],
447
- outputs=lyrics_text
448
- )
449
-
450
- # NEW: Download text
451
  download_btn.click(
452
  download_text_file,
453
  inputs=lyrics_text,
454
  outputs=file_output
455
  ).then(
456
- lambda: "💾 **Text ready for download!**",
457
  outputs=output
458
  )
459
 
460
- # NEW: Clear text
461
  clear_btn.click(
462
- lambda: ("", "Text cleared."),
463
- outputs=[lyrics_text, output]
464
  )
465
 
466
- # NEW: Generate song
467
- song_btn.click(
468
  generate_song_from_text,
469
- inputs=[lyrics_text, style, title, instrumental, model, custom_mode],
470
  outputs=output
471
  )
472
 
473
  if __name__ == "__main__":
474
- print("🚀 Starting Suno Lyrics Generator")
475
  print(f"🔑 SunoKey: {'✅ Set' if SUNO_KEY else '❌ Not set'}")
476
  app.launch(server_name="0.0.0.0", server_port=7860, share=False)
 
10
  if not SUNO_KEY:
11
  print("⚠️ SunoKey not set!")
12
 
13
+ def generate_song_from_text(lyrics_text, style, title, instrumental, model, custom_mode=True):
14
+ """Generate a song from lyrics text"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  if not SUNO_KEY:
16
  return "❌ Error: SunoKey not configured in environment variables"
17
 
18
  if not lyrics_text.strip():
19
+ return "❌ Error: Please provide lyrics"
20
+
21
+ if not style.strip():
22
+ return "❌ Error: Please provide a music style"
23
+
24
+ if not title.strip():
25
+ return "❌ Error: Please provide a song title"
26
 
27
  try:
28
+ # Always use custom mode for full control
29
  request_data = {
30
+ "customMode": True, # Always True for our use case
31
  "instrumental": instrumental,
32
  "model": model,
33
+ "callBackUrl": "http://dummy.com/callback",
34
+ "style": style,
35
+ "title": title,
36
  }
37
 
38
+ if not instrumental:
39
+ # Non-instrumental requires lyrics as prompt
40
+ # Apply character limits based on model
41
+ if len(lyrics_text) > 5000 and model in ["V4_5", "V4_5PLUS", "V4_5ALL", "V5"]:
42
+ lyrics_text = lyrics_text[:5000]
43
+ yield f"⚠️ Lyrics truncated to 5000 characters for {model} model\n\n"
44
+ elif len(lyrics_text) > 3000 and model == "V4":
45
+ lyrics_text = lyrics_text[:3000]
46
+ yield f"⚠️ Lyrics truncated to 3000 characters for V4 model\n\n"
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  request_data["prompt"] = lyrics_text
49
+ else:
50
+ # For instrumental, clear the prompt
51
+ request_data["prompt"] = ""
52
+
53
+ # Apply style length limits
54
+ if len(style) > 1000 and model in ["V4_5", "V4_5PLUS", "V4_5ALL", "V5"]:
55
+ style = style[:1000]
56
+ elif len(style) > 200 and model == "V4":
57
+ style = style[:200]
58
+ yield f"⚠️ Style truncated to 200 characters for V4 model\n\n"
59
+
60
+ # Apply title length limits
61
+ if len(title) > 100 and model in ["V4_5", "V4_5PLUS", "V5"]:
62
+ title = title[:100]
63
+ elif len(title) > 80 and model in ["V4", "V4_5ALL"]:
64
+ title = title[:80]
65
+ yield f"⚠️ Title truncated to 80 characters for {model} model\n\n"
66
+
67
+ # Update with possibly truncated values
68
+ request_data["style"] = style
69
+ request_data["title"] = title
70
+
71
+ yield f"✅ **Submitting song request...**\n\n"
72
+ yield f"**Title:** {title}\n"
73
+ yield f"**Style:** {style}\n"
74
+ yield f"**Model:** {model}\n"
75
+ yield f"**Instrumental:** {'Yes' if instrumental else 'No'}\n"
76
+ if not instrumental:
77
+ yield f"**Lyrics length:** {len(lyrics_text)} characters\n\n"
78
+ yield f"⏳ Processing...\n"
79
 
80
  # Submit generation request
81
  resp = requests.post(
 
89
  )
90
 
91
  if resp.status_code != 200:
92
+ yield f"❌ Submission failed: HTTP {resp.status_code}"
93
+ return
94
 
95
  data = resp.json()
96
  if data.get("code") != 200:
97
+ yield f"❌ API error: {data.get('msg', 'Unknown')}"
98
+ return
99
 
100
  task_id = data["data"]["taskId"]
101
+ yield f"✅ **Request submitted!**\nTask ID: `{task_id}`\n\n⏳ Waiting for song generation...\n"
102
 
103
  # Poll for results
104
  for attempt in range(60): # 60 attempts * 5 seconds = 300 seconds max (5 minutes)
 
130
  output += f"**Stream URL:** {stream_url}\n\n"
131
  output += f"**Download URL:** {download_url}\n\n"
132
  output += f"**Listen Now:** [Click to Stream]({stream_url})\n\n"
133
+
134
+ # Add audio player for streaming
135
+ if stream_url and stream_url != 'No URL':
136
+ output += f"""<audio controls style="width: 100%; margin: 10px 0;">
137
+ <source src="{stream_url}" type="audio/mpeg">
138
+ Your browser does not support the audio element.
139
+ </audio>\n\n"""
140
+
141
  output += "---\n\n"
142
 
143
  output += f"⏱️ Generated in about {(attempt + 1) * 5} seconds\n\n"
144
  output += "⚠️ **Note:** Files are retained for 15 days"
145
+ yield output
146
  else:
147
+ yield "✅ Completed but no songs found in response"
148
+ return
149
 
150
  elif status == "FAILED":
151
  error = check_data["data"].get("errorMessage", "Unknown error")
152
+ yield f"❌ Task failed: {error}"
153
+ return
154
 
155
  else:
156
  # Still processing
157
  if attempt % 6 == 0: # Update every 30 seconds
158
+ yield f"⏳ Status: {status}\nAttempt: {attempt + 1}/60\nTask ID: `{task_id}`\n\nStill processing... (Usually takes 30-180 seconds)\n\nTypical timing:\n- 30-40s: Stream URL ready\n- 2-3 min: Download URL ready"
159
  else:
160
  yield f"⚠️ Check error: HTTP {check.status_code}"
161
 
162
  except Exception as e:
163
  yield f"⚠️ Error checking status: {str(e)}"
164
 
165
+ yield "⏰ Timeout after 300 seconds. Try checking again later."
166
 
167
  except Exception as e:
168
+ yield f"❌ Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  def download_text_file(text):
171
  """Create downloadable text file"""
172
  if not text.strip():
173
  return None
174
 
175
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False, encoding='utf-8') as f:
176
  f.write(text)
177
  temp_path = f.name
178
 
 
195
  except Exception as e:
196
  return f"❌ Error reading file: {str(e)}"
197
 
198
+ def clear_all():
199
+ """Clear all input fields"""
200
+ return "", "", "Generated Song", False, "V4_5ALL", ""
201
+
202
  # Create the app
203
+ with gr.Blocks(title="Suno Song Generator", theme="soft") as app:
204
+ gr.Markdown("# 🎵 Suno Song Generator")
205
+ gr.Markdown("Create songs from lyrics and style using Suno AI")
 
 
 
206
 
207
  with gr.Row():
208
  with gr.Column(scale=1):
209
+ # Lyrics Input
210
+ gr.Markdown("### Step 1: Enter Lyrics")
211
 
212
+ with gr.Tab("Paste Lyrics"):
213
+ lyrics_text = gr.Textbox(
214
+ label="Lyrics",
215
+ placeholder="Paste your lyrics here...\n\nExample:\n(Verse 1)\nSun is shining, sky is blue\nBirds are singing, just for you...",
216
+ lines=15,
217
+ interactive=True
218
+ )
 
 
219
 
220
+ with gr.Tab("Upload Lyrics"):
221
  file_upload = gr.File(
222
  label="Upload Text File (.txt)",
223
  file_types=[".txt"],
224
  type="filepath"
225
  )
226
+ upload_btn = gr.Button("📁 Load from File", variant="secondary")
 
 
 
 
 
 
 
 
 
 
227
 
228
+ # Song Settings
229
+ gr.Markdown("### Step 2: Song Settings")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
  with gr.Row():
232
  style = gr.Textbox(
233
  label="Music Style",
234
+ placeholder="Example: Pop, Rock, Jazz, Classical, Electronic, Hip Hop, Country",
235
  value="Pop",
236
+ interactive=True,
237
+ scale=2
238
  )
239
+
240
+ with gr.Row():
241
  title = gr.Textbox(
242
  label="Song Title",
243
+ placeholder="My Awesome Song",
244
  value="Generated Song",
245
+ interactive=True,
246
+ scale=2
247
+ )
248
+
249
+ with gr.Row():
250
+ instrumental = gr.Checkbox(
251
+ label="Instrumental (No Vocals)",
252
+ value=False,
253
+ interactive=True
254
+ )
255
+ model = gr.Dropdown(
256
+ label="Model",
257
+ choices=["V5", "V4_5PLUS", "V4_5ALL", "V4_5", "V4"],
258
+ value="V4_5ALL",
259
  interactive=True
260
  )
261
 
262
+ # Action Buttons
263
+ with gr.Row():
264
+ generate_btn = gr.Button("🎶 Generate Song", variant="primary", scale=2)
265
+ clear_btn = gr.Button("🗑️ Clear All", variant="secondary", scale=1)
 
 
266
 
267
+ with gr.Row():
268
+ download_btn = gr.Button("💾 Download Lyrics", variant="secondary")
269
 
270
  # Instructions
271
  gr.Markdown("""
272
+ **How to use:**
273
+ 1. Paste lyrics or upload a .txt file
274
+ 2. Set music style (genre)
275
+ 3. Enter song title
276
+ 4. Choose model (V4_5ALL recommended)
277
+ 5. Click Generate Song!
278
+
279
+ **Tips:**
280
+ - For best results, use structured lyrics with verses/chorus
281
+ - Style examples: "Pop", "Rock guitar solo", "Jazz piano", "Electronic dance"
282
+ - V5: Latest model, best quality
283
+ - V4_5ALL: Good balance, up to 8 minutes
284
+ - Instrumental: Check for music only
285
 
286
+ **Generation time:**
287
+ - 30-40s: Stream URL ready
288
+ - 2-3 min: Download URL ready
 
289
  """)
290
 
291
  with gr.Column(scale=2):
292
+ # Output Area
293
  output = gr.Markdown(
294
+ label="Generation Status",
295
+ value="### Ready to generate!\n\n1. Enter lyrics\n2. Set style and title\n3. Click 'Generate Song'"
296
  )
297
 
298
+ # Hidden download component
299
  file_output = gr.File(label="Download Lyrics", visible=False)
300
 
301
  gr.Markdown("---")
 
303
  """
304
  <div style="text-align: center; padding: 20px;">
305
  <p>Powered by <a href="https://suno.ai" target="_blank">Suno AI</a> •
306
+ <a href="https://sunoapi.org" target="_blank">Suno API Docs</a></p>
307
+ <p><small>Create custom songs by providing lyrics and music style</small></p>
 
308
  </div>
309
  """,
310
  elem_id="footer"
 
312
 
313
  # Event handlers
314
 
315
+ # Upload text from file
 
 
 
 
 
 
 
316
  upload_btn.click(
317
  upload_text_file,
318
  inputs=file_upload,
319
  outputs=lyrics_text
320
  ).then(
321
+ lambda: "📁 **Lyrics loaded from file!**\n\nReady to generate song.",
322
  outputs=output
323
  )
324
 
325
+ # Download lyrics
 
 
 
 
 
 
 
326
  download_btn.click(
327
  download_text_file,
328
  inputs=lyrics_text,
329
  outputs=file_output
330
  ).then(
331
+ lambda: "💾 **Lyrics ready for download!**",
332
  outputs=output
333
  )
334
 
335
+ # Clear all
336
  clear_btn.click(
337
+ clear_all,
338
+ outputs=[lyrics_text, style, title, instrumental, model, output]
339
  )
340
 
341
+ # Generate song
342
+ generate_btn.click(
343
  generate_song_from_text,
344
+ inputs=[lyrics_text, style, title, instrumental, model],
345
  outputs=output
346
  )
347
 
348
  if __name__ == "__main__":
349
+ print("🚀 Starting Suno Song Generator")
350
  print(f"🔑 SunoKey: {'✅ Set' if SUNO_KEY else '❌ Not set'}")
351
  app.launch(server_name="0.0.0.0", server_port=7860, share=False)