Update app.py
Browse files
app.py
CHANGED
|
@@ -36,96 +36,133 @@ async def receive_updates(request: Request):
|
|
| 36 |
# ضمان إن الرجوع JSON دايمًا
|
| 37 |
return JSONResponse(content=result)
|
| 38 |
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
#
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
#
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
#
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
#
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
| 74 |
def process_text(user_text: str):
|
| 75 |
client = openai.OpenAI(api_key=api_key, base_url=base_url)
|
| 76 |
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
system_prompt = f"""
|
| 80 |
-
You are a helpful English grammar corrector for A1/A2 CEFR students.
|
| 81 |
-
Correct grammar, spelling, and literal translation mistakes.
|
| 82 |
-
If the input is only a list of words (not sentences), only correct spelling.
|
| 83 |
-
Return ONLY the revised text (no explanations).
|
| 84 |
-
"""
|
| 85 |
|
|
|
|
| 86 |
resp = client.chat.completions.create(
|
| 87 |
model=model_link,
|
| 88 |
messages=[
|
| 89 |
{"role": "system", "content": system_prompt},
|
| 90 |
{"role": "user", "content": user_text},
|
| 91 |
],
|
| 92 |
-
max_tokens=
|
| 93 |
-
temperature=0.
|
| 94 |
-
stream=False,
|
| 95 |
-
)
|
| 96 |
-
|
| 97 |
-
corrected_text = resp.choices[0].message.content.strip()
|
| 98 |
-
print("After correction:", corrected_text)
|
| 99 |
-
print("--------------------------------------")
|
| 100 |
-
|
| 101 |
-
except Exception as e:
|
| 102 |
-
# مهم جدًا: رجّع نص error مش object
|
| 103 |
-
return {"ok": False, "when": "During correcting sentences", "error": str(e)}
|
| 104 |
-
|
| 105 |
-
# 2) استخراج الأخطاء (diff)
|
| 106 |
-
try:
|
| 107 |
-
mistakes_prompt = f"""
|
| 108 |
-
Compare the user text and the corrected text, and list EVERY correction made.
|
| 109 |
-
Return ONLY a list of mistakes/corrections (no revised text).
|
| 110 |
-
|
| 111 |
-
User text: "{user_text}"
|
| 112 |
-
Corrected text: "{corrected_text}"
|
| 113 |
-
"""
|
| 114 |
-
|
| 115 |
-
resp2 = client.chat.completions.create(
|
| 116 |
-
model=model_link,
|
| 117 |
-
messages=[
|
| 118 |
-
{"role": "system", "content": "You are a grammar checker bot."},
|
| 119 |
-
{"role": "user", "content": mistakes_prompt},
|
| 120 |
-
],
|
| 121 |
-
max_tokens=800,
|
| 122 |
-
temperature=0,
|
| 123 |
stream=False,
|
| 124 |
)
|
| 125 |
|
| 126 |
-
|
| 127 |
|
| 128 |
-
|
|
|
|
| 129 |
|
| 130 |
except Exception as e:
|
| 131 |
-
return {"ok": False, "
|
|
|
|
| 36 |
# ضمان إن الرجوع JSON دايمًا
|
| 37 |
return JSONResponse(content=result)
|
| 38 |
|
| 39 |
+
import re
|
| 40 |
+
|
| 41 |
+
INTENTS = {
|
| 42 |
+
"GREETING": "تحية/بداية محادثة",
|
| 43 |
+
"COURSES_MENU": "طلب قائمة الكورسات",
|
| 44 |
+
"COURSE_TYPE_DETAILS": "سؤال عن نوع كورس محدد",
|
| 45 |
+
"CENTER_INFO": "سؤال عن المركز",
|
| 46 |
+
"CHILDREN_COURSES": "كورس أطفال",
|
| 47 |
+
"ONLINE_COURSES": "كورسات أونلاين",
|
| 48 |
+
"WEEKEND_COURSES": "كورسات ويكند",
|
| 49 |
+
"HUMAN_AGENT": "طلب خدمة عملاء/موظف",
|
| 50 |
+
"OTHER": "غير معروف/خارج النطاق",
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
def detect_intent(text: str) -> str:
|
| 54 |
+
t = (text or "").strip().lower()
|
| 55 |
+
|
| 56 |
+
# 1) Greetings
|
| 57 |
+
if re.search(r"\b(hi|hello|hey|start)\b", t) or any(x in t for x in ["اهلا", "أهلا", "السلام", "هاي", "مرحبا", "ابدأ", "ابدء"]):
|
| 58 |
+
return "GREETING"
|
| 59 |
+
|
| 60 |
+
# 2) Human agent
|
| 61 |
+
if any(x in t for x in ["خدمة العملاء", "موظف", "حد يرد", "اكلم", "اتواصل", "رقم", "واتساب", "support", "agent"]):
|
| 62 |
+
return "HUMAN_AGENT"
|
| 63 |
+
|
| 64 |
+
# 3) Courses menu / asking about courses generally
|
| 65 |
+
if any(x in t for x in ["كورسات", "دورات", "courses", "الكورسات المتاحة", "عايز كورس", "عايز اتعلم", "الالماني عندكم", "الماني"]):
|
| 66 |
+
return "COURSES_MENU"
|
| 67 |
+
|
| 68 |
+
# 4) Specific course types
|
| 69 |
+
# Express / Intensive / Regular / Weekend / Online / Children
|
| 70 |
+
if any(x in t for x in ["express", "اكسبريس", "سريع", "super intensive"]):
|
| 71 |
+
return "COURSE_TYPE_DETAILS"
|
| 72 |
+
if any(x in t for x in ["intensive", "انتنسب", "مكثف", "مكثفة"]):
|
| 73 |
+
return "COURSE_TYPE_DETAILS"
|
| 74 |
+
if any(x in t for x in ["regular", "ريجولار", "عادي", "منتظم"]):
|
| 75 |
+
return "COURSE_TYPE_DETAILS"
|
| 76 |
+
if any(x in t for x in ["weekend", "ويكند", "الجمعة", "السبت", "عطلة"]):
|
| 77 |
+
return "WEEKEND_COURSES"
|
| 78 |
+
if any(x in t for x in ["online", "اونلاين", "أونلاين", "زووم", "من البيت"]):
|
| 79 |
+
return "ONLINE_COURSES"
|
| 80 |
+
if any(x in t for x in ["children", "kids", "اطفال", "أطفال", "طفل", "سن", "سنين"]):
|
| 81 |
+
return "CHILDREN_COURSES"
|
| 82 |
+
|
| 83 |
+
# 5) Center info
|
| 84 |
+
if any(x in t for x in ["المركز", "adk", "ädk", "فروع", "branch", "اتأسس", "تاريخ", "goethe", "معتمد"]):
|
| 85 |
+
return "CENTER_INFO"
|
| 86 |
+
|
| 87 |
+
return "OTHER"
|
| 88 |
+
|
| 89 |
+
KB_TEXT = """
|
| 90 |
+
المركز:
|
| 91 |
+
(ÄDK)- Egyptian-German Cultural Centre was established in 1998. With various branches in Cairo, ÄDK offers German language courses for adults from A1 to C1 and for children from A1 to B1. Over the years thousands have graduated and have learned in ÄDK. In addition to our language courses, ÄDK organizes cultural projects independently, or in conjunction with the Goethe institute.
|
| 92 |
+
ÄDK is the first institute to be accredited from the Goethe institute in the Middle East and North Africa region.
|
| 93 |
+
|
| 94 |
+
أنواع الكورسات:
|
| 95 |
+
1) Express Courses:
|
| 96 |
+
- Super intensive courses لتعلم الألماني بسرعة وكفاءة. Challenging وتحتاج مجهود.
|
| 97 |
+
- ممكن تحجز Stage كاملة (A1-A2-B1).
|
| 98 |
+
- 3 محاضرات في الأسبوع، كل محاضرة 4 ساعات.
|
| 99 |
+
- مدة الـ stage: شهرين ونصف.
|
| 100 |
+
|
| 101 |
+
2) Intensive Courses:
|
| 102 |
+
- ممكن تحجز Stage كاملة (A1-A2-B1).
|
| 103 |
+
- محاضرتين في الأسبوع، كل محاضرة 4 ساعات.
|
| 104 |
+
- مدة الـ stage: 3 شهور ونصف.
|
| 105 |
+
|
| 106 |
+
3) Regular Courses:
|
| 107 |
+
- ممكن تحجز كل level لوحده من (A1.1 إلى B1.3).
|
| 108 |
+
- محاضرتين في الأسبوع، كل محاضرة 4 ساعات.
|
| 109 |
+
- مدة الكورس: شهر ونصف.
|
| 110 |
+
|
| 111 |
+
4) Weekend Courses:
|
| 112 |
+
- للناس اللي مش فاضيين خلال الأسبوع بسبب شغل/دراسة.
|
| 113 |
+
- بتتبع نفس outline وساعات الـ Regular (intensive و normal).
|
| 114 |
+
|
| 115 |
+
5) Online Courses:
|
| 116 |
+
- attending online.
|
| 117 |
+
|
| 118 |
+
6) Children Courses:
|
| 119 |
+
- من 5 سنوات حتى 15 سنة.
|
| 120 |
+
- الهدف: تنمية مهارات الطفل واللغة وتشجيع التفكير الحر والنقدي والاستقلالية.
|
| 121 |
+
"""
|
| 122 |
+
|
| 123 |
+
def build_system_prompt(intent: str) -> str:
|
| 124 |
+
return f"""
|
| 125 |
+
أنت مساعد واتساب رسمي ولطيف لمركز ÄDK لتعليم اللغة الألمانية.
|
| 126 |
+
لازم ترد بالعربي المصري بشكل friendly ومختصر وواضح.
|
| 127 |
+
|
| 128 |
+
قواعد مهمة جدًا:
|
| 129 |
+
- استخدم فقط المعلومات الموجودة داخل "قاعدة المعرفة" أدناه.
|
| 130 |
+
- ممنوع تمامًا تخترع أسعار، مواعيد، فروع بالتفصيل، أماكن، أو أي تفاصيل غير موجودة.
|
| 131 |
+
- ممنوع تتكلم عن المنافسين أو تقارن أو تقدم معلومات عامة عن كورسات الألماني خارج قاعدة المعرفة.
|
| 132 |
+
- لو المستخدم سأل عن حاجة مش موجودة في قاعدة المعرفة: قول له بصراحة إن المعلومة مش متاحة عندك دلوقتي، واقترح "التحدث مع خدمة العملاء".
|
| 133 |
+
- لو الـ intent = GREETING: قدم رسالة ترحيب + خيارات قصيرة.
|
| 134 |
+
- لو الـ intent = COURSES_MENU: اعرض الأنواع المتاحة (Regular/Express/Intensive/Weekend/Online/Children) واسأل يختار نوع.
|
| 135 |
+
- لو الـ intent متعلق بنوع كورس: اعرض تفاصيل النوع من قاعدة المعرفة فقط.
|
| 136 |
+
- الرد يكون نص فقط (بدون JSON)، وجمل قصيرة.
|
| 137 |
+
|
| 138 |
+
الـ intent الحالي: {intent}
|
| 139 |
+
|
| 140 |
+
قاعدة المعرفة:
|
| 141 |
+
{KB_TEXT}
|
| 142 |
+
""".strip()
|
| 143 |
|
| 144 |
def process_text(user_text: str):
|
| 145 |
client = openai.OpenAI(api_key=api_key, base_url=base_url)
|
| 146 |
|
| 147 |
+
intent = detect_intent(user_text)
|
| 148 |
+
system_prompt = build_system_prompt(intent)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
|
| 150 |
+
try:
|
| 151 |
resp = client.chat.completions.create(
|
| 152 |
model=model_link,
|
| 153 |
messages=[
|
| 154 |
{"role": "system", "content": system_prompt},
|
| 155 |
{"role": "user", "content": user_text},
|
| 156 |
],
|
| 157 |
+
max_tokens=500,
|
| 158 |
+
temperature=0.2,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
stream=False,
|
| 160 |
)
|
| 161 |
|
| 162 |
+
answer = resp.choices[0].message.content.strip()
|
| 163 |
|
| 164 |
+
# لو تحب ترجع intent كمان (مفيد للـ webhook logic)
|
| 165 |
+
return {"ok": True, "intent": intent, "reply": answer}
|
| 166 |
|
| 167 |
except Exception as e:
|
| 168 |
+
return {"ok": False, "error": str(e)}
|