Zenaight commited on
Commit
e8bd6cd
·
verified ·
1 Parent(s): 4421556

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +161 -165
main.py CHANGED
@@ -1,166 +1,162 @@
1
- import os, json
2
- from fastapi import FastAPI, Request, HTTPException, Query
3
- from fastapi.responses import PlainTextResponse, JSONResponse
4
- import httpx
5
- import base64
6
- import asyncio
7
-
8
- app = FastAPI()
9
-
10
- VERIFY_TOKEN = os.getenv("VERIFY_TOKEN", "") # set in HF Secrets
11
- PHONE_NUMBER_ID = os.getenv("PHONE_NUMBER_ID", "")
12
- WHATSAPP_API_TOKEN = os.getenv("WHATSAPP_API_TOKEN", "")
13
- RUMAS_API_URL = os.getenv("RUMAS_API_URL", "")
14
-
15
- async def forward_to_rumas(b64_str: str, wa_id: str):
16
- """Fire-and-forget call to RUMAS /api/process_id."""
17
- payload = {
18
- "data": [b64_str],
19
- "configurations": {
20
- "iddetectionconfidence": "80",
21
- "smartidconfidence": "50",
22
- "greenidconfidence": "50",
23
- "binaryString": "1111111011110011"
24
- }
25
- }
26
- short = b64_str[:40] # first 40 chars for reference
27
- try:
28
- print(f"[RUMAS] ➜ sending image ({len(b64_str)} bytes) "
29
- f"preview='{short}…'")
30
-
31
- print("Payload to RUMAS:", json.dumps(payload)[:300], "…")
32
-
33
- async with httpx.AsyncClient(timeout=60) as client:
34
- resp = await client.post(RUMAS_API_URL, json=payload)
35
- resp.raise_for_status()
36
- # ── log the full JSON response (truncated to 300 chars for brevity) ──
37
- data = resp.json()
38
- print(f"[RUMAS] ✔ 200 {json.dumps(data)[:300]}…")
39
- body = data
40
- print(f"[RUMAS] ✔ {resp.status_code}")
41
- pretty_print_dict(body)
42
-
43
- # ── send parsed ID back to WhatsApp ──
44
- if wa_id and data.get("status") == "success":
45
- det = data["results"][0]["detections"][0]
46
- # build a line-by-line summary of every field
47
- fields = [
48
- "status", "message", "id_num", "name", "surname",
49
- "date_of_birth", "gender", "id_type", "cob",
50
- "citizen", "citizen_status", "date_issued", "age"
51
- ]
52
- lines = ["✅ *ID processed*"]
53
- for field in fields:
54
- # Title-case the key and fetch its value (empty string if missing)
55
- pretty_key = field.replace("_", " ").title()
56
- lines.append(f"*{pretty_key}*: {det.get(field, '')}")
57
- send_whatsapp_message(wa_id, "\n".join(lines))
58
-
59
- except Exception as e:
60
- print(f"[RUMAS] ✘ error while sending '{short}…' →", e)
61
-
62
- def pretty_print_dict(d, indent=0):
63
- for k, v in d.items():
64
- if isinstance(v, dict):
65
- print(' ' * indent + f"{k}:")
66
- pretty_print_dict(v, indent + 2)
67
- elif isinstance(v, list):
68
- print(' ' * indent + f"{k}: [")
69
- for item in v:
70
- if isinstance(item, dict):
71
- pretty_print_dict(item, indent + 2)
72
- else:
73
- print(' ' * (indent + 2) + str(item))
74
- print(' ' * indent + "]")
75
- else:
76
- print(' ' * indent + f"{k}: {v}")
77
-
78
- @app.get("/webhook") # verification
79
- def verify(
80
- hub_mode: str = Query(None, alias="hub.mode"),
81
- hub_token: str = Query(None, alias="hub.verify_token"),
82
- hub_challenge: str = Query(None, alias="hub.challenge")
83
- ):
84
- if hub_mode == "subscribe" and hub_token == VERIFY_TOKEN:
85
- return PlainTextResponse(hub_challenge)
86
- raise HTTPException(status_code=403, detail="Invalid token")
87
-
88
- def send_whatsapp_message(wa_id, reply):
89
- url = f"https://graph.facebook.com/v23.0/{PHONE_NUMBER_ID}/messages"
90
- headers = {
91
- "Authorization": f"Bearer {WHATSAPP_API_TOKEN}",
92
- "Content-Type": "application/json"
93
- }
94
- payload = {
95
- "messaging_product": "whatsapp",
96
- "to": wa_id,
97
- "type": "text",
98
- "text": {"body": reply}
99
- }
100
- httpx.post(url, headers=headers, json=payload)
101
-
102
- @app.post("/webhook") # incoming WhatsApp updates
103
- async def receive_update(req: Request):
104
- data = await req.json()
105
- try:
106
- change = data["entry"][0]["changes"][0]["value"]
107
- contacts = change.get("contacts")
108
- messages = change.get("messages")
109
- if not contacts or not messages:
110
- # Missing expected payload—ignore
111
- print("Ignoring update, no contacts or messages field")
112
- return JSONResponse({"status": "ignored", "reason": "no contacts/messages"})
113
-
114
- wa_id = contacts[0]["wa_id"]
115
- msg = messages[0]
116
- except (KeyError, IndexError, TypeError) as e:
117
- print("Malformed webhook payload:", e)
118
- return JSONResponse({"status": "ignored", "reason": "malformed payload"})
119
-
120
- # IMAGE: if user sent an image, convert to Base64 preview
121
- if msg["type"] == "image":
122
- media_id = msg["image"]["id"]
123
- # 1) get media URL
124
- media_resp = httpx.get(
125
- f"https://graph.facebook.com/v23.0/{media_id}",
126
- headers={"Authorization": f"Bearer {WHATSAPP_API_TOKEN}"}
127
- )
128
- media_resp.raise_for_status()
129
- media_url = media_resp.json()["url"]
130
- # 2) download bytes with auth
131
- media_bytes = httpx.get(
132
- media_url,
133
- headers={"Authorization": f"Bearer {WHATSAPP_API_TOKEN}"}
134
- ).content
135
- # 3) encode full & preview
136
- full_b64 = base64.b64encode(media_bytes).decode("utf-8")
137
- preview = full_b64[:10]
138
-
139
- # 4) forward full string to RUMAS (non-blocking)
140
- asyncio.create_task(forward_to_rumas(full_b64, wa_id))
141
-
142
- # 5) echo preview to the user
143
- send_whatsapp_message(wa_id, f"Base64: {preview}")
144
- return JSONResponse({"status": "image_preview_sent", "preview": preview})
145
-
146
- # TEXT: simple echo
147
- if msg["type"] == "text":
148
- incoming = msg["text"]["body"]
149
- reply = f"You said: {incoming}"
150
- send_whatsapp_message(wa_id, reply)
151
- return JSONResponse({"status": "replied"})
152
-
153
- # OTHER: ignore
154
- return JSONResponse({"status": "ignored", "type": msg["type"]})
155
-
156
- # health-check endpoint for token
157
- @app.post("/send")
158
- async def check_token():
159
- token = os.getenv("WHATSAPP_API_TOKEN", "")
160
- if token:
161
- return {"token_loaded": True}
162
- raise HTTPException(status_code=400, detail="Token not found")
163
-
164
- @app.get("/ping") # health check
165
- def ping():
166
  return {"pong": True}
 
