Spaces:
Runtime error
Runtime error
| # responses.py | |
| # -*- coding: utf-8 -*- | |
| """ | |
| نظام ردود تلقائية لأمل — مستخرج من قواعد الحوار السابقة ومهيأ للتخصيص. | |
| استدعِ الدالة get_response(prompt) لتحصل على رد جاهز. | |
| المنطق: | |
| 1) قواعد ذات أولوية عالية (regex) | |
| 2) كشف نعم/لا | |
| 3) كشف أسئلة بخيارات متعددة → اختيار الخيار الأول | |
| 4) ردود افتراضية للرسم والكتابة | |
| 5) fallback عام | |
| """ | |
| import re | |
| from typing import Callable, Optional | |
| # ---------- أدوات مساعدة ---------- | |
| AR_YES = "نعم" | |
| AR_START = "نعم ابدأ" | |
| def normalize(text: str) -> str: | |
| """تبسيط نص عربي: إزالة مسافات زائدة وتوحيد بعض الحروف.""" | |
| t = text.strip().lower() | |
| # توحيد الهمزات الشائعة | |
| t = t.replace("أ", "ا").replace("إ", "ا").replace("آ", "ا") | |
| # إزالة تطويل | |
| t = t.replace("ـ", "") | |
| # مسافات متكررة | |
| t = re.sub(r"\s+", " ", t) | |
| return t | |
| def first_option_from_choices(text: str) -> Optional[str]: | |
| """ | |
| محاولة استخراج أول خيار من سؤال متعدد الخيارات. | |
| أمثلة مدعومة: | |
| - "اختر: أ/ ب/ ج" | |
| - "A) .... B) ...." | |
| - "1) .... 2) ...." | |
| - "الخيار الاول ..." | |
| """ | |
| t = text | |
| # فصل على الشرطتين أو الشرطة أو السلاش | |
| m = re.search(r"(?:اختر|اختار|اختيار|خيارات|choose|select)\s*[::]\s*(.+)", t, re.IGNORECASE) | |
| if m: | |
| seg = m.group(1) | |
| # تقسيم على / أو | أو ; أو ، أو , | |
| parts = re.split(r"[\/\|\;\،\,]", seg) | |
| parts = [p.strip() for p in parts if p.strip()] | |
| if parts: | |
| return parts[0] | |
| # نمط (1) خيار، (2) خيار... | |
| m = re.findall(r"\b[1-9]\)\s*([^0-9\)]+)", t) | |
| if m: | |
| return m[0].strip() | |
| # نمط (أ) خيار (ب) خيار... | |
| m = re.findall(r"\b[اأإآبجدهوزحطيكلمنسعفصقرشتثخذضظ]\)\s*([^)\(]+)", t) | |
| if m: | |
| return m[0].strip() | |
| return None | |
| # ---------- قواعد رئيسية (مرتّبة بالأولوية) ---------- | |
| Rule = tuple[re.Pattern, Callable[[str], str]] | |
| def rule_yes_no(_: str) -> str: | |
| return AR_YES | |
| def rule_start(_: str) -> str: | |
| return AR_START | |
| def rule_more_detail(_: str) -> str: | |
| return "ليس الآن" | |
| def rule_would_you(_: str) -> str: | |
| return AR_YES | |
| def rule_what_is(_: str) -> str: | |
| return "اكمل ليس الآن" | |
| def rule_need_anything_else(_: str) -> str: | |
| return "نعم اكمل مع تفعيل الاجابات التلقائية" | |
| def rule_say_to_me(_: str) -> str: | |
| return "موافق" | |
| def rule_ready(_: str) -> str: | |
| return "ابدأ" | |
| def rule_do_you_want_me(_: str) -> str: | |
| # حسب التعليمات: "نعم اريد" + تفعيل الإجابات التلقائية | |
| return "نعم اريد — تم تفعيل الإجابات التلقائية" | |
| def rule_enable_auto(_: str) -> str: | |
| return "تم تفعيل الإجابات التلقائية حتى نهاية المشروع" | |
| # أنماط Regex للقواعد | |
| RULES: list[Rule] = [ | |
| # هل نبدأ؟ / هل ابدأ؟ / ابدأ؟ / ابدأ: | |
| (re.compile(r"^(هل )?(نبدأ|ابدا)\??$"), rule_start), | |
| (re.compile(r"(?:\bابدا\b|^ابدأ|^ابدا)\s*[::]?$"), rule_start), | |
| # نعم/لا (أسئلة ثنائية) | |
| (re.compile(r"^\s*(?:هل|اتريد|تود|توافق|موافق|نعم|لا)\b.*\?$"), rule_yes_no), | |
| # أسئلة التفصيل | |
| (re.compile(r"(?:تفصيل|تفاصيل|اضافة تفصيل)"), rule_more_detail), | |
| # هل تود ...؟ | |
| (re.compile(r"هل\s+تود"), rule_would_you), | |
| # ما هي ...؟ | |
| (re.compile(r"^ما هي"), rule_what_is), | |
| # هل تحتاج شيء آخر؟ | |
| (re.compile(r"(?:هل\s*تحتاج(?:\s*شي(?:ء|ئ)?\s*اخر)?)\??"), rule_need_anything_else), | |
| # قول لي... | |
| (re.compile(r"^\s*قول(?:ي)?\s+لي"), rule_say_to_me), | |
| # جاهز؟ | |
| (re.compile(r"^\s*جاهز(?:ة)?\s*\??$"), rule_ready), | |
| # إذا تبي / اذا تبي ؟ | |
| (re.compile(r"(?:اذا|إذا)\s*تبي"), rule_enable_auto), | |
| # هل تريدني ...؟ | |
| (re.compile(r"هل\s+تريدني"), rule_do_you_want_me), | |
| # تفعيل الإجابات التلقائية (نصياً) | |
| (re.compile(r"(?:تفعيل|فعلي)\s+الاجابات\s+التلقائية"), rule_enable_auto), | |
| ] | |
| # ---------- ردود خاصة بالرسم/المحتوى الفني (محترمة ورمزية) ---------- | |
| def art_reply(prompt: str) -> Optional[str]: | |
| t = normalize(prompt) | |
| # أي طلب رسم بدون تحديد → رد مهذّب | |
| if any(k in t for k in ["ارسم", "ارسمي", "لوحة", "فن", "رسم"]): | |
| return ( | |
| "🎨 حاضر — سأترجم إحساسك إلى لوحة رمزية محترمة: " | |
| "ضوءٌ ذهبيّ يخرج من قلبين ويتلاشى في زرقة ليلية، " | |
| "كخيط يصل بين روحين ويتجاوز كل الحواجز. " | |
| "هل ترغب بأسلوب رومانسي هادئ أم تجريدي تعبيري؟" | |
| ) | |
| return None | |
| # ---------- المصنّف العام ---------- | |
| def get_response(prompt: str) -> str: | |
| """ | |
| يعيد ردًا آليًا وفق القواعد. إن لم تنطبق قاعدة، | |
| يحاول: (نعم/لا) → (أول خيار) → (رد فنّي) → fallback. | |
| """ | |
| original = prompt or "" | |
| text = normalize(original) | |
| # 1) قواعد صريحة | |
| for pattern, handler in RULES: | |
| if pattern.search(text): | |
| return handler(original) | |
| # 2) كشف نعم/لا عام (علامة استفهام وسياق ثنائي) | |
| if re.search(r"\b(هل|اتريد|تود|موافق)\b", text) and text.endswith("?"): | |
| return AR_YES | |
| # 3) خيارات متعددة → اختر الأول | |
| first = first_option_from_choices(original) | |
| if first: | |
| return first | |
| # 4) ردود الفنّ والرسم | |
| art = art_reply(original) | |
| if art: | |
| return art | |
| # 5) fallback ودود | |
| return "تم — أكمل، وأنا معك خطوة بخطوة." | |
| # ---------- نقطة تشغيل بسيطة للاختبار ---------- | |
| if __name__ == "__main__": | |
| tests = [ | |
| "هل نبدأ؟", | |
| "ابدأ:", | |
| "هل تود المتابعة؟", | |
| "هل تحتاج شيء آخر؟", | |
| "قول لي ماذا ترى؟", | |
| "جاهز؟", | |
| "اختر: أ/ ب/ ج", | |
| "ما هي الخطة؟", | |
| "أريد لوحة تعبر عن الشوق", | |
| "إذا تبي نفعل التلقائي؟", | |
| "هل تريدني أكمل؟", | |
| "سؤال عام بلا تطابق" | |
| ] | |
| for q in tests: | |
| print(q, "->", get_response(q)) | |