MySafeCode commited on
Commit
45fc344
·
verified ·
1 Parent(s): 51e4d18

Update aa.py

Browse files
Files changed (1) hide show
  1. aa.py +212 -182
aa.py CHANGED
@@ -187,15 +187,6 @@ def create_html_receipt(song_data, task_id, ownership_proof):
187
  .download-link:hover {{
188
  background: #2980b9;
189
  }}
190
- .qr-placeholder {{
191
- text-align: center;
192
- margin: 20px 0;
193
- }}
194
- .qr-placeholder img {{
195
- max-width: 150px;
196
- border: 1px solid #ddd;
197
- border-radius: 5px;
198
- }}
199
  </style>
200
  </head>
201
  <body>
@@ -275,7 +266,6 @@ def create_html_receipt(song_data, task_id, ownership_proof):
275
  </div>
276
 
277
  <script>
278
- // Add print functionality
279
  window.onload = function() {{
280
  console.log('Receipt loaded - you can print or save as PDF');
281
  }}
@@ -285,20 +275,55 @@ def create_html_receipt(song_data, task_id, ownership_proof):
285
 
286
  return html
287
 
288
- def download_receipt(song_data, task_id, ownership_proof):
289
  """
290
- Create a downloadable receipt file
 
291
  """
292
- html_content = create_html_receipt(song_data, task_id, ownership_proof)
293
- title = song_data.get('title', 'song').replace(' ', '_').replace('/', '_')
294
- filename = f"receipt_{title}_{task_id[:8]}.html"
295
 
296
- return html_content, filename
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
 
298
  def get_task_info(task_id):
299
  """Manually check any Suno task status"""
300
  if not task_id:
301
- return "❌ Please enter a Task ID"
302
 
303
  try:
304
  resp = requests.get(
@@ -309,10 +334,13 @@ def get_task_info(task_id):
309
  )
310
 
311
  if resp.status_code != 200:
312
- return f"❌ HTTP Error {resp.status_code}\n\n{resp.text}"
313
 
314
  data = resp.json()
315
 
 
 
 
316
  # Format the response for display
317
  output = f"## 🔍 Task Status: `{task_id}`\n\n"
318
 
@@ -326,25 +354,6 @@ def get_task_info(task_id):
326
  output += f"**Created:** {task_data.get('createTime', 'N/A')}\n"
327
 
328
  if status == "SUCCESS":
329
- response_data = task_data.get("response", {})
330
-
331
- # Try to parse response (could be string or dict)
332
- if isinstance(response_data, str):
333
- try:
334
- response_data = json.loads(response_data)
335
- except:
336
- output += f"\n**Raw Response:**\n```\n{response_data}\n```\n"
337
- response_data = {}
338
-
339
- # Check for song data
340
- songs = []
341
- if isinstance(response_data, dict):
342
- songs = response_data.get("sunoData", [])
343
- if not songs:
344
- songs = response_data.get("data", [])
345
- elif isinstance(response_data, list):
346
- songs = response_data
347
-
348
  if songs:
349
  output += f"\n## 🎵 Generated Songs ({len(songs)})\n\n"
350
 
@@ -361,8 +370,8 @@ def get_task_info(task_id):
361
  # Generate ownership proof if title is custom
362
  if is_custom:
363
  proof = generate_ownership_proof(task_id, title, song.get('id'))
364
- output += f"**🔐 Proof Generated:** [Download Receipt](#)\n"
365
- output += f"**Proof Hash:** `{proof['proof'][:16]}...`\n"
366
 
367
  # Audio URLs
368
  audio_url = song.get('audioUrl') or song.get('audio_url')
@@ -385,18 +394,6 @@ def get_task_info(task_id):
385
  Your browser does not support audio.
