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()