Mr-Help's picture
Update main.py
055d179 verified
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]
}
)