hamza2923 commited on
Commit
3c38334
·
verified ·
1 Parent(s): 6bf1c66

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +182 -63
app.py CHANGED
@@ -1,74 +1,193 @@
1
  import gradio as gr
2
- import pyttsx3
 
3
  import os
4
- import warnings
5
 
6
- # Suppress pygame welcome message
7
- with warnings.catch_warnings():
8
- warnings.simplefilter("ignore")
9
- import pygame
10
-
11
- def get_voices():
12
- """Initialize engine and get available voices with error handling"""
13
  try:
14
- engine = pyttsx3.init()
15
- voices = engine.getProperty('voices')
16
- return {f"{voice.name} ({voice.languages[0] if voice.languages else 'Unknown'})": voice.id
17
- for voice in voices}
18
  except Exception as e:
19
- print(f"Error initializing TTS engine: {e}")
20
- # Return a default voice if engine fails
21
- return {"Default Voice": None}
22
 
23
- # Get available voices
24
- voice_map = get_voices()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
- def text_to_speech(text, voice_name, rate=200):
27
- """
28
- Convert text to speech with selected voice and rate.
29
- Saves output as an audio file and returns the file path.
30
- """
31
- try:
32
- # Initialize engine for each call
33
- engine = pyttsx3.init()
34
-
35
- # Set voice if available
36
- voice_id = voice_map.get(voice_name)
37
- if voice_id:
38
- engine.setProperty('voice', voice_id)
39
-
40
- # Set speech rate
41
- engine.setProperty('rate', rate)
42
-
43
- # Save audio to a file
44
- output_file = "output.wav"
45
- engine.save_to_file(text, output_file)
46
- engine.runAndWait()
47
-
48
- # Ensure file exists before returning
49
- if os.path.exists(output_file):
50
- return output_file
51
- return None
52
- except Exception as e:
53
- print(f"Error in text_to_speech: {e}")
54
- return None
55
 
56
- # Gradio interface
57
- with gr.Blocks(title="Text-to-Speech with Different Voices") as demo:
58
- gr.Markdown("# Text-to-Speech Converter")
59
- gr.Markdown("Enter text and select a voice to convert it to speech with different voices and accents.")
60
-
61
- text_input = gr.Textbox(label="Enter Text", placeholder="Type your text here...")
62
- voice_dropdown = gr.Dropdown(choices=list(voice_map.keys()), label="Select Voice/Accent", value=list(voice_map.keys())[0] if voice_map else None)
63
- rate_slider = gr.Slider(minimum=100, maximum=300, value=200, step=10, label="Speech Rate")
64
-
65
- convert_button = gr.Button("Convert to Speech")
66
- audio_output = gr.Audio(label="Generated Speech")
67
-
68
- convert_button.click(
69
- fn=text_to_speech,
70
- inputs=[text_input, voice_dropdown, rate_slider],
71
- outputs=audio_output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  )
73
 
74
  if __name__ == "__main__":
 
1
  import gradio as gr
2
+ import edge_tts
3
+ import asyncio
4
  import os
5
+ from typing import Dict
6
 
7
+ async def generate_speech(text: str, voice: str) -> str:
8
+ """Generate speech from text using the specified voice"""
 
 
 
 
 
9
  try:
10
+ communicate = edge_tts.Communicate(text, voice)
11
+ output_file = "output.mp3"
12
+ await communicate.save(output_file)
13
+ return output_file
14
  except Exception as e:
15
+ print(f"Error: {e}")
16
+ return None
 
17
 
