Phoenixak99 commited on
Commit
89e7597
Β·
verified Β·
1 Parent(s): 65b9319

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -384
app.py CHANGED
@@ -27,7 +27,6 @@ from wordpress_xmlrpc.methods import media
27
  import smtplib
28
  from email.mime.text import MIMEText
29
  from email.mime.multipart import MIMEMultipart
30
- import math
31
 
32
  # Add enhanced CSS to block download buttons in audio players
33
  st.markdown("""
@@ -397,7 +396,7 @@ def show_sidebar():
397
  # Format for premium users - CORRECTED LIMITS PER TIER
398
  daily_limit = 0
399
  download_limit = 0
400
- duration_limit = 300
401
 
402
  plan_id = subscription_status.get('subscription_plan_id')
403
  if isinstance(plan_id, int):
@@ -1328,258 +1327,7 @@ def load_and_play_generated_audio(response, genre=None, energy_level=None, tempo
1328
  st.error(f"Failed to process generated audio: {e}")
1329
  return None, None
1330
 
1331
- def generate_long_audio_chunked(genre, energy_level, tempo, description, total_duration):
1332
- """
1333
- Generate long audio by making multiple sequential API calls and stitching the results
1334
- with improved error handling and robustness for different audio formats
1335
- """
1336
- # Maximum duration for a single request that works reliably
1337
- max_chunk_duration = 120 # Based on your working threshold
1338
-
1339
- # Calculate how many chunks we need
1340
- num_chunks = math.ceil(total_duration / max_chunk_duration)
1341
-
1342
- # Prepare to collect audio pieces
1343
- audio_chunks = []
1344
- sample_rate = None
1345
-
1346
- # Process each chunk
1347
- overall_progress = st.progress(0)
1348
- status_text = st.empty()
1349
-
1350
- try:
1351
- for i in range(num_chunks):
1352
- # Calculate duration for this chunk
1353
- chunk_duration = min(max_chunk_duration, total_duration - (i * max_chunk_duration))
1354
-
1355
- # Update the description for continuity
1356
- chunk_description = description
1357
- if i > 0:
1358
- chunk_description += f" (continuation part {i+1})"
1359
-
1360
- # Update status
1361
- status_text.markdown(f"🎡 **Generating part {i+1} of {num_chunks}** ({chunk_duration}s)...")
1362
-
1363
- # Prepare and send the request
1364
- prompt = f"Genre: {genre}, Energy Level: {energy_level}, Tempo: {tempo}, Description: {chunk_description}"
1365
- payload = {"inputs": {"prompt": prompt, "duration": chunk_duration}}
1366
- api_headers = get_api_headers()
1367
-
1368
- # Make the request with appropriate timeout
1369
- response = time_post_request(
1370
- API_URL,
1371
- headers=api_headers,
1372
- payload=payload,
1373
- timeout=1200 # Match the endpoint timeout
1374
- )
1375
-
1376
- if not response or response.status_code != 200:
1377
- error_code = response.status_code if response else "No response"
1378
- status_text.error(f"❌ Error generating part {i+1}: HTTP {error_code}")
1379
- return None, None
1380
-
1381
- # Parse the response
1382
- try:
1383
- response_data = json.loads(response.content)
1384
-
1385
- # Check for error in response
1386
- if isinstance(response_data, dict) and 'error' in response_data:
1387
- status_text.error(f"❌ API error in part {i+1}: {response_data['error']}")
1388
- return None, None
1389
-
1390
- # Extract audio data from first item in the list
1391
- if isinstance(response_data, list) and len(response_data) > 0:
1392
- chunk_data = response_data[0]
1393
-
1394
- # Extract audio data
1395
- if "generated_audio" in chunk_data:
1396
- chunk_audio = np.array(chunk_data["generated_audio"])
1397
-
1398
- # Log shape for debugging
1399
- print(f"Chunk {i+1} audio shape: {chunk_audio.shape}")
1400
-
1401
- # Check for inconsistent shapes
1402
- if len(audio_chunks) > 0:
1403
- existing_shape = audio_chunks[0].shape
1404
- if len(existing_shape) != len(chunk_audio.shape):
1405
- print(f"WARNING: Shape mismatch between chunks. Existing: {existing_shape}, New: {chunk_audio.shape}")
1406
-
1407
- # Store sample rate from first chunk
1408
- if sample_rate is None and "sample_rate" in chunk_data:
1409
- sample_rate = chunk_data["sample_rate"]
1410
- print(f"Using sample rate: {sample_rate}")
1411
-
1412
- # Add to our collection
1413
- audio_chunks.append(chunk_audio)
1414
- else:
1415
- raise ValueError(f"No 'generated_audio' found in chunk {i+1}")
1416
- else:
1417
- raise ValueError(f"Unexpected response format for chunk {i+1}")
1418
-
1419
- # Update progress
1420
- overall_progress.progress((i + 1) / num_chunks)
1421
-
1422
- except Exception as e:
1423
- import traceback
1424
- print(f"Error processing chunk {i+1}:")
1425
- print(traceback.format_exc())
1426
- status_text.error(f"❌ Error processing response for part {i+1}: {str(e)}")
1427
- return None, None
1428
-
1429
- # Handle the case when we couldn't get any valid chunks
1430
- if not audio_chunks:
1431
- status_text.error("❌ No valid audio chunks were generated.")
1432
- return None, None
1433
-
1434
- # Check if we at least have a sample rate
1435
- if sample_rate is None:
1436
- sample_rate = 44100 # Default to standard sample rate if not provided
1437
- print("WARNING: No sample rate provided, using default 44100 Hz")
1438
-
1439
- # Combine audio chunks with crossfading
1440
- status_text.markdown("πŸ”„ Stitching audio chunks together...")
1441
- try:
1442
- # First check if we only have one chunk (no stitching needed)
1443
- if len(audio_chunks) == 1:
1444
- final_audio = audio_chunks[0]
1445
- else:
1446
- final_audio = combine_audio_with_crossfade(audio_chunks, sample_rate)
1447
-
1448
- # Final check for valid audio
1449
- if final_audio is None or final_audio.size == 0:
1450
- status_text.error("❌ Failed to create valid audio output.")
1451
- return None, None
1452
-
1453
- status_text.success("βœ… Full audio track generated successfully!")
1454
- overall_progress.progress(1.0)
1455
-
1456
- return final_audio, sample_rate
1457
-
1458
- except Exception as e:
1459
- import traceback
1460
- print(f"Error combining audio chunks:")
1461
- print(traceback.format_exc())
1462
- status_text.error(f"❌ Error combining audio chunks: {str(e)}")
1463
- return None, None
1464
-
1465
- except Exception as e:
1466
- import traceback
1467
- print(f"Unexpected error in generation process:")
1468
- print(traceback.format_exc())
1469
- status_text.error(f"❌ Unexpected error in generation process: {str(e)}")
1470
- return None, None
1471
 
1472
-
1473
- def combine_audio_with_crossfade(audio_chunks, sample_rate, crossfade_duration=2.0):
1474
- """
1475
- Combine multiple audio chunks with crossfading between them with improved
1476
- robustness for handling different array shapes and potential edge cases.
1477
-
1478
- Parameters:
1479
- audio_chunks: List of numpy arrays containing audio data
1480
- sample_rate: Sample rate of the audio
1481
- crossfade_duration: Crossfade duration in seconds
1482
-
1483
- Returns:
1484
- numpy.ndarray: Combined audio with crossfading
1485
- """
1486
- if not audio_chunks:
1487
- return None
1488
-
1489
- if len(audio_chunks) == 1:
1490
- return audio_chunks[0]
1491
-
1492
- # Print debugging info about chunks
1493
- print(f"Combining {len(audio_chunks)} audio chunks")
1494
- for i, chunk in enumerate(audio_chunks):
1495
- print(f"Chunk {i} shape: {chunk.shape}")
1496
-
1497
- # Calculate crossfade samples
1498
- crossfade_samples = int(crossfade_duration * sample_rate)
1499
- print(f"Crossfade samples: {crossfade_samples}")
1500
-
1501
- # Function to ensure consistent array dimensions
1502
- def normalize_audio_shape(audio):
1503
- """Make sure audio is 2D with shape (channels, samples)"""
1504
- if audio is None or audio.size == 0:
1505
- return np.zeros((1, 0)) # Return empty mono audio
1506
-
1507
- # Convert to 2D if needed
1508
- if audio.ndim == 1:
1509
- return audio.reshape(1, -1) # Convert mono to shape (1, samples)
1510
- elif audio.ndim == 2:
1511
- # If shape is (samples, channels), transpose to (channels, samples)
1512
- if audio.shape[0] > 2 and (audio.shape[1] == 1 or audio.shape[1] == 2):
1513
- return audio.T
1514
- return audio
1515
- else:
1516
- # Unexpected shape - flatten to mono
1517
- print(f"WARNING: Unexpected audio shape {audio.shape}, flattening to mono")
1518
- flattened = audio.flatten()
1519
- return flattened.reshape(1, -1)
1520
-
1521
- # Normalize all chunks to ensure consistent shapes
1522
- normalized_chunks = [normalize_audio_shape(chunk) for chunk in audio_chunks]
1523
-
1524
- # Initialize with first chunk
1525
- combined_audio = normalized_chunks[0]
1526
-
1527
- # Add each subsequent chunk with crossfading
1528
- for i, next_chunk in enumerate(normalized_chunks[1:], 1):
1529
- print(f"Combining chunk {i} with combined audio")
1530
- print(f"Combined audio shape: {combined_audio.shape}, next chunk shape: {next_chunk.shape}")
1531
-
1532
- # Ensure both audio chunks have the same number of channels
1533
- if combined_audio.shape[0] != next_chunk.shape[0]:
1534
- # Handle different channel counts by converting to mono if needed
1535
- channels_to_use = min(combined_audio.shape[0], next_chunk.shape[0])
1536
- if channels_to_use == 1:
1537
- # Convert both to mono
1538
- if combined_audio.shape[0] > 1:
1539
- combined_audio = np.mean(combined_audio, axis=0, keepdims=True)
1540
- if next_chunk.shape[0] > 1:
1541
- next_chunk = np.mean(next_chunk, axis=0, keepdims=True)
1542
- else:
1543
- # Use only the first channel from each
1544
- combined_audio = combined_audio[:channels_to_use]
1545
- next_chunk = next_chunk[:channels_to_use]
1546
-
1547
- # Check if we have enough samples for crossfading
1548
- if (combined_audio.shape[1] >= crossfade_samples and
1549
- next_chunk.shape[1] >= crossfade_samples):
1550
-
1551
- # Create fade curves
1552
- fade_out = np.linspace(1, 0, crossfade_samples)
1553
- fade_in = np.linspace(0, 1, crossfade_samples)
1554
-
1555
- # Create temporary copies to avoid modifying originals
1556
- combined_end = combined_audio[:, -crossfade_samples:].copy()
1557
- next_start = next_chunk[:, :crossfade_samples].copy()
1558
-
1559
- # Apply crossfade
1560
- for channel in range(combined_audio.shape[0]):
1561
- combined_end[channel] *= fade_out
1562
- next_start[channel] *= fade_in
1563
-
1564
- # Overlap and add
1565
- overlap_region = combined_end + next_start
1566
-
1567
- # Concatenate
1568
- combined_audio = np.concatenate([
1569
- combined_audio[:, :-crossfade_samples],
1570
- overlap_region,
1571
- next_chunk[:, crossfade_samples:]
1572
- ], axis=1)
1573
- else:
1574
- # Not enough samples for crossfade, just concatenate
1575
- print("WARNING: Not enough samples for crossfade, simple concatenation used")
1576
- combined_audio = np.concatenate([combined_audio, next_chunk], axis=1)
1577
-
1578
- print(f"Final combined audio shape: {combined_audio.shape}")
1579
- return combined_audio
1580
-
1581
-
1582
- # Modify your existing generate_audio function to use chunking for long durations
1583
  def generate_audio(genre, energy_level, tempo, description, duration):
1584
  # Create placeholders
1585
  status_placeholder = st.empty()
@@ -1620,7 +1368,12 @@ def generate_audio(genre, energy_level, tempo, description, duration):
1620
  if is_free_tier:
1621
  if duration > 30:
1622
  st.warning("⚠️ Free tier users are limited to 30-second generations.")
1623
- st.info("πŸ’‘ Upgrade to a premium plan to generate longer tracks!")
 
 
 
 
 
1624
  duration = 30 # Force duration to 30 seconds for free tier
1625
 
1626
  # Check if server is cold
@@ -1629,7 +1382,8 @@ def generate_audio(genre, energy_level, tempo, description, duration):
1629
  "πŸ”„ **Server is currently starting up.**\n\n"
1630
  "Our AI model needs some time to load and prepare when the server has been inactive.\n"
1631
  "This can take up to **7 minutes** for free users.\n\n"
1632
- "πŸ’‘ **Upgrade to a premium plan to reduce or eliminate wait times!**"
 
1633
  )
1634
 
1635
  # Wait for server to warm up with progress display
@@ -1643,154 +1397,78 @@ def generate_audio(genre, energy_level, tempo, description, duration):
1643
  if not server_ready:
1644
  st.error(
1645
  "❌ Server initialization timed out.\n\n"
1646
- "Consider upgrading to premium for reliable, fast access."
 
1647
  )
1648
  return None
1649
 
1650
  # Clear warmup messages
1651
  for placeholder in [status_placeholder, progress_placeholder, subscription_placeholder, stage_placeholder]:
1652
  placeholder.empty()
1653
-
1654
- # IMPORTANT: Choose between normal and chunked generation based on duration
1655
- if duration <= 120: # For shorter durations that work reliably
1656
- # Prepare standard generation request
1657
- prompt = f"Genre: {genre}, Energy Level: {energy_level}, Tempo: {tempo}, Description: {description}"
1658
- payload = {"inputs": {"prompt": prompt, "duration": duration}}
1659
- api_headers = get_api_headers()
1660
-
1661
- # Make the generation request
1662
- with st.spinner("🎡 Generating your music... This may take a few moments."):
1663
- response = time_post_request(API_URL, headers=api_headers, payload=payload, timeout=1200)
1664
 
1665
- if response and response.status_code == 200:
1666
- # Check for error in response before showing success message
1667
- try:
1668
- response_data = json.loads(response.content)
1669
- if 'error' in response_data:
1670
- error_msg = response_data['error']
1671
- if 'CUDA error' in error_msg:
1672
- st.error("❌ The AI server is currently experiencing GPU resource issues.")
1673
- st.info("Please try again in a few minutes. This is a temporary server issue.")
1674
- return None
1675
- else:
1676
- st.error(f"❌ Server error: {error_msg}")
1677
- return None
1678
-
1679
- # If we get here, response is valid
1680
- st.success("✨ Music generated successfully!")
1681
- except Exception as parse_error:
1682
- print(f"Error parsing response to check for errors: {parse_error}")
1683
- st.success("✨ Music generated successfully!")
1684
-
1685
- # Load and play the generated audio
1686
- result = load_and_play_generated_audio(
1687
- response=response,
1688
- genre=genre,
1689
- energy_level=energy_level,
1690
- tempo=tempo,
1691
- description=description,
1692
- duration=duration
1693
- )
1694
-
1695
- # Only update count if audio was successfully generated
1696
- if result[0] is not None:
1697
- update_generation_url = "https://songlabai.com/wp-json/custom-api/v1/update-generation-count"
1698
- requests.post(update_generation_url, headers=auth_headers)
1699
-
1700
- return response # Return the response for future use
1701
- else:
1702
- error_code = response.status_code if response else "No response"
1703
- st.error(f"❌ Failed to generate audio (Error {error_code}).")
1704
- return None
1705
 
1706
- else:
1707
- # For longer durations, use the chunked approach
1708
- st.info("πŸ’‘ Generating a longer track in multiple parts. This may take several minutes.")
1709
-
1710
- # Generate audio in chunks and stitch together
1711
- audio_array, sample_rate = generate_long_audio_chunked(
1712
- genre, energy_level, tempo, description, duration
1713
- )
1714
 
1715
- if audio_array is not None and sample_rate is not None:
1716
- # Convert the audio to a format that can be played
1717
- with st.spinner("πŸ”„ Processing final audio..."):
1718
- # Convert numpy array to bytes with careful handling of array shape
1719
- audio_buffer = BytesIO()
1720
-
1721
- # The critical fix: transpose the array if needed
1722
- # SoundFile expects shape (samples, channels) but our array is (channels, samples)
1723
- if audio_array.ndim == 2 and audio_array.shape[0] <= 2:
1724
- # This is the key fix - transpose from (channels, samples) to (samples, channels)
1725
- print(f"Transposing audio array from shape {audio_array.shape}")
1726
- audio_array_to_save = audio_array.T
1727
- else:
1728
- audio_array_to_save = audio_array
1729
-
1730
- # Ensure it's the right data type
1731
- if audio_array_to_save.dtype != np.float32:
1732
- audio_array_to_save = audio_array_to_save.astype(np.float32)
1733
-
1734
- print(f"Writing audio with shape {audio_array_to_save.shape} to WAV file")
1735
- sf.write(audio_buffer, audio_array_to_save, sample_rate, format='WAV', subtype='PCM_16')
1736
- audio_buffer.seek(0)
1737
-
1738
- # Convert to AudioSegment for compatibility with your existing code
1739
- try:
1740
- audio_segment = AudioSegment.from_file(audio_buffer, format="wav")
1741
- except Exception as e:
1742
- print(f"Error converting to AudioSegment: {e}")
1743
- # Alternative approach if the first method fails
1744
- audio_buffer.seek(0)
1745
- with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_file:
1746
- temp_filename = temp_file.name
1747
- temp_file.write(audio_buffer.read())
1748
-
1749
- # Now load from the temporary file
1750
- audio_segment = AudioSegment.from_file(temp_filename, format="wav")
1751
- # Clean up temp file
1752
- os.unlink(temp_filename)
1753
-
1754
- # Store in session state (matching your existing patterns)
1755
- st_state.audio_pydub = audio_segment
1756
- st_state.audio_sample_rate = sample_rate
1757
- st_state.augmented_audio_pydub = audio_segment
1758
- st_state.augmented_audio_sample_rate = sample_rate
1759
-
1760
- # Set bytes for player
1761
- audio_buffer.seek(0)
1762
- st.session_state.audio_bytes = audio_buffer.getvalue()
1763
- st.session_state.playing_state = 'generated'
1764
 
1765
- # Store metadata
1766
- st.session_state.audio_metadata = {
1767
- 'genre': genre,
1768
- 'energy_level': energy_level,
1769
- 'tempo': tempo,
1770
- 'description': description,
1771
- 'duration': duration,
1772
- 'generated_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1773
- }
1774
 
1775
- # Display the audio
1776
- st.success("✨ Long music track generated successfully!")
1777
- display_audio_player(is_final=False)
 
 
 
 
 
 
1778
 
1779
- # Update generation count on WordPress
1780
- update_generation_url = "https://songlabai.com/wp-json/custom-api/v1/update-generation-count"
1781
- requests.post(update_generation_url, headers=auth_headers)
 
 
1782
 
1783
- return True
1784
  else:
1785
- st.error("❌ Failed to generate the complete audio track.")
 
 
 
 
 
 
1786
  return None
1787
-
1788
  except Exception as e:
1789
  import traceback
1790
  print(f"Detailed error in generate_audio: {traceback.format_exc()}")
1791
  st.error(f"An unexpected error occurred: {e}")
1792
  return None
1793
-
1794
  def update_generate_button(genre, energy_level, tempo, description, duration):
1795
  """Create or update the generate button based on current state"""
1796
  generate_btn_col, login_prompt_col = st.columns([1, 2])
@@ -1934,7 +1612,7 @@ with duration_col:
1934
  duration = st.slider(
1935
  "Duration (in seconds):",
1936
  min_value=15,
1937
- max_value=300,
1938
  value=30,
1939
  step=1
1940
  )
 
27
  import smtplib
28
  from email.mime.text import MIMEText
29
  from email.mime.multipart import MIMEMultipart
 
30
 
31
  # Add enhanced CSS to block download buttons in audio players
32
  st.markdown("""
 
396
  # Format for premium users - CORRECTED LIMITS PER TIER
397
  daily_limit = 0
398
  download_limit = 0
399
+ duration_limit = 140
400
 
401
  plan_id = subscription_status.get('subscription_plan_id')
402
  if isinstance(plan_id, int):
 
1327
  st.error(f"Failed to process generated audio: {e}")
1328
  return None, None
1329
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1330
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1331
  def generate_audio(genre, energy_level, tempo, description, duration):
1332
  # Create placeholders
1333
  status_placeholder = st.empty()
 
1368
  if is_free_tier:
1369
  if duration > 30:
1370
  st.warning("⚠️ Free tier users are limited to 30-second generations.")
1371
+ st.info("πŸ’‘ Upgrade to a premium plan to generate longer tracks!\n\n" +
1372
+ "**Available Plans:**\n" +
1373
+ "- **$24.99/month:** Up to 3 generations per day, 1 download per month\n" +
1374
+ "- **$99.99/month:** Up to 5 generations per day, 5 downloads per month\n" +
1375
+ "- **$269.97/month:** Up to 20 generations per day, 15 downloads per month\n\n" +
1376
+ "πŸ‘‰ [Upgrade Now](https://songlabai.com/subscribe/)")
1377
  duration = 30 # Force duration to 30 seconds for free tier
1378
 
1379
  # Check if server is cold
 
1382
  "πŸ”„ **Server is currently starting up.**\n\n"
1383
  "Our AI model needs some time to load and prepare when the server has been inactive.\n"
1384
  "This can take up to **7 minutes** for free users.\n\n"
1385
+ "πŸ’‘ **Upgrade to a premium plan to reduce or eliminate wait times!**\n"
1386
+ "πŸ‘‰ [Upgrade Now](https://songlabai.com/subscribe/)"
1387
  )
