raghavNCI commited on
Commit
68f07e2
Β·
1 Parent(s): 89615e3

wa integrating llm

Browse files
Files changed (2) hide show
  1. routes/question.py +21 -10
  2. routes/wa_gateway.py +63 -75
routes/question.py CHANGED
@@ -77,17 +77,28 @@ async def ask_question(input: QuestionInput):
77
  "answer": "Cannot answer – no relevant context found.",
78
  "sources": sources
79
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
- # Step 3: Ask Mistral to answer
82
- answer_prompt = (
83
- f"You are a concise news assistant. Answer the user's question clearly using the context below if relevant. "
84
- f"Make sure you are precise, accurate and to the point. Do not assume that the reader has any prerequisite understanding of the subject."
85
- f"If the context is not helpful, you may rely on your own knowledge, but do not mention the context or question again.\n\n"
86
- f"Context:\n{context}\n\n"
87
- f"Question: {question}\n\n"
88
- f"Answer:"
89
- )
90
- answer_raw = mistral_generate(answer_prompt, max_new_tokens=256)
91
 
92
  if not answer_raw:
93
  final_answer = "Cannot answer – model did not return a valid response."
 
77
  "answer": "Cannot answer – no relevant context found.",
78
  "sources": sources
79
  }
80
+
81
+ # Step 3: Ask Mistral to answer
82
+ answer_prompt = (
83
+ f"You are a concise news assistant. Answer the user's question clearly using the context below if relevant. "
84
+ f"Make sure you are precise, accurate and to the point. Do not assume that the reader has any prerequisite understanding of the subject."
85
+ f"If the context is not helpful, you may rely on your own knowledge, but do not mention the context or question again.\n\n"
86
+ f"Context:\n{context}\n\n"
87
+ f"Question: {question}\n\n"
88
+ f"Answer:"
89
+ )
90
+ answer_raw = mistral_generate(answer_prompt, max_new_tokens=256)
91
+
92
+ else:
93
+
94
+ answer_prompt = (
95
+ f"You are a concise news assistant. Answer the user's question clearly using the context below if relevant. "
96
+ f"Make sure you are precise, accurate and to the point. Do not assume that the reader has any prerequisite understanding of the subject."
97
+ f"Question: {question}\n\n"
98
+ f"Answer:"
99
+ )
100
 
101
+ answer_raw = mistral_generate(answer_prompt, max_new_tokens=256)
 
 
 
 
 
 
 
 
 
102
 
103
  if not answer_raw:
104
  final_answer = "Cannot answer – model did not return a valid response."
routes/wa_gateway.py CHANGED
@@ -1,120 +1,108 @@
1
  # app/routes/wa_gateway.py
2
  from fastapi import APIRouter, Request
3
- import os
4
- import requests
5
  from dotenv import load_dotenv
6
  from fastapi.responses import PlainTextResponse, JSONResponse
7
 
 
 
 
8
  load_dotenv()
9
 
10
  wa_router = APIRouter()
11
 
12
- VERIFY_TOKEN = os.getenv("VERIFY_TOKEN")
13
- ACCESS_TOKEN = os.getenv("WHATSAPP_ACCESS_TOKEN")
14
- PHONE_NUMBER_ID = os.getenv("WHATSAPP_PHONE_NUMBER_ID")
15
- RECIPIENT_NUMBER = "+353 89 949 5777" # or pass dynamically
16
-
17
- def send_preferences_flow(to, name):
18
- url = f"https://graph.facebook.com/v22.0/714483311743364/messages"
 
 
 
 
 
 
19
  headers = {
20
  "Authorization": f"Bearer {ACCESS_TOKEN}",
21
- "Content-Type": "application/json"
22
  }
