MySafeCode commited on
Commit
897f827
·
verified ·
1 Parent(s): c2e4a34

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -356
app.py CHANGED
@@ -1,356 +1,50 @@
1
- import streamlit as st
2
- import json
3
- import requests
4
- import time
5
- from datetime import datetime
6
-
7
- st.set_page_config(
8
- page_title="Suno API Generator",
9
- page_icon="🎵",
10
- layout="wide"
11
- )
12
-
13
- # Load YOUR secret names
14
- SUNO_API_KEY = st.secrets.get("SunoKey", "")
15
- CALLBACK_URL = "https://1hit.no/wav/cb.php"
16
-
17
- # Initialize session state
18
- if 'task_id' not in st.session_state:
19
- st.session_state.task_id = None
20
- if 'polling' not in st.session_state:
21
- st.session_state.polling = False
22
- if 'poll_results' not in st.session_state:
23
- st.session_state.poll_results = []
24
- if 'auto_poll' not in st.session_state:
25
- st.session_state.auto_poll = False
26
-
27
- st.title("🎵 Suno API Audio Generator")
28
-
29
- # Info section
30
- with st.expander("📋 How it works", expanded=True):
31
- st.markdown("""
32
- ### Workflow:
33
- 1. **Step 1**: Submit task to Suno API → Get `taskId`
34
- 2. **Step 2**: Suno processes audio (async)
35
- 3. **Step 3**: Suno sends callback to: `https://1hit.no/wav/cb.php`
36
- 4. **Step 4**: You can view callbacks at: `https://1hit.no/wav/view.php`
37
- 5. **Step 5**: OR use Poll button to check status via `/api/v1/wav/record-info`
38
-
39
- ### Polling Endpoint:
40
- ```javascript
41
- fetch('https://api.sunoapi.org/api/v1/wav/record-info', {
42
- method: 'GET',
43
- headers: {
44
- 'Authorization': 'Bearer YOUR_TOKEN'
45
- }
46
- })
47
- ```
48
- """)
49
-
50
- col1, col2 = st.columns([2, 1])
51
-
52
- with col1:
53
- st.header("🚀 Step 1: Submit to Suno API")
54
-
55
- # Form inputs
56
- task_id = st.text_input("Task ID", value="5c79****be8e", help="Enter your Suno task ID")
57
- audio_id = st.text_input("Audio ID", value="e231****-****-****-****-****8cadc7dc", help="Enter your Suno audio ID")
58
-
59
- if st.button("🎵 Generate Audio", type="primary", use_container_width=True):
60
- if not SUNO_API_KEY:
61
- st.error("❌ SunoKey not configured in Hugging Face secrets")
62
- st.info("Add `SunoKey` secret in Hugging Face Space settings")
63
- st.stop()
64
-
65
- if not task_id or not audio_id:
66
- st.error("❌ Please enter both Task ID and Audio ID")
67
- st.stop()
68
-
69
- with st.spinner("Sending request to Suno API..."):
70
- headers = {
71
- "Authorization": f"Bearer {SUNO_API_KEY}",
72
- "Content-Type": "application/json"
73
- }
74
-
75
- payload = {
76
- "taskId": task_id,
77
- "audioId": audio_id,
78
- "callBackUrl": CALLBACK_URL
79
- }
80
-
81
- try:
82
- response = requests.post(
83
- "https://api.sunoapi.org/api/v1/wav/generate",
84
- headers=headers,
85
- json=payload,
86
- timeout=30
87
- )
88
-
89
- if response.status_code == 200:
90
- result = response.json()
91
-
92
- # Display response
93
- with st.expander("📋 API Response", expanded=True):
94
- st.json(result)
95
-
96
- if result.get("code") == 200 and "data" in result and "taskId" in result["data"]:
97
- st.session_state.task_id = result["data"]["taskId"]
98
- st.success(f"✅ Task submitted successfully!")
99
- st.info(f"**Task ID:** `{st.session_state.task_id}`")
100
-
101
- # Auto-fill poll input
102
- st.session_state.poll_task_input = st.session_state.task_id
103
-
104
- st.markdown("---")
105
- st.markdown("### 🔄 Next Steps:")
106
- st.markdown("""
107
- 1. **Automatic Callback**: Suno will send result to your callback URL
108
- 2. **Manual Poll**: Use the Poll button to check status
109
- 3. **View Logs**: Check [Callback Viewer](https://1hit.no/wav/view.php)
110
- """)
111
- else:
112
- st.error("❌ Unexpected response format")
113
- else:
114
- st.error(f"❌ API Error: {response.status_code}")
115
- try:
116
- error_data = response.json()
117
- st.json(error_data)
118
- except:
119
- st.text(f"Response: {response.text}")
120
-
121
- except requests.exceptions.Timeout:
122
- st.error("⏰ Request timed out after 30 seconds")
123
- except requests.exceptions.ConnectionError:
124
- st.error("🔌 Connection error - check your internet connection")
125
- except requests.exceptions.RequestException as e:
126
- st.error(f"⚠️ Request failed: {str(e)}")
127
-
128
- with col2:
129
- st.header("🔍 Step 2: Poll Status")
130
-
131
- # Manual task ID input for polling
132
- poll_task_id = st.text_input(
133
- "Task ID to Poll",
134
- value=st.session_state.get('poll_task_input', st.session_state.task_id or ""),
135
- help="Enter task ID to check status",
136
- key="poll_task_input"
137
- )
138
-
139
- col2a, col2b = st.columns(2)
140
-
141
- with col2a:
142
- if st.button("🔄 Poll Once", type="secondary", use_container_width=True):
143
- if not poll_task_id:
144
- st.error("❌ Please enter a Task ID")
145
- st.stop()
146
-
147
- if not SUNO_API_KEY:
148
- st.error("❌ SunoKey not configured")
149
- st.stop()
150
-
151
- # Single poll
152
- poll_status(poll_task_id, single_poll=True)
153
-
154
- with col2b:
155
- if st.button("🔁 Auto Poll (10s)", type="secondary", use_container_width=True):
156
- if not poll_task_id:
157
- st.error("❌ Please enter a Task ID")
158
- st.stop()
159
-
160
- if not SUNO_API_KEY:
161
- st.error("❌ SunoKey not configured")
162
- st.stop()
163
-
164
- # Start auto-polling
165
- st.session_state.auto_poll = True
166
- st.session_state.auto_poll_task_id = poll_task_id
167
- st.rerun()
168
-
169
- # Polling function
170
- def poll_status(task_id, single_poll=False):
171
- """Poll Suno API for task status using /api/v1/wav/record-info"""
172
- headers = {
173
- "Authorization": f"Bearer {SUNO_API_KEY}",
174
- "Content-Type": "application/json"
175
- }
176
-
177
- try:
178
- with st.spinner(f"Checking status for task: {task_id}..."):
179
- # Poll using the correct endpoint
180
- response = requests.get(
181
- f"https://api.sunoapi.org/api/v1/wav/record-info",
182
- headers=headers,
183
- timeout=30
184
- )
185
-
186
- if response.status_code == 200:
187
- result = response.json()
188
-
189
- # Add to poll results
190
- poll_entry = {
191
- "timestamp": datetime.now().strftime("%H:%M:%S"),
192
- "task_id": task_id,
193
- "response": result
194
- }
195
- st.session_state.poll_results.append(poll_entry)
196
-
197
- # Display result
198
- if result.get("code") == 200:
199
- data = result.get("data", {})
200
-
201
- if data.get("successFlag") == "SUCCESS":
202
- # Audio is ready!
203
- audio_url = data.get("response", {}).get("audioWavUrl")
204
- if audio_url:
205
- st.success("✅ Audio ready!")
206
- st.balloons()
207
-
208
- # Display audio info
209
- st.markdown("### 🎵 Audio Information")
210
- cols = st.columns(2)
211
- with cols[0]:
212
- st.metric("Task ID", data.get("taskId", "N/A")[:12] + "...")
213
- st.metric("Music ID", data.get("musicId", "N/A")[:12] + "...")
214
- with cols[1]:
215
- st.metric("Status", data.get("successFlag", "N/A"))
216
- st.metric("Created", data.get("createTime", "N/A"))
217
-
218
- # Audio player
219
- st.markdown("### 🔊 Listen")
220
- st.audio(audio_url, format="audio/wav")
221
-
222
- # Download section
223
- st.markdown("### 📥 Download")
224
- st.code(audio_url)
225
-
226
- col_dl1, col_dl2 = st.columns(2)
227
- with col_dl1:
228
- st.download_button(
229
- label="⬇ Download WAV",
230
- data=requests.get(audio_url).content if audio_url.startswith("http") else b"",
231
- file_name=f"audio_{data.get('taskId', 'unknown')[:8]}.wav",
232
- mime="audio/wav",
233
- key=f"download_{task_id}"
234
- )
235
- with col_dl2:
236
- if st.button("📋 Copy URL", key=f"copy_{task_id}"):
237
- st.code(audio_url)
238
- st.success("URL copied to clipboard!")
239
-
240
- # Stop auto-polling if active
241
- if st.session_state.get('auto_poll'):
242
- st.session_state.auto_poll = False
243
- st.success("✅ Auto-polling stopped (audio ready)")
244
- else:
245
- st.info("⏳ Audio still processing...")
246
- st.json(data)
247
- else:
248
- # Still processing or error
249
- status = data.get("successFlag", "UNKNOWN")
250
- if status == "PROCESSING":
251
- st.info(f"⏳ Processing... ({status})")
252
- elif status == "FAILED":
253
- st.error(f"❌ Processing failed: {data.get('errorMessage', 'Unknown error')}")
254
- else:
255
- st.info(f"ℹ️ Status: {status}")
256
-
257
- # Show progress info
258
- st.json(data)
259
- else:
260
- st.error(f"❌ API Error: {result.get('msg', 'Unknown error')}")
261
- st.json(result)
262
- else:
263
- st.error(f"❌ Status check failed: {response.status_code}")
264
- try:
265
- error_data = response.json()
266
- st.json(error_data)
267
- except:
268
- st.text(f"Response: {response.text}")
269
-
270
- except Exception as e:
271
- st.error(f"⚠️ Polling error: {str(e)}")
272
-
273
- # Auto-polling logic
274
- if st.session_state.get('auto_poll') and st.session_state.get('auto_poll_task_id'):
275
- task_id = st.session_state.auto_poll_task_id
276
-
277
- # Create a placeholder for auto-poll status
278
- poll_placeholder = st.empty()
279
-
280
- with poll_placeholder.container():
281
- st.info(f"🔁 Auto-polling task: `{task_id[:12]}...` (every 10 seconds)")
282
-
283
- # Poll once
284
- poll_status(task_id, single_poll=True)
285
-
286
- # Schedule next poll
287
- time.sleep(10)
288
- st.rerun()
289
-
290
- # Display poll results if any
291
- if st.session_state.poll_results:
292
- st.markdown("---")
293
- st.header("📊 Polling History")
294
-
295
- # Show last 5 results
296
- recent_results = list(reversed(st.session_state.poll_results[-5:]))
297
-
298
- for i, result in enumerate(recent_results):
299
- with st.expander(f"Poll {i+1} - {result['timestamp']} - Task: {result['task_id'][:12]}...", expanded=(i == len(recent_results)-1)):
300
- response_data = result["response"]
301
-
302
- if response_data.get("code") == 200:
303
- data = response_data.get("data", {})
304
- status = data.get("successFlag", "UNKNOWN")
305
-
306
- # Status badge
307
- if status == "SUCCESS":
308
- st.success(f"✅ {status}")
309
- elif status == "PROCESSING":
310
- st.info(f"⏳ {status}")
311
- elif status == "FAILED":
312
- st.error(f"❌ {status}")
313
- else:
314
- st.warning(f"⚠️ {status}")
315
-
316
- # Display key info
317
- cols = st.columns(3)
318
- with cols[0]:
319
- st.metric("Task ID", data.get("taskId", "N/A")[:12] + "...")
320
- with cols[1]:
321
- st.metric("Music ID", data.get("musicId", "N/A")[:12] + "...")
322
- with cols[2]:
323
- st.metric("Status", status)
324
-
325
- # Show audio if available
326
- audio_url = data.get("response", {}).get("audioWavUrl")
327
- if audio_url:
328
- st.audio(audio_url, format="audio/wav")
329
- st.markdown(f"**Audio URL:** `{audio_url}`")
330
-
331
- # Show full response
332
- with st.expander("📋 Full Response JSON"):
333
- st.json(response_data)
334
- else:
335
- st.error(f"❌ Error: {response_data.get('msg', 'Unknown error')}")
336
- st.json(response_data)
337
-
338
- # Quick links and info
339
- st.markdown("---")
340
- st.markdown("### 📝 Quick Links")
341
- st.markdown("""
342
- - 🔗 [View Suno Callbacks](https://1hit.no/wav/view.php) - See all callback logs
343
- - 📚 [Suno API Documentation](https://docs.sunoapi.org/) - Official API docs
344
- - 🔄 **Poll Endpoint**: `GET https://api.sunoapi.org/api/v1/wav/record-info`
345
- """)
346
-
347
- # Secret status
348
- with st.expander("🔐 Secret Status", expanded=False):
349
- if SUNO_API_KEY:
350
- masked_key = f"{SUNO_API_KEY[:8]}...{SUNO_API_KEY[-8:]}" if len(SUNO_API_KEY) > 16 else "••••••••"
351
- st.success(f"✅ SunoKey loaded ({len(SUNO_API_KEY)} chars)")
352
- st.code(f"SunoKey: {masked_key}")
353
- else:
354
- st.error("❌ SunoKey not found")
355
-
356
- st.info(f"**Callback URL:** `{CALLBACK_URL}`")
 
