import json import re import requests from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse # ========================= # Config # ========================= GREENAPI_INSTANCE_ID = "7105210836" GREENAPI_TOKEN = "805b69f6c85d4e6caea0edaba692b889abecc9e6bb8b457e8f" GREENAPI_BASE = f"https://7105.api.greenapi.com/waInstance{GREENAPI_INSTANCE_ID}" # Interactive buttons endpoint GREENAPI_SEND_URL_BUTTON_URL = f"{GREENAPI_BASE}/sendInteractiveButtons/{GREENAPI_TOKEN}" # Interactive REPLY buttons endpoint GREENAPI_SEND_REPLY_BUTTONS_URL = f"{GREENAPI_BASE}/sendInteractiveButtonsReply/{GREENAPI_TOKEN}" # Plain text endpoint (لو عندك endpoint مختلف في GreenAPI غيّره هنا) GREENAPI_SEND_TEXT_URL = ( f"https://7105.api.greenapi.com/" f"waInstance{GREENAPI_INSTANCE_ID}/sendMessage/{GREENAPI_TOKEN}" ) COMPLAINT_FORM_URL = "https://mrhelp92.github.io/Complaint-form/" # <-- حط لينك فورم الشكوى الحقيقي AI_BOT_URL = "https://mr-help-adkbase.hf.space/processtext" # <-- endpoint بتاع البوت TIMEOUT_SEC = 60 # (لو عايز تفضل GAS زي ما هو موجود) GAS_WEBAPP_URL = "https://script.google.com/macros/s/AKfycbxFLlPzSvXM6xpVXR3-BjoK1lkNjYb8o1pctXI4Q2NZvv6wqKnIaSQA6hhL5lP_TQbTgQ/exec" app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=False, allow_methods=["POST", "OPTIONS"], allow_headers=["*"], ) # ========================= # Intent detection (بسيط) # ========================= GREET_WORDS = [ "اهلا", "أهلا", "مرحبا", "هاي", "hello", "hi", "السلام عليكم", "سلام عليكم", "مساء الخير", "صباح الخير", "مساء الفل", "صباح الفل" ] COMPLAINT_WORDS = [ "شكوى", "شكاوي", "اشتكي", "مشكلة", "مشكلتي", "تذمر", "زعلان", "سيء", "خدمة سيئة", "عايز أشتكي", "عايز اشتكي", "complaint" ] def detect_intent_simple(text: str) -> str: t = (text or "").strip().lower() if any(w in t for w in [x.lower() for x in GREET_WORDS]): return "GREETING" if any(w in t for w in [x.lower() for x in COMPLAINT_WORDS]): return "COMPLAINT" return "OTHER" # ========================= # GreenAPI send helpers # ========================= def send_url_button(chat_id: str, header: str, body: str, footer: str, url: str, button_text: str = "تسجيل الشكوى"): payload = { "chatId": chat_id, "body": body, "header": header, "footer": footer, "buttons": [ { "type": "url", "buttonId": "1", "buttonText": button_text, "url": url } ] } resp = requests.post(GREENAPI_SEND_URL_BUTTON_URL, json=payload, timeout=TIMEOUT_SEC) return resp.status_code, (resp.text or "")[:1500] def send_reply_buttons(chat_id: str, header: str, body: str, footer: str, buttons: list): """ buttons example: [{"buttonId":"1","buttonText":"..."}, ...] """ payload = { "chatId": chat_id, "body": body, "header": header, "footer": footer, "buttons": buttons } resp = requests.post(GREENAPI_SEND_REPLY_BUTTONS_URL, json=payload, timeout=TIMEOUT_SEC) return resp.status_code, (resp.text or "")[:1500] def send_text_message(chat_id: str, message: str): payload = { "chatId": chat_id, "message": message } headers = { "Content-Type": "application/json" } resp = requests.post( GREENAPI_SEND_TEXT_URL, json=payload, headers=headers, timeout=TIMEOUT_SEC ) return resp.status_code, (resp.text or "")[:1500] # ========================= # AI bot call # ========================= def call_ai_bot(message: str): payload = {"message": message} resp = requests.post(AI_BOT_URL, json=payload, timeout=TIMEOUT_SEC) resp.raise_for_status() try: return resp.json() except Exception: return {"ok": False, "raw": resp.text} # ========================= # Webhook receiver # ========================= def extract_text_message(msg_data: dict) -> str: """ يرجّع نص المستخدم سواء كان: - textMessage - extendedTextMessage - interactiveButtonsResponse (ضغط زرار) """ if not isinstance(msg_data, dict): return "" t = (msg_data.get("typeMessage") or "").strip() # 1) رسالة نصية عادية if t == "textMessage": return ((msg_data.get("textMessageData") or {}).get("textMessage") or "").strip() # 2) رسالة نصية ممتدة (شائع) if t == "extendedTextMessage": return ((msg_data.get("extendedTextMessageData") or {}).get("text") or "").strip() # 3) ضغط زرار (Interactive Buttons Response) if t == "interactiveButtonsResponse": r = msg_data.get("interactiveButtonsResponse") or {} # أهم حاجة: selectedDisplayText (نص الزرار) txt = (r.get("selectedDisplayText") or "").strip() if txt: return txt # fallback: selectedId return (r.get("selectedId") or "").strip() # fallback عام for path in [ ("textMessageData", "textMessage"), ("extendedTextMessageData", "text"), ("interactiveButtonsResponse", "selectedDisplayText"), ("interactiveButtonsResponse", "selectedId"), ("text",), ("message",), ]: cur = msg_data for k in path: cur = cur.get(k) if isinstance(cur, dict) else None if isinstance(cur, str) and cur.strip(): return cur.strip() return "" @app.post("/recieve") async def webhook_receiver(req: Request): try: body = await req.json() except Exception: raw = await req.body() print("===== RECEIVED RAW =====") print(raw) print("========================") return {"ok": True} print("===== RECEIVED JSON =====") print(json.dumps(body, ensure_ascii=False, indent=2)) print("=========================") # 1) فلتر نوع الويبهوك if body.get("typeWebhook") != "incomingMessageReceived": return {"ok": True, "ignored": True} # 2) استخرج wid + chatId + الرسالة instance_wid = (body.get("instanceData") or {}).get("wid") # ده wid بتاع الـ instance sender_data = body.get("senderData") or {} chat_id = sender_data.get("chatId") # ده اللي لازم تبعت له الرد msg_data = body.get("messageData") or {} type_message = (msg_data.get("typeMessage") or "") text_message = extract_text_message(msg_data) print(">>> instance_wid:", instance_wid) print(">>> chat_id:", chat_id) print(">>> typeMessage:", type_message) print(">>> text_message:", text_message) # لو مفيش chat_id أو مفيش رسالة نصية، نوقف if not chat_id or not text_message: return {"ok": True, "skipped": True} # 3) حدّد intent intent = detect_intent_simple(text_message) print(">>> intent:", intent) # 4) ردود حسب intent if intent == "GREETING": header = "أهلاً بيك في ÄDK 👋" body_txt = ( "منورنا! 😊\n" "أنا مساعد ÄDK، تحب اساعدك ازاي؟" ) footer = "ÄDK - German Courses" buttons = [ {"buttonId": "1", "buttonText": "أنواع الكورسات"}, {"buttonId": "2", "buttonText": "تحديد مستوى"}, {"buttonId": "3", "buttonText": "تواصل معنا"}, ] status, txt = send_reply_buttons(chat_id, header, body_txt, footer, buttons) print(">>> sent GREETING buttons:", status, txt) return {"ok": True, "intent": intent} if intent == "COMPLAINT": header = "احنا هنا عشان نساعدك 🤝" body_txt = "يسعدنا تواصلك. سجل الشكوى من الرابط ده، وفريقنا هيتواصل معاك في أقرب وقت." footer = "شكراً لاختيار ÄDK" status, txt = send_url_button( chat_id=chat_id, header=header, body=body_txt, footer=footer, url=COMPLAINT_FORM_URL, button_text="تسجيل الشكوى" ) print(">>> sent COMPLAINT url button:", status, txt) return {"ok": True, "intent": intent} # 5) غير كده → نبعته للـ AI bot try: bot_res = call_ai_bot(text_message) # نتوقع {ok, intent, reply} reply = "" if isinstance(bot_res, dict): reply = (bot_res.get("reply") or "").strip() if not reply: reply = "تمام — وصلت رسالتك. ممكن توضّحلي قصدك أكتر؟" status, txt = send_text_message(chat_id, reply) print(">>> sent AI reply:", status, txt) return {"ok": True, "intent": "AI", "bot_intent": (bot_res.get("intent") if isinstance(bot_res, dict) else None)} except Exception as e: print("❌ AI bot failed:", str(e)) # fallback لطيف status, txt = send_text_message(chat_id, "تمام — حصلت مشكلة بسيطة. ممكن تعيد إرسال رسالتك تاني؟") print(">>> sent fallback:", status, txt) return JSONResponse(status_code=200, content={"ok": True, "intent": "AI_FAILED", "error": str(e)}) # ========================= # Complaints proxy (زي ما هو عندك) # ========================= @app.post("/complaints") async def complaints_proxy(req: Request): try: payload = await req.json() except Exception as e: print("❌ Failed to parse incoming JSON:", str(e)) return JSONResponse(status_code=400, content={"ok": False, "error": "invalid json body"}) print("========== INCOMING PAYLOAD ==========") print(json.dumps(payload, ensure_ascii=False, indent=2)) print("======================================") try: gas_resp = requests.post( GAS_WEBAPP_URL, json=payload, headers={"Content-Type": "application/json"}, timeout=60 ) except Exception as e: print("❌ ERROR calling GAS:", repr(e)) return JSONResponse( status_code=502, content={"ok": False, "error": "failed to reach GAS", "details": str(e)} ) print("========== GAS STATUS ==========") print(gas_resp.status_code) print("========== GAS RAW TEXT (first 1500 chars) ==========") print((gas_resp.text or "")[:1500]) print("=====================================================") try: gas_json = gas_resp.json() return JSONResponse(status_code=200, content=gas_json) except Exception: return JSONResponse( status_code=200, content={ "ok": False, "error": "GAS returned non-JSON", "gas_status": gas_resp.status_code, "raw": (gas_resp.text or "")[:1500] } )