1388
 
1389
  # Wait for server to warm up with progress display
 
1397
  if not server_ready:
1398
  st.error(
1399
  "❌ Server initialization timed out.\n\n"
1400
+ "Consider upgrading to premium for reliable, fast access.\n\n"
1401
+ "πŸ‘‰ [Upgrade Now](https://songlabai.com/subscribe/)"
1402
  )
1403
  return None
1404
 
1405
  # Clear warmup messages
1406
  for placeholder in [status_placeholder, progress_placeholder, subscription_placeholder, stage_placeholder]:
1407
  placeholder.empty()
 
 
 
 
 
 
 
 
 
 
 
1408
 
1409
+ # Prepare generation request
1410
+ prompt = f"Genre: {genre}, Energy Level: {energy_level}, Tempo: {tempo}, Description: {description}"
1411
+ payload = {"inputs": {"prompt": prompt, "duration": duration}}
1412
+ api_headers = get_api_headers()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1413
 
1414
+ # Make the generation request
1415
+ with st.spinner("🎡 Generating your music... This may take a few moments."):
1416
+ response = time_post_request(API_URL, headers=api_headers, payload=payload, timeout=1200)
 
 
 
 
 
1417
 
1418
+ if response and response.status_code == 200:
1419
+ # Check for error in response before showing success message
1420
+ try:
1421
+ response_data = json.loads(response.content)
1422
+ if 'error' in response_data:
1423
+ error_msg = response_data['error']
1424
+ if 'CUDA error' in error_msg:
1425
+ st.error("❌ The AI server is currently experiencing GPU resource issues.")
1426
+ st.info("Please try again in a few minutes. This is a temporary server issue.")
1427
+ print(f"CUDA error from server: {error_msg}")
1428
+ return None
1429
+ else:
1430
+ st.error(f"❌ Server error: {error_msg}")
1431
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1432
 
