File size: 32,826 Bytes
2989e11
 
805f5c6
2989e11
 
c3107e0
2989e11
 
a91333d
450d5fc
01d0dbc
bec0470
af04993
805f5c6
2989e11
805f5c6
 
2989e11
805f5c6
c3107e0
 
2989e11
805f5c6
721d5e4
805f5c6
dad2736
68aa84c
 
 
171d2b4
8b63294
9b76954
 
 
 
5d46dc9
 
171d2b4
 
9b76954
 
 
e3fb9f1
 
5d46dc9
9b76954
 
 
171d2b4
 
5d46dc9
 
 
9b76954
 
5d46dc9
 
 
 
 
171d2b4
7e28919
 
 
 
 
 
 
 
 
9b76954
 
 
 
 
 
 
00d8745
9b76954
 
 
 
 
 
 
 
 
 
 
 
 
16022dc
9b76954
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e28919
 
 
 
9b76954
171d2b4
 
9b76954
 
171d2b4
 
9b76954
 
 
 
 
 
 
 
 
 
 
171d2b4
9b76954
 
 
 
 
 
171d2b4
e3fb9f1
 
 
 
 
b72b061
171d2b4
9b76954
59f9d0d
 
 
1762a38
 
 
 
 
59f9d0d
1762a38
 
 
 
 
171d2b4
9b76954
 
 
 
 
c3107e0
171d2b4
9b76954
 
 
 
 
c3107e0
9b76954
 
 
 
 
 
c3107e0
9b76954
 
 
 
 
 
c3107e0
171d2b4
9b76954
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9861c54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68d3b7b
f18d4f5
 
 
68d3b7b
f18d4f5
68d3b7b
 
 
 
 
 
9861c54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171d2b4
 
9b76954
 
 
c3107e0
9b76954
 
c3107e0
9b76954
 
 
 
 
c3107e0
9b76954
 
c3107e0
9b76954
 
 
 
933315b
9b76954
933315b
9b76954
933315b
9b76954
 
 
 
 
933315b
9b76954
 
 
c065bd7
9b76954
 
 
 
 
 
 
 
933315b
8f377cf
 
 
 
 
 
 
 
 
 
 
 
 
db13ff9
8f377cf
ee6015c
8f377cf
 
d560989
8f377cf
 
 
 
 
db13ff9
 
 
 
9861c54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
01d0dbc
 
9861c54
db13ff9
 
1a4b8ed
8f377cf
1a4b8ed
ee6015c
8f377cf
 
1a4b8ed
 
 
 
8f377cf
1a4b8ed
 
8f377cf
1a4b8ed
 
 
8f377cf
1a4b8ed
 
8f377cf
 
1a4b8ed
d560989
 
ee6015c
1a4b8ed
db13ff9
8f377cf
ee6015c
 
 
8f377cf
ee6015c
8f377cf
 
1a4b8ed
01d0dbc
8f377cf
171d2b4
ee6015c
8f377cf
 
 
 
 
 
 
 
 
 
 
68aa84c
d560989
8f377cf
 
 
 
 
 
 
68aa84c
d560989
8f377cf
75710eb
 
68d3b7b
9861c54
 
 
 
 
 
 
 
 
 
d560989
8f377cf
 
 
ee6015c
d560989
 
 
ee6015c
8f377cf
d560989
8f377cf
 
 
 
 
 
 
d560989
8f377cf
 
 
 
d560989
8f377cf
68aa84c
d560989
8f377cf
 
 
d560989
8f377cf
 
 
 
 
 
ee6015c
8f377cf
 
 
 
68aa84c
 
 
 
 
 
 
 
 
8f377cf
 
 
 
68aa84c
 
8f377cf
 
 
ee6015c
d560989
 
01d0dbc
68aa84c
8f377cf
ee6015c
68aa84c
171d2b4
9b76954
 
 
 
933315b
9b76954
 
b72b061
9b76954
 
 
 
 
 
 
 
68aa84c
ffcfc6d
68aa84c
ffcfc6d
68aa84c
 
ffcfc6d
 
70a9952
 
 
 
 
65168b2
2f90f4f
65168b2
 
 
70a9952
ffcfc6d
 
 
70a9952
 
ffcfc6d
68aa84c
2f90f4f
 
 
 
65168b2
ffcfc6d
65168b2
 
 
2f90f4f
65168b2
 
2f90f4f
 
 
 
 
 
 
68aa84c
ffcfc6d
 
65168b2
ffcfc6d
2f90f4f
65168b2
ffcfc6d
68aa84c
ffcfc6d
2f90f4f
 
