MySafeCode commited on
Commit
93d8b27
·
verified ·
1 Parent(s): cc45c3f

Delete app2.py

Browse files
Files changed (1) hide show
  1. app2.py +0 -491
app2.py DELETED
@@ -1,491 +0,0 @@
1
- import gradio as gr
2
- import requests
3
- import os
4
- import time
5
- import json
6
- from datetime import datetime
7
- import re
8
-
9
- # Suno API key
10
- SUNO_KEY = os.environ.get("SunoKey", "")
11
- if not SUNO_KEY:
12
- print("⚠️ SunoKey not set in environment variables!")
13
-
14
- # API endpoints
15
- API_BASE = "https://api.sunoapi.org"
16
- CREDIT_URL = f"{API_BASE}/api/v1/generate/credit"
17
- GENERATION_RECORD_URL = f"{API_BASE}/api/v1/generate/record-info"
18
- VOCAL_SEPARATION_URL = f"{API_BASE}/api/v1/vocal-removal/generate"
19
- SEPARATION_RECORD_URL = f"{API_BASE}/api/v1/vocal-removal/record-info"
20
-
21
- def check_credits():
22
- """Check available credits"""
23
- try:
24
- response = requests.get(CREDIT_URL, headers={"Authorization": f"Bearer {SUNO_KEY}"}, timeout=10)
25
- if response.status_code == 200:
26
- data = response.json()
27
- if data.get("code") == 200:
28
- credits = data.get("data", {}).get("credit_balance", 0)
29
- return f"✅ Available credits: **{credits}**"
30
- return "⚠️ Could not retrieve credits"
31
- except:
32
- return "⚠️ Credit check failed"
33
-
34
- def get_music_tasks():
35
- """Get list of recent music generation tasks"""
36
- if not SUNO_KEY:
37
- return "❌ API key not configured", []
38
-
39
- try:
40
- response = requests.get(
41
- GENERATION_RECORD_URL,
42
- headers={"Authorization": f"Bearer {SUNO_KEY}"},
43
- params={"page": 1, "pageSize": 20},
44
- timeout=30
45
- )
46
-
47
- if response.status_code == 200:
48
- data = response.json()
49
- if data.get("code") == 200:
50
- tasks = data.get("data", {}).get("data", [])
51
-
52
- if not tasks:
53
- return "📭 No music generation tasks found. Please generate music first.", []
54
-
55
- task_list = []
56
- for task in tasks:
57
- task_id = task.get("taskId", "")
58
- status = task.get("status", "")
59
- audio_urls = task.get("audioUrl", [])
60
-
61
- # Get audio IDs if available
62
- audio_info = []
63
- if isinstance(audio_urls, list):
64
- for i, url in enumerate(audio_urls[:2]): # First 2 variants
65
- # Extract audio ID from URL or use placeholder
66
- audio_id = extract_audio_id(url) or f"variant-{i+1}"
67
- audio_info.append(f"Audio {i+1}: {audio_id}")
68
-
69
- task_info = f"Task: `{task_id[:8]}...` | Status: {status}"
70
- if audio_info:
71
- task_info += f" | {', '.join(audio_info)}"
72
-
73
- task_list.append((task_id, task_info))
74
-
75
- return f"✅ Found {len(task_list)} recent tasks", task_list
76
- else:
77
- return f"❌ API error: {data.get('msg')}", []
78
- else:
79
- return f"❌ HTTP error: {response.status_code}", []
80
-
81
- except Exception as e:
82
- return f"❌ Error: {str(e)}", []
83
-
84
- def extract_audio_id(url):
85
- """Extract audio ID from URL"""
86
- if not url:
87
- return None
88
-
89
- # Try to find UUID pattern in URL
90
- uuid_pattern = r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
91
- match = re.search(uuid_pattern, url, re.IGNORECASE)
92
- if match:
93
- return match.group(0)
94
-
95
- # Try to find in common URL patterns
96
- patterns = [
97
- r'audioId=([^&]+)',
98
- r'audio/([^/]+)',
99
- r'id=([^&]+)'
100
- ]
101
-
102
- for pattern in patterns:
103
- match = re.search(pattern, url)
104
- if match:
105
- return match.group(1)
106
-
107
- return None
108
-
109
- def get_audio_ids_from_task(task_id):
110
- """Get audio IDs for a specific task"""
111
- if not task_id:
112
- return "❌ Please select a task first", []
113
-
114
- try:
115
- response = requests.get(
116
- GENERATION_RECORD_URL,
117
- headers={"Authorization": f"Bearer {SUNO_KEY}"},
118
- params={"taskId": task_id},
119
- timeout=30
120
- )
121
-
122
- if response.status_code == 200:
123
- data = response.json()
124
- if data.get("code") == 200:
125
- task_data = data.get("data", {})
126
- audio_urls = task_data.get("audioUrl", [])
127
-
128
- if isinstance(audio_urls, list) and audio_urls:
129
- audio_options = []
130
- for i, url in enumerate(audio_urls):
131
- audio_id = extract_audio_id(url) or f"audio-{i+1}"
132
- display_name = f"Audio {i+1}"
133
- if audio_id:
134
- display_name += f" (ID: {audio_id[:8]}...)"
135
- audio_options.append((url, display_name))
136
-
137
- return f"✅ Found {len(audio_options)} audio tracks", audio_options
138
- else:
139
- return "⚠️ No audio tracks found for this task", []
140
- else:
141
- return f"❌ API error: {data.get('msg')}", []
142
- else:
143
- return f"❌ HTTP error: {response.status_code}", []
144
-
145
- except Exception as e:
146
- return f"❌ Error: {str(e)}", []
147
-
148
- def separate_vocals(task_id, audio_url, separation_type):
149
- """Separate vocals and instruments from selected audio"""
150
- if not SUNO_KEY:
151
- yield "❌ Error: SunoKey not configured"
152
- return
153
-
154
- if not task_id or not audio_url:
155
- yield "❌ Error: Please select both Task and Audio"
156
- return
157
-
158
- # Extract audio ID from URL
159
- audio_id = extract_audio_id(audio_url)
160
- if not audio_id:
161
- yield "❌ Could not extract Audio ID from the selected audio. Please check the URL format."
162
- return
163
-
164
- # Validate separation type
165
- if separation_type not in ["separate_vocal", "split_stem"]:
166
- yield "❌ Error: Invalid separation type"
167
- return
168
-
169
- # Submit separation task
170
- try:
171
- resp = requests.post(
172
- VOCAL_SEPARATION_URL,
173
- json={
174
- "taskId": task_id,
175
- "audioId": audio_id,
176
- "type": separation_type,
177
- "callBackUrl": "http://dummy.com/callback"
178
- },
179
- headers={
180
- "Authorization": f"Bearer {SUNO_KEY}",
181
- "Content-Type": "application/json"
182
- },
183
- timeout=30
184
- )
185
-
186
- if resp.status_code != 200:
187
- yield f"❌ Submission failed: HTTP {resp.status_code}"
188
- return
189
-
190
- data = resp.json()
191
- if data.get("code") != 200:
192
- yield f"❌ API error: {data.get('msg', 'Unknown')}"
193
- return
194
-
195
- separation_task_id = data["data"]["taskId"]
196
- yield f"✅ **Separation Task Submitted!**\n\n"
197
- yield f"**Separation Task ID:** `{separation_task_id}`\n"
198
- yield f"**Original Task ID:** `{task_id}`\n"
199
- yield f"**Audio ID:** `{audio_id}`\n"
200
- yield f"**Separation Type:** {separation_type}\n\n"
201
- yield f"⏳ **Processing...** (Usually takes 30-120 seconds)\n\n"
202
-
203
- # Poll for results
204
- for attempt in range(40): # 40 attempts * 5 seconds = 200 seconds max
205
- time.sleep(5)
206
-
207
- try:
208
- check = requests.get(
209
- SEPARATION_RECORD_URL,
210
- headers={"Authorization": f"Bearer {SUNO_KEY}"},
211
- params={"taskId": separation_task_id},
212
- timeout=30
213
- )
214
-
215
- if check.status_code == 200:
216
- check_data = check.json()
217
- status = check_data["data"].get("successFlag", "PENDING")
218
-
219
- if status == "SUCCESS":
220
- # Success! Extract separation results
221
- separation_info = check_data["data"].get("response", {})
222
-
223
- # Format output based on separation type
224
- output = "🎵 **Separation Complete!**\n\n"
225
-
226
- if separation_type == "separate_vocal":
227
- output += "## 🎤 2-Stem Separation\n\n"
228
- output += f"**🎤 Vocals:** [Download]({separation_info.get('vocalUrl', 'N/A')})\n"
229
- output += f"**🎵 Instrumental:** [Download]({separation_info.get('instrumentalUrl', 'N/A')})\n"
230
- if separation_info.get('originUrl'):
231
- output += f"**📁 Original:** [Download]({separation_info.get('originUrl')})\n"
232
-
233
- elif separation_type == "split_stem":
234
- output += "## 🎛️ 12-Stem Separation\n\n"
235
-
236
- stems = [
237
- ("🎤 Vocals", separation_info.get('vocalUrl')),
238
- ("🎤 Backing Vocals", separation_info.get('backingVocalsUrl')),
239
- ("🥁 Drums", separation_info.get('drumsUrl')),
240
- ("🎸 Bass", separation_info.get('bassUrl')),
241
- ("🎸 Guitar", separation_info.get('guitarUrl')),
242
- ("🎹 Keyboard", separation_info.get('keyboardUrl')),
243
- ("🎻 Strings", separation_info.get('stringsUrl')),
244
- ("🎺 Brass", separation_info.get('brassUrl')),
245
- ("🎷 Woodwinds", separation_info.get('woodwindsUrl')),
246
- ("🪇 Percussion", separation_info.get('percussionUrl')),
247
- ("🎹 Synth", separation_info.get('synthUrl')),
248
- ("🎛️ FX/Other", separation_info.get('fxUrl')),
249
- ("📁 Original", separation_info.get('originUrl'))
250
- ]
251
-
252
- for stem_name, stem_url in stems:
253
- if stem_url:
254
- output += f"**{stem_name}:** [Download]({stem_url})\n"
255
-
256
- output += f"\n⏱️ **Processing Time:** {(attempt + 1) * 5} seconds\n"
257
- output += f"📊 **Separation Task ID:** `{separation_task_id}`\n"
258
- output += f"⚠️ **Note:** Download links expire in 14 days\n"
259
-
260
- yield output
261
- return
262
-
263
- elif status in ["CREATE_TASK_FAILED", "GENERATE_AUDIO_FAILED", "CALLBACK_EXCEPTION"]:
264
- error = check_data["data"].get("errorMessage", "Unknown error")
265
- yield f"❌ **Separation failed:** {status}\n\n"
266
- yield f"**Error:** {error}\n"
267
- return
268
-
269
- else:
270
- # PENDING or other statuses
271
- yield (f"⏳ **Status:** {status}\n"
272
- f"📊 **Progress:** {attempt + 1}/40 attempts\n"
273
- f"⏱️ **Elapsed:** {(attempt + 1) * 5} seconds\n\n"
274
- f"Still processing...")
275
- else:
276
- yield f"⚠️ **Check error:** HTTP {check.status_code}\n"
277
-
278
- except Exception as e:
279
- yield f"⚠️ **Error checking status:** {str(e)}\n"
280
-
281
- yield "⏰ **Timeout after 200 seconds.** Try checking the task manually later.\n"
282
- yield f"**Separation Task ID:** `{separation_task_id}`\n"
283
-
284
- except Exception as e:
285
- yield f"❌ **Error submitting task:** {str(e)}"
286
-
287
- def refresh_tasks():
288
- """Refresh the list of available tasks"""
289
- status, tasks = get_music_tasks()
290
- task_options = [("", "Select a task...")] + tasks if tasks else [("", "No tasks found")]
291
- return status, gr.Dropdown(choices=[opt[1] for opt in task_options], value=task_options[0][1]), task_options
292
-
293
- # Create the app
294
- with gr.Blocks(title="Suno Stem Separator", theme="soft") as app:
295
- gr.Markdown("# 🎵 Suno AI Stem Separator")
296
- gr.Markdown("Separate vocals and instruments from your Suno AI generated music")
297
-
298
- # Credit display at top
299
- credit_display = gr.Markdown(check_credits(), elem_id="credits")
300
-
301
- with gr.Tabs():
302
- with gr.TabItem("🎵 Step 1: Select Your Music"):
303
- gr.Markdown("""
304
- ### Find your generated music tracks
305
-
306
- 1. Click **Refresh Tasks** to load your recent Suno AI music generations
307
- 2. Select a task from the dropdown
308
- 3. The system will automatically find available audio tracks
309
- """)
310
-
311
- with gr.Row():
312
- refresh_btn = gr.Button("🔄 Refresh Tasks", variant="secondary")
313
- task_status = gr.Markdown("Click 'Refresh Tasks' to load your music tasks")
314
-
315
- with gr.Row():
316
- with gr.Column(scale=1):
317
- task_dropdown = gr.Dropdown(
318
- label="Select Music Generation Task",
319
- choices=["Select a task..."],
320
- value="Select a task...",
321
- interactive=True
322
- )
323
-
324
- gr.Markdown("""
325
- **What is a Task ID?**
326
- - When you generate music with Suno AI, each generation gets a unique Task ID
327
- - This ID is required to separate vocals from your music
328
- - Select your task from the dropdown above
329
- """)
330
-
331
- with gr.Column(scale=1):
332
- audio_status = gr.Markdown("Select a task to see available audio tracks")
333
- audio_dropdown = gr.Dropdown(
334
- label="Select Audio Track to Separate",
335
- choices=["First select a task..."],
336
- value="First select a task...",
337
- interactive=True
338
- )
339
-
340
- gr.Markdown("""
341
- **What is an Audio ID?**
342
- - Each music generation can have multiple audio variants
343
- - The Audio ID identifies which specific track to process
344
- - Usually you'll have 2-4 audio tracks per generation
345
- """)
346
-
347
- # Hidden storage for task data
348
- task_store = gr.State([]) # Stores (task_id, display_name) pairs
349
-
350
- with gr.TabItem("🎛️ Step 2: Configure Separation"):
351
- gr.Markdown("""
352
- ### Configure how you want to separate the audio
353
-
354
- **Choose separation type:**
355
- - **🎤 Vocal Separation (1 credit)**: Separate vocals from instrumental
356
- - **🎛️ Full Stem Separation (5 credits)**: Split into 12 individual instrument stems
357
-
358
- **Stem types in full separation:**
359
- - Vocals, Backing Vocals, Drums, Bass, Guitar
360
- - Keyboard, Strings, Brass, Woodwinds, Percussion
361
- - Synthesizer, FX/Other
362
- """)
363
-
364
- separation_type = gr.Radio(
365
- label="Separation Type",
366
- choices=[
367
- ("🎤 Vocal Separation (2 stems, 1 credit)", "separate_vocal"),
368
- ("🎛️ Full Stem Separation (12 stems, 5 credits)", "split_stem")
369
- ],
370
- value="separate_vocal",
371
- info="Choose how detailed the separation should be"
372
- )
373
-
374
- with gr.Row():
375
- selected_task_display = gr.Textbox(
376
- label="Selected Task ID",
377
- interactive=False,
378
- value="No task selected"
379
- )
380
- selected_audio_display = gr.Textbox(
381
- label="Selected Audio ID",
382
- interactive=False,
383
- value="No audio selected"
384
- )
385
-
386
- separate_btn = gr.Button("🚀 Start Separation", variant="primary", scale=1)
387
-
388
- gr.Markdown("""
389
- **⚠️ Important Notes:**
390
- - Each separation consumes credits (shown at top of page)
391
- - Processing takes 30-120 seconds
392
- - Download links expire after 14 days
393
- - You can reuse the Separation Task ID to download files later
394
- """)
395
-
396
- with gr.TabItem("📥 Step 3: Get Results"):
397
- output = gr.Markdown(
398
- label="Separation Results",
399
- value="Your separated stems will appear here once processing is complete..."
400
- )
401
-
402
- gr.Markdown("""
403
- **What to expect:**
404
- 1. After clicking **Start Separation**, you'll get a Separation Task ID
405
- 2. The system will automatically check progress every 5 seconds
406
- 3. When complete, you'll see download links for all stems
407
- 4. Links remain active for **14 days** - download promptly!
408
-
409
- **Need to check a previous separation?**
410
- Use the **Check Existing Task** tab (coming soon!)
411
- """)
412
-
413
- gr.Markdown("---")
414
- gr.Markdown(
415
- """
416
- <div style="text-align: center; padding: 20px;">
417
- <p>Powered by <a href="https://suno.ai" target="_blank">Suno AI</a> •
418
- <a href="https://sunoapi.org" target="_blank">Suno API</a> •
419
- <a href="https://docs.sunoapi.org" target="_blank">API Docs</a></p>
420
- <p><small>This tool helps you separate vocals and instruments from Suno AI generated music.</small></p>
421
- </div>
422
- """,
423
- elem_id="footer"
424
- )
425
-
426
- # Event handlers
427
- def on_task_select(selected_display, task_store_data):
428
- """When a task is selected from dropdown"""
429
- # Find the actual task_id from the display name
430
- for task_id, display_name in task_store_data:
431
- if display_name == selected_display:
432
- # Get audio IDs for this task
433
- status, audio_options = get_audio_ids_from_task(task_id)
434
-
435
- # Update audio dropdown
436
- audio_choices = [("", "Select audio...")] + audio_options if audio_options else [("", "No audio found")]
437
-
438
- return (
439
- status,
440
- gr.Dropdown(choices=[opt[1] for opt in audio_choices], value=audio_choices[0][1]),
441
- task_id[:12] + "..." if len(task_id) > 12 else task_id,
442
- "Select audio above..."
443
- )
444
-
445
- return "❌ Task not found", gr.Dropdown(choices=["Task not found"], value="Task not found"), "Error", "Error"
446
-
447
- def on_audio_select(selected_audio_display, audio_options_data):
448
- """When an audio is selected"""
449
- # Extract audio ID from the selected option
450
- # The display format is "Audio 1 (ID: abc123...)" or similar
451
- import re
452
- match = re.search(r'ID:\s*([^\s)]+)', selected_audio_display)
453
- audio_id = match.group(1) if match else selected_audio_display
454
-
455
- return audio_id
456
-
457
- # Connect events
458
- refresh_btn.click(
459
- refresh_tasks,
460
- outputs=[task_status, task_dropdown, task_store]
461
- )
462
-
463
- task_dropdown.change(
464
- on_task_select,
465
- inputs=[task_dropdown, task_store],
466
- outputs=[audio_status, audio_dropdown, selected_task_display, selected_audio_display]
467
- )
468
-
469
- audio_dropdown.change(
470
- lambda x: x, # Simple pass-through for now
471
- inputs=[audio_dropdown],
472
- outputs=[selected_audio_display]
473
- )
474
-
475
- separate_btn.click(
476
- separate_vocals,
477
- inputs=[selected_task_display, audio_dropdown, separation_type],
478
- outputs=[output]
479
- )
480
-
481
- if __name__ == "__main__":
482
- print("🚀 Starting Suno Stem Separator")
483
- print(f"🔑 SunoKey: {'✅ Set' if SUNO_KEY else '❌ Not set'}")
484
- print("🌐 Open your browser to: http://localhost:7860")
485
- print("\n💡 Instructions:")
486
- print("1. Make sure you have generated music with Suno AI")
487
- print("2. Refresh tasks to load your music generations")
488
- print("3. Select a task and audio track")
489
- print("4. Choose separation type and start processing")
490
-
491
- app.launch(server_name="0.0.0.0", server_port=7860, share=False)