386
  </audio>\n"""
387
 
388
- # Add receipt download button if custom title
389
- if is_custom:
390
- # Create a unique ID for this song's receipt
391
- receipt_id = f"receipt_{task_id}_{i}"
392
- output += f"""\n<div style="margin: 10px 0;">
393
- <button onclick="downloadReceipt('{task_id}', {i})"
394
- style="background: #27ae60; color: white; border: none;
395
- padding: 10px 20px; border-radius: 5px; cursor: pointer;">
396
- 📥 Download Ownership Receipt
397
- </button>
398
- </div>\n"""
399
-
400
  output += f"**Prompt:** {song.get('prompt', 'N/A')[:100]}...\n"
401
  output += f"**Duration:** {song.get('duration', 'N/A')}s\n"
402
  output += f"**Created:** {song.get('createTime', 'N/A')}\n\n"
@@ -420,12 +417,12 @@ def get_task_info(task_id):
420
 
421
  # Show raw JSON for debugging
422
  output += "\n## 📋 Raw Response\n"
423
- output += f"```json\n{json.dumps(data, indent=2)}\n```"
424
 
425
- return output
426
 
427
  except Exception as e:
428
- return f"❌ Error checking task: {str(e)}"
429
 
430
  def generate_song_from_text(lyrics_text, style, title, instrumental, model):
431
  """Generate a song from lyrics text"""
@@ -527,8 +524,6 @@ def generate_song_from_text(lyrics_text, style, title, instrumental, model):
527
  task_id = data["taskId"]
528
  elif "data" in data and "taskId" in data["data"]:
529
  task_id = data["data"]["taskId"]
530
- elif data.get("data") and "taskId" in data.get("data", {}):
531
- task_id = data["data"]["taskId"]
532
 
533
  if not task_id:
534
  yield f"❌ Could not extract Task ID from response"
@@ -560,7 +555,7 @@ def generate_song_from_text(lyrics_text, style, title, instrumental, model):
560
  time.sleep(30)
561
 
562
  # Single status check
563
- status_result = get_task_info(task_id)
564
  yield "\n## 📊 Status Check (30s)\n\n"
565
  yield status_result
566
 
@@ -571,35 +566,30 @@ def generate_song_from_text(lyrics_text, style, title, instrumental, model):
571
  except Exception as e:
572
  yield f"❌ **Unexpected Error:** {str(e)}"
573
 
574
- # Function to download receipt for a specific song
575
- def download_song_receipt(task_id, song_index, songs_data):
576
  """
577
  Generate and return a downloadable receipt for a specific song
578
  """
579
  try:
580
- # Parse songs data if it's a string
581
- if isinstance(songs_data, str):
582
- songs_data = json.loads(songs_data)
583
-
584
- # Get the specific song
585
- if isinstance(songs_data, dict):
586
- songs = songs_data.get("sunoData", [])
587
- if not songs:
588
- songs = songs_data.get("data", [])
589
- elif isinstance(songs_data, list):
590
- songs = songs_data
591
  else:
592
- songs = []
593
 
 
594
  if 0 <= song_index - 1 < len(songs):
595
  song = songs[song_index - 1]
596
 
597
- # Generate ownership proof
598
- proof = generate_ownership_proof(
599
- task_id,
600
- song.get('title'),
601
- song.get('id')
602
- )
 
 
 
603
 
604
  # Create HTML receipt
605
  html_content = create_html_receipt(song, task_id, proof)
@@ -608,12 +598,17 @@ def download_song_receipt(task_id, song_index, songs_data):
608
  title = song.get('title', 'song').replace(' ', '_').replace('/', '_')
609
  filename = f"receipt_{title}_{task_id[:8]}.html"
610
 
611
- return html_content, filename
 
 
 
 
 
612
  else:
613
- return None, None
614
  except Exception as e:
615
  print(f"Error generating receipt: {e}")
616
- return None, None
617
 
618
  # Function to handle URL parameters
619
  def parse_url_params(request: gr.Request):
@@ -624,7 +619,6 @@ def parse_url_params(request: gr.Request):
624
  query_params = parse_qs(urlparse(request.request.url).query)
625
  if 'taskid' in query_params:
626
  task_id = query_params['taskid'][0]
627
- # Remove any whitespace
628
  task_id = task_id.strip()
629
  except Exception as e:
630
  print(f"Error parsing URL params: {e}")
@@ -636,10 +630,9 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Suno Song Generator with Receipts"
636
  gr.Markdown("# 🎵 Suno Song Generator with Anonymous Ownership Proofs")
637
  gr.Markdown("Create songs and get cryptographically signed ownership receipts")
638
 
639
- # We'll use a hidden component to track initial load
640
- initial_load_done = gr.State(value=False)
641
- # Store songs data for receipt generation
642
- current_songs_data = gr.State(value={})
643
 
644
  with gr.TabItem("Audio Link"):
645
  gr.HTML("""