65168b2
2f90f4f
ffcfc6d
9b76954
 
015f0c6
9b76954
 
 
 
 
171d2b4
68aa84c
 
163c092
 
9b76954
9b7c8ee
9b76954
9b7c8ee
 
 
 
 
 
 
163c092
 
 
 
 
 
 
 
 
68aa84c
163c092
 
 
9b7c8ee
 
9b76954
 
9b7c8ee
163c092
 
9b7c8ee
7e28919
 
 
68aa84c
 
 
 
 
 
 
 
 
ffcfc6d
 
 
68aa84c
7e28919
 
 
9b76954
7e28919
 
9b7c8ee
9b76954
 
 
 
 
933315b
9534dd6
c3107e0
02b2822
 
 
 
 
 
 
 
 
 
 
 
171d2b4
9534dd6
9b76954
b50ee8d
4c1afba
c3107e0
 
 
 
 
 
 
 
 
 
9b76954
 
 
 
 
 
 
 
f1eabe1
9b76954
 
 
171d2b4
9b76954
 
 
 
c3107e0
 
 
 
02b2822
171d2b4
c3107e0
e770b38
 
c3107e0
 
 
e770b38
c3107e0
9b76954
e770b38
 
 
 
c3107e0
 
 
 
 
 
 
9b76954
c3107e0
 
 
 
 
 
 
e770b38
 
c3107e0
9b76954
171d2b4
e770b38
9b76954
 
c3107e0
9b76954
 
 
c3107e0
9b76954
e770b38
 
9b76954
c3107e0
 
 
 
 
 
 
 
 
 
 
 
 
171d2b4
9b76954
c3107e0
9b76954
c3107e0
 
 
 
 
 
 
 
 
 
 
9b76954
 
 
 
171d2b4
c3107e0
e770b38
c3107e0
 
e770b38
9b76954
 
 
e770b38
c3107e0
e770b38
c3107e0
 
e770b38
 
c3107e0
 
e770b38
 
c3107e0
e770b38
 
c3107e0
 
9b76954
 
e770b38
 
 
e39c97d
e770b38
 
 
9b76954
 
 
 
 
 
 
 
 
c3107e0
 
171d2b4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
import io
import json
import os
import time
import uuid
from datetime import datetime
from io import BytesIO
from tempfile import NamedTemporaryFile
from xmlrpc.client import Binary
import jwt
import threading

import numpy as np
import requests
import scipy
import soundfile as sf
import streamlit as st
import streamlit_vertical_slider as svs
from pydub import AudioSegment
from scipy.signal import butter, sosfilt
from streamlit import session_state as st_state
from woocommerce import API
from wordpress_xmlrpc import Client
from wordpress_xmlrpc.compat import xmlrpc_client
from wordpress_xmlrpc.methods import media

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart


# Try to get API_URL from environment variables, if not found set to a default value
try:
    API_URL = os.environ["API_URL"]
except KeyError:
    st.error("API_URL environment variable is not set.")
    st.stop()
    
    # Try to get the Bearer token from environment variables, if not found set to a default value
try:
    BEARER_TOKEN = os.environ["BEARER_TOKEN"]
except KeyError:
    st.error("BEARER_TOKEN environment variable is not set.")
    st.stop()

print("API_URL:", os.environ["API_URL"])
print("BEARER_TOKEN:", os.environ["BEARER_TOKEN"])



page_bg_img = '''
<style>
.stApp {
background-image: url("https://songlabai.com/wp-content/uploads/2024/03/4.png");
background-size: cover;
}
</style>
'''
st.markdown(page_bg_img, unsafe_allow_html=True)