1
+ import os, json
2
+ from fastapi import FastAPI, Request, HTTPException, Query
3
+ from fastapi.responses import PlainTextResponse, JSONResponse
4
+ import httpx
5
+ import base64
6
+ import asyncio
7
+
8
+ app = FastAPI()
9
+
10
+ VERIFY_TOKEN = os.getenv("VERIFY_TOKEN", "") # set in HF Secrets
11
+ PHONE_NUMBER_ID = os.getenv("PHONE_NUMBER_ID", "")
12
+ WHATSAPP_API_TOKEN = os.getenv("WHATSAPP_API_TOKEN", "")
13
+ RUMAS_API_URL = os.getenv("RUMAS_API_URL", "")
14
+
15
+ async def forward_to_rumas(b64_str: str, wa_id: str):
16
+ """Fire-and-forget call to RUMAS /api/process_id."""
17
+ payload = {
18
+ "data": [b64_str],
19
+ "configurations": {
20
+ "iddetectionconfidence": "80",
21
+ "smartidconfidence": "50",
22
+ "greenidconfidence": "50",
23
+ "binaryString": "1111111011110011"
24
+ }
25
+ }
26
+ short = b64_str[:40] # first 40 chars for reference
27
+ try:
28
+ print(f"[RUMAS] ➜ sending image ({len(b64_str)} bytes) "
29
+ f"preview='{short}…'")
30
+
31
+ print("Payload to RUMAS:", json.dumps(payload)[:300], "…")
32
+
33
+ async with httpx.AsyncClient(timeout=60) as client:
34
+ resp = await client.post(RUMAS_API_URL, json=payload)
35
+ resp.raise_for_status()
36
+ # ── log the full JSON response (truncated to 300 chars for brevity) ──
37
+ data = resp.json()
38
+ print(f"[RUMAS] ✔ 200 {json.dumps(data)[:300]}…")
39
+ body = data
40
+ print(f"[RUMAS] ✔ {resp.status_code}")
41
+ pretty_print_dict(body)
42
+
43
+ # ── send parsed ID back to WhatsApp ──
44
+ if wa_id and data.get("status") == "success":
45
+ det = data["results"][0]["detections"][0]
46
+ reply = (
47
+ "✅ *ID processed*\n"
48
+ f"*Name*: {det.get('name','?')} {det.get('surname','')}\n"
49
+ f"*ID No.*: {det.get('id_num','?')}\n"
50
+ f"*DOB*: {det.get('date_of_birth','?')}\n"
51
+ f"*Gender*: {det.get('gender','?')}"
52
+ )
53
+ send_whatsapp_message(wa_id, reply)
54
+
55
+ except Exception as e:
56
+ print(f"[RUMAS] ✘ error while sending '{short}…' →", e)
57
+
58
+ def pretty_print_dict(d, indent=0):
59
+ for k, v in d.items():
60
+ if isinstance(v, dict):
61
+ print(' ' * indent + f"{k}:")
62
+ pretty_print_dict(v, indent + 2)
63
+ elif isinstance(v, list):
64
+ print(' ' * indent + f"{k}: [")
65
+ for item in v:
66
+ if isinstance(item, dict):
67
+ pretty_print_dict(item, indent + 2)
68
+ else:
69
+ print(' ' * (indent + 2) + str(item))
70
+ print(' ' * indent + "]")
71
+ else:
72
+ print(' ' * indent + f"{k}: {v}")
73
+
74
+ @app.get("/webhook") # verification
75
+ def verify(
76
+ hub_mode: str = Query(None, alias="hub.mode"),
77
+ hub_token: str = Query(None, alias="hub.verify_token"),
78
+ hub_challenge: str = Query(None, alias="hub.challenge")
79
+ ):
80
+ if hub_mode == "subscribe" and hub_token == VERIFY_TOKEN:
81
+ return PlainTextResponse(hub_challenge)
82
+ raise HTTPException(status_code=403, detail="Invalid token")
83
+
84
+ def send_whatsapp_message(wa_id, reply):
85
+ url = f"https://graph.facebook.com/v23.0/{PHONE_NUMBER_ID}/messages"
86
+ headers = {
87
+ "Authorization": f"Bearer {WHATSAPP_API_TOKEN}",
88
+ "Content-Type": "application/json"
89
+ }
90
+ payload = {
91
+ "messaging_product": "whatsapp",
92
+ "to": wa_id,
93
+ "type": "text",
94
+ "text": {"body": reply}
95
+ }
96
+ httpx.post(url, headers=headers, json=payload)
97
+
98
+ @app.post("/webhook") # incoming WhatsApp updates
99
+ async def receive_update(req: Request):
100
+ data = await req.json()
101
+ try:
102
+ change = data["entry"][0]["changes"][0]["value"]
103
+ contacts = change.get("contacts")
104
+ messages = change.get("messages")
105
+ if not contacts or not messages:
106
+ # Missing expected payload—ignore
107
+ print("Ignoring update, no contacts or messages field")
108
+ return JSONResponse({"status": "ignored", "reason": "no contacts/messages"})
109
+
110
+ wa_id = contacts[0]["wa_id"]
111
+ msg = messages[0]
112
+ except (KeyError, IndexError, TypeError) as e:
113
+ print("Malformed webhook payload:", e)
114
+ return JSONResponse({"status": "ignored", "reason": "malformed payload"})
115
+
116
+ # IMAGE: if user sent an image, convert to Base64 preview
117
+ if msg["type"] == "image":
118
+ media_id = msg["image"]["id"]
119
+ # 1) get media URL
120
+ media_resp = httpx.get(
121
+ f"https://graph.facebook.com/v23.0/{media_id}",
122
+ headers={"Authorization": f"Bearer {WHATSAPP_API_TOKEN}"}
123
+ )
124
+ media_resp.raise_for_status()
125
+ media_url = media_resp.json()["url"]
126
+ # 2) download bytes with auth
127
+ media_bytes = httpx.get(
128
+ media_url,
129
+ headers={"Authorization": f"Bearer {WHATSAPP_API_TOKEN}"}
130
+ ).content
131
+ # 3) encode full & preview
132
+ full_b64 = base64.b64encode(media_bytes).decode("utf-8")
133
+ preview = full_b64[:10]
134
+
135
+ # 4) forward full string to RUMAS (non-blocking)
136
+ asyncio.create_task(forward_to_rumas(full_b64, wa_id))
137
+
138
+ # 5) echo preview to the user
139
+ send_whatsapp_message(wa_id, f"Base64: {preview}")
140
+ return JSONResponse({"status": "image_preview_sent", "preview": preview})
141
+
142
+ # TEXT: simple echo
143
+ if msg["type"] == "text":
144
+ incoming = msg["text"]["body"]
145
+ reply = f"You said: {incoming}"
146
+ send_whatsapp_message(wa_id, reply)
147
+ return JSONResponse({"status": "replied"})
148
+
149
+ # OTHER: ignore
150
+ return JSONResponse({"status": "ignored", "type": msg["type"]})
151
+
152
+ # health-check endpoint for token
153
+ @app.post("/send")
154
+ async def check_token():
155
+ token = os.getenv("WHATSAPP_API_TOKEN", "")
156
+ if token:
157
+ return {"token_loaded": True}
158
+ raise HTTPException(status_code=400, detail="Token not found")
159
+
160
+ @app.get("/ping") # health check
161
+ def ping():
 
 
 
 
162
  return {"pong": True}