@@ -656,29 +649,23 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Suno Song Generator with Receipts"
656
  <a href=" https://www.videolan.org/vlc/" target="_blank">Download VLC media player</a>
657
  <p>13 feb 2026 - Making a backup of dataset available, but made to many commits. :)</p>
658
  <a href="https://huggingface.co/datasets/MySafeCode/1hit.no-Music-Images/" target="_blank">https://huggingface.co/datasets/MySafeCode/1hit.no-Music-Images/</a>
659
-
660
  """)
661
 
662
-
663
- with gr.Tab("🎶 Generate Song", id="generate_tab") as tab_generate:
664
  with gr.Row():
665
  with gr.Column(scale=1):
666
- # Lyrics Input
667
  gr.Markdown("### Step 1: Enter Lyrics")
668
-
669
  lyrics_text = gr.Textbox(
670
  label="Lyrics",
671
- placeholder="Paste your lyrics here...\n\nExample:\n(Verse 1)\nSun is shining, sky is blue\nBirds are singing, just for you...",
672
  lines=10,
673
  interactive=True
674
  )
675
 
676
- # Song Settings
677
  gr.Markdown("### Step 2: Song Settings")
678
-
679
  style = gr.Textbox(
680
  label="Music Style",
681
- placeholder="Example: Pop, Rock, Jazz, Classical, Electronic, Hip Hop, Country",
682
  value="Folk soul flamenco glam rock goa trance fusion",
683
  interactive=True
684
  )
@@ -703,71 +690,54 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Suno Song Generator with Receipts"
703
  interactive=True
704
  )
705
 
706
- # Action Buttons
707
  generate_btn = gr.Button("🚀 Generate Song", variant="primary")
708
  clear_btn = gr.Button("🗑️ Clear All", variant="secondary")
709
 
710
- # Instructions
711
  gr.Markdown("""
712
- **How to use:**
713
- 1. Paste lyrics (or leave empty for instrumental)
714
- 2. Set music style
715
- 3. Enter song title
716
- 4. Choose model
717
- 5. Click Generate!
718
-
719
  **Ownership Proof:**
720
  - Use a **custom title** to generate a cryptographic proof
721
  - Default titles won't generate proofs
722
  - Download HTML receipt to prove ownership
723
-
724
- **Tips:**
725
- - V4_5ALL: Best overall quality
726
- - V5: Latest model
727
- - Instrumental: No vocals, just music
728
  """)
729
 
730
  with gr.Column(scale=2):
731
- # Output Area
732
  output = gr.Markdown(
733
  value="### Ready to generate!\n\nEnter lyrics and settings, then click 'Generate Song'"
734
  )
735
 
736
- with gr.Tab("🔍 Check Any Task", id="check_tab") as tab_check:
737
  with gr.Row():
738
  with gr.Column(scale=1):
739
  gr.Markdown("### Check Task Status")
740
- gr.Markdown("Enter any Suno Task ID to check its status and download receipts")
741
 
742
  check_task_id = gr.Textbox(
743
  label="Task ID",
744
- placeholder="Enter Task ID from generation or separation",
745
- info="From Song Generator or Vocal Separator"
746
  )
747
 
748
- check_btn = gr.Button("🔍 Check Status", variant="primary")
749
- check_clear_btn = gr.Button("🗑️ Clear", variant="secondary")
 
750
 
751
- # Receipt download section (hidden initially)
752
- receipt_download = gr.File(
753
- label="📥 Download Receipt",
754
- visible=False,
755
- interactive=False
 
 
756
  )
 
 
757
 
758
- # URL parameter info
759
  gr.Markdown("""
760
  **Quick access via URL:**
761
  Add `?taskid=YOUR_TASK_ID` to the URL
762
 
763
- Example:
764
- `https://1hit.no/gen/view.php?task_id=fa3529d5cbaa93427ee4451976ed5c4b`
765
-
766
  **Ownership Proof:**
767
  - Custom titles get SHA256-HMAC proofs
768
  - Proof uses Task ID as seed
769
  - Secret salt "Salt" for signing