def save_to_wordpress(audio_array, sample_rate):
    # Convert audio_array to float32 if not already
    audio_array = audio_array.astype(np.float32)

    # Save the audio to a BytesIO buffer
    wav_bytes = BytesIO()
    sf.write(wav_bytes, audio_array, samplerate=sample_rate, format='WAV')
    wav_bytes.seek(0)

    # Define your WordPress site URL and authentication credentials
    wordpress_url = "https://songlabai.com/xmlrpc.php"
    woocommerce_url = "https://songlabai.com"
    consumer_key = "ck_93d516ba12289a6fd0eced56bbc0b05ecbf98735"
    consumer_secret = "cs_9d5eb716d631db408a4c47796b5d18b0313d8559"
    username = "admin_h2ibbgql"
    password = "Pressabc1!"

    # Authenticate with WordPress XML-RPC API
    title = f"generated_audio_{datetime.now().timestamp()}.wav"
    file_data = {
        "name": title,
        "type": "audio/x-wav",  # Change the MIME type according to your file type
        "bits": xmlrpc_client.Binary(wav_bytes.getvalue()),
    }
    wp_client = Client(wordpress_url, username, password)
    for _ in range(4):
        try:
            # Upload the file to WordPress Media Library
            media_response = wp_client.call(media.UploadFile(file_data))

            # Handle the response
            if media_response:
                print(
                    "File successfully uploaded to WordPress with attachment ID:",
                    media_response,
                )

                # Create product data for WooCommerce
                product_data = {
                    "status": "pending",
                    "name": title,
                    "type": "simple",
                    "regular_price": "1.00",  # Set the price as needed
                    "sku": str(uuid.uuid4()),
                    "downloadable": True,
                    "download_limit": -1,
                    "download_expiry": -1,
                }

                # Authenticate with WooCommerce API
                wc_api = API(
                    url=woocommerce_url,
                    consumer_key=consumer_key,
                    consumer_secret=consumer_secret,
                    version="wc/v3",
                )

                # Create the product
                response = wc_api.post("products", product_data)

                # Handle the response
                if response.status_code == 201:
                    print(
                        "Product successfully created in WooCommerce:", response.json()
                    )
                    # Update product to add downloadable file URL
                    product_update_data = {
                        "downloads": [
                            {
                                "name": media_response["title"],
                                "file": media_response["link"],
                            }
                        ]
                    }
                    product_id = response.json().get("id")
                    response = wc_api.put(f"products/{product_id}", product_update_data)

                    if response.status_code == 200:
                        print(
                            "Downloadable file URL added to product:", response.json()
                        )
                        return (
                            response.json()["permalink"],
                            response.json()["permalink"].split("p=")[-1],
                        )
                    else:
                        print(
                            "Error adding downloadable file URL to product:",
                            response.text,
                        )
                else:
                    print("Error creating product in WooCommerce:", response.text)
            else:
                print("Error uploading file to WordPress.")
            break
        except Exception as e:
            print("Error:", e)
            continue  # Retry on error

    # If upload fails, return placeholders
    return "https://songlabai.com/contact_us/", "N/A"



# Streamlit app title
st.title("Songlab AI")
#cookies = cookie_manager.get_all(key='init_get_all')


# Ensure session state keys are initialized
if "jwt_token" not in st.session_state:
    st.session_state["jwt_token"] = None
if "session_id" not in st.session_state:
    st.session_state["session_id"] = None
if 'login_needed' not in st.session_state:
    st.session_state['login_needed'] = False
if 'generate_audio_params' not in st.session_state:
    st.session_state['generate_audio_params'] = None


if st.session_state.get("jwt_token"):
    if st.button("Log out", key="logout_button"):
        # Clear all user-specific session state
        st.session_state.clear()
        st.success("Logged out successfully!")
        st.rerun()
        
def get_api_headers():
    return {
        "Authorization": f"Bearer {BEARER_TOKEN}",
        "Content-Type": "application/json",
    }


# Function to get the auth headers using the current jwt_token
def get_auth_headers():
    jwt_token = st.session_state.get("jwt_token")
    if jwt_token:
        return {
            "Authorization": f"Bearer {jwt_token}",
            "Content-Type": "application/json",
            "Cache-Control": "no-store",
        }
    else:
        return {
            "Content-Type": "application/json",
            "Cache-Control": "no-store",
        }

        
if "session_id" not in st.session_state:
    st.session_state["session_id"] = str(uuid.uuid4())
    st.write("Session ID:", st.session_state["session_id"])
    st.write("Current JWT Token:", st.session_state.get("jwt_token"))
    st.write("Session State:", st.session_state)


# Initialize session state variables
if "vocal_audio" not in st_state:
    st_state.vocal_audio = None
if "vocal_sample_rate" not in st_state:
    st_state.vocal_sample_rate = None

if "audio" not in st_state:
    st_state.audio = None
if "audio_pydub" not in st_state:
    st_state.audio_pydub = None
if "audio_sample_rate" not in st_state:
    st_state.audio_sample_rate = None

if "augmented_audio" not in st_state:
    st_state.augmented_audio = None
if "augmented_audio_pydub" not in st_state:
    st_state.augmented_audio_pydub = None
if "augmented_audio_sample_rate" not in st_state:
    st_state.augmented_audio_sample_rate = None