1
+ <?php
2
+ // view.php - View Suno callbacks
3
+ $logFile = 'callback_log.json';
4
+ $logData = file_exists($logFile) ? json_decode(file_get_contents($logFile), true) : [];
5
+
6
+ if (isset($_POST['clear'])) {
7
+ file_put_contents($logFile, '[]');
8
+ header('Location: view.php');
9
+ exit();
10
+ }
11
+ ?>
12
+ <!DOCTYPE html>
13
+ <html>
14
+ <head>
15
+ <title>Suno Callbacks</title>
16
+ <style>
17
+ body { font-family: Arial; padding: 20px; }
18
+ table { width: 100%; border-collapse: collapse; }
19
+ th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
20
+ th { background-color: #667eea; color: white; }
21
+ .success { background: #d4edda; }
22
+ .error { background: #f8d7da; }
23
+ audio { width: 200px; }
24
+ </style>
25
+ </head>
26
+ <body>
27
+ <h1>Suno Callbacks (<?php echo count($logData); ?>)</h1>
28
+ <form method="POST"><button type="submit" name="clear">Clear Logs</button></form>
29
+ <table>
30
+ <tr><th>Time</th><th>Task ID</th><th>Status</th><th>Audio</th><th>Actions</th></tr>
31
+ <?php foreach(array_reverse($logData) as $log): ?>
32
+ <tr class="<?php echo ($log['callback_data']['code']??0)==200?'success':'error'; ?>">
33
+ <td><?php echo $log['timestamp']; ?></td>
34
+ <td><?php echo $log['callback_data']['data']['taskId']??'N/A'; ?></td>
35
+ <td><?php echo ($log['callback_data']['code']??0)==200?'✅':'❌'; ?></td>
36
+ <td>
37
+ <?php if(isset($log['callback_data']['data']['response']['audioWavUrl'])): ?>
38
+ <audio controls src="<?php echo htmlspecialchars($log['callback_data']['data']['response']['audioWavUrl']); ?>"></audio>
39
+ <?php endif; ?>
40
+ </td>
41
+ <td>
42
+ <?php if(isset($log['callback_data']['data']['response']['audioWavUrl'])): ?>
43
+ <a href="<?php echo htmlspecialchars($log['callback_data']['data']['response']['audioWavUrl']); ?>" download>Download</a>
44
+ <?php endif; ?>
45
+ </td>
46
+ </tr>
47
+ <?php endforeach; ?>
48
+ </table>
49
+ </body>
50
+ </html>