770
- - Download HTML receipt to prove ownership
771
  """)
772
 
773
  with gr.Column(scale=2):
@@ -781,19 +751,14 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Suno Song Generator with Receipts"
781
 
782
  ### 🎶 Generate Song Tab
783
  1. **Enter Lyrics** (or leave empty for instrumental)
784
- 2. **Set Music Style** (e.g., "Pop", "Rock", "Jazz")
785
- 3. **Enter Song Title** (use a custom title for ownership proof)
786
  4. **Choose Model** (V4_5ALL recommended)
787
  5. **Click "Generate Song"**
788
 
789
  ### 🔍 Check Any Task via URL
790
  Add `?taskid=YOUR_TASK_ID` to the URL
791
 
792
- Example:
793
- ```
794
- https://1hit.no/gen/view.php?task_id=fa3529d5cbaa93427ee4451976ed5c4b
795
- ```
796
-
797
  ### 🔐 Anonymous Ownership System
798
 
799
  **How it works:**
@@ -809,53 +774,24 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Suno Song Generator with Receipts"
809
  - The proof can be verified using the same secret salt
810
  - No need to store personal data
811
  - Task ID is unique to each generation
812
-
813
- **Using receipts:**
814
- - Save the HTML receipt locally
815
- - It contains all song metadata and the proof
816
- - Can be used to claim ownership later
817
- - Verification system coming soon!
818
-
819
- ### 📞 Callback Status
820
- https://1hit.no/gen/view.php
821
-
822
- **No audio links?**
823
- - Wait 2-3 minutes
824
- - Check status again
825
- - Generation may have failed
826
  """)
827
 
828
  with gr.Tab("📚 Less Instructions", id="less_instructions_tab"):
829
  gr.Markdown("""
830
- ## 📖 How to Use This App
831
-
832
- ### 🎶 Generate Song Tab
833
- 1. **Enter Lyrics** (or leave empty for instrumental)
834
- 2. **Set Music Style** (e.g., "Pop", "Rock", "Jazz")
835
- 3. **Enter Song Title**
836
- 4. **Choose Model** (V4_5ALL recommended)
837
- 5. **Click "Generate Song"**
838
 
839
- ### 🔍 Check Any Task via URL
840
- Add `?taskid=YOUR_TASK_ID` to the URL
 
 
841
 
842
- Example:
843
- ```
844
- https://1hit.no/gen/view.php?task_id=fa3529d5cbaa93427ee4451976ed5c4b
845
- ```
846
 
847
  ### 🔐 Anonymous Ownership
848
  - Custom titles get cryptographic proofs
849
  - Download HTML receipt to prove ownership
850
  - Use Task ID as seed with secret salt "Salt"
851
-
852
- ### 📞 Callback Status
853
- https://1hit.no/gen/view.php
854
-
855
- **No audio links?**
856
- - Wait 2-3 minutes
857
- - Check status again
858
- - Generation may have failed
859
  """)
860
 
861
  gr.Markdown("---")
@@ -866,13 +802,13 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Suno Song Generator with Receipts"
866
  <a href="https://sunoapi.org" target="_blank">Suno API Docs</a></p>
867
  <p><small>Create custom songs with anonymous ownership proofs</small></p>
868
  </div>
869
- """,
870
- elem_id="footer"
871
  )
872
 
873
- # Event handlers for Generate Song tab
874
  def clear_all():
875
- return "", "Folk soul flamenco glam rock goa trance fusion", "Generated Song", False, "V4_5ALL", "### Ready to generate!\n\nEnter lyrics and settings, then click 'Generate Song'"
 
876
 
877
  clear_btn.click(
878
  clear_all,
@@ -885,21 +821,115 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Suno Song Generator with Receipts"
885
  outputs=output
886
  )
887
 
888
- # Event handlers for Check Any Task tab
889
  def clear_check():
890
- return "", "### Enter a Task ID above\n\nPaste any Suno Task ID to check its current status and results.", gr.File(visible=False)
 
891
 
892
  check_clear_btn.click(
893
  clear_check,
894
- outputs=[check_task_id, check_output, receipt_download]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
895
  )
896
 
897
- def check_and_store(task_id):
898
- """Check task and store songs data for receipt generation"""
899
- result = get_task_info(task_id)
 
900
 
901
- # Try to extract songs data for receipt generation
902
- songs_data = {}
903
  try:
904
- # Parse the result to extract songs data
905
- # This is a bit hacky - in production you'd want to parse the actual API response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  .download-link:hover {{
188
  background: #2980b9;
189
  }}
 
 
 
 
 
 
 
 
 
190
  </style>
191
  </head>
192
  <body>
 
266
  </div>
267
 
268
  <script>
 
269
  window.onload = function() {{
270
  console.log('Receipt loaded - you can print or save as PDF');
271
  }}
 
275
 
276
  return html
277
 
278
+ def extract_songs_from_response(data):
279
  """
