Download app.py from sg123321/xtts67: direct link, hf CLI and curl.
- Browser
- Download file 8.6 kB
-
https://huggingface.co/spaces/sg123321/xtts67/resolve/main/app.py
- Command line
-
hf download hf://spaces/sg123321/xtts67/app.py
-
curl -L -o app.py https://huggingface.co/spaces/sg123321/xtts67/resolve/main/app.py
8.6 kB
| 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 | |
| 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 | |
| ) |