| """ |
| app.py – Gradio TTS Space (Arabic only) |
| يدعم: Piper · Supertonic-3 · Chatterbox Multilingual |
| """ |
| import sys |
| print("=== app.py starting ===", flush=True) |
|
|
| |
| _import_errors = [] |
|
|
| try: |
| import onnxruntime |
| print(f"[ok] onnxruntime {onnxruntime.__version__}", flush=True) |
| except Exception as e: |
| _import_errors.append(f"onnxruntime: {e}") |
|
|
| try: |
| from piper import PiperVoice |
| print("[ok] piper", flush=True) |
| except Exception as e: |
| _import_errors.append(f"piper: {e}") |
|
|
| try: |
| from supertonic import TTS as _ST |
| print("[ok] supertonic", flush=True) |
| except Exception as e: |
| _import_errors.append(f"supertonic: {e}") |
|
|
| try: |
| from engines import generate_audio, MODELS_CONFIG |
| print("[ok] engines", flush=True) |
| except Exception as e: |
| _import_errors.append(f"engines: {e}") |
| print(f"[FATAL] engines import failed: {e}", flush=True) |
| sys.exit(1) |
|
|
| if _import_errors: |
| print("[WARNING] بعض الـ imports فشلت:", flush=True) |
| for err in _import_errors: |
| print(f" - {err}", flush=True) |
|
|
| |
| import os |
| import wave |
| import tempfile |
| import gradio as gr |
|
|
| MODEL_DESCRIPTIONS = { |
| "Piper – ar (Arabic)": "🎙️ Piper VITS · ONNX CPU · عربي فصحى (أردني)", |
| "Supertonic-3 – M1 (Arabic)": "⚡ Supertonic-3 · صوت ذكر · عربي", |
| "Supertonic-3 – F1 (Arabic)": "⚡ Supertonic-3 · صوت أنثى · عربي", |
| "Chatterbox Multilingual – ar": "🔊 Chatterbox ML · ONNX · عربي", |
| } |
|
|
| MODEL_NAMES = list(MODELS_CONFIG.keys()) |
|
|
|
|
| def update_desc(model_name): |
| return MODEL_DESCRIPTIONS.get(model_name, "") |
|
|
|
|
| def run_tts(model_name, text): |
| if not model_name: |
| return None, "❌ اختر موديل أولاً" |
| if not text or not text.strip(): |
| return None, "❌ اكتب نصاً أولاً" |
|
|
| try: |
| tmp = tempfile.NamedTemporaryFile(suffix=".wav", delete=False) |
| out_path = tmp.name |
| tmp.close() |
|
|
| print(f"[run_tts] model={model_name!r} text={text[:60]!r}", flush=True) |
|
|
| generate_audio(model_name, text, out_path) |
|
|
| exists = os.path.exists(out_path) |
| size = os.path.getsize(out_path) if exists else -1 |
| print(f"[run_tts] exists={exists} size={size}", flush=True) |
|
|
| if not exists or size <= 44: |
| return None, f"❌ الملف فارغ أو غير موجود (size={size})" |
|
|
| |
| try: |
| with wave.open(out_path, "r") as wf: |
| frames = wf.getnframes() |
| rate = wf.getframerate() |
| print(f"[run_tts] WAV frames={frames} rate={rate} dur={frames/rate:.2f}s", flush=True) |
| if frames == 0: |
| return None, "❌ WAV header موجود بس مفيش audio — راجع terminal" |
| except Exception: |
| |
| pass |
|
|
| return out_path, f"✅ تم التوليد ({size // 1024} KB)" |
|
|
| except Exception as e: |
| import traceback |
| print(f"[run_tts] ERROR:\n{traceback.format_exc()}", flush=True) |
| return None, f"❌ خطأ: {e}" |
|
|
|
|
| |
| with gr.Blocks( |
| title="🎙️ TTS عربي – Piper · Supertonic-3 · Chatterbox", |
| theme=gr.themes.Soft(primary_hue="indigo"), |
| ) as demo: |
|
|
| gr.Markdown(""" |
| # 🎙️ مقارنة نماذج TTS العربية |
| **Piper · Supertonic-3 · Chatterbox Multilingual** |
| |
| كل النماذج تعمل على CPU عبر ONNX Runtime. |
| أول تشغيل لكل نموذج يحمّله من HuggingFace تلقائياً. |
| """) |
|
|
| with gr.Row(): |
| with gr.Column(scale=1): |
| model_dropdown = gr.Dropdown( |
| choices=MODEL_NAMES, |
| value=MODEL_NAMES[0], |
| label="🤖 اختر النموذج", |
| ) |
| model_desc = gr.Markdown( |
| value=MODEL_DESCRIPTIONS.get(MODEL_NAMES[0], ""), |
| ) |
| text_input = gr.Textbox( |
| label="📝 النص العربي", |
| placeholder="اكتب النص هنا …", |
| lines=5, |
| rtl=True, |
| ) |
| generate_btn = gr.Button("🔊 توليد الصوت", variant="primary") |
|
|
| with gr.Column(scale=1): |
| audio_out = gr.Audio( |
| label="🎵 الصوت المولّد", |
| type="filepath", |
| show_download_button=True, |
| interactive=False, |
| ) |
| status_out = gr.Markdown(value="") |
|
|
| model_dropdown.change( |
| fn=update_desc, |
| inputs=[model_dropdown], |
| outputs=[model_desc], |
| ) |
| generate_btn.click( |
| fn=run_tts, |
| inputs=[model_dropdown, text_input], |
| outputs=[audio_out, status_out], |
| ) |
|
|
| gr.Markdown(""" |
| --- |
| ### 📦 ملاحظات |
| - **Piper**: يحتاج `espeak-ng` مثبّتاً على النظام |
| - **Supertonic-3**: ~400MB عند أول تحميل |
| - **Chatterbox ML**: ~2GB عند أول تحميل |
| """) |
|
|
|
|
| if __name__ == "__main__": |
| demo.launch() |