280
+ Properly extract songs data from the API response
281
+ Returns a list of song dictionaries
282
  """
283
+ songs = []
 
 
284
 
285
+ try:
286
+ if data.get("code") == 200:
287
+ task_data = data.get("data", {})
288
+
289
+ if task_data.get("status") == "SUCCESS":
290
+ response_data = task_data.get("response", {})
291
+
292
+ # Handle different response formats
293
+ if isinstance(response_data, str):
294
+ try:
295
+ response_data = json.loads(response_data)
296
+ except:
297
+ response_data = {}
298
+
299
+ # Extract songs from various possible locations
300
+ if isinstance(response_data, dict):
301
+ # Try different possible keys where songs might be
302
+ songs = response_data.get("sunoData", [])
303
+ if not songs:
304
+ songs = response_data.get("data", [])
305
+ if not songs:
306
+ # Sometimes the response itself is a list
307
+ if isinstance(response_data.get("response"), list):
308
+ songs = response_data.get("response", [])
309
+ elif isinstance(response_data, list):
310
+ songs = response_data
311
+
312
+ # Add task_id and other metadata to each song
313
+ for song in songs:
314
+ if isinstance(song, dict):
315
+ song['taskId'] = task_data.get('taskId')
316
+ song['status'] = task_data.get('status')
317
+
318
+ return songs
319
+ except Exception as e:
320
+ print(f"Error extracting songs: {e}")
321
+ return []
322
 
323
  def get_task_info(task_id):
324
  """Manually check any Suno task status"""
325
  if not task_id:
326
+ return "❌ Please enter a Task ID", []
327
 
328
  try:
329
  resp = requests.get(
 
334
  )
335
 
336
  if resp.status_code != 200:
337
+ return f"❌ HTTP Error {resp.status_code}\n\n{resp.text}", []
338
 
339
  data = resp.json()
340
 
341
+ # Extract songs for receipt generation
342
+ songs = extract_songs_from_response(data)
343
+
344
  # Format the response for display
345
  output = f"## 🔍 Task Status: `{task_id}`\n\n"
346
 
 
354
  output += f"**Created:** {task_data.get('createTime', 'N/A')}\n"
355
 
356
  if status == "SUCCESS":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  if songs:
358
  output += f"\n## 🎵 Generated Songs ({len(songs)})\n\n"
359
 
 
370
  # Generate ownership proof if title is custom
371
  if is_custom:
372
  proof = generate_ownership_proof(task_id, title, song.get('id'))
373
+ song['_proof'] = proof # Store proof with song
374
+ output += f"**🔐 Proof Generated:** `{proof['proof'][:16]}...`\n"
375
 
376
  # Audio URLs
377
  audio_url = song.get('audioUrl') or song.get('audio_url')
 
394
  Your browser does not support audio.
395
  </audio>\n"""
396
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  output += f"**Prompt:** {song.get('prompt', 'N/A')[:100]}...\n"
398
  output += f"**Duration:** {song.get('duration', 'N/A')}s\n"
399
  output += f"**Created:** {song.get('createTime', 'N/A')}\n\n"
 
417
 
418
  # Show raw JSON for debugging
419
  output += "\n## 📋 Raw Response\n"
420
+ output += f"```json\n{json.dumps(data, indent=2)[:1000]}...\n```"
421
 
422
+ return output, songs
423
 
424
  except Exception as e:
425
+ return f"❌ Error checking task: {str(e)}", []
426
 
427
  def generate_song_from_text(lyrics_text, style, title, instrumental, model):
428
  """Generate a song from lyrics text"""
 
524
  task_id = data["taskId"]
525
  elif "data" in data and "taskId" in data["data"]:
526
  task_id = data["data"]["taskId"]
 
 
527
 
528
  if not task_id:
529
  yield f"❌ Could not extract Task ID from response"
 
555
  time.sleep(30)
556
 
557
  # Single status check
