| import openai |
| import os |
| from dotenv import load_dotenv, dotenv_values |
| from fastapi import FastAPI, Request |
| from pydantic import BaseModel |
| from fastapi.responses import RedirectResponse, HTMLResponse |
| from fastapi.responses import JSONResponse |
| import urllib.parse |
| import requests |
|
|
| |
| load_dotenv() |
| api_key = os.environ.get('HUGGINGFACEHUB_API_TOKEN') |
|
|
| |
| model_link = "meta-llama/Meta-Llama-3-8B-Instruct" |
| base_url = "https://router.huggingface.co/v1" |
|
|
| app = FastAPI() |
|
|
| class Message(BaseModel): |
| message: str |
|
|
| @app.get("/", response_class=HTMLResponse) |
| async def read_root(): |
| return """Welcome to Up to 12 Chat Processor""" |
| |
| @app.post("/processtext") |
| async def receive_updates(request: Request): |
| data = await request.json() |
| print("Received Update:", data) |
|
|
| result = process_text(data.get("message", "")) |
| print("Assistant:", result) |
|
|
| |
| return JSONResponse(content=result) |
|
|
| import re |
|
|
| INTENTS = { |
| "GREETING": "تحية/بداية محادثة", |
| "COURSES_MENU": "طلب قائمة الكورسات", |
| "COURSE_TYPE_DETAILS": "سؤال عن نوع كورس محدد", |
| "CENTER_INFO": "سؤال عن المركز", |
| "CHILDREN_COURSES": "كورس أطفال", |
| "ONLINE_COURSES": "كورسات أونلاين", |
| "WEEKEND_COURSES": "كورسات ويكند", |
| "HUMAN_AGENT": "طلب خدمة عملاء/موظف", |
| "OTHER": "غير معروف/خارج النطاق", |
| } |
|
|
| def detect_intent(text: str) -> str: |
| t = (text or "").strip().lower() |
|
|
| |
| if re.search(r"\b(hi|hello|hey|start)\b", t) or any(x in t for x in ["اهلا", "أهلا", "السلام", "هاي", "مرحبا", "ابدأ", "ابدء"]): |
| return "GREETING" |
|
|
| |
| if any(x in t for x in ["خدمة العملاء", "موظف", "حد يرد", "اكلم", "اتواصل", "رقم", "واتساب", "support", "agent"]): |
| return "HUMAN_AGENT" |
|
|
| |
| if any(x in t for x in ["كورسات", "دورات", "courses", "الكورسات المتاحة", "عايز كورس", "عايز اتعلم", "الالماني عندكم", "الماني"]): |
| return "COURSES_MENU" |
|
|
| |
| |
| if any(x in t for x in ["express", "اكسبريس", "سريع", "super intensive"]): |
| return "COURSE_TYPE_DETAILS" |
| if any(x in t for x in ["intensive", "انتنسب", "مكثف", "مكثفة"]): |
| return "COURSE_TYPE_DETAILS" |
| if any(x in t for x in ["regular", "ريجولار", "عادي", "منتظم"]): |
| return "COURSE_TYPE_DETAILS" |
| if any(x in t for x in ["weekend", "ويكند", "الجمعة", "السبت", "عطلة"]): |
| return "WEEKEND_COURSES" |
| if any(x in t for x in ["online", "اونلاين", "أونلاين", "زووم", "من البيت"]): |
| return "ONLINE_COURSES" |
| if any(x in t for x in ["children", "kids", "اطفال", "أطفال", "طفل", "سن", "سنين"]): |
| return "CHILDREN_COURSES" |
|
|
| |
| if any(x in t for x in ["المركز", "adk", "ädk", "فروع", "branch", "اتأسس", "تاريخ", "goethe", "معتمد"]): |
| return "CENTER_INFO" |
|
|
| return "OTHER" |
|
|
| KB_TEXT = """ |
| المركز: |
| (Ä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. |
| ÄDK is the first institute to be accredited from the Goethe institute in the Middle East and North Africa region. |
| |
| أنواع الكورسات: |
| 1) Express Courses: |
| - Super intensive courses لتعلم الألماني بسرعة وكفاءة. Challenging وتحتاج مجهود. |
| - ممكن تحجز Stage كاملة (A1-A2-B1). |
| - 3 محاضرات في الأسبوع، كل محاضرة 4 ساعات. |
| - مدة الـ stage: شهرين ونصف. |
| |
| 2) Intensive Courses: |
| - ممكن تحجز Stage كاملة (A1-A2-B1). |
| - محاضرتين في الأسبوع، كل محاضرة 4 ساعات. |
| - مدة الـ stage: 3 شهور ونصف. |
| |
| 3) Regular Courses: |
| - ممكن تحجز كل level لوحده من (A1.1 إلى B1.3). |
| - محاضرتين في الأسبوع، كل محاضرة 4 ساعات. |
| - مدة الكورس: شهر ونصف. |
| |
| 4) Weekend Courses: |
| - للناس اللي مش فاضيين خلال الأسبوع بسبب شغل/دراسة. |
| - بتتبع نفس outline وساعات الـ Regular (intensive و normal). |
| |
| 5) Online Courses: |
| - attending online. |
| |
| 6) Children Courses: |
| - من 5 سنوات حتى 15 سنة. |
| - الهدف: تنمية مهارات الطفل واللغة وتشجيع التفكير الحر والنقدي والاستقلالية. |
| """ |
|
|
| def build_system_prompt(intent: str) -> str: |
| return f""" |
| أنت مساعد واتساب لمركز ÄDK لتعليم اللغة الألمانية. |
| اكتب بالعربي المصري بطريقة ودودة وطبيعية ومحترمة، وجُمل قصيرة. |
| |
| قواعد أسلوب (مهم جدًا): |
| - ممنوع أخطاء لغوية مثل: "اقترحك" أو "يهتم بيك". استخدم: "أقترح" / "أنسب" / "تحب" / "ممكن". |
| - استخدم ضمير المخاطب الصحيح: "إنت/حضرتك" (اختر واحد واثبت عليه). استخدم "إنت" هنا. |
| - أسئلة الاختيار تكون بصيغة سليمة: "تحب كورس أي نوع؟" أو "إنت مهتم بأي كورس؟" وليس "يهتم بيك". |
| - متبعتش تحية زي مرحباً او أهلاً. رد مباشرة على رسالة العميل حسب نوعها |
| |
| قواعد المحتوى: |
| - استخدم فقط المعلومات الموجودة في "قاعدة المعرفة" أدناه. |
| - ممنوع تخترع أسعار/مواعيد/فروع/أماكن/تفاصيل غير موجودة. |
| - ممنوع تقارن بمنافسين أو تقدم معلومات عامة خارج قاعدة المعرفة. |
| |
| لو المستخدم سأل عن معلومة غير موجودة في قاعدة المعرفة: |
| - لا تقل صراحة "المعلومة مش عندي" ولا تستخدم صيغة اعتذار طويلة. |
| - استخدم صياغة لطيفة توصل نفس المعنى بدون إحراج، مثل: |
| 1) "تمام — هخلي فريق خدمة العملاء يتواصل معاك ويوضح لك التفاصيل." |
| 2) "خلّيني أسجّل استفسارك، وخدمة العملاء هيردّوا عليك بالتفاصيل." |
| 3) "عشان أديك إجابة دقيقة، هحوّل سؤالك لخدمة العملاء." |
| - في النهاية اسأل سؤال واحد يساعد خدمة العملاء: (اسمك/رقمك/أقرب فرع/تفضل أونلاين ولا حضور). |
| *لو الرقم جاي من واتساب مش محتاج تسأل عنه.* |
| |
| توجيهات حسب الـ Intent: |
| - GREETING: رحّب + اعرض 3 اختيارات واضحة. |
| - COURSES_MENU: اعرض الأنواع المتاحة فقط (Regular/Express/Intensive/Weekend/Online/Children) واسأل: "تحب تعرف تفاصيل أنهي نوع؟" |
| - COURSE_TYPE_DETAILS / ONLINE_COURSES / WEEKEND_COURSES / CHILDREN_COURSES: اذكر التفاصيل من قاعدة المعرفة فقط، ثم اسأل سؤال متابعة واحد. |
| - CENTER_INFO: اذكر معلومات المركز من قاعدة المعرفة فقط، ثم اسأل لو محتاج يتواصل مع خدمة العملاء. |
| |
| إخراج الرد: |
| - الرد يكون نص فقط. |
| - لا تكتب JSON ولا عناوين تقنية ولا نقاط كثيرة (حد أقصى 5 سطور). |
| - لا تذكر كلمة "قاعدة المعرفة". |
| |
| الـ Intent الحالي: {intent} |
| |
| قاعدة المعرفة: |
| {KB_TEXT} |
| """.strip() |
|
|
| def process_text(user_text: str): |
| client = openai.OpenAI(api_key=api_key, base_url=base_url) |
|
|
| intent = detect_intent(user_text) |
| system_prompt = build_system_prompt(intent) |
|
|
| try: |
| resp = client.chat.completions.create( |
| model=model_link, |
| messages=[ |
| {"role": "system", "content": system_prompt}, |
| {"role": "user", "content": user_text}, |
| ], |
| max_tokens=500, |
| temperature=0.2, |
| stream=False, |
| ) |
|
|
| answer = resp.choices[0].message.content.strip() |
|
|
| |
| return {"ok": True, "intent": intent, "reply": answer} |
|
|
| except Exception as e: |
| return {"ok": False, "error": str(e)} |