| | 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 |
| |
|
| | |
| | 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}") |
| |
|
| | |
| | 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" |
| |
|
| | |
| |
|
| | def get_file_list(): |
| | """Supabase se saari audio files ki list layega""" |
| | if not supabase: return [] |
| | try: |
| | res = supabase.storage.from_(BUCKET_NAME).list() |
| | |
| | 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 |
| |
|
| | |
| |
|
| | |
| | @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}" |
| |
|
| | |
| | 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 "⚠️ कृपया आवाज़ का नाम लिखें।" |
| | |
| | |
| | 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})" |
| |
|
| | |
| | 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}" |
| |
|
| | |
| | with gr.Blocks(title="My Voice AI", theme=gr.themes.Soft()) as app: |
| | |
| | gr.Markdown("## 🎙️ My Hindi Voice Studio") |
| | |
| | with gr.Tabs(): |
| | |
| | |
| | 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") |
| | |
| | |
| | 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]) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | 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") |
| |
|
| | |
| | |
| | lib_dropdown.change(load_file_preview, lib_dropdown, preview_player) |
| | |
| | |
| | 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] |
| | ) |
| |
|
| | |
| | if __name__ == "__main__": |
| | app.launch( |
| | auth=(config.APP_USER, config.APP_PASS), |
| | server_name="0.0.0.0", |
| | server_port=7860 |
| | ) |