558
+ status_result, songs = get_task_info(task_id)
559
  yield "\n## 📊 Status Check (30s)\n\n"
560
  yield status_result
561
 
 
566
  except Exception as e:
567
  yield f"❌ **Unexpected Error:** {str(e)}"
568
 
569
+ def download_song_receipt(task_id, song_index, songs_json):
 
570
  """
571
  Generate and return a downloadable receipt for a specific song
572
  """
573
  try:
574
+ # Parse songs data
575
+ if isinstance(songs_json, str):
576
+ songs = json.loads(songs_json)
 
 
 
 
 
 
 
 
577
  else:
578
+ songs = songs_json
579
 
580
+ # Get the specific song
581
  if 0 <= song_index - 1 < len(songs):
582
  song = songs[song_index - 1]
583
 
584
+ # Check if we already have a proof stored
585
+ proof = song.get('_proof')
586
+ if not proof:
587
+ # Generate ownership proof
588
+ proof = generate_ownership_proof(
589
+ task_id,
590
+ song.get('title'),
591
+ song.get('id')
592
+ )
593
 
594
  # Create HTML receipt
595
  html_content = create_html_receipt(song, task_id, proof)
 
598
  title = song.get('title', 'song').replace(' ', '_').replace('/', '_')
599
  filename = f"receipt_{title}_{task_id[:8]}.html"
600
 
601
+ # Save temporarily and return path
602
+ temp_path = f"/tmp/{filename}"
603
+ with open(temp_path, 'w', encoding='utf-8') as f:
604
+ f.write(html_content)
605
+
606
+ return temp_path
607
  else:
608
+ return None
609
  except Exception as e:
610
  print(f"Error generating receipt: {e}")
611
+ return None
612
 
613
  # Function to handle URL parameters
614
  def parse_url_params(request: gr.Request):
 
619
  query_params = parse_qs(urlparse(request.request.url).query)
620
  if 'taskid' in query_params:
621
  task_id = query_params['taskid'][0]
 
622
  task_id = task_id.strip()
623
  except Exception as e:
624
  print(f"Error parsing URL params: {e}")
 
630
  gr.Markdown("# 🎵 Suno Song Generator with Anonymous Ownership Proofs")
631
  gr.Markdown("Create songs and get cryptographically signed ownership receipts")
632
 
633
+ # State to store songs data for receipt generation
634
+ current_songs = gr.State(value=[])
635
+ current_task_id = gr.State(value="")
 
636
 
637
  with gr.TabItem("Audio Link"):
638
  gr.HTML("""
 
649
  <a href=" https://www.videolan.org/vlc/" target="_blank">Download VLC media player</a>
650
  <p>13 feb 2026 - Making a backup of dataset available, but made to many commits. :)</p>
651
  <a href="https://huggingface.co/datasets/MySafeCode/1hit.no-Music-Images/" target="_blank">https://huggingface.co/datasets/MySafeCode/1hit.no-Music-Images/</a>
 
652
  """)
653
 
654
+ with gr.Tab("🎶 Generate Song", id="generate_tab"):
 
655
  with gr.Row():
656
  with gr.Column(scale=1):
 
657
  gr.Markdown("### Step 1: Enter Lyrics")
 
658
  lyrics_text = gr.Textbox(
659
  label="Lyrics",
660
+ placeholder="Paste your lyrics here...",
661
  lines=10,
662
  interactive=True
663
  )
664
 
 
665
  gr.Markdown("### Step 2: Song Settings")
 
666
  style = gr.Textbox(
667
  label="Music Style",
668
+ placeholder="Example: Pop, Rock, Jazz",
669
  value="Folk soul flamenco glam rock goa trance fusion",
670
  interactive=True
671
  )
 
690
  interactive=True
691
  )
692
 
 
693
  generate_btn = gr.Button("🚀 Generate Song", variant="primary")
694
  clear_btn = gr.Button("🗑️ Clear All", variant="secondary")
695
 
 
696
  gr.Markdown("""
 
 
 
 
 
 
 
697
  **Ownership Proof:**
698
  - Use a **custom title** to generate a cryptographic proof
699
  - Default titles won't generate proofs
700
  - Download HTML receipt to prove ownership
 
 
 
 
 
701
  """)
702
 
703
  with gr.Column(scale=2):
 
704
  output = gr.Markdown(
705
  value="### Ready to generate!\n\nEnter lyrics and settings, then click 'Generate Song'"
706
  )
