File size: 8,603 Bytes
1dd5ac4
5de0578
 
c0b8023
 
 
3767dfa
b629f13
5de0578
b629f13
c0b8023
 
 
 
1dd5ac4
c0b8023
1dd5ac4
9c8f593
b629f13
c0b8023
5de0578
1dd5ac4
5de0578
 
b629f13
 
1dd5ac4
b629f13
 
 
1dd5ac4
 
b629f13
 
1dd5ac4
b629f13
1dd5ac4
b629f13
1dd5ac4
 
b629f13
 
 
 
 
 
 
1dd5ac4
 
b629f13
1dd5ac4
 
 
b629f13
 
 
c0b8023
b629f13
 
 
 
1dd5ac4
b629f13
 
1dd5ac4
b629f13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1dd5ac4
b629f13
1dd5ac4
b629f13
 
1dd5ac4
b629f13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1dd5ac4
3767dfa
b629f13
3767dfa
 
 
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
import os
import gradio as gr
import torch
import spaces
from TTS.api import TTS
from supabase import create_client, Client
import config 
import uuid

# --- 1. Supabase Connection & Setup ---
supabase = None
if config.IS_CONNECTED:
    try:
        supabase: Client = create_client(config.SUPABASE_URL, config.SUPABASE_KEY)
        print("✅ Supabase Connected!")
    except Exception as e:
        print(f"❌ Supabase Error: {e}")

# Model Setup
os.environ["COQUI_TOS_AGREED"] = "1"
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"⏳ Loading XTTS Model on {device}...")
tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to(device)

BUCKET_NAME = "voice-bucket"

# --- Helper Functions ---

def get_file_list():
    """Supabase se saari audio files ki list layega"""
    if not supabase: return []
    try:
        res = supabase.storage.from_(BUCKET_NAME).list()
        # Sirf wav/mp3 files filter karein
        files = [f['name'] for f in res if f['name'].endswith(('.wav', '.mp3'))]
        return sorted(files)
    except Exception as e:
        print(f"List Error: {e}")
        return []

def get_public_url(filename):
    """File ka direct link banayega sunne ke liye"""
    if not supabase: return None
    return f"{config.SUPABASE_URL}/storage/v1/object/public/{BUCKET_NAME}/{filename}"

def download_voice(filename):
    """Generate karne ke liye file download karega"""
    local_path = f"temp_{filename}"
    with open(local_path, 'wb+') as f:
        res = supabase.storage.from_(BUCKET_NAME).download(filename)
        f.write(res)
    return local_path

# --- CORE FUNCTIONS (Tabs Logic) ---

# TAB 1: Generate
@spaces.GPU(duration=120)
def generate_audio(text, language, selected_voice):
    if not selected_voice:
        return None, "⚠️ पहले कोई आवाज़ (Sample) चुनें!"
    
    try:
        speaker_wav = download_voice(selected_voice)
        output_path = "output.wav"
        
        tts.tts_to_file(
            text=text, 
            file_path=output_path, 
            speaker_wav=speaker_wav, 
            language=language
        )
        return output_path, "✅ ऑडियो तैयार है!"
    except Exception as e:
        return None, f"❌ Error: {e}"

# TAB 2: Save New Sample
def save_new_sample(audio_file, custom_name):
    if not supabase: return "❌ Database connect nahi hai."
    if not audio_file: return "⚠️ ऑडियो फाइल नहीं मिली।"
    if not custom_name: return "⚠️ कृपया आवाज़ का नाम लिखें।"
    
    # Filename clean karein (spaces hata kar)
    clean_name = custom_name.strip().replace(" ", "_")
    filename = f"{clean_name}.wav"
    
    try:
        with open(audio_file, 'rb') as f:
            supabase.storage.from_(BUCKET_NAME).upload(filename, f)
        return f"🎉 '{filename}' सेव हो गया! अब आप इसे Home टैब में चुन सकते हैं।"
    except Exception as e:
        return f"❌ Error: शायद इस नाम की फाइल पहले से है. ({e})"

# TAB 3: Manage (Delete/Rename/Preview)
def update_library_view():
    """Library refresh karega"""
    files = get_file_list()
    return gr.Dropdown(choices=files, value=files[0] if files else None), "📂 लिस्ट अपडेटेड"

def load_file_preview(filename):
    """Select karte hi audio sunayega"""
    if not filename: return None
    return get_public_url(filename)

def delete_sample(filename):
    if not supabase or not filename: return "⚠️ कुछ सेलेक्ट नहीं किया।"
    try:
        supabase.storage.from_(BUCKET_NAME).remove([filename])
        return "🗑️ फाइल डिलीट हो गई!"
    except Exception as e:
        return f"❌ Delete Error: {e}"