18
+ # Expanded list of voices organized by language and gender
19
+ VOICES: Dict[str, str] = {
20
+ # English (US)
21
+ "Jenny (Female, US)": "en-US-JennyNeural",
22
+ "Guy (Male, US)": "en-US-GuyNeural",
23
+ "Aria (Female, US)": "en-US-AriaNeural",
24
+ "Davis (Male, US)": "en-US-DavisNeural",
25
+ "Jane (Female, US)": "en-US-JaneNeural",
26
+ "Jason (Male, US)": "en-US-JasonNeural",
27
+ "Nancy (Female, US)": "en-US-NancyNeural",
28
+ "Tony (Male, US)": "en-US-TonyNeural",
29
+ "Sara (Female, US)": "en-US-SaraNeural",
30
+ "Brandon (Male, US)": "en-US-BrandonNeural",
31
+
32
+ # English (UK)
33
+ "Libby (Female, UK)": "en-GB-LibbyNeural",
34
+ "Ryan (Male, UK)": "en-GB-RyanNeural",
35
+ "Sonia (Female, UK)": "en-GB-SoniaNeural",
36
+ "Thomas (Male, UK)": "en-GB-ThomasNeural",
37
+
38
+ # English (Australia)
39
+ "Natasha (Female, AU)": "en-AU-NatashaNeural",
40
+ "William (Male, AU)": "en-AU-WilliamNeural",
41
+
42
+ # English (India)
43
+ "Neerja (Female, IN)": "en-IN-NeerjaNeural",
44
+ "Prabhat (Male, IN)": "en-IN-PrabhatNeural",
45
+
46
+ # Spanish
47
+ "Elvira (Female, ES)": "es-ES-ElviraNeural",
48
+ "Alvaro (Male, ES)": "es-ES-AlvaroNeural",
49
+ "Ana (Female, AR)": "es-AR-AnaNeural",
50
+ "Tomas (Male, AR)": "es-AR-TomasNeural",
51
+ "Camila (Female, MX)": "es-MX-CamilaNeural",
52
+ "Jorge (Male, MX)": "es-MX-JorgeNeural",
53
+
54
+ # French
55
+ "Denise (Female, FR)": "fr-FR-DeniseNeural",
56
+ "Henri (Male, FR)": "fr-FR-HenriNeural",
57
+ "Sylvie (Female, CA)": "fr-CA-SylvieNeural",
58
+ "Antoine (Male, CA)": "fr-CA-AntoineNeural",
59
+
60
+ # German
61
+ "Katja (Female, DE)": "de-DE-KatjaNeural",
62
+ "Conrad (Male, DE)": "de-DE-ConradNeural",
63
+ "Amala (Female, CH)": "de-CH-AmalaNeural",
64
+ "Jan (Male, CH)": "de-CH-JanNeural",
65
+
66
+ # Italian
67
+ "Elsa (Female, IT)": "it-IT-ElsaNeural",
68
+ "Diego (Male, IT)": "it-IT-DiegoNeural",
69
+
70
+ # Portuguese
71
+ "Francisca (Female, PT)": "pt-PT-FranciscaNeural",
72
+ "Duarte (Male, PT)": "pt-PT-DuarteNeural",
73
+ "Yara (Female, BR)": "pt-BR-YaraNeural",
74
+ "Antonio (Male, BR)": "pt-BR-AntonioNeural",
75
+
76
+ # Japanese
77
+ "Nanami (Female, JP)": "ja-JP-NanamiNeural",
78
+ "Keita (Male, JP)": "ja-JP-KeitaNeural",
79
+
80
+ # Chinese
81
+ "Xiaoxiao (Female, CN)": "zh-CN-XiaoxiaoNeural",
82
+ "Yunyang (Male, CN)": "zh-CN-YunyangNeural",
83
+ "HsiaoChen (Female, TW)": "zh-TW-HsiaoChenNeural",
84
+ "YunJhe (Male, TW)": "zh-TW-YunJheNeural",
85
+
86
+ # Korean
87
+ "SunHi (Female, KR)": "ko-KR-SunHiNeural",
88
+ "InJoon (Male, KR)": "ko-KR-InJoonNeural",
89
+
90
+ # Russian
91
+ "Svetlana (Female, RU)": "ru-RU-SvetlanaNeural",
92
+ "Dmitry (Male, RU)": "ru-RU-DmitryNeural",
93
+
94
+ # Arabic
95
+ "Salma (Female, EG)": "ar-EG-SalmaNeural",
96
+ "Shakir (Male, EG)": "ar-EG-ShakirNeural",
97
+ "Hamed (Male, SA)": "ar-SA-HamedNeural",
98
+
99
+ # Hindi
100
+ "Swara (Female, IN)": "hi-IN-SwaraNeural",
101
+ "Madhur (Male, IN)": "hi-IN-MadhurNeural",
102
+
103
+ # And many more...
104
+ "Brigitte (Female, BE)": "fr-BE-BrigitteNeural",
105
+ "Gerard (Male, BE)": "fr-BE-GerardNeural",
106
+ "Finn (Male, NL)": "nl-NL-FinnNeural",
107
+ "Maarten (Male, NL)": "nl-NL-MaartenNeural",
108
+ "Sofie (Female, NL)": "nl-NL-SofieNeural",
109
+ }
110
 
