daswer123 commited on
Commit
0d5d091
1 Parent(s): 3863ab9

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +256 -0
  2. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import gradio as gr
3
+ import os
4
+ from typing import Optional
5
+ from dotenv import load_dotenv
6
+ from elevenlabs_wrapper import ElevenLabsManager
7
+
8
+ class ElevenLabsApp:
9
+ def __init__(self):
10
+ self.manager: Optional[ElevenLabsManager] = None
11
+ # Load API key from .env
12
+ load_dotenv()
13
+ self.api_key = os.getenv('ELEVENLABS_API_KEY')
14
+
15
+ # Try to validate API key on initialization
16
+ self.show_interface = False
17
+ self.initial_voices = []
18
+ if self.api_key:
19
+ try:
20
+ self.manager = ElevenLabsManager(api_key=self.api_key)
21
+ self.initial_voices = self.get_filtered_voices("all")
22
+ self.show_interface = True
23
+ except Exception as e:
24
+ print(f"Failed to validate initial API key: {str(e)}")
25
+
26
+ self.create_interface()
27
+
28
+ def validate_api_key(self, api_key: str):
29
+ try:
30
+ self.manager = ElevenLabsManager(api_key=api_key)
31
+ voices = self.get_filtered_voices("all")
32
+ initial_voice = voices[0] if voices else None
33
+ return "API key validated successfully!", gr.update(visible=True), gr.update(visible=False), gr.update(choices=voices, value=initial_voice)
34
+ except Exception as e:
35
+ return f"Error: {str(e)}", gr.update(visible=False), gr.update(visible=True), gr.update(choices=[], value=None)
36
+
37
+ def get_filtered_voices(self, filter_type: str):
38
+ if not self.manager:
39
+ return []
40
+ voices = self.manager.get_voices(filter_type)
41
+ voice_list = [f"{voice['name']} ({voice['category']})" for voice in voices]
42
+ return voice_list
43
+
44
+ def update_voice_list(self, filter_type: str):
45
+ voices = self.get_filtered_voices(filter_type)
46
+ initial_voice = voices[0] if voices else None
47
+ return gr.update(choices=voices, value=initial_voice)
48
+
49
+ def clone_voice(self, name: str, description: str, files):
50
+ if not self.manager:
51
+ return "Please validate API key first", None
52
+ try:
53
+ file_paths = [f.name for f in files]
54
+ voice_id = self.manager.clone_voice(name, file_paths, description)
55
+ voices = self.get_filtered_voices("all")
56
+ return f"Voice cloned successfully! Voice ID: {voice_id}", None
57
+ except Exception as e:
58
+ return f"Error cloning voice: {str(e)}", None
59
+
60
+ def delete_voice(self, voice_name: str):
61
+ if not self.manager or not voice_name:
62
+ return "Please select a voice to delete"
63
+ try:
64
+ voice_id = self.manager.find_voice_by_name(voice_name.split(" (")[0])
65
+ if voice_id:
66
+ success = self.manager.delete_voice(voice_id)
67
+ if success:
68
+ return "Voice deleted successfully!"
69
+ return "Failed to delete voice"
70
+ return "Voice not found"
71
+ except Exception as e:
72
+ return f"Error deleting voice: {str(e)}"
73
+
74
+ def set_model(self, model_name: str):
75
+ if not self.manager:
76
+ return "Please validate API key first"
77
+ try:
78
+ self.manager.set_model(model_name)
79
+ return f"Model changed to {model_name}"
80
+ except Exception as e:
81
+ return f"Error changing model: {str(e)}"
82
+
83
+ def generate_speech(self, text: str, voice_name: str, stability: float, similarity_boost: float, model: str):
84
+ if not self.manager:
85
+ return "Please validate API key first", None
86
+ try:
87
+ if not text.strip():
88
+ return "Please enter some text", None
89
+ if not voice_name:
90
+ return "Please select a voice", None
91
+
92
+ self.manager.set_stability(stability)
93
+ self.manager.set_similarity_boost(similarity_boost)
94
+ self.manager.set_model(model)
95
+ voice_id = self.manager.find_voice_by_name(voice_name.split(" (")[0])
96
+ audio = self.manager.generate_audio(text, voice_id)
97
+
98
+ filename = str(time.time()) + ".wav"
99
+ os.makedirs("temp", exist_ok=True)
100
+ output_path = os.path.join("temp", filename)
101
+ self.manager.save_audio(audio, output_path)
102
+
103
+ return "Speech generated successfully!", output_path
104
+ except Exception as e:
105
+ return f"Error generating speech: {str(e)}", None
106
+
107
+ def create_interface(self):
108
+ with gr.Blocks() as app:
109
+ gr.Markdown("# ElevenLabs Text-to-Speech Interface")
110
+
111
+ with gr.Row():
112
+ api_key_input = gr.Textbox(
113
+ label="Enter your ElevenLabs API key",
114
+ type="password",
115
+ placeholder="Enter API key here...",
116
+ value=self.api_key if self.api_key else ""
117
+ )
118
+ validate_btn = gr.Button("Validate API Key")
119
+ api_status = gr.Textbox(label="Status", interactive=False)
120
+
121
+ main_interface = gr.Column(visible=self.show_interface)
122
+ with main_interface:
123
+ with gr.Row():
124
+ with gr.Column(scale=2):
125
+ with gr.Accordion(label="Voice", open=True):
126
+ voice_filter = gr.Dropdown(
127
+ choices=["all", "cloned", "non-cloned"],
128
+ label="Filter Voices",
129
+ value="all"
130
+ )
131
+ with gr.Row():
132
+ voice_dropdown = gr.Dropdown(
133
+ label="Select Voice",
134
+ interactive=True,
135
+ choices=self.initial_voices,
136
+ value=self.initial_voices[0] if self.initial_voices else None
137
+ )
138
+ refresh_btn = gr.Button("Refresh Voices")
139
+ delete_btn = gr.Button("Delete Selected Voice")
140
+ delete_status = gr.Textbox(
141
+ label="Deletion Status",
142
+ interactive=False
143
+ )
144
+
145
+ with gr.Accordion("Voice Settings", open=False):
146
+ model_dropdown = gr.Dropdown(
147
+ choices=["eleven_turbo_v2_5", "eleven_multilingual_v2"],
148
+ value="eleven_turbo_v2_5",
149
+ label="Model"
150
+ )
151
+ stability = gr.Slider(
152
+ minimum=0,
153
+ maximum=1,
154
+ value=0.5,
155
+ label="Stability",
156
+ info="Higher values make the voice more consistent"
157
+ )
158
+ similarity_boost = gr.Slider(
159
+ minimum=0,
160
+ maximum=1,
161
+ value=0.75,
162
+ label="Similarity Boost",
163
+ info="Higher values make the voice more similar to the original"
164
+ )
165
+
166
+ with gr.Accordion("Clone New Voice", open=False):
167
+ clone_name = gr.Textbox(
168
+ label="Voice Name",
169
+ placeholder="Enter a name for your cloned voice"
170
+ )
171
+ clone_description = gr.Textbox(
172
+ label="Voice Description",
173
+ placeholder="Enter a description for your voice"
174
+ )
175
+ clone_files = gr.File(
176
+ label="Upload Audio Files",
177
+ file_count="multiple"
178
+ )
179
+ clone_btn = gr.Button("Clone Voice")
180
+ clone_status = gr.Textbox(
181
+ label="Cloning Status",
182
+ interactive=False
183
+ )
184
+
185
+ with gr.Column(scale=3):
186
+ text_input = gr.Textbox(
187
+ label="Text to Convert",
188
+ placeholder="Enter text here...",
189
+ lines=5
190
+ )
191
+ generate_btn = gr.Button("Generate Speech", variant="primary")
192
+ with gr.Row():
193
+ status_box = gr.Textbox(
194
+ label="Generation Status",
195
+ interactive=False
196
+ )
197
+ audio_output = gr.Audio(
198
+ label="Generated Speech",
199
+ type="filepath"
200
+ )
201
+
202
+ api_key_view = gr.Column(visible=not self.show_interface)
203
+ with api_key_view:
204
+ gr.Markdown("Please enter your API key to continue")
205
+
206
+ validate_btn.click(
207
+ fn=self.validate_api_key,
208
+ inputs=[api_key_input],
209
+ outputs=[api_status, main_interface, api_key_view, voice_dropdown]
210
+ )
211
+
212
+ voice_filter.change(
213
+ fn=self.update_voice_list,
214
+ inputs=[voice_filter],
215
+ outputs=[voice_dropdown]
216
+ )
217
+
218
+ refresh_btn.click(
219
+ fn=self.update_voice_list,
220
+ inputs=[voice_filter],
221
+ outputs=[voice_dropdown]
222
+ )
223
+
224
+ clone_btn.click(
225
+ fn=self.clone_voice,
226
+ inputs=[clone_name, clone_description, clone_files],
227
+ outputs=[clone_status, audio_output]
228
+ ).then(
229
+ fn=self.update_voice_list,
230
+ inputs=[voice_filter],
231
+ outputs=[voice_dropdown]
232
+ )
233
+
234
+ delete_btn.click(
235
+ fn=self.delete_voice,
236
+ inputs=[voice_dropdown],
237
+ outputs=[delete_status]
238
+ ).then(
239
+ fn=self.update_voice_list,
240
+ inputs=[voice_filter],
241
+ outputs=[voice_dropdown]
242
+ )
243
+
244
+ generate_btn.click(
245
+ fn=self.generate_speech,
246
+ inputs=[text_input, voice_dropdown, stability, similarity_boost, model_dropdown],
247
+ outputs=[status_box, audio_output]
248
+ )
249
+
250
+ return app
251
+
252
+ if __name__ == "__main__":
253
+ app = ElevenLabsApp()
254
+ app.create_interface().launch(
255
+ inbrowser=True
256
+ )
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ elevenlabs
3
+ python-dotenv