def rename_sample(old_name, new_name):
    if not supabase or not old_name or not new_name: return "⚠️ नाम सही नहीं है।"
    
    clean_new = new_name.strip().replace(" ", "_")
    if not clean_new.endswith(".wav"): clean_new += ".wav"
    
    try:
        supabase.storage.from_(BUCKET_NAME).move(old_name, clean_new)
        return f"✏️ नाम बदलकर '{clean_new}' हो गया!"
    except Exception as e:
        return f"❌ Rename Error: {e}"

# --- UI LAYOUT (Tabs Style) ---
with gr.Blocks(title="My Voice AI", theme=gr.themes.Soft()) as app:
    
    gr.Markdown("## 🎙️ My Hindi Voice Studio")
    
    with gr.Tabs():
        
        # --- TAB 1: HOME (GENERATE) ---
        with gr.TabItem("🏠 Home (Generate)"):
            with gr.Row():
                voice_selector = gr.Dropdown(
                    label="1. आवाज़ चुनें (Sample Voice)", 
                    choices=get_file_list(),
                    interactive=True
                )
                refresh_home_btn = gr.Button("🔄 रिफ्रेश लिस्ट", size="sm")
            
            with gr.Row():
                txt_input = gr.Textbox(label="2. क्या बुलवाना है? (Text)", lines=3, placeholder="नमस्ते, आप कैसे हैं?")
                lang_drop = gr.Dropdown(label="भाषा (Language)", choices=["hi", "en"], value="hi")
            
            gen_btn = gr.Button("🚀 आवाज़ बनाओ (Generate)", variant="primary")
            
            with gr.Row():
                audio_out = gr.Audio(label="Result")
                status_home = gr.Textbox(label="Status")
            
            # Events
            refresh_home_btn.click(lambda: gr.Dropdown(choices=get_file_list()), outputs=voice_selector)
            gen_btn.click(generate_audio, [txt_input, lang_drop, voice_selector], [audio_out, status_home])

        # --- TAB 2: ADD NEW VOICE ---
        with gr.TabItem("➕ Add Sample (Save)"):
            gr.Markdown("अपनी या किसी की भी आवाज़ सेव करें ताकि बाद में यूज़ कर सकें।")
            
            new_audio = gr.Audio(label="आवाज़ रिकॉर्ड करें या अपलोड करें", type="filepath")
            new_name = gr.Textbox(label="इस आवाज़ का नाम (Example: Meri_Awaz)", placeholder="Naam likhein...")
            
            save_btn = gr.Button("💾 सेव करें (Save to Cloud)", variant="primary")
            status_save = gr.Textbox(label="Status")
            
            save_btn.click(save_new_sample, [new_audio, new_name], status_save)

        # --- TAB 3: MY LIBRARY (LIST/EDIT) ---
        with gr.TabItem("📂 My Library"):
            gr.Markdown("यहाँ आपकी सारी सेव की हुई आवाज़ें हैं।")
            
            with gr.Row():
                lib_dropdown = gr.Dropdown(label="फाइल चुनें", choices=get_file_list(), interactive=True)
                refresh_lib_btn = gr.Button("🔄 रिफ्रेश", size="sm")
            
            preview_player = gr.Audio(label="Preview (सुनें)")
            
            with gr.Accordion("🛠️ Edit / Delete Options", open=False):
                with gr.Row():
                    rename_txt = gr.Textbox(label="नया नाम (New Name)", placeholder="New_Name.wav")
                    rename_btn = gr.Button("✏️ नाम बदलें (Rename)")
                
                delete_btn = gr.Button("🗑️ हमेशा के लिए डिलीट करें (Delete)", variant="stop")
            
            status_lib = gr.Textbox(label="Status")

            # Events
            # Select karte hi play karega
            lib_dropdown.change(load_file_preview, lib_dropdown, preview_player)
            
            # Buttons Logic
            refresh_lib_btn.click(update_library_view, None, [lib_dropdown, status_lib])
            
            delete_btn.click(delete_sample, lib_dropdown, status_lib).then(
                update_library_view, None, [lib_dropdown, status_lib]
            )
            
            rename_btn.click(rename_sample, [lib_dropdown, rename_txt], status_lib).then(
                update_library_view, None, [lib_dropdown, status_lib]
            )

# Login System
if __name__ == "__main__":
    app.launch(
        auth=(config.APP_USER, config.APP_PASS),
        server_name="0.0.0.0", 
        server_port=7860
    )