1433
+ # If we get here, response is valid
1434
+ st.success("✨ Music generated successfully!")
1435
+ except Exception as parse_error:
1436
+ print(f"Error parsing response to check for errors: {parse_error}")
1437
+ # Continue with normal flow - will be caught in load_and_play if there's an issue
1438
+ st.success("✨ Music generated successfully!")
 
 
 
1439
 
1440
+ # Load and play the generated audio
1441
+ result = load_and_play_generated_audio(
1442
+ response=response,
1443
+ genre=genre,
1444
+ energy_level=energy_level,
1445
+ tempo=tempo,
1446
+ description=description,
1447
+ duration=duration
1448
+ )
1449
 
1450
+ # Only update count if audio was successfully generated
1451
+ if result[0] is not None:
1452
+ # Update generation count on WordPress
1453
+ update_generation_url = "https://songlabai.com/wp-json/custom-api/v1/update-generation-count"
1454
+ requests.post(update_generation_url, headers=auth_headers)
1455
 
1456
+ return response # Return the response for future use
1457
  else:
1458
+ error_code = response.status_code if response else "No response"
1459
+ st.error(
1460
+ f"❌ Failed to generate audio (Error {error_code}).\n\n"
1461
+ "This might be due to high server load or an error.\n\n"
1462
+ "πŸ’‘ **Tip:** Premium users experience fewer failures and faster generation times.\n\n"
1463
+ "πŸ‘‰ [Upgrade Now](https://songlabai.com/subscribe/)"
1464
+ )
1465
  return None
 
1466
  except Exception as e:
1467
  import traceback
1468
  print(f"Detailed error in generate_audio: {traceback.format_exc()}")
1469
  st.error(f"An unexpected error occurred: {e}")
1470
  return None
1471
+
1472
  def update_generate_button(genre, energy_level, tempo, description, duration):
1473
  """Create or update the generate button based on current state"""
1474
  generate_btn_col, login_prompt_col = st.columns([1, 2])
 
1612
  duration = st.slider(
1613
  "Duration (in seconds):",
1614
  min_value=15,
1615
+ max_value=140,
1616
  value=30,
1617
  step=1
1618
  )