| import os, json
|
| from fastapi import FastAPI, Request, HTTPException, Query
|
| from fastapi.responses import PlainTextResponse, JSONResponse
|
| import httpx
|
| import base64
|
|
|
| app = FastAPI()
|
|
|
| VERIFY_TOKEN = os.getenv("VERIFY_TOKEN", "")
|
| PHONE_NUMBER_ID = os.getenv("PHONE_NUMBER_ID", "")
|
| WHATSAPP_API_TOKEN = os.getenv("WHATSAPP_API_TOKEN", "")
|
|
|
| @app.get("/webhook")
|
| def verify(
|
| hub_mode: str = Query(None, alias="hub.mode"),
|
| hub_token: str = Query(None, alias="hub.verify_token"),
|
| hub_challenge: str = Query(None, alias="hub.challenge")
|
| ):
|
| if hub_mode == "subscribe" and hub_token == VERIFY_TOKEN:
|
| return PlainTextResponse(hub_challenge)
|
| raise HTTPException(status_code=403, detail="Invalid token")
|
|
|
| def send_whatsapp_message(wa_id, reply):
|
| url = f"https://graph.facebook.com/v23.0/{PHONE_NUMBER_ID}/messages"
|
| headers = {
|
| "Authorization": f"Bearer {WHATSAPP_API_TOKEN}",
|
| "Content-Type": "application/json"
|
| }
|
| payload = {
|
| "messaging_product": "whatsapp",
|
| "to": wa_id,
|
| "type": "text",
|
| "text": {"body": reply}
|
| }
|
| httpx.post(url, headers=headers, json=payload)
|
|
|
| @app.post("/webhook")
|
| async def receive_update(req: Request):
|
| data = await req.json()
|
| try:
|
| change = data["entry"][0]["changes"][0]["value"]
|
| contacts = change.get("contacts")
|
| messages = change.get("messages")
|
| if not contacts or not messages:
|
|
|
| print("Ignoring update, no contacts or messages field")
|
| return JSONResponse({"status": "ignored", "reason": "no contacts/messages"})
|
|
|
| wa_id = contacts[0]["wa_id"]
|
| msg = messages[0]
|
| except (KeyError, IndexError, TypeError) as e:
|
| print("Malformed webhook payload:", e)
|
| return JSONResponse({"status": "ignored", "reason": "malformed payload"})
|
|
|
|
|
| if msg["type"] == "image":
|
| media_id = msg["image"]["id"]
|
|
|
| media_resp = httpx.get(
|
| f"https://graph.facebook.com/v23.0/{media_id}",
|
| headers={"Authorization": f"Bearer {WHATSAPP_API_TOKEN}"}
|
| )
|
| media_resp.raise_for_status()
|
| media_url = media_resp.json()["url"]
|
|
|
| media_bytes = httpx.get(
|
| media_url,
|
| headers={"Authorization": f"Bearer {WHATSAPP_API_TOKEN}"}
|
| ).content
|
|
|
| preview = base64.b64encode(media_bytes).decode("utf-8")[:10]
|
|
|
| send_whatsapp_message(wa_id, f"Base64: {preview}")
|
| return JSONResponse({"status": "image_preview_sent", "preview": preview})
|
|
|
|
|
| if msg["type"] == "text":
|
| incoming = msg["text"]["body"]
|
| reply = f"You said: {incoming}"
|
| send_whatsapp_message(wa_id, reply)
|
| return JSONResponse({"status": "replied"})
|
|
|
|
|
| return JSONResponse({"status": "ignored", "type": msg["type"]})
|
|
|
|
|
| @app.post("/send")
|
| async def check_token():
|
| token = os.getenv("WHATSAPP_API_TOKEN", "")
|
| if token:
|
| return {"token_loaded": True}
|
| raise HTTPException(status_code=400, detail="Token not found")
|
|
|
| @app.get("/ping")
|
| def ping():
|
| return {"pong": True} |