| import gradio as gr |
| import edge_tts |
| import tempfile |
| import asyncio |
|
|
| |
| VOICE_MAP = { |
| "رجل (مصري)": "ar-EG-ShakirNeural", |
| "سيدة (مصرية)": "ar-EG-SalmaNeural", |
| "رجل (سعودي)": "ar-SA-HamedNeural", |
| "سيدة (سعودية)": "ar-SA-ZariyahNeural", |
| "English (US) M": "en-US-EricNeural", |
| "English (US) F": "en-US-AriaNeural" |
| } |
|
|
| async def generate_speech(text, voice, emotion, is_symbol, rate, pitch): |
| if not text or not text.strip(): return None |
| |
| |
| final_rate = rate if rate and isinstance(rate, str) and len(rate.strip()) > 0 else "+0%" |
| final_pitch = pitch if pitch and isinstance(pitch, str) and len(pitch.strip()) > 0 else "+0Hz" |
| |
| |
| selected_voice = "ar-SA-HamedNeural" |
| if voice in VOICE_MAP: selected_voice = VOICE_MAP[voice] |
| elif voice in VOICE_MAP.values(): selected_voice = voice |
| |
| print(f"Generating: {len(text)} chars | {selected_voice} | {final_rate} | {final_pitch}") |
|
|
| try: |
| output_file = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) |
| output_path = output_file.name |
| output_file.close() |
| |
| communicate = edge_tts.Communicate(text, selected_voice, rate=final_rate, pitch=final_pitch) |
| await communicate.save(output_path) |
| return output_path |
| except Exception as e: |
| print(f"ERROR: {str(e)}") |
| raise gr.Error(f"TTS Error: {str(e)}") |
|
|
| |
| with gr.Blocks(title="Natiq Pro API") as demo: |
| with gr.Row(visible=False): |
| t = gr.Textbox(label="Text") |
| v = gr.Textbox(label="Voice") |
| e = gr.Textbox(label="Emotion", value="neutral") |
| s = gr.Checkbox(label="Is Symbol", value=True) |
| r = gr.Textbox(label="Rate", value="+0%") |
| p = gr.Textbox(label="Pitch", value="+0Hz") |
| |
| o = gr.Audio(label="Output", type="filepath") |
| b = gr.Button("Generate", visible=False) |
| |
| |
| b.click(generate_speech, inputs=[t,v,e,s,r,p], outputs=[o], api_name="text_to_speech_edge") |
|
|
| if __name__ == "__main__": |
| demo.queue().launch() |