genres = [
    "Pop",
    "Rock",
    "Hip Hop",
    "Jazz",
    "Blues",
    "Country",
    "Classical",
    "Electronic",
    "Reggae",
    "Folk",
    "R&B",
    "Metal",
    "Punk",
    "Indie",
    "Dance",
    "World",
    "Gospel",
    "Soul",
    "Funk",
    "Ambient",
    "Techno",
    "Disco",
    "House",
    "Trance",
    "Dubstep",
]
genre = st.selectbox("Select Genre:", genres)
energy_levels = ["Low", "Medium", "High"]
energy_level = st.radio("Energy Level:", energy_levels, horizontal=True)
description = st.text_input("Description:", "")
tempo = st.slider("Tempo (in bpm):", min_value=40, max_value=100, value=60, step=5)

# First, check subscription status if user is logged in
if st.session_state.get("jwt_token"):
    auth_headers = get_auth_headers()
    subscription_url = "https://songlabai.com/wp-json/custom-api/v1/subscription"
    subscription_response = requests.get(subscription_url, headers=auth_headers)
    
    if subscription_response.status_code == 200:
        subscription_data = subscription_response.json()
        subscription_plan_id = subscription_data.get("subscription_plan_id")
        # Free tier has plan ID 576 or null
        is_free_tier = not subscription_plan_id or subscription_plan_id == 576
    else:
        is_free_tier = True  # Default to free tier if unable to verify
else:
    is_free_tier = True  # Default to free tier if not logged in

# First, check subscription status if user is logged in
if st.session_state.get("jwt_token"):
    auth_headers = get_auth_headers()
    subscription_url = "https://songlabai.com/wp-json/custom-api/v1/subscription"
    subscription_response = requests.get(subscription_url, headers=auth_headers)
    
    if subscription_response.status_code == 200:
        subscription_data = subscription_response.json()
        # Convert subscription_plan_id to string for comparison
        subscription_plan_id = str(subscription_data.get("subscription_plan_id"))
        is_free_tier = subscription_plan_id == "576" or subscription_data.get("status") == "no_subscription"
        
# Show appropriate duration slider based on subscription tier
if is_free_tier:
    duration = st.slider(
        "Duration (in seconds):",
        min_value=15,
        max_value=30,  # Restricted to 30 seconds for free tier
        value=30,
        step=1,
        help="Free tier users are limited to 30-second generations. Upgrade to create longer tracks!"
    )
else:
    duration = st.slider(
        "Duration (in seconds):",
        min_value=15,
        max_value=300,
        value=30,
        step=1
    )


def convert_audio_segment_to_float_array(audio_pydub):
    """
    Convert a pydub AudioSegment to a NumPy array of type float32.

    Args:
    audio_pydub (AudioSegment): The AudioSegment object to be converted.

    Returns:
    np.ndarray: A NumPy array containing the audio data as float32.
    """
    # Get the raw audio data as a sequence of samples
    samples = audio_pydub.get_array_of_samples()

    # Convert the samples to a NumPy array and normalize to float32
    audio_array = np.array(samples).astype(np.float32)

    # Normalize the audio array to range between -1.0 and 1.0
    max_val = 2**15  # Assuming 16-bit audio, modify this if using different bit depths
    audio_array /= max_val
    return audio_array

def time_post_request(api_url, headers=None, payload=None, timeout=None):
    """
    Times the execution of a POST request.

    Parameters:
    - api_url (str): The URL to which the POST request is sent.
    - headers (dict): The headers to include in the POST request.
    - payload (dict): The payload to include in the POST request.
    - timeout (int): The timeout value in seconds for the POST request (optional).

    Returns:
    - response (requests.Response): The response object returned by the POST request.
    - execution_time (float): The time it took to execute the POST request.
    """
    start_time = time.time()
    response = requests.post(api_url, headers=headers, json=payload, timeout=timeout)
    end_time = time.time()

    execution_time = end_time - start_time
    print(f"Execution time: {execution_time} seconds")

    return response

def check_server_status():
    """Check if the server is warm by making a minimal request"""
    warmup_payload = {"inputs": {"prompt": "warmup", "duration": 1}}
    try:
        response = time_post_request(
            API_URL,
            headers=get_api_headers(),
            payload=warmup_payload,
            timeout=10  # Short timeout for quick check
        )
        return response is not None and response.status_code == 200
    except:
        return False