707
 
708
+ with gr.Tab("🔍 Check Any Task", id="check_tab"):
709
  with gr.Row():
710
  with gr.Column(scale=1):
711
  gr.Markdown("### Check Task Status")
 
712
 
713
  check_task_id = gr.Textbox(
714
  label="Task ID",
715
+ placeholder="Enter Task ID from generation"
 
716
  )
717
 
718
+ with gr.Row():
719
+ check_btn = gr.Button("🔍 Check Status", variant="primary")
720
+ check_clear_btn = gr.Button("🗑️ Clear", variant="secondary")
721
 
722
+ # Receipt download section
723
+ gr.Markdown("### 📥 Download Receipts")
724
+ receipt_dropdown = gr.Dropdown(
725
+ label="Select Song for Receipt",
726
+ choices=[],
727
+ interactive=True,
728
+ visible=False
729
  )
730
+ download_btn = gr.Button("📥 Download Selected Receipt", variant="secondary", visible=False)
731
+ receipt_file = gr.File(label="Downloaded Receipt", visible=False)
732
 
 
733
  gr.Markdown("""
734
  **Quick access via URL:**
735
  Add `?taskid=YOUR_TASK_ID` to the URL
736
 
 
 
 
737
  **Ownership Proof:**
738
  - Custom titles get SHA256-HMAC proofs
739
  - Proof uses Task ID as seed
740
  - Secret salt "Salt" for signing
 
741
  """)
742
 
743
  with gr.Column(scale=2):
 
751
 
752
  ### 🎶 Generate Song Tab
753
  1. **Enter Lyrics** (or leave empty for instrumental)
754
+ 2. **Set Music Style**
755
+ 3. **Enter Song Title** (use custom title for ownership proof)
756
  4. **Choose Model** (V4_5ALL recommended)
757
  5. **Click "Generate Song"**
758
 
759
  ### 🔍 Check Any Task via URL
760
  Add `?taskid=YOUR_TASK_ID` to the URL
761
 
 
 
 
 
 
762
  ### 🔐 Anonymous Ownership System
763
 
764
  **How it works:**
 
774
  - The proof can be verified using the same secret salt
775
  - No need to store personal data
776
  - Task ID is unique to each generation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
777
  """)
778
 
779
  with gr.Tab("📚 Less Instructions", id="less_instructions_tab"):
780
  gr.Markdown("""
781
+ ## 📖 Quick Guide
 
 
 
 
 
 
 
782
 
783
+ ### 🎶 Generate Song
784
+ 1. Enter lyrics
785
+ 2. Set style & title
786
+ 3. Click Generate
787
 
788
+ ### 🔍 Check Task
789
+ Add `?taskid=YOUR_TASK_ID` to URL
 
 
790
 
791
  ### 🔐 Anonymous Ownership
792
  - Custom titles get cryptographic proofs
793
  - Download HTML receipt to prove ownership
794
  - Use Task ID as seed with secret salt "Salt"
 
 
 
 
 
 
 
 
795
  """)
796
 
797
  gr.Markdown("---")
 
802
  <a href="https://sunoapi.org" target="_blank">Suno API Docs</a></p>
803
  <p><small>Create custom songs with anonymous ownership proofs</small></p>
804
  </div>
805
+ """
 
806
  )
807
 
808
+ # Event handlers
809
  def clear_all():
810
+ return ("", "Folk soul flamenco glam rock goa trance fusion", "Generated Song",
811
+ False, "V4_5ALL", "### Ready to generate!\n\nEnter lyrics and settings, then click 'Generate Song'")
812
 
813
  clear_btn.click(
814
  clear_all,
 
821
  outputs=output
822
  )
823
 
 
824
  def clear_check():
825
+ return ("", "### Enter a Task ID above\n\nPaste any Suno Task ID to check its current status and results.",
826
+ [], "", gr.Dropdown(choices=[], visible=False), gr.Button(visible=False), gr.File(visible=False))
827
 
