rairo commited on
Commit
460d20c
·
verified ·
1 Parent(s): 6f7dd31

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +142 -71
main.py CHANGED
@@ -24,6 +24,13 @@ load_dotenv()
24
  nameserver1 = os.getenv('nameserver1', '8.8.8.8')
25
  nameserver2 = os.getenv('nameserver2', '8.8.4.4')
26
 
 
 
 
 
 
 
 
27
  # Configure global DNS resolution
28
  def setup_dns():
29
  """Configure DNS resolution globally"""
@@ -49,6 +56,72 @@ def setup_dns():
49
  # Setup DNS resolution
50
  setup_dns()
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  # Initialize WhatsApp
53
  try:
54
  messenger = WhatsApp(
@@ -102,87 +175,85 @@ def hook():
102
  """Main webhook handler"""
103
  try:
104
  data = request.get_json()
105
- logger.info("Received webhook data: %s", data)
106
-
107
- changed_field = messenger.changed_field(data)
108
- if changed_field != "messages":
109
- return "OK", 200
110
-
111
- if not messenger.is_message(data):
112
- delivery = messenger.get_delivery(data)
113
- if delivery:
114
- logger.info(f"Message delivery status: {delivery}")
115
- return "OK", 200
116
-
117
- # Extract message details
118
  mobile = messenger.get_mobile(data)
119
- name = messenger.get_name(data)
120
- message_type = messenger.get_message_type(data)
121
 
122
- logger.info(f"New Message; sender:{mobile} name:{name} type:{message_type}")
123
-
124
- # Handle different message types
125
- try:
126
- if message_type == "text":
127
- message = messenger.get_message(data)
128
- logger.info("Message: %s", message)
129
- messenger.send_message(f"Hi {name}, nice to connect with you", mobile)
130
-
131
- elif message_type == "interactive":
132
- message_response = messenger.get_interactive_response(data)
133
- interactive_type = message_response.get("type")
134
- message_id = message_response[interactive_type]["id"]
135
- message_text = message_response[interactive_type]["title"]
136
- logger.info(f"Interactive Message; {message_id}: {message_text}")
137
-
138
- elif message_type == "location":
139
- message_location = messenger.get_location(data)
140
- message_latitude = message_location["latitude"]
141
- message_longitude = message_location["longitude"]
142
- logger.info("Location: %s, %s", message_latitude, message_longitude)
143
-
144
- elif message_type in ["image", "video", "audio", "document"]:
145
- handle_media_message(messenger, data, message_type, mobile)
146
-
147
  else:
148
- logger.info(f"{mobile} sent unsupported message type: {message_type}")
149
- logger.debug(f"Full message data: {data}")
150
-
151
- except Exception as e:
152
- logger.error(f"Error processing message type {message_type}: {str(e)}")
153
- return "Internal server error", 500
154
-
 
 
 
 
 
155
  return "OK", 200
156
 
157
  except Exception as e:
158
- logger.error(f"Error in webhook handler: {str(e)}")
159
  return "Internal server error", 500
160
 
161
- def handle_media_message(messenger, data, message_type, mobile):
162
- """Handle different types of media messages"""
163
- try:
164
- media_methods = {
165
- "image": messenger.get_image,
166
- "video": messenger.get_video,
167
- "audio": messenger.get_audio,
168
- "document": messenger.get_document
169
- }
170
 
171
- media = media_methods[message_type](data)
172
- media_id, mime_type = media["id"], media["mime_type"]
 
 
 
 
 
 
 
173
 
174
- try:
175
- media_url = messenger.query_media_url(media_id)
176
- media_filename = messenger.download_media(media_url, mime_type)
177
- logger.info(f"{mobile} sent {message_type} {media_filename}")
178
- except requests.exceptions.ConnectionError as ce:
179
- logger.error(f"Connection error while downloading {message_type}: {str(ce)}")
180
- except Exception as e:
181
- logger.error(f"Error downloading {message_type}: {str(e)}")
182
-
183
- except Exception as e:
184
- logger.error(f"Error processing {message_type} message: {str(e)}")
185
- raise
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
  def test_connection():
188
  """Test DNS resolution and connection to Graph API"""
 
24
  nameserver1 = os.getenv('nameserver1', '8.8.8.8')
25
  nameserver2 = os.getenv('nameserver2', '8.8.4.4')
26
 
27
+ # Configure Gemini AI
28
+ genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
29
+ gemini = genai.GenerativeModel('gemini-2.0-flash-exp')
30
+
31
+ products_df = pd.read_csv("supermarket_data1.csv")
32
+ user_carts: Dict[str, List[dict]] = {}
33
+
34
  # Configure global DNS resolution
35
  def setup_dns():
36
  """Configure DNS resolution globally"""
 
56
  # Setup DNS resolution
57
  setup_dns()
58
 
59
+ def parse_user_intent(text: str) -> dict:
60
+ """Use Gemini to parse user intent and context"""
61
+ try:
62
+ prompt = f"""Analyze this shopping query and return JSON with:
63
+ - intent: [product_search, cart_check, checkout, other]
64
+ - scenario: brief description
65
+ - budget: extracted number or null
66
+ - required_categories: list of relevant product categories
67
+ - constraints: list of important constraints
68
+
69
+ Query: {text}"""
70
+
71
+ response = gemini.generate_content(prompt)
72
+ return eval(response.text)
73
+ except Exception as e:
74
+ logger.error(f"Gemini parse error: {e}")
75
+ return {"intent": "other"}
76
+
77
+ def search_products(query: dict, branch: str = "Harare") -> pd.DataFrame:
78
+ """Search products based on Gemini analysis"""
79
+ try:
80
+ filtered = products_df[
81
+ (products_df["Branch"] == branch) &
82
+ (products_df["Category"].isin(query.get("required_categories", []))) &
83
+ (products_df["Price"] <= (query.get("budget") or float('inf')))
84
+ ]
85
+ return filtered.sort_values("Price").head(5)
86
+ except Exception as e:
87
+ logger.error(f"Search error: {e}")
88
+ return pd.DataFrame()
89
+
90
+ def create_cart_response(user_id: str, products: pd.DataFrame, total: float = 0):
91
+ """Create interactive cart response with buttons"""
92
+ products_text = "\n".join(
93
+ f"{row['Product']} - ${row['Price']:.2f}"
94
+ for _, row in products.iterrows()
95
+ )
96
+
97
+ buttons = []
98
+ if not products.empty:
99
+ for _, row in products.iterrows():
100
+ buttons.append({
101
+ "type": "reply",
102
+ "reply": {"id": f"add_{row.name}", "title": f"Add {row['Product']}"}
103
+ })
104
+ buttons.append({"type": "reply", "reply": {"id": "cancel", "title": "Cancel"}})
105
+ else:
106
+ return {"text": "No products found matching your criteria."}
107
+
108
+ cart = user_carts.get(user_id, [])
109
+ if cart:
110
+ cart_total = sum(item["price"] for item in cart)
111
+ response_text = (
112
+ f"Suggested Products:\n{products_text}\n\n"
113
+ f"Current Cart Total: ${cart_total:.2f}\n"
114
+ "Select products to add:"
115
+ )
116
+ buttons.extend([
117
+ {"type": "reply", "reply": {"id": "checkout", "title": "Checkout"}},
118
+ {"type": "reply", "reply": {"id": "continue", "title": "Keep Shopping"}}
119
+ ])
120
+ else:
121
+ response_text = f"Suggested Products:\n{products_text}\n\nSelect products to add:"
122
+
123
+ return {"text": response_text, "buttons": buttons}
124
+
125
  # Initialize WhatsApp
126
  try:
127
  messenger = WhatsApp(
 
175
  """Main webhook handler"""
176
  try:
177
  data = request.get_json()
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  mobile = messenger.get_mobile(data)
 
 
179
 
180
+ if messenger.is_message(data):
181
+ message = messenger.get_message(data)
182
+ intent = parse_user_intent(message)
183
+
184
+ if intent["intent"] == "checkout":
185
+ return handle_checkout(mobile)
186
+
187
+ elif intent["intent"] == "cart_check":
188
+ return send_cart_summary(mobile)
189
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  else:
191
+ products = search_products(intent)
192
+ response = create_cart_response(mobile, products)
193
+ messenger.send_interactive_button(
194
+ response["text"],
195
+ response["buttons"],
196
+ mobile
197
+ )
198
+
199
+ elif messenger.is_interactive(data):
200
+ response = messenger.get_interactive_response(data)
201
+ handle_button_click(mobile, response["id"])
202
+
203
  return "OK", 200
204
 
205
  except Exception as e:
206
+ logger.error(f"Webhook error: {e}")
207
  return "Internal server error", 500
208
 
209
+ def handle_button_click(user_id: str, button_id: str):
210
+ """Handle interactive button clicks"""
211
+ if button_id.startswith("add_"):
212
+ product_id = int(button_id.split("_")[1])
213
+ product = products_df.loc[product_id].to_dict()
214
+ user_carts.setdefault(user_id, []).append(product)
215
+ messenger.send_message(f"{product['Product']} added to cart!", user_id)
 
 
216
 
217
+ elif button_id == "checkout":
218
+ messenger.send_interactive_button(
219
+ "Confirm checkout?",
220
+ [
221
+ {"type": "reply", "reply": {"id": "confirm", "title": "Confirm"}},
222
+ {"type": "reply", "reply": {"id": "cancel", "title": "Cancel"}}
223
+ ],
224
+ user_id
225
+ )
226
 
227
+ elif button_id == "confirm":
228
+ cart = user_carts.pop(user_id, [])
229
+ total = sum(item["Price"] for item in cart)
230
+ messenger.send_message(
231
+ f"Order confirmed! Total: ${total:.2f}\n"
232
+ "Your items will be ready for pickup in 1 hour.",
233
+ user_id
234
+ )
235
+
236
+ def send_cart_summary(user_id: str):
237
+ """Send current cart summary to user"""
238
+ cart = user_carts.get(user_id, [])
239
+ if not cart:
240
+ messenger.send_message("Your cart is empty!", user_id)
241
+ return
242
+
243
+ cart_text = "\n".join(
244
+ f"{item['Product']} - ${item['Price']:.2f}"
245
+ for item in cart
246
+ )
247
+ total = sum(item["Price"] for item in cart)
248
+
249
+ messenger.send_interactive_button(
250
+ f"Current Cart:\n{cart_text}\nTotal: ${total:.2f}",
251
+ [
252
+ {"type": "reply", "reply": {"id": "checkout", "title": "Checkout"}},
253
+ {"type": "reply", "reply": {"id": "clear", "title": "Clear Cart"}}
254
+ ],
255
+ user_id
256
+ )
257
 
258
  def test_connection():
259
  """Test DNS resolution and connection to Graph API"""