def wait_for_server_warmup(status_placeholder, progress_placeholder, subscription_info_placeholder, stage_placeholder):
    """Handle server warmup with detailed progress stages and proceed immediately when server is ready"""
    stages = [
        {"time": 0, "message": "πŸš€ Initializing server resources..."},
        {"time": 60, "message": "βš™οΈ Loading the AI model into memory..."},
        {"time": 180, "message": "πŸ”§ Optimizing model parameters..."},
        {"time": 300, "message": "πŸ“Š Configuring generation settings..."},
        {"time": 360, "message": "✨ Finalizing server preparation..."}
    ]
    
    subscription_info = """
    ### πŸ“‹ **Subscription Tiers**

    **Free User**
    - 🎡 **Generations:** 3 music generations
    - πŸ“₯ **Downloads:** No downloads allowed
    - 🎼 **Submit your track from dashboard**
    - πŸ’° **Receive 50% commission**
    - πŸ’΅ **Tracks sale for $1 on website**

    **Tier 2 - $24.99/month**
    - 🎡 **Generations:** Up to 3 music generations per day
    - πŸ“₯ **Downloads:** 1 download per month
    - πŸ”’ **Private Tracks:** Create unpublished, private tracks
    - πŸ“Š **Dashboard:** Access your profile and save up to 2 tracks

    **Tier 3 - $99.99/month**
    - 🎡 **Generations:** Up to 5 music generations per day
    - πŸ“₯ **Downloads:** 5 downloads per month
    - πŸ“Š **Dashboard:** Full profile access for managing and saving your tracks
    - πŸ’Ύ **Storage:** Save up to 10 tracks

    **Tier 4 - $269.97/month**
    - 🎡 **Generations:** Up to 20 music generations per day
    - πŸ“₯ **Downloads:** 15 downloads per month
    - 🏒 **Commercial Use:** Includes rights for commercial purposes
    - πŸ“Š **Dashboard:** Advanced profile management for commercial accounts

    ### πŸš€ **Why Subscribe?**
    Upgrade now to unlock more features and enhance your music creation experience!
    """

    start_time = time.time()
    total_warmup_time = 420  # 7 minutes
    current_stage = 0
    last_check_time = 0
    
    while time.time() - start_time < total_warmup_time:
        elapsed = time.time() - start_time
        remaining = total_warmup_time - elapsed
        progress = elapsed / total_warmup_time
        
        # Update current stage
        while current_stage < len(stages) - 1 and elapsed > stages[current_stage + 1]["time"]:
            current_stage += 1
            
        minutes_remaining = int(remaining // 60)
        seconds_remaining = int(remaining % 60)
        
        # Update UI
        status_placeholder.markdown("### πŸ”„ AI Server Initialization in Progress")
        progress_placeholder.progress(progress)
        stage_placeholder.info(
            f"{stages[current_stage]['message']}\n\n"
            f"⏳ Estimated time remaining: {minutes_remaining}m {seconds_remaining}s\n\n"
            "ℹ️ **Why the wait?** The AI model needs time to load and prepare when the server is inactive.\n"
            "Upgrading to a premium plan keeps the server active longer, reducing or eliminating wait times!\n"
            "πŸ‘‰ [Upgrade Now](https://songlabai.com/subscribe/)"
        )
        subscription_info_placeholder.markdown(subscription_info)
        
        # Check if server is ready every 5 seconds
        if elapsed - last_check_time >= 5:
            last_check_time = elapsed
            if check_server_status():
                status_placeholder.success("πŸŽ‰ Server is ready! Proceeding to music generation...")
                return True
                
        time.sleep(0.1)
        
    return False


def generate_audio(genre, energy_level, tempo, description, duration):
    # Create placeholders
    status_placeholder = st.empty()
    progress_placeholder = st.empty()
    subscription_placeholder = st.empty()
    stage_placeholder = st.empty()
    
    try:
        # First, verify user is logged in and has permissions
        if st.session_state.get("jwt_token") is None:
            st.error("You must be logged in to generate audio.")
            return None
                
        auth_headers = get_auth_headers()
        
        # Check subscription status
        subscription_url = "https://songlabai.com/wp-json/custom-api/v1/subscription"
        subscription_response = requests.get(subscription_url, headers=auth_headers)
        if subscription_response.status_code != 200:
            st.error("Failed to retrieve your subscription status.")
            return None
                
        subscription_data = subscription_response.json()
        
        # Check for free tier duration restriction
        is_free_tier = subscription_plan_id == "576" or subscription_data.get("status") == "no_subscription"
        if is_free_tier:
            if duration > 30:
                st.warning("⚠️ Free tier users are limited to 30-second generations.")
                st.info("πŸ’‘ Upgrade to a premium plan to generate longer tracks!\n\n" + 
                       "**Available Plans:**\n" +
                       "- **$24.99/month:** Up to 3 generations per day, 1 download per month\n" +
                       "- **$99.99/month:** Up to 5 generations per day, 5 downloads per month\n" +
                       "- **$269.97/month:** Up to 20 generations per day, 15 downloads per month\n\n" +
                       "πŸ‘‰ [Upgrade Now](https://songlabai.com/subscribe/)")
                duration = 30  # Force duration to 30 seconds for free tier
                
        # Check if server is cold
        if not check_server_status():
            status_placeholder.warning(
                "πŸ”„ **Server is currently starting up.**\n\n"
                "Our AI model needs some time to load and prepare when the server has been inactive.\n"
                "This can take up to **7 minutes** for free users.\n\n"
                "πŸ’‘ **Upgrade to a premium plan to reduce or eliminate wait times!**\n"
                "πŸ‘‰ [Upgrade Now](https://songlabai.com/subscribe/)"
            )
                
            # Wait for server to warm up with progress display
            server_ready = wait_for_server_warmup(
                status_placeholder,
                progress_placeholder,
                subscription_placeholder,
                stage_placeholder
            )
                
            if not server_ready:
                st.error(
                    "❌ Server initialization timed out.\n\n"
                    "Consider upgrading to premium for reliable, fast access.\n\n"
                    "πŸ‘‰ [Upgrade Now](https://songlabai.com/subscribe/)"
                )
                return None
                    
        # Clear warmup messages
        for placeholder in [status_placeholder, progress_placeholder, subscription_placeholder, stage_placeholder]:
            placeholder.empty()
                
        # Prepare generation request
        prompt = f"Genre: {genre}, Energy Level: {energy_level}, Tempo: {tempo}, Description: {description}"
        payload = {"inputs": {"prompt": prompt, "duration": duration}}
        api_headers = get_api_headers()
        
        # Make the generation request
        with st.spinner("🎡 Generating your music... This may take a few moments."):
            response = time_post_request(API_URL, headers=api_headers, payload=payload, timeout=600)
            
            if response and response.status_code == 200:
                st.success("✨ Music generated successfully!")
                # Pass all parameters to load_and_play_generated_audio
                load_and_play_generated_audio(
                    response=response,
                    genre=genre,
                    energy_level=energy_level,
                    tempo=tempo,
                    description=description,
                    duration=duration
                )
                
                # Update generation count
                update_generation_url = "https://songlabai.com/wp-json/custom-api/v1/update-generation-count"
                requests.post(update_generation_url, headers=auth_headers)
                
                return response  # Return the response for email notification
            else:
                st.error(
                    "❌ Failed to generate audio.\n\n"
                    "This might be due to high server load or an error.\n\n"
                    "πŸ’‘ **Tip:** Premium users experience fewer failures and faster generation times.\n\n"
                    "πŸ‘‰ [Upgrade Now](https://songlabai.com/subscribe/)"
                )
                return None
    except Exception as e:
        st.error(f"An unexpected error occurred: {str(e)}")
        return None

def download_audio():
    if st_state.audio_pydub is None:
        st.error("No audio available to download.")
        return

    # Convert AudioSegment to bytes
    audio_bytes = st_state.audio_pydub.export(format="wav").read()

    # Create a download button
    st.download_button(
        label="Download Generated Audio",
        data=audio_bytes,
        file_name="generated_audio.wav",
        mime="audio/wav",
        on_click=update_download_count
    )

def notify_admin_of_generation(perm_link, product_code):
    """
    Notify admin of new song generation using WordPress REST API
    """
    try:
        notification_url = "https://songlabai.com/wp-json/songlab/v1/notify"
        
        # Get user ID from JWT token
        user_id = None
        if st.session_state.get("jwt_token"):
            try:
                decoded = jwt.decode(st.session_state["jwt_token"], options={"verify_signature": False})
                user_id = decoded.get('data', {}).get('user', {}).get('id')
                print(f"Decoded JWT token: {decoded}")  # Debug print
            except Exception as e:
                print(f"Error decoding JWT: {str(e)}")
                user_id = None
        
        # Prepare the notification data
        payload = {
            "link": perm_link,
            "product_code": product_code,
            "user_id": user_id
        }
        
        # Print what we're sending
        print(f"Sending notification to {notification_url}")
        print(f"With payload: {payload}")
        print(f"JWT token: {st.session_state.get('jwt_token')}")
        
        # Send the notification
        headers = {
            'Content-Type': 'application/json'
        }
        
        response = requests.post(notification_url, json=payload, headers=headers)
        
        # Print response details
        print(f"Response status code: {response.status_code}")
        print(f"Response headers: {response.headers}")
        try:
            print(f"Response JSON: {response.json()}")
        except:
            print(f"Raw response text: {response.text}")
        
        if response.status_code == 200:
            print("βœ“ Admin notification sent successfully")
            return True
        else:
            print(f"Γ— Failed to send admin notification (HTTP {response.status_code})")
            return False
            
    except Exception as e:
        print(f"Γ— Error sending notification: {str(e)}")
        import traceback
        print(traceback.format_exc())  # Print full stack trace
        return False

        
def update_download_count():
    auth_headers = get_auth_headers()
    update_download_url = "https://songlabai.com/wp-json/custom-api/v1/update-download-count"
    update_response = requests.post(update_download_url, headers=auth_headers)
    if update_response.status_code != 200:
        st.error("Failed to update your download count.")
        return


def load_and_play_generated_audio(response, genre=None, energy_level=None, tempo=None, description=None, duration=None):
    import soundfile as sf
    from io import BytesIO

    response_eval = json.loads(response.content)
    generated_audio = response_eval[0]["generated_audio"]
    sample_rate = response_eval[0]["sample_rate"]

    # Check if the audio is stereo or mono
    if isinstance(generated_audio[0], list):  # Stereo
        audio_array = np.array(generated_audio).T
    else:  # Mono
        audio_array = np.array(generated_audio)

    # Convert the float32 audio data to int16
    max_val = np.max(np.abs(audio_array))
    if max_val > 0:
        audio_array = audio_array / max_val  # Normalize to [-1.0, 1.0]
    int_audio = np.int16(audio_array * 32767)

    # Write the audio data to a BytesIO buffer using soundfile
    audio_buffer = BytesIO()
    sf.write(audio_buffer, int_audio, sample_rate, format='WAV', subtype='PCM_16')
    audio_buffer.seek(0)

    # Read the audio data into an AudioSegment
    audio_segment = AudioSegment.from_file(audio_buffer, format="wav")

    st_state.audio_pydub = audio_segment
    st_state.audio_sample_rate = sample_rate
    st_state.augmented_audio_pydub = st_state.audio_pydub

    # Play the audio
    st.audio(audio_buffer.getvalue())

    # Save the audio to WordPress and get perm_link and product_code
    perm_link, product_code = save_to_wordpress(audio_array, sample_rate)

    # Get user ID from JWT token
    user_id = None
    if st.session_state.get("jwt_token"):
        try:
            decoded = jwt.decode(st.session_state["jwt_token"], options={"verify_signature": False})
            user_id = decoded.get('user_id', 'Unknown')
        except:
            user_id = 'Unknown'

    # Send notification using simplified function
    notify_admin_of_generation(perm_link, product_code)


    # Define col_btn and col_text
    col_btn, col_text = st.columns([2, 4])

    with col_btn:
        st.markdown("[Publish your Song](https://songlabai.com/contact_us/)")
        st.markdown("[Download Song](https://songlabai.com/download-music/)")

    with col_text:
        st.write(
            f"To Publish, please contact the admin by sending the following link: {perm_link}"
        )
        st.write(f"To download use the following product code: {product_code}")

if st.button("Generate Audio", key="generate_audio_button"):
    if genre and energy_level and description and tempo:
        if st.session_state.get("jwt_token") is None:
            # User is not logged in
            st.session_state['login_needed'] = True
            st.session_state['generate_audio_params'] = {
                'genre': genre,
                'energy_level': energy_level,
                'tempo': tempo,
                'description': description,
                'duration': duration
            }
            st.warning("Please log in to generate audio.")
        else:
            generate_audio(genre, energy_level, tempo, description, duration)
    else:
        st.info("Description field is required.")

if st.session_state.get('login_needed') and st.session_state.get("jwt_token") is None:
    st.header("Please log in to continue")
    username = st.text_input("Username", key="username_input")
    password = st.text_input("Password", type="password", key="password_input", value="")

    if st.button("Log in", key="login_button"):
        login_url = "https://songlabai.com/wp-json/jwt-auth/v1/token"
        data = {
            "username": username,
            "password": password
        }
        response = requests.post(login_url, data=data)
        if response.status_code == 200 and 'token' in response.json():
            result = response.json()
            st.session_state["jwt_token"] = result["token"]
            st.session_state["session_id"] = str(uuid.uuid4())  # Generate new session ID
            st.success("Logged in successfully!")
            st.session_state['login_needed'] = False
            # Trigger a rerun to immediately hide the login form
            st.rerun()
            # Retrieve the parameters and generate audio if they were stored
            params = st.session_state.get('generate_audio_params')
            if params:
                generate_audio(**params)
                st.session_state['generate_audio_params'] = None
        else:
            st.error("Invalid username or password")
            # Keep login_needed True
    # Add Register link
    st.markdown("Don't have an account? [Register here](https://songlabai.com/register/)")
else:
    pass  # Do nothing if login is not needed


# Post-processing options
st.header("Post-processing Options")

vocal_file = st.file_uploader(
    "Upload Vocal File", type=["mp3", "wav", "ogg", "flac", "aac"]
)
if vocal_file:
    st_state.vocal_audio = vocal_file.read()
    # st.audio(st_state.vocal_audio, format="audio/wav")

# Mixing
mix_vocals = st.checkbox("Mix Vocals")

if mix_vocals and st_state.vocal_audio is not None:
    with NamedTemporaryFile() as f:
        f.write(st_state.vocal_audio)
        st_state.vocal_audio = AudioSegment.from_file(f.name)
    st_state.augmented_audio_pydub = st_state.augmented_audio_pydub.overlay(
        st_state.vocal_audio, position=100
    )
    # st.audio(st_state.augmented_audio_pydub.export().read())
    st_state.augmented_audio = convert_audio_segment_to_float_array(
        st_state.augmented_audio_pydub
    )
    st_state.augmented_audio_sample_rate = st_state.augmented_audio_pydub.frame_rate
elif not mix_vocals and st_state.vocal_audio is not None:
    st_state.augmented_audio_pydub = st_state.audio_pydub
    st_state.augmented_audio_sample_rate = st_state.audio_pydub.frame_rate
# Mastering
st.header("Mastering")
st.markdown("")
# Volume Balance, Compression Ratio, and Reverb Amount
vol_col, pitch_shift,buttons_col = st.columns([2, 2, 2.5,])
with buttons_col:
    with st.container(height=371, border=True):
        st.markdown("")
        apply_stereo = st.button("Apply Stereo Effect")
        st.markdown("")
        reverse = st.button("Apply Audio Reverse ")
        st.markdown("")
        reset_post_processing = st.button("Undo All Post-processings")
        st.markdown("")

with vol_col:
    with st.container(border=True):
        volume_balance = svs.vertical_slider(
            "Volume Balance",
            min_value=-10.0,
            max_value=10.0,
            default_value=0.0,
            step=0.1,
            slider_color="green",
            track_color="lightgray",
            thumb_color="red",
            thumb_shape="pill",
        )
        vol_button = st.button("Apply Vol-Balance")


# Pitch shifting
with pitch_shift:
    with st.container(border=True):
        pitch_semitones = svs.vertical_slider(
            label="Pitch (semitones)",
            min_value=-12,
            max_value=12,
            default_value=0,
            step=1,
            slider_color="red",
            track_color="lightgray",
            thumb_color="red",
            thumb_shape="pill",
        )
        pitch_shift_button = st.button(
            "Apply Pitch Shift",
        )


if st_state.augmented_audio_pydub is not None:
    if vol_button:
        st_state.augmented_audio_pydub = st_state.augmented_audio_pydub + volume_balance

    if apply_stereo:
        st_state.augmented_audio_pydub = st_state.augmented_audio_pydub.pan(
            -0.5
        ).overlay(st_state.augmented_audio_pydub.pan(0.5))
    if reverse:
        st_state.augmented_audio_pydub = st_state.augmented_audio_pydub.reverse()
    if pitch_shift_button:
        st_state.augmented_audio_pydub = st_state.augmented_audio_pydub._spawn(
            st_state.augmented_audio_pydub.raw_data,
            overrides={
                "frame_rate": int(
                    st_state.augmented_audio_pydub.frame_rate
                    * (2 ** (pitch_semitones / 12.0))
                )
            },
        )

# Display the final audio
if st_state.augmented_audio_pydub is not None:
    st.audio(st_state.augmented_audio_pydub.export().read())
    # sample_rate = st_state.augmented_audio_sample_rate
    # st.audio(st_state.augmented_audio, format="audio/wav", sample_rate=sample_rate*2, start_time=0)

st.link_button(
    label="⬇️ Download/Save",
    url="https://songlabai.com/subscribe/",
    type="primary",
    use_container_width=True,
)
# m = st.markdown("""
# <style>
# div.stButton > button:first-child {
# # color: rgb(204, 49, 49);
# # background-color: ;
# # border-radius: 5%;
# backgroud-color: #00ff00;
# }
# # </style>""", unsafe_allow_html=True)

if reset_post_processing and st_state.audio_pydub is not None:
    st_state.augmented_audio_pydub = st_state.audio_pydub