TTS / app.py
OsamaCoooooll's picture
Update app.py
1a323ee verified
from google import genai
from google.genai import types
import os
import wave
import tempfile
import gradio as gr
import requests
# ─── 1. Read & validate API key from environment ────────────────────────────────
api_key = os.getenv("GOOGLE_API_KEY")
eleven_api_key = os.getenv("ELEVEN_API_KEY")
if not eleven_api_key:
raise ValueError("Environment variable 'GOOGLE_API_KEY' غير موجود.")
if not api_key:
raise ValueError("Environment variable 'ELEVEN_API_KEY' غير موجود.")
# ─── 2. Instantiate the new Gen AI client ───────────────────────────────────────
client = genai.Client(api_key=api_key)
# ─── 3. Helper to write raw PCM bytes into a .wav file ───────────────────────────
def wave_file(pcm_bytes: bytes, channels: int = 1, rate: int = 24000, sample_width: int = 2) -> str:
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_file:
with wave.open(tmp_file.name, "wb") as wf:
wf.setnchannels(channels)
wf.setsampwidth(sample_width)
wf.setframerate(rate)
wf.writeframes(pcm_bytes)
return tmp_file.name
# ─── 4. Attribute descriptions (assumed imported in Arabic) ─────────────────────
tone_descriptions = {
"دافئة ومبهجة": "استخدم نبرة ودودة وجذابة. تحدث بنغمة مبهجة مع ابتسامة طفيفة في الصوت وإيقاع إيجابي يشعر المستمعين بالترحيب والراحة.",
"جدية": "اعتمد أسلوبًا رصينًا وسلطويًا. حافظ على استقرار في النغمة وتحدث بوتيرة معتدلة لإيصال الجدية.",
"متحمسة": "أضف طاقة عالية في كل عبارة. استخدم تغييرات ديناميكية في النغمة مع سرعة في الإلقاء لإيصال الحماس.",
"هادئة": "تحدث بإيقاع ناعم وثابت. حافظ على نغمة لطيفة وتجنب تغييرات مفاجئة لخلق تأثير مريح.",
"حزينة": "اخفض النغمة وقلل السرعة قليلًا. استخدم نغمة حزينة تعكس الأسى أو الشوق.",
"غاضبة": "زد من حدة الصوت واستخدم نغمة حادة. تحدث بسرعة وبحدة لتوصيل الغضب دون أن تكون قاسيًا.",
"ودودة": "استخدم نغمة دافئة ومحاكية للحوار. تحدث بإيقاع طبيعي ونغمة جذابة وكأنك تتحدث مع صديق.",
"متعاطفة": "استخدم نبرة ناعمة وحنونة. قلل الحدة قليلاً وتحدث برقة لتظهر التعاطف.",
"ساخرة": "استخدم نبرة مبالغ فيها قليلاً مع لمسة من التهكم. أبطئ في نهاية بعض الكلمات وغيّر النغمة للإشارة إلى السخرية.",
"رومانسية": "تحدث بنغمة ناعمة ودافئة. استخدم إيقاعًا بطيئًا مع عاطفة واضحة لإيصال الحميمية.",
"واثقة": "حافظ على صوت قوي وواضح. استخدم نغمة ثابتة وإلقاء واضح لعرض الثقة بالنفس.",
"محايدة": "تحدث بنبرة متوازنة دون عاطفة. استخدم وتيرة ثابتة وصوت معتدل.",
"مرحة": "أضف لمسة من الدعابة في الإلقاء. استخدم توقيتًا ذكيًا وتغييرات خفيفة في النغمة لخلق طابع مرح.",
"درامية": "استخدم تعبيرًا قويًا مع تغييرات واسعة في النغمة. قف عند اللحظات المهمة وأبرز الكلمات الرئيسية.",
"مشجعة": "اعتمد نبرة إيجابية وداعمة. استخدم نغمة صاعدة في الكلمات الإيجابية وحافظ على دفء في الإلقاء.",
"فضولية": "تحدث بنغمة فضولية. ارفع النغمة في نهاية الجمل وأضف وقفات خفيفة وكأنك تتساءل.",
"ملهمة": "استخدم نغمة قوية وملهمة. تحدث بإيقاع مقصود مع نغمة تصاعدية في العبارات المحفزة.",
"متوترة": "استخدم إلقاء سريع ومضغوط. تحدث بنغمة حادة وقِف قليلًا لإيصال الإلحاح.",
"كئيبة": "اخفض النغمة وسرعة الحديث. تحدث بإيقاع حزين مع وقفات طويلة تعكس الحزن.",
"متفائلة": "ارفع النغمة في نهاية الجمل. استخدم نغمة دافئة وإلقاء معتدل لإيصال الأمل."
}
tempo_descriptions = {
"بطيء جدًا": "انطق كل كلمة بوضوح وبتأنٍ شديد. حافظ على وتيرة بطيئة لتسهيل الاستيعاب.",
"بطيء": "تحدث بسرعة أبطأ من المعتاد مع وقفات خفيفة بين الجمل لزيادة الوضوح.",
"عادي": "استخدم سرعة الحديث المعتادة (حوالي 120–150 كلمة في الدقيقة). تحدث بشكل طبيعي وكأنك في محادثة يومية.",
"سريع": "زد السرعة إلى حوالي 160–180 كلمة في الدقيقة، مع الحفاظ على الوضوح لنقل الحماس.",
"سريع جدًا": "تحدث بسرعة تفوق 180 كلمة في الدقيقة. انطق بوضوح ولكن بسرعة مناسبة للمعلومات العاجلة.",
"متغير": "غيّر السرعة بين الكلمات: أبطئ في النقاط المهمة وسرّع في العبارات المكررة لخلق تدفق طبيعي."
}
clarity_descriptions = {
"واضح جدًا": "انطق كل صوت بوضوح تام. حافظ على سرعة معتدلة وتجنب التمتمة أو السهو.",
"واضح": "استخدم وضوحًا عاليًا في النطق مع بعض الانسيابية الطبيعية في الحديث.",
"متوسط": "استخدم وضوحًا تقليديًا كما في الحديث اليومي. يمكن أن تمتزج بعض الحروف بشكل طبيعي.",
"غير واضح قليلًا": "استخدم نطقًا غير رسمي مع بعض الاسترخاء في الحروف أو إسقاطها بشكل بسيط.",
"ناعم ولطيف": "اخفض مستوى الصوت وتحدث بلطف. انطق الكلمات بهدوء لإضفاء طابع حميمي.",
"متمتم": "انطق الكلمات بصوت منخفض مع وضوح أقل. يمكن أن تمتزج الكلمات ببعضها.",
"حاد وواضح": "أبرز الحروف الساكنة بقوة مع نطق دقيق. استخدم نغمة واضحة وقوية.",
"بنبرة هوائية": "أضف بعض الهواء في الصوت أثناء النطق. تحدث بلطف وبهمس خفيف.",
"بهمس": "تحدث بصوت منخفض جدًا مع إغلاق جزئي للأوتار الصوتية. يصلح للحديث السري أو القريب جدًا.",
"مرتفع وواضح": "استخدم صوتًا قويًا وواضحًا مع نبرة بارزة. نطق كل كلمة بثقة وحزم."
}
style_descriptions = {
"تحفيزي وغير رسمي": "تحدث بأسلوب ودي ومشجع. استخدم لغة غير رسمية مع نبرة إيجابية ملهمة.",
"رسمي": "اعتمد لغة مهنية ومنظمة. تحدث بنبرة محترمة دون استخدام العامية أو الاختصارات.",
"روائي": "استخدم أسلوب قصصي مع تغييرات في النغمة وتوقفات درامية لجذب المستمع.",
"مهني": "تحدث بلغة عمل واضحة ومحايدة. حافظ على نغمة واثقة دون عاطفة زائدة.",
"حواري": "اعتمد أسلوبًا عفويًا وغير رسمي. تحدث كما لو كنت في محادثة ودية.",
"أكاديمي": "استخدم لغة دقيقة ومصطلحات واضحة. تحدث بأسلوب محاضرة هادئ ومركز.",
"إقناعي": "تحدث بثقة وحماس. أبرز النقاط المهمة بنغمة صاعدة وأسلوب مقنع.",
"وصفي": "استخدم نغمة توضيحية مع إبراز الصفات والكلمات الحسية.",
"تفسيري": "اعتمد أسلوبًا تعليميًا واضحًا. قسم المعلومات إلى خطوات وتحدث بتأنٍ.",
"نقاشي": "استخدم نغمة قوية ومتحدية. زد من سرعة الحديث أثناء الردود وشدد على النقاط الجدلية.",
"شعري": "تحدث بإيقاع لحني وجمالي. أطِل في نطق الحروف وامنح الحديث طابعًا غنائيًا.",
"نشرة إخبارية": "استخدم نغمة محايدة وواضحة. تحدث بوضوح وبدون عاطفة، كما في الأخبار.",
"تعليمي": "تحدث بأسلوب منظم وواضح. استخدم توقفات قصيرة بين الخطوات للمساعدة في الفهم.",
"سرد خارجي (شخص ثالث)": "تحدث كراوٍ خارجي. غيّر النغمة للحوار وابقَ على وتيرة متزنة.",
"شهادة شخصية": "استخدم نغمة صادقة وشخصية. تحدث وكأنك تروي تجربة حقيقية.",
"أسلوب مقابلة": "قلد نمط سؤال وجواب. ارفع نغمة السؤال، ثم انزلها في الجواب مع توقفات طبيعية.",
"مرِح وعفوي": "استخدم نبرة مرحة ومبالغ فيها قليلًا. غير السرعة والنغمة لإضافة حس فكاهي.",
"تقني ودقيق": "استخدم نبرة حيادية ومصطلحات دقيقة. تحدث بثبات وبدون تغييرات كبيرة في النغمة.",
"فلسفي": "استخدم نبرة تأملية وهادئة. تحدث بإيقاع بطيء وتوقفات طويلة لإيصال العمق الفكري.",
"روحي أو ديني": "استخدم نغمة مطمئنة ومحترمة. تحدث بلطف واحترام لإيصال الشعور الروحي."
}
# accent_descriptions = {
# "العربية الفصحى": (
# "نطق رسمي وواضح، مع الالتزام الكامل بعلامات التشكيل مثل الضم والفتح والكسر. "
# "الحروف المفخمة مثل ص، ط، ق تُنطق بقوة ووضوح، دون تليين أو اختصار. "
# "مخارج الحروف دقيقة ومحافظة، خاصة في العين، الحاء، الغين، والخاء. "
# "الإيقاع متزن ومعتدل، النبرة محايدة وجادة، تشبه أداء نشرات الأخبار أو تلاوة القرآن. "
# "يُتجنب تماماً استخدام التعابير المحكية أو العامية."
# ),
# "المصرية": (
# "نطق الجيم ناعم ومفتوح، أقرب إلى 'zh' (كما في كلمة 'جميل'). "
# "القاف تُنطق غالباً همزة، خاصة في وسط الكلمة: 'قال' تُصبح 'آل'. "
# "الإيقاع مرن ومتنوع، مع نبرة صوت صاعدة قليلاً في نهاية الجمل الاستفهامية أو التعجبية. "
# "نبرة الصوت ودودة وعفوية، تميل إلى الفكاهة والخفة في الأداء. "
# "التلفظ سريع نسبياً، مع سلاسة ومدّ بسيط أحيانًا في النهايات."
# ),
# "الشامية": (
# "القاف غالبًا ما تتحول إلى همزة ناعمة: 'قلب' تُنطق 'ألب'. "
# "الراء تُنطق بخفة دون تفخيم، وتظهر بوضوح في نهايات الكلمات. "
# "يتم تمطيط الحروف الصوتية في كلمات مثل 'كتير'، مع مدّ خفيف يدل على اللين والهدوء. "
# "نبرة الصوت هادئة، رقيقة، وتميل للانخفاض في نهاية الجملة. "
# "الإيقاع متوازن وناعم، مع تسلسل موسيقي بسيط يعطي إحساسًا بالارتياح والود."
# ),
# "السورية": (
# "نطق القاف كهمزة واضح، خاصة في المحادثة اليومية: 'قال' تُلفظ 'آل'. "
# "النبرة مستقرة ودافئة، مع بعض التمطيط اللطيف في كلمات مثل 'تمام التمام'. "
# "الصوت يُستخدم بنغمة معتدلة تميل للهدوء، دون تغييرات حادة في طبقة الصوت. "
# "الإيقاع سلس، مريح، ويظهر فيه الاتزان في تشكيل الجمل والنبرات. "
# "المقاطع تُلفظ بشكل واضح لكن غير مشدد، ما يعطي انطباعاً بالبساطة والود."
# ),
# "اللبنانية": (
# "لهجة موسيقية بإيقاع صاعد وهابط، يتغير حسب العاطفة أو نوع الجملة. "
# "القاف تُخفف إلى همزة، والنطق يكون ناعمًا وسلسًا. "
# "الراء تُنطق بخفة، وأحيانًا بترجيع بسيط يجعلها مميزة في الأداء. "
# "سرعة الكلام متوسطة إلى سريعة، مع وضوح المقاطع وإبراز نهايات الجمل بتغييرات لحنية ملحوظة. "
# "نبرة الصوت ناعمة، عاطفية، ومعبّرة، ما يجعلها جذابة في الأداء الصوتي وتناسب النصوص الحوارية أو العاطفية."
# ),
# "الفلسطينية": (
# "نطق واضح ودقيق لمخارج الحروف، مع ميل لتخفيف القاف إلى همزة في الكلام العامّي. "
# "الراء تُفخم أحيانًا بشكل طفيف، خاصة عند التأكيد أو الانفعال. "
# "الإيقاع متزن وجاد نسبياً، مع نبرة مستقرة تميل إلى الثبات في نهاية الجمل. "
# "النغمة الصوتية واضحة ومباشرة، وتُظهر درجة من الجدية والانضباط في الأداء. "
# "الكلمات تُلفظ بطريقة كاملة مع وضوح التشكيل عند الحاجة دون مبالغة."
# ),
# "الأردنية": (
# "قريبة من الفلسطينية لكن بنبرة أكثر رسمية وثباتاً. "
# "القاف غالبًا تُفخم وتُلفظ بوضوح، بخلاف اللهجات الشامية الأخرى. "
# "نبرة الصوت مستقيمة، جدية، وفيها نوع من الوقار والهدوء، مع استخدام نغمة معتدلة في جميع الجمل. "
# "الإيقاع منتظم ومتحكم به، دون مبالغة في التغيير اللحني، ويُظهر وضوحًا في النطق والحزم في الأداء. "
# "مثالية للنصوص الرسمية أو الخطاب التقريري بأسلوب عامّي خفيف."
# ),
# "الخليجية": (
# "القاف تُنطق بوضوح ومفخمة، مما يعطي طابعًا قويًا للنبرة. "
# "الذال تتحول أحيانًا إلى د حسب السياق: 'ذهب' → 'دَهَب'. "
# "الإيقاع بطيء نسبياً ومستقر، مع نغمة رزينة ونبرة منخفضة. "
# "الصوت يميل إلى الرسمية والاحترام، وتُلفظ الكلمات بطريقة محافظة مع استخدام تعبيرات محلية أصيلة. "
# "النبرة العامة رصينة وتقليدية، تعكس شخصية هادئة وواثقة."
# ),
# "السعودية": (
# "تشمل لهجتين أساسيتين: نجدية (وسطى) وحجازية (غربية)، وتميل بشكل عام إلى نطق القاف بوضوح. "
# "نبرة الصوت واضحة ومفهومة، وتستخدم طبقة متوسطة إلى منخفضة، مع نغمة ترحيبية مألوفة. "
# "الإيقاع معتدل، لا هو سريع ولا بطيء، مع تغير طفيف في النبرة في الجمل الطويلة. "
# "اللهجة تُظهر رسمية معتدلة، ويمكن استخدامها بمرونة سواء في الحديث العفوي أو النص الرسمي."
# ),
# "الإماراتية": (
# "لهجة محافظة وناعمة، تُستخدم فيها القاف بوضوح دون تليين. "
# "الكلمات تُلفظ برتابة موسيقية خفيفة، والنبرة الصوتية ثابتة وهادئة. "
# "الإيقاع بطيء إلى معتدل، مع تفخيم خفيف لبعض الحروف مثل الراء والصاد حسب السياق. "
# "تُستخدم طبقة صوت متوسطة، ولا يُكثر من تغيير النغمة، مما يعطي الأداء طابعًا وقورًا وبسيطًا. "
# "مناسبة لنصوص فيها خصوصية ثقافية أو طابع رسمي تقليدي."
# ),
# "الكويتية": (
# "نطق مميز وواضح خاصة في القاف والصاد، مع ميل طفيف للتفخيم. "
# "القاف تُلفظ غالبًا بقوة في بداية الكلمة، وتُظهر جديّة في الأداء. "
# "الإيقاع متوسط إلى بطيء، مع استخدام نغمة مرحة أو ودودة خصوصًا في الجمل التفاعلية. "
# "الصوت يحمل مزيجًا من الرسمية والعفوية، مما يجعله مناسبًا للمواقف اليومية أو الخطابات شبه الرسمية. "
# "الميل لنغمة صاعدة في نهاية الجملة يُضفي على الأداء طابعًا حيًا دون مبالغة."
# ),
# "القطرية": (
# "نغمة صوت أعمق قليلاً من الإماراتية، مع نطق واضح للحروف، خصوصًا الذال والثاء. "
# "القاف تُلفظ مفخمة وبشكل تقليدي دون تليين. "
# "الإيقاع بطيء نسبياً، والكلام يتم بنبرة هادئة ورزينة. "
# "تُستخدم طبقات صوت منخفضة تعكس الوقار، ويُظهر الأداء وضوحًا في مخارج الحروف مع تجنب السرعة. "
# "مثالية لنصوص تُظهر الاحترام والرسمية والبُعد الثقافي المحلي."
# ),
# "البحرينية": (
# "لهجة موسيقية بطابع خاص، تتغير فيها طبقة الصوت بسلاسة، مع نغمة خفيفة تُظهر الارتياح والتلقائية. "
# "القاف تُلفظ أحياناً 'چ'، خاصة في اللهجة الشعبية. "
# "الإيقاع متنوع، ويتراوح بين السرعة في الجمل الحماسية والبطء في العبارات التفسيرية. "
# "نبرة الصوت مرنة، وتُظهر دفئاً اجتماعياً وودّياً، مناسبة للنصوص الحوارية والعاطفية. "
# "الأداء يُفضّل فيه بعض التمطيط الخفيف في نهايات الكلمات للتعبير."
# ),
# "العمانية": (
# "نبرة محافظة ومتماسكة، تعتمد على وضوح مخارج الحروف دون مبالغة. "
# "القاف والثاء تُلفظ بوضوح تام، مما يعطي اللهجة طابعاً فصيحاً نسبياً. "
# "الإيقاع بطيء إلى معتدل، مع طبقة صوت منخفضة ومتوازنة. "
# "الصوت يُستخدم بوقار، دون تغييرات لحنية حادة، ما يضيف هيبة واستقراراً للنبرة العامة. "
# "مناسبة للحوارات الرسمية أو المواد ذات الطابع التراثي والوقور."
# ),
# "اليمنية": (
# "لهجة صنعانية أو تعزية بنغمة صوت مرتفعة قليلاً مقارنة بالخليجية، مع نطق واضح ومفخّم للقاف. "
# "النغمة ديناميكية وتميل للتغيير السريع، مما يُضفي نشاطاً وحيوية على الأداء. "
# "الإيقاع سريع نسبياً، والكلمات غالباً تُلفظ بكثافة وتتابع، مع تكرار لبعض التعابير لزيادة التأكيد. "
# "الصوت يظهر فيه حماس ومباشرة، ومناسب للحوارات الحيّة أو السرد القصصي الشعبي. "
# "المقاطع تُنطق كاملة دون حذف، رغم سرعة الأداء، مما يجعلها فصيحة بطريقتها الخاصة."
# ),
# "العراقية": (
# "القاف تُلفظ 'گ' بوضوح، وتُعطي الكلمة نغمة قوية وعميقة. "
# "الأداء الصوتي غني بالتنويع، مع تغييرات نغمية واضحة حسب الانفعال والمعنى. "
# "نغمة الصوت فيها دفء عاطفي عند الحديث الودي، وقوة درامية في الجمل الجادة. "
# "الإيقاع متوسط السرعة، ويميل إلى استخدام تعبيرات صوتية لإيصال المشاعر. "
# "اللهجة مناسبة جداً للنصوص التي تتطلب تعبيرًا غنيًا وحضورًا صوتيًا قويًا."
# ),
# "المغاربية": (
# "لهجة سريعة الإيقاع، تتداخل فيها عناصر من الفرنسية والأمازيغية، وتُلفظ بعض الحروف مثل القاف كـ 'گ'. "
# "الجمل قصيرة وسريعة، مع نغمة صوت صاخبة ونشطة. "
# "النطق يميل إلى اختزال المقاطع، ما يجعل الأداء سريعًا ومباشرًا. "
# "يُستخدم الكثير من الكلمات المستعارة ونطقها بأسلوب محلي. "
# "النبرة العامة قوية، ديناميكية، وغير تقليدية، ومناسبة لنصوص ترفيهية أو شبابية."
# ),
# "المغربية": (
# "لهجة فرعية من المغاربية، لكن أسرع إيقاعًا وأكثر حيوية. "
# "القاف تُنطق 'گ' غالبًا، وتُختصر بعض الحروف أو تُدمج داخل الجملة. "
# "الإيقاع سريع جداً، مع نغمة صوت قوية وتعبيرية. "
# "يُكثر من الكلمات المختصرة، وتُظهر النبرة استقلالية واختزالًا في التوصيل. "
# "مثالية للمواقف اليومية أو السياقات الحية، لكن تتطلب تبسيطًا في النص المكتوب كي يسهل تحويله إلى كلام مسموع بوضوح."
# ),
# "الجزائرية": (
# "تتضمن الكثير من الكلمات الفرنسية، مع نغمة صوتية سريعة وجدية. "
# "الأداء الصوتي غالبًا مباشر وقوي، مع إيقاع متقطع. "
# "الحروف تُنطق بجفاف نسبي، والنغمة تميل إلى الرسمية والحدة في بعض الأحيان. "
# "النبرة العامة لا تتغير كثيراً، ما يضيف طابعًا حازمًا للأداء. "
# "مناسبة للنصوص ذات الطابع الرسمي أو الخطابي، حيث يُراد إيصال الجدية والانضباط."
# ),
# "السودانية": (
# "نغمة صوت مريحة ومتمهلة، مع ميل واضح لتمطيط الحروف الصوتية. "
# "القاف تُنطق أحياناً 'غ' في الكلام الشعبي، مما يضفي طابعاً خاصاً ومميزاً. "
# "الإيقاع بطيء نسبياً، مع استخدام صوت هادئ ومنخفض النغمة. "
# "الأداء الصوتي يميل إلى الهدوء والسلاسة، ما يجعله مناسباً للسرد أو التعليم أو الرسائل الودية. "
# "اللهجة تحمل طابعاً دافئاً وبسيطاً، يوصل المعنى دون تعقيد أو تكلف."
# ),
# "الحجازية": (
# "نطق القاف واضح وصريح، دون تفخيم مبالغ فيه، ويُحافظ على فصاحته نسبياً. "
# "النغمة رخيمة ومتزنة، تُستخدم طبقات صوت مريحة مع وضوح في مخارج الحروف. "
# "الإيقاع معتدل، لا يميل للسرعة أو البطء، مع تغييرات خفيفة في النبرة حسب العاطفة. "
# "اللهجة تتميّز بالودّ والتهذيب، مع نبرة ترحيبية مألوفة. "
# "مناسبة للحوارات الاجتماعية والروايات الصوتية الهادئة."
# ),
# "النجدية": (
# "نغمة رزينة وواضحة، تتميز بثبات طبقة الصوت وقوة نطق القاف والمفخّمات. "
# "النبرة رسمية قليلاً، وتعكس طابعًا تقليديًا محترمًا في الأداء الصوتي. "
# "الإيقاع ثابت ومتوازن، دون مبالغة في التنغيم أو التمطيط. "
# "تُستخدم للخطابات الجادة أو النصوص التعليمية والشرعية بأسلوب شعبي. "
# "اللهجة مناسبة للنصوص التي تتطلب وضوحًا وقوة في التوصيل."
# ),
# "الحضرمية": (
# "نطق القاف يتحول إلى 'گ'، مع طبقة صوت منخفضة وهادئة. "
# "نغمة مميزة تميل إلى البطء والتأني، وتعكس طابعًا وقورًا ومحافظًا. "
# "الأداء الصوتي سلس، والكلمات تُنطق بشكل كامل دون اختزال. "
# "الإيقاع بطيء نسبيًا، مما يناسب النصوص الروحية أو السردية الهادئة. "
# "اللهجة تُضفي شعورًا بالطمأنينة والتواضع في النبرة."
# ),
# "الحسانية": (
# "لهجة مميزة تُستخدم فيها نغمة منخفضة ومتمهلة، مع تمديد واضح للأصوات الطويلة. "
# "الكلمات تُنطق ببطء ووضوح، مع نبرة صوت معتدلة وثابتة. "
# "القاف تُلفظ بوضوح، دون تليين، مع استخدام نبرة تقليدية فصيحة في بعض السياقات. "
# "الإيقاع هادئ، يُناسب النصوص التعليمية أو الأدبية. "
# "اللهجة تُحافظ على الإرث العربي الأصيل في طريقة النطق."
# ),
# "العربية التشادية": (
# "نطق بسيط ومباشر، يُقارب الفصحى مع ميل للوضوح والسهولة في الكلمات. "
# "الأداء الصوتي مبسّط وسلس، مع غياب التعقيدات النغمية أو التمطيط. "
# "الإيقاع معتدل، مناسب للمواد التوعوية أو التعليمية. "
# "الحروف تُنطق بوضوح، ولا يتم اختصارها كثيرًا، مع تجنّب المفردات العامّية الثقيلة. "
# "النبرة الصوتية حيادية، مما يجعلها سهلة الفهم لمجموعة واسعة من المستمعين."
# ),
# "عربية جوبا": (
# "لهجة مبسطة مع الكثير من الكلمات المختصرة، تتأثر بالإنجليزية واللغات المحلية. "
# "نغمة مرحة وخفيفة، مع سرعة واضحة في الأداء. "
# "الكلمات تُلفظ بأسلوب مباشر وغير رسمي، وغالباً تُختصر المقاطع. "
# "الإيقاع سريع نسبياً، مما يعطي طابعًا نشيطًا ومناسبًا للمواقف اليومية أو الشبابية. "
# "النبرة الصوتية ودودة وتلقائية، ما يُناسب النصوص الخفيفة أو الحوارية."
# ),
# "المالطية": (
# "مزيج فريد بين العربية القديمة والإيطالية، مع نطق متأثر بالصوت الأوروبي. "
# "القاف تُخفف غالبًا، والحروف الصوتية تُلفظ بأسلوب إيطالي واضح. "
# "الإيقاع سريع إلى متوسط، والنغمة تُظهر حيوية وتغيّر لحني متكرر. "
# "الصوت ديناميكي، يُظهر تأثرًا بالثقافة اللاتينية، مع وضوح في نهاية الجمل. "
# "مناسبة للنصوص الحركية، السياحية، أو التفاعلية."
# ),
# }
accent_descriptions = {
"العربية الفصحى": "استخدم النطق بالعربية الفصحى.",
"المصرية": "استخدم اللهجة المصرية.",
"الشامية": "استخدم اللهجة الشامية.",
"السورية": "استخدم اللهجة السورية الشامية.",
"اللبنانية": "استخدم اللهجة اللبنانية.",
"الفلسطينية": "استخدم اللهجة الفلسطينية.",
"الأردنية": "استخدم اللهجة الأردنية.",
"الخليجية": "استخدم اللهجة الخليجية.",
"السعودية": "استخدم اللهجة السعودية.",
"الإماراتية": "استخدم اللهجة الإماراتية.",
"الكويتية": "استخدم اللهجة الكويتية.",
"القطرية": "استخدم اللهجة القطرية.",
"البحرينية": "استخدم اللهجة البحرينية.",
"العمانية": "استخدم اللهجة العمانية.",
"اليمنية": "استخدم اللهجة اليمنية.",
"العراقية": "استخدم اللهجة العراقية.",
"المغاربية": "استخدم اللهجة المغاربية.",
"المغربية": "استخدم اللهجة المغربية.",
"الجزائرية": "استخدم اللهجة الجزائرية.",
"السودانية": "استخدم اللهجة السودانية.",
"الحجازية": "استخدم اللهجة الحجازية.",
"النجدية": "استخدم اللهجة النجدية.",
"الحضرمية": "استخدم اللهجة الحضرمية.",
"الحسانية": "استخدم اللهجة الحسانية.",
"العربية التشادية": "استخدم اللهجة التشادية.",
"عربية جوبا": "استخدم لهجة جوبا.",
"المالطية": "استخدم اللهجة المالطية."
}
voice_name_map = {
"سارة": "Achernar",
"سامي": "Achird",
"كريم": "Algenib",
"فهد": "Algieba",
"يوسف": "Alnilam",
"رنا": "Aoede",
"نورا": "Autonoe",
"جنى": "Callirrhoe",
"بدر": "Charon",
"فرح": "Despina",
"حاتم": "Enceladus",
"أنس": "Fenrir",
"هالة": "Gacrux",
"مالك": "Iapetus",
"إياد": "Orus",
"راكان": "Puck",
"هيثم": "Sadachbia",
"نادر": "Sadaltager",
"وليد": "Schedar",
"سمية": "Zephyr",
"دعاء": "Erinome",
"أميرة": "Laomedeia",
"بتول": "Kore",
"زينب": "Leda",
"باسل": "Pulcherrima",
"حسام": "Umbriel",
"ياسمين": "Vindemiatrix",
"طارق": "Zubenelgenubi",
"لينا": "Sulafat",
"مازن": "Rasalgethi"
}
# ─── Additional helper function ──────────────────────────────────────────────
def convert_text_to_dialect(text: str, accent: str) -> str:
"""Uses Gemini 2.0 Flash model to rewrite the text into a specified dialect."""
prompt = f"""
قم بتحويل النص التالي إلى لهجة {accent} مع الحفاظ على نفس المعنى وعدد الجمل.
عدّل فقط الكلمات والتعابير لتتناسب مع اللهجة المطلوبة.
الرجاء إرسال النص الناتج فقط دون أي شروحات أو تعليقات إضافية.
النص:
{text}
"""
response = client.models.generate_content(
model="gemini-2.0-flash",
contents=[prompt],
config=types.GenerateContentConfig(
temperature=0.3,
max_output_tokens=1000
)
)
return response.text.strip()
# ─── 5. Main TTS-generation function ─────────────────────────────────────────────
def generate_audio(
model_choice: str,
language: str,
accent: str,
tone: str,
speed: str,
clarity: str,
style: str,
convert_method: str,
speaker_mode: str,
speaker1_name: str,
speaker1_voice: str,
speaker2_name: str,
speaker2_voice: str,
text: str,
voice_name: str,
premium_voice_id: str,
extra_prompt: str,
) -> tuple:
tone_desc = tone_descriptions.get(tone, tone)
speed_desc = tempo_descriptions.get(speed, speed)
clarity_desc = clarity_descriptions.get(clarity, clarity)
style_desc = style_descriptions.get(style, style)
accent_desc = accent_descriptions.get(accent, f"استخدم لهجة {accent} الطبيعية.")
header = f"""
[اللغة]: تحدث بـ {language}، وتأكد من أن جميع التعبيرات والمفردات تتماشى مع الاستخدام الطبيعي للغة.
[نبرة الصوت]: {tone_desc}
[سرعة الكلام]: {speed_desc}
[الوضوح]: {clarity_desc}
[الأسلوب]: {style_desc}
[اللهجة]: {accent_desc}
""".strip()
conversion_instruction = ""
converted_text = text
if convert_method == "تحويل بسيط":
conversion_instruction = (
f"[تحويل]: قم فقط بتعديل المفردات والتعابير لتتناسب مع اللهجة {accent} "
"دون تغيير المعنى أو حذف/إضافة جمل."
)
if convert_method == "تحويل متطور":
converted_text = convert_text_to_dialect(text, accent)
speaker_instruction = ""
if speaker_mode == "عدة أصوات":
speaker_instruction = (
"[تعليمات]: لا تنطق أسماء المتحدثين (مثل: خالد، سارة) أثناء قراءة النص. "
"استخدم صوت كل متحدث حسب اسمه فقط."
)
if convert_method == "تحويل بسيط":
text_instruction = (
"[المهمة]: اقرأ النص التالي مع تطبيق تعليمات التحويل البسيط مع الالتزام بالسمات المذكورة أعلاه. "
"لا تقرأ التعليمات. "
"توقف برهة عند علامات الترقيم (مثل الفاصلة، النقطة، النقطتين)، "
"وتوقف تام عند الانتقال إلى سطر جديد كما يفعل القارئ الطبيعي."
)
else:
text_instruction = (
"[المهمة]: اقرأ النص التالي فقط كما هو مكتوب، مع الالتزام بالسمات المذكورة أعلاه. "
"لا تقرأ التعليمات، ولا تقم بتعديله أو إعادة تفسيره. "
"توقف برهة عند علامات الترقيم (مثل الفاصلة، النقطة، النقطتين)، "
"وتوقف تام عند الانتقال إلى سطر جديد كما يفعل القارئ الطبيعي."
)
full_prompt = f"{header}"
if conversion_instruction:
full_prompt += f"\n\n{conversion_instruction}"
if speaker_instruction:
full_prompt += f"\n\n{speaker_instruction}"
if extra_prompt.strip():
full_prompt += f"\n[ملاحظات إضافية]: {extra_prompt.strip()}"
full_prompt += f"\n\n{text_instruction}\n\n[النص]:\n{converted_text}"
if speaker_mode == "عدة أصوات":
speaker1_real_voice = voice_name_map.get(speaker1_voice, speaker1_voice)
speaker2_real_voice = voice_name_map.get(speaker2_voice, speaker2_voice)
response = client.models.generate_content(
model=model_choice,
contents=full_prompt,
config=types.GenerateContentConfig(
response_modalities=["AUDIO"],
speech_config=types.SpeechConfig(
multi_speaker_voice_config=types.MultiSpeakerVoiceConfig(
speaker_voice_configs=[
types.SpeakerVoiceConfig(
speaker=speaker1_name.strip(),
voice_config=types.VoiceConfig(
prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name=speaker1_real_voice)
)
),
types.SpeakerVoiceConfig(
speaker=speaker2_name.strip(),
voice_config=types.VoiceConfig(
prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name=speaker2_real_voice)
)
)
]
)
),
)
)
else:
voice_name_real = voice_name_map.get(voice_name, voice_name)
response = client.models.generate_content(
model=model_choice,
contents=full_prompt,
config=types.GenerateContentConfig(
response_modalities=["AUDIO"],
speech_config=types.SpeechConfig(
voice_config=types.VoiceConfig(
prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name=voice_name_real)
)
),
),
)
pcm_data = response.candidates[0].content.parts[0].inline_data.data
wav_path = wave_file(pcm_data)
if premium_voice_id == "":
return wav_path, converted_text if convert_method == "تحويل متطور" else ""
else:
url = f"https://api.elevenlabs.io/v1/speech-to-speech/{premium_voice_id}"
headers = {"xi-api-key": eleven_api_key}
with open(wav_path, "rb") as audio_file:
files = {"audio": audio_file}
data = {"model_id": "eleven_multilingual_sts_v2", "output_format": "mp3_44100_128"}
response = requests.post(url, headers=headers, files=files, data=data)
if response.ok:
with open("output.mp3", "wb") as f:
f.write(response.content)
return "output.mp3", converted_text if convert_method == "تحويل متطور" else ""
else:
return wav_path, converted_text if convert_method == "تحويل متطور" else ""
# ─── 6. Gradio UI (Arabic) ──────────────────────────────────────────────────────
model_choices = ["gemini-2.5-flash-preview-tts", "gemini-2.5-pro-preview-tts"]
language_choices = ["العربية", "الإنجليزية", "الفرنسية"]
tone_choices = list(tone_descriptions.keys())
speed_choices = list(tempo_descriptions.keys())
clarity_choices = list(clarity_descriptions.keys())
style_choices = list(style_descriptions.keys())
voice_name_choices = list(voice_name_map.keys())
accent_choices = list(accent_descriptions.keys())
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("## 🎤 مولد الصوت باستخدام Gemini")
with gr.Row():
with gr.Column():
model_choice = gr.Dropdown(model_choices, value=model_choices[0], label="نموذج Gemini")
language = gr.Dropdown(language_choices, value=language_choices[0], label="اللغة")
accent = gr.Dropdown(accent_choices, value=accent_choices[0], label="اللهجة")
convert_method = gr.Dropdown(
label="طريقة تحويل النص إلى اللهجة",
choices=["بدون تحويل", "تحويل بسيط", "تحويل متطور"],
value="بدون تحويل"
)
tone = gr.Dropdown(tone_choices, value=tone_choices[0], label="النبرة / الشعور")
speed = gr.Dropdown(speed_choices, value=speed_choices[2], label="سرعة الكلام")
clarity = gr.Dropdown(clarity_choices, value=clarity_choices[1], label="وضوح الصوت")
style = gr.Dropdown(style_choices, value=style_choices[0], label="الأسلوب")
speaker_mode = gr.Radio(["صوت واحد", "عدة أصوات"], value="صوت واحد", label="وضع المتحدثين")
with gr.Row(visible=True) as single_speaker_input:
voice_name = gr.Dropdown(voice_name_choices, value=voice_name_choices[0], label="اختر اسم المتحدث (في حالة صوت واحد)")
with gr.Row(visible=False) as speaker_inputs:
with gr.Column():
speaker1_name = gr.Textbox(label="اسم المتحدث الأول", value="سارة")
speaker1_voice = gr.Dropdown(voice_name_choices, value=voice_name_choices[23], label="صوت المتحدث الأول")
with gr.Column():
speaker2_name = gr.Textbox(label="اسم المتحدث الثاني", value="خالد")
speaker2_voice = gr.Dropdown(voice_name_choices, value=voice_name_choices[24], label="صوت المتحدث الثاني")
premium_voice_id = gr.Textbox(label="معرف الصوت المميز (اختياري)")
extra_prompt = gr.Textbox(label="تعليمات إضافية للنموذج (اختياري)", lines=2)
with gr.Column():
text = gr.Textbox(
label="النص المطلوب نطقه",
lines=6
)
converted_output_text = gr.Textbox(
label="النص بعد تحويله للهجة المطلوبة",
lines=6,
visible=False
)
output = gr.Audio(label="الصوت الناتج", type="filepath")
generate_btn = gr.Button("🎧 توليد الصوت")
def toggle_inputs(mode):
if mode == "عدة أصوات":
new_text = (
"خالد: مرحباً، كيف كان يومك يا سارة؟\n"
"سارة: بخير الحمد لله، وأنت؟\n"
"خالد: بخير, اليوم عثرت على الكتاب الذي كنت أبحث عنه منذ فترة طويلة\n"
"سارة: سعيدة لسماع هذا!"
)
return gr.update(visible=False), gr.update(visible=True), gr.update(value=new_text)
else:
new_text = (
"في يوم من الأيام، قرر سامي أن يغادر بلدته الصغيرة ليبحث عن فرصة عمل في المدينة الكبيرة. "
"كان يشعر بالقلق والخوف من المجهول، لكنه كان يعلم أن عليه أن يخوض هذه التجربة ليحقق أحلامه. "
"ودّع والدته التي أوصته بأن يبقى على تواصل دائم معها، وأن لا ينسى القيم التي نشأ عليها. "
"عندما وصل إلى المدينة، صُدم من صخبها واختلاف نمط الحياة فيها. حاول التأقلم، لكنه واجه صعوبات كثيرة في البداية، "
"خاصةً في التعامل مع الناس وفهم لهجتهم المختلفة. ومع ذلك، لم يفقد الأمل، وظل يبحث عن فرصة تُناسب مهاراته وطموحاته."
)
return gr.update(visible=True), gr.update(visible=False), gr.update(value=new_text)
speaker_mode.change(
fn=toggle_inputs,
inputs=speaker_mode,
outputs=[single_speaker_input, speaker_inputs, text]
)
def handle_generate_audio(*args):
audio_path, converted_text = generate_audio(*args)
return audio_path, gr.update(value=converted_text, visible=bool(converted_text))
text.value = (
"في يوم من الأيام، قرر سامي أن يغادر بلدته الصغيرة ليبحث عن فرصة عمل في المدينة الكبيرة. "
"كان يشعر بالقلق والخوف من المجهول، لكنه كان يعلم أن عليه أن يخوض هذه التجربة ليحقق أحلامه. "
"ودّع والدته التي أوصته بأن يبقى على تواصل دائم معها، وأن لا ينسى القيم التي نشأ عليها. "
"عندما وصل إلى المدينة، صُدم من صخبها واختلاف نمط الحياة فيها. حاول التأقلم، لكنه واجه صعوبات كثيرة في البداية، "
"خاصةً في التعامل مع الناس وفهم لهجتهم المختلفة. ومع ذلك، لم يفقد الأمل، وظل يبحث عن فرصة تُناسب مهاراته وطموحاته."
)
generate_btn.click(
fn=handle_generate_audio,
inputs=[
model_choice,
language,
accent,
tone,
speed,
clarity,
style,
convert_method,
speaker_mode,
speaker1_name,
speaker1_voice,
speaker2_name,
speaker2_voice,
text,
voice_name,
premium_voice_id,
extra_prompt
],
outputs=[output, converted_output_text]
)
demo.launch()