ADK-Bot / main.py
Mr-Help's picture
Update main.py
703d236 verified
import json
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from greenapi import (
extract_text_message,
get_device_key_by_instance_id,
send_text_message,
send_url_button,
)
from engine.conversation_engine import process_message
from messages import log_message
from handoff.sales import create_sales_handoff
from handoff.support import create_support_handoff
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=False,
allow_methods=["POST", "OPTIONS"],
allow_headers=["*"],
)
@app.get("/health")
async def health():
print(">>> /health called")
return {"ok": True, "service": "up"}
@app.get("/")
async def root():
return {
"ok": True,
"service": "ADK Bot API",
"message": "Server is running"
}
@app.get("/receive-test")
async def receive_test():
print(">>> /receive-test called")
return {"ok": True, "message": "receive endpoint reachable"}
@app.post("/receive")
async def webhook_receiver(req: Request):
print("========== /receive HIT ==========")
try:
raw_body = await req.body()
print(">>> RAW BODY BYTES:")
print(raw_body)
except Exception as e:
print(">>> FAILED TO READ RAW BODY:", str(e))
raw_body = b""
try:
headers = dict(req.headers)
print(">>> HEADERS:")
print(json.dumps(headers, ensure_ascii=False, indent=2))
except Exception as e:
print(">>> FAILED TO READ HEADERS:", str(e))
body = None
try:
if raw_body:
body = json.loads(raw_body.decode("utf-8"))
else:
body = {}
except Exception as e:
print(">>> FAILED TO PARSE JSON:", str(e))
return JSONResponse(
status_code=200,
content={
"ok": True,
"debug": "request reached /receive but body is not valid JSON"
}
)
print("===== RECEIVED JSON =====")
print(json.dumps(body, ensure_ascii=False, indent=2))
print("=========================")
# مؤقتًا نطبع typeWebhook حتى لو مختلفة
webhook_type = body.get("typeWebhook")
print(">>> typeWebhook:", webhook_type)
if webhook_type != "incomingMessageReceived":
print(">>> ignored non-incoming webhook")
return {
"ok": True,
"ignored": True,
"typeWebhook": webhook_type
}
instance_data = body.get("instanceData") or {}
sender_data = body.get("senderData") or {}
msg_data = body.get("messageData") or {}
# مبدئيًا هنطبع كل الاحتمالات
print(">>> instanceData:", instance_data)
print(">>> senderData:", sender_data)
print(">>> messageData:", msg_data)
# مهم: بعض payloads فيها idInstance وبعضها wid فقط
instance_id = str(
instance_data.get("idInstance")
or instance_data.get("wid")
or ""
)
chat_id = sender_data.get("chatId")
text_message = extract_text_message(msg_data)
print(">>> resolved instance_id:", instance_id)
print(">>> resolved chat_id:", chat_id)
print(">>> resolved text_message:", text_message)
if not instance_id or not chat_id or not text_message:
print(">>> skipped because missing required fields")
return {
"ok": True,
"skipped": True,
"resolved_instance_id": instance_id,
"resolved_chat_id": chat_id,
"resolved_text_message": text_message,
}
device_key = get_device_key_by_instance_id(instance_id)
print(">>> resolved device_key:", device_key)
if not device_key:
print(">>> Unknown instance_id:", instance_id)
return {
"ok": True,
"skipped": True,
"reason": "unknown_instance_id",
"instance_id": instance_id
}
customer_phone = chat_id.replace("@c.us", "")
bot_number = device_key
try:
log_message(customer_phone, bot_number, "in", text_message)
except Exception as e:
print(">>> failed to log incoming message:", str(e))
try:
result = process_message(
bot_number=bot_number,
customer_phone=customer_phone,
text=text_message
)
print(">>> engine result:")
print(json.dumps(result, ensure_ascii=False, indent=2))
except Exception as e:
print(">>> engine error:", str(e))
fallback_reply = "تمام، حصلت مشكلة بسيطة. ممكن تعيد إرسال رسالتك مرة تانية؟"
try:
status, txt = send_text_message(device_key, chat_id, fallback_reply)
print(">>> fallback send status:", status)
print(">>> fallback send body:", txt)
log_message(customer_phone, bot_number, "out", fallback_reply)
except Exception as send_err:
print(">>> failed to send fallback:", str(send_err))
return JSONResponse(
status_code=200,
content={"ok": True, "error": str(e), "fallback_sent": True}
)
reply = (result.get("reply") or "").strip()
action = result.get("action")
if action and action.get("type") == "url_button":
try:
status, txt = send_url_button(
device_key=device_key,
chat_id=chat_id,
header=action.get("header", "مرحباً بك"),
body=action.get("body", reply),
footer=action.get("footer", ""),
url=action.get("url"),
button_text=action.get("button_text", "فتح الرابط")
)
print(">>> sent url button status:", status)
print(">>> sent url button body:", txt)
try:
log_message(customer_phone, bot_number, "out", action.get("body", reply))
except Exception as e:
print(">>> failed to log outgoing url button body:", str(e))
except Exception as e:
print(">>> failed to send url button:", str(e))
fallback_reply = action.get("body", reply) or "تمام، افتح الرابط من فضلك."
try:
status, txt = send_text_message(device_key, chat_id, fallback_reply)
print(">>> url fallback send status:", status)
print(">>> url fallback send body:", txt)
log_message(customer_phone, bot_number, "out", fallback_reply)
except Exception as send_err:
print(">>> failed to send url fallback:", str(send_err))
else:
try:
status, txt = send_text_message(device_key, chat_id, reply)
print(">>> sent text status:", status)
print(">>> sent text body:", txt)
try:
log_message(customer_phone, bot_number, "out", reply)
except Exception as e:
print(">>> failed to log outgoing text:", str(e))
except Exception as e:
print(">>> failed to send text:", str(e))
if action and action.get("type") == "handoff":
department = action.get("department")
summary = action.get("summary", "")
metadata = result.get("flow_data", {})
try:
if department == "sales":
create_sales_handoff(
customer_phone=customer_phone,
bot_number=bot_number,
summary=summary,
metadata=metadata
)
elif department == "support":
create_support_handoff(
customer_phone=customer_phone,
bot_number=bot_number,
summary=summary,
metadata=metadata
)
print(">>> handoff created:", department)
except Exception as e:
print(">>> failed to create handoff:", str(e))
return {
"ok": True,
"device_key": device_key,
"customer_phone": customer_phone,
"state": result.get("next_state"),
"has_action": bool(action),
}
@app.post("/complaints/callback")
async def complaints_callback(req: Request):
print("========== /complaints/callback HIT ==========")
try:
payload = await req.json()
except Exception:
return JSONResponse(status_code=400, content={"ok": False, "error": "invalid json"})
print("===== COMPLAINT CALLBACK =====")
print(json.dumps(payload, ensure_ascii=False, indent=2))
print("==============================")
uid = payload.get("uid", "")
complaint_number = payload.get("complaint_number", "")
status = payload.get("status", "")
return {
"ok": True,
"uid": uid,
"complaint_number": complaint_number,
"status": status
}