Spaces:
Running
Running
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() | |