23
  payload = {
24
  "messaging_product": "whatsapp",
25
- "to": to,
26
- "type": "interactive",
27
- "interactive": {
28
- "type": "list",
29
- "header": { "type": "text", "text": "Select Your Interests" },
30
- "body": { "text": f"Hi {name}! Please pick your preferred news topics." },
31
- "footer": { "text": "Powered by nuse" },
32
- "action": {
33
- "button": "Choose Topics",
34
- "sections": [{
35
- "title": "Categories",
36
- "rows": [
37
- { "id": "world", "title": "World" },
38
- { "id": "india", "title": "India" },
39
- { "id": "finance", "title": "Finance" },
40
- { "id": "sports", "title": "Sports" },
41
- { "id": "entertainment", "title": "Entertainment" }
42
- ]
43
- }]
44
- }
45
- }
46
  }
47
 
48
- response = requests.post(url, headers=headers, json=payload)
49
  try:
50
- response.raise_for_status()
51
- return {"status": "sent", "response": response.json()}
 
52
  except Exception as e:
53
  return {"status": "failed", "error": str(e)}
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  @wa_router.get("/webhook")
56
  async def verify_webhook(request: Request):
57
  params = request.query_params
58
  if params.get("hub.mode") == "subscribe" and params.get("hub.verify_token") == VERIFY_TOKEN:
59
- # Return raw plain text (not JSON)
60
  return PlainTextResponse(content=params.get("hub.challenge"))
61
  return JSONResponse(status_code=403, content={"error": "Verification failed"})
62
 
 
 
 
63
  @wa_router.post("/webhook")
64
  async def receive_whatsapp_event(request: Request):
65
  body = await request.json()
66
- print("[WEBHOOK] Incoming message:", body)
67
 
68
- # Detect message and extract user number + message
69
  try:
70
- entry = body["entry"][0]
71
- changes = entry["changes"][0]
72
- value = changes["value"]
73
  messages = value.get("messages")
74
  contacts = value.get("contacts")
75
 
76
  if messages and contacts:
77
- msg = messages[0]
78
  contact = contacts[0]
79
 
80
- from_number = msg["from"]
81
- sender_name = contact["profile"]["name"] # <- πŸ‘ˆ This is the name
82
- text = msg["text"]["body"]
83
-
84
- print(f"[INFO] Message from {sender_name} ({from_number}): {text}")
85
-
86
- response = send_preferences_flow(from_number, sender_name)
87
 
88
- if response["status"] == "failed":
89
- print("[ERROR] Failed to send interactive message:", response["error"])
90
 
91
- # Trigger your response logic here β€” for example, reply with interactive message
 
 
92
 
93
  except Exception as e:
94
  print("[ERROR] Webhook processing failed:", str(e))
95
 
96
  return JSONResponse(content={"status": "received"})
97
-
98
- @wa_router.post("/whatsapp/send")
99
- def send_whatsapp_message():
100
- url = f"https://graph.facebook.com/v17.0/{PHONE_NUMBER_ID}/messages"
101
- headers = {
102
- "Authorization": f"Bearer {ACCESS_TOKEN}",
103
- "Content-Type": "application/json"
104
- }
105
- payload = {
106
- "messaging_product": "whatsapp",
107
- "to": RECIPIENT_NUMBER,
108
- "type": "template",
109
- "template": {
110
- "name": "hello_world",
111
- "language": { "code": "en_US" }
112
- }
113
- }
114
-
115
- response = requests.post(url, headers=headers, json=payload)
116
- try:
117
- response.raise_for_status()
118
- return {"status": "sent", "response": response.json()}
119
- except Exception as e:
120
- return {"status": "failed", "error": str(e)}
 
1
  # app/routes/wa_gateway.py
2
  from fastapi import APIRouter, Request
3
+ import os, requests, asyncio
 
4
  from dotenv import load_dotenv
5
  from fastapi.responses import PlainTextResponse, JSONResponse
6
 
7
+ # ----- import the Q&A logic -----
8
+ from routes.question import ask_question, QuestionInput # ← new
9
+
10
  load_dotenv()
11
 
12
  wa_router = APIRouter()
13
 
