| | import os |
| | import uuid |
| | import gradio as gr |
| | import torch |
| | import spaces |
| | from TTS.api import TTS |
| | from supabase import create_client, Client |
| | import config |
| |
|
| | |
| | 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) |
| |
|
| | |
| | def get_voice_list(): |
| | if not supabase: return [] |
| | try: |
| | res = supabase.storage.from_("voice-bucket").list() |
| | files = [f['name'] for f in res if f['name'].endswith(('.wav', '.mp3'))] |
| | return files |
| | except Exception as e: |
| | return [] |
| |
|
| | def download_cloud_voice(filename): |
| | local_path = f"temp_{filename}" |
| | with open(local_path, 'wb+') as f: |
| | res = supabase.storage.from_("voice-bucket").download(filename) |
| | f.write(res) |
| | return local_path |
| |
|
| | |
| | @spaces.GPU(duration=120) |
| | def generate_preview(text, language, upload_voice, cloud_voice_name): |
| | speaker_wav = None |
| | if upload_voice is not None: |
| | speaker_wav = upload_voice |
| | elif cloud_voice_name: |
| | try: |
| | speaker_wav = download_cloud_voice(cloud_voice_name) |
| | except Exception as e: |
| | return None, f"Error downloading: {e}" |
| | else: |
| | return None, "β οΈ Please select a voice!" |
| |
|
| | output_path = "preview.wav" |
| | tts.tts_to_file(text=text, file_path=output_path, speaker_wav=speaker_wav, language=language) |
| | return output_path, "β
Preview Ready!" |
| |
|
| | def save_to_cloud(preview_path, text, language): |
| | if not preview_path or not os.path.exists(preview_path): |
| | return "β οΈ No preview found!" |
| | if not supabase: |
| | return "β Supabase not connected!" |
| |
|
| | filename = f"final_{language}_{uuid.uuid4()}.wav" |
| | try: |
| | with open(preview_path, 'rb') as f: |
| | supabase.storage.from_("voice-bucket").upload(filename, f) |
| | |
| | storage_url = f"{config.SUPABASE_URL}/storage/v1/object/public/voice-bucket/{filename}" |
| | |
| | data = {"name": f"Clone_{language}", "file_path": storage_url, "ref_text": text} |
| | supabase.table("clones").insert(data).execute() |
| | |
| | return f"π Saved! Link: {storage_url}" |
| | except Exception as e: |
| | return f"β Save Error: {e}" |
| |
|
| | |
| | with gr.Blocks(title="Shubham's Secure Voice AI") as app: |
| | gr.Markdown("## π Secure XTTS Voice Cloning") |
| | |
| | with gr.Row(): |
| | with gr.Column(): |
| | txt_input = gr.Textbox(label="Text", lines=3, value="Namaste!") |
| | lang_dropdown = gr.Dropdown(label="Language", choices=["hi", "en"], value="hi") |
| | with gr.Column(): |
| | voice_upload = gr.Audio(label="Upload Voice", type="filepath") |
| | voice_dropdown = gr.Dropdown(label="Select from Cloud", choices=get_voice_list()) |
| | refresh_btn = gr.Button("π Refresh List") |
| |
|
| | btn_preview = gr.Button("π Generate Preview", variant="primary") |
| | audio_output = gr.Audio(label="Preview") |
| | status_msg = gr.Textbox(label="Status") |
| | btn_save = gr.Button("βοΈ Save to Cloud", variant="secondary") |
| |
|
| | |
| | refresh_btn.click(lambda: gr.Dropdown(choices=get_voice_list()), outputs=voice_dropdown) |
| | btn_preview.click(generate_preview, inputs=[txt_input, lang_dropdown, voice_upload, voice_dropdown], outputs=[audio_output, status_msg]) |
| | btn_save.click(save_to_cloud, inputs=[audio_output, txt_input, lang_dropdown], outputs=status_msg) |
| |
|
| | |
| | if __name__ == "__main__": |
| | app.launch( |
| | auth=(config.APP_USER, config.APP_PASS), |
| | server_name="0.0.0.0", |
| | server_port=7860 |
| | ) |