111
+ def text_to_speech(text: str, voice: str) -> str:
112
+ """Wrapper function to run async code"""
113
+ return asyncio.run(generate_speech(text, voice))
114
+
115
+ def get_languages() -> list:
116
+ """Extract unique languages from voice names"""
117
+ languages = set()
118
+ for name in VOICES.keys():
119
+ if '(' in name and ')' in name:
120
+ lang = name.split('(')[1].split(')')[0]
121
+ languages.add(lang)
122
+ return sorted(languages)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
+ def filter_voices(language: str) -> Dict[str, str]:
125
+ """Filter voices by selected language"""
126
+ if not language or language == "All":
127
+ return VOICES
128
+ return {name: voice for name, voice in VOICES.items() if f"({language})" in name}
129
+
130
+ def update_voice_dropdown(language: str) -> Dict:
131
+ """Update voice dropdown based on selected language"""
132
+ filtered_voices = filter_voices(language)
133
+ return gr.Dropdown.update(
134
+ choices=list(filtered_voices.keys()),
135
+ value=list(filtered_voices.keys())[0] if filtered_voices else None
136
+ )
137
+
138
+ with gr.Blocks(title="Multi-Voice Text-to-Speech", theme="soft") as demo:
139
+ gr.Markdown("""
140
+ # 🎤 Advanced Text-to-Speech Converter
141
+ ### With 100+ Voices Across Multiple Languages
142
+ """)
143
+
144
+ with gr.Row():
145
+ with gr.Column():
146
+ text_input = gr.Textbox(
147
+ label="Enter your text",
148
+ placeholder="Type or paste your text here...",
149
+ lines=5,
150
+ max_lines=10
151
+ )
152
+
153
+ with gr.Row():
154
+ language_filter = gr.Dropdown(
155
+ ["All"] + get_languages(),
156
+ label="Filter by Language",
157
+ value="All"
158
+ )
159
+ voice_dropdown = gr.Dropdown(
160
+ list(VOICES.keys()),
161
+ label="Select Voice",
162
+ value="Jenny (Female, US)"
163
+ )
164
+
165
+ generate_btn = gr.Button("Generate Speech", variant="primary")
166
+
167
+ with gr.Column():
168
+ audio_output = gr.Audio(label="Generated Speech", autoplay=True)
169
+ download_btn = gr.DownloadButton(
170
+ "Download Audio",
171
+ visible=False,
172
+ file_name="speech.mp3"
173
+ )
174
+
175
+ # Interactive components
176
+ language_filter.change(
177
+ update_voice_dropdown,
178
+ inputs=language_filter,
179
+ outputs=voice_dropdown
180
+ )
181
+
182
+ generate_btn.click(
183
+ text_to_speech,
184
+ inputs=[text_input, voice_dropdown],
185
+ outputs=[audio_output, download_btn]
186
+ )
187
+
188
+ audio_output.change(
189
+ lambda: gr.DownloadButton.update(visible=True),
190
+ outputs=download_btn
191
  )
192
 
193
  if __name__ == "__main__":