14
+ VERIFY_TOKEN = os.getenv("VERIFY_TOKEN")
15
+ ACCESS_TOKEN = os.getenv("WHATSAPP_ACCESS_TOKEN")
16
+ PHONE_NUMBER_ID = os.getenv("WHATSAPP_PHONE_NUMBER_ID")
17
+
18
+ # ------------------------------------------------------------------
19
+ # Helper: actually POST a plain-text WhatsApp message via Graph API
20
+ # ------------------------------------------------------------------
21
+ def send_whatsapp_text(to: str, text: str) -> dict:
22
+ """
23
+ Send a plain text message (max 4096 chars per WhatsApp limits).
24
+ Returns {'status': 'sent' | 'failed', ... } for easy logging.
25
+ """
26
+ url = f"https://graph.facebook.com/v17.0/{PHONE_NUMBER_ID}/messages"
27
  headers = {
28
  "Authorization": f"Bearer {ACCESS_TOKEN}",
29
+ "Content-Type": "application/json",
30
  }
31
  payload = {
32
  "messaging_product": "whatsapp",
33
+ "to": to,
34
+ "type": "text",
35
+ "text": {"body": text[:4096]}, # truncate if necessary
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  }
37
 
 
38
  try:
39
+ r = requests.post(url, headers=headers, json=payload)
40
+ r.raise_for_status()
41
+ return {"status": "sent", "response": r.json()}
42
  except Exception as e:
43
  return {"status": "failed", "error": str(e)}
44
 
45
+ # ------------------------------------------------------------------
46
+ # Helper: glue logic – ask Mistral and relay the reply to WhatsApp
47
+ # ------------------------------------------------------------------
48
+ async def nuse_interact(to: str, name: str, prompt: str) -> dict:
49
+ """
50
+ 1. Call ask_question() directly (no HTTP round-trip);
51
+ 2. Extract the answer text (+sources if you like);
52
+ 3. Push it back to the user via WhatsApp API.
53
+ """
54
+ # 1) Ask the news assistant
55
+ qa_result = await ask_question(QuestionInput(question=prompt))
56
+ answer_text = qa_result["answer"]
57
+
58
+ # Optional: include sources as bullet list
59
+ if qa_result.get("sources"):
60
+ bullet_list = "\n".join(f"β€’ {s['title']}" for s in qa_result["sources"])
61
+ answer_text = f"{answer_text}\n\nSources:\n{bullet_list}"
62
+
63
+ # 2) Send to WhatsApp
64
+ return send_whatsapp_text(to, answer_text)
65
+
66
+ # ------------------------------------------------------------------
67
+ # Webhook verification (unchanged)
68
+ # ------------------------------------------------------------------
69
  @wa_router.get("/webhook")
70
  async def verify_webhook(request: Request):
71
  params = request.query_params
72
  if params.get("hub.mode") == "subscribe" and params.get("hub.verify_token") == VERIFY_TOKEN:
 
73
  return PlainTextResponse(content=params.get("hub.challenge"))
74
  return JSONResponse(status_code=403, content={"error": "Verification failed"})
75
 
76
+ # ------------------------------------------------------------------
77
+ # Incoming WhatsApp messages
78
+ # ------------------------------------------------------------------
79
  @wa_router.post("/webhook")
80
  async def receive_whatsapp_event(request: Request):
81
  body = await request.json()
82
+ print("[WEBHOOK] Incoming:", body)
83
 
 
84
  try:
85
+ entry = body["entry"][0]
86
+ changes = entry["changes"][0]
87
+ value = changes["value"]
88
  messages = value.get("messages")
89
  contacts = value.get("contacts")
90
 
91
  if messages and contacts:
92
+ msg = messages[0]
93
  contact = contacts[0]
94
 
95
+ from_number = msg["from"]
96
+ sender_name = contact["profile"]["name"]
97
+ incoming_txt = msg["text"]["body"]
 
 
 
 
98
 
99
+ print(f"[INFO] {sender_name} ({from_number}): {incoming_txt}")
 
100
 
101
+ # Hand off to Q&A -> WhatsApp reply
102
+ result = await nuse_interact(from_number, sender_name, incoming_txt)
103
+ print("[INFO] Reply status:", result)
104
 
105
  except Exception as e:
106
  print("[ERROR] Webhook processing failed:", str(e))
107
 
108
  return JSONResponse(content={"status": "received"})