828
  check_clear_btn.click(
829
  clear_check,
830
+ outputs=[check_task_id, check_output, current_songs, current_task_id,
831
+ receipt_dropdown, download_btn, receipt_file]
832
+ )
833
+
834
+ def check_and_update(task_id):
835
+ """Check task and update UI with receipt options"""
836
+ if not task_id:
837
+ return ("Please enter a Task ID", [], "",
838
+ gr.Dropdown(choices=[], visible=False), gr.Button(visible=False), gr.File(visible=False))
839
+
840
+ result, songs = get_task_info(task_id)
841
+
842
+ # Update dropdown with songs that have custom titles
843
+ receipt_choices = []
844
+ for i, song in enumerate(songs, 1):
845
+ if song.get('title') not in ["Generated Song", "Untitled"]:
846
+ receipt_choices.append(f"{i}. {song.get('title', 'Untitled')}")
847
+
848
+ show_receipt_section = len(receipt_choices) > 0
849
+
850
+ return (result, songs, task_id,
851
+ gr.Dropdown(choices=receipt_choices, visible=show_receipt_section),
852
+ gr.Button(visible=show_receipt_section),
853
+ gr.File(visible=False))
854
+
855
+ check_btn.click(
856
+ check_and_update,
857
+ inputs=[check_task_id],
858
+ outputs=[check_output, current_songs, current_task_id,
859
+ receipt_dropdown, download_btn, receipt_file]
860
  )
861
 
862
+ def download_selected_receipt(task_id, selection, songs):
863
+ """Download receipt for selected song"""
864
+ if not selection or not songs:
865
+ return None
866
 
 
 
867
  try:
868
+ # Extract song index from selection
869
+ song_index = int(selection.split('.')[0])
870
+ receipt_path = download_song_receipt(task_id, song_index, songs)
871
+ return receipt_path
872
+ except Exception as e:
873
+ print(f"Error in download: {e}")
874
+ return None
875
+
876
+ download_btn.click(
877
+ download_selected_receipt,
878
+ inputs=[current_task_id, receipt_dropdown, current_songs],
879
+ outputs=[receipt_file]
880
+ )
881
+
882
+ # Handle URL parameters on load
883
+ def on_page_load(request: gr.Request):
884
+ task_id = parse_url_params(request)
885
+
886
+ if task_id:
887
+ result, songs = get_task_info(task_id)
888
+
889
+ # Update dropdown with songs that have custom titles
890
+ receipt_choices = []
891
+ for i, song in enumerate(songs, 1):
892
+ if song.get('title') not in ["Generated Song", "Untitled"]:
893
+ receipt_choices.append(f"{i}. {song.get('title', 'Untitled')}")
894
+
895
+ show_receipt_section = len(receipt_choices) > 0
896
+
897
+ return (
898
+ task_id, # check_task_id
899
+ result, # check_output
900
+ songs, # current_songs
901
+ task_id, # current_task_id
902
+ gr.Tabs(selected="check_tab"), # Switch to check tab
903
+ gr.Dropdown(choices=receipt_choices, visible=show_receipt_section),
904
+ gr.Button(visible=show_receipt_section),
905
+ gr.File(visible=False)
906
+ )
907
+ else:
908
+ return (
909
+ "", # check_task_id
910
+ "### Enter a Task ID above\n\nPaste any Suno Task ID to check its current status and results.",
911
+ [], # current_songs
912
+ "", # current_task_id
913
+ gr.Tabs(selected="generate_tab"),
914
+ gr.Dropdown(choices=[], visible=False),
915
+ gr.Button(visible=False),
916
+ gr.File(visible=False)
917
+ )
918
+
919
+ app.load(
920
+ fn=on_page_load,
921
+ inputs=[],
922
+ outputs=[check_task_id, check_output, current_songs, current_task_id,
923
+ gr.Tabs(), receipt_dropdown, download_btn, receipt_file],
924
+ queue=False
925
+ )
926
+
927
+ # Launch the app
928
+ if __name__ == "__main__":
929
+ print("🚀 Starting Suno Song Generator with Anonymous Ownership Proofs")
930
+ print(f"🔑 SunoKey: {'✅ Set' if SUNO_KEY else '❌ Not set'}")
931
+ print(f"🔐 Secret Salt: {'✅ Configured' if SECRET_SALT else '❌ Not set'}")
932
+ print("🌐 Open your browser to: http://localhost:7860")
933
+ print("🔗 Use URL parameter: http://localhost:7860?taskid=YOUR_TASK_ID")
934
+
935
+ app.launch(server_name="0.0.0.0", server_port=7860, share=False)