Update app.py
Browse files
app.py
CHANGED
@@ -49,6 +49,7 @@ class Order(Base):
|
|
49 |
price = Column(String, default="0")
|
50 |
status = Column(String, default="Pending Payment")
|
51 |
payment_reference = Column(String, nullable=True)
|
|
|
52 |
timestamp = Column(DateTime, default=datetime.utcnow)
|
53 |
|
54 |
class UserProfile(Base):
|
@@ -212,9 +213,10 @@ def stream_image_completion(image_b64: str):
|
|
212 |
def process_order_flow(user_id: str, message: str) -> str:
|
213 |
"""
|
214 |
Implements an FSM-based order flow that:
|
215 |
-
-
|
216 |
-
-
|
217 |
-
-
|
|
|
218 |
"""
|
219 |
# Retrieve or initialize conversation state
|
220 |
state = user_state.get(user_id)
|
@@ -253,7 +255,6 @@ def process_order_flow(user_id: str, message: str) -> str:
|
|
253 |
if dish.lower() in message.lower():
|
254 |
found_dish = dish
|
255 |
break
|
256 |
-
|
257 |
numbers = re.findall(r'\d+', message)
|
258 |
if found_dish:
|
259 |
state.data["dish"] = found_dish
|
@@ -262,9 +263,11 @@ def process_order_flow(user_id: str, message: str) -> str:
|
|
262 |
if quantity <= 0:
|
263 |
return "Please enter a valid quantity (e.g., 1, 2, 3)."
|
264 |
state.data["quantity"] = quantity
|
265 |
-
state.step = 3 #
|
|
|
266 |
else:
|
267 |
state.step = 2 # ask for quantity
|
|
|
268 |
else:
|
269 |
return "I couldn't identify the dish. Please type the dish name from our menu."
|
270 |
|
@@ -278,44 +281,59 @@ def process_order_flow(user_id: str, message: str) -> str:
|
|
278 |
return "Please enter a valid quantity (e.g., 1, 2, 3)."
|
279 |
state.data["quantity"] = quantity
|
280 |
state.step = 3
|
|
|
281 |
|
282 |
-
# --- Step 3:
|
283 |
if state.step == 3:
|
284 |
-
|
285 |
-
state.data["
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
)
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
317 |
else:
|
318 |
-
|
|
|
|
|
|
|
319 |
|
320 |
return ""
|
321 |
|
@@ -508,8 +526,6 @@ async def chatbot_response(request: Request, background_tasks: BackgroundTasks):
|
|
508 |
return StreamingResponse(stream_response(), media_type="text/plain")
|
509 |
|
510 |
# --- Other Endpoints (Chat History, Order Details, User Profile, Analytics, Voice, Payment Callback) ---
|
511 |
-
# ... (Implement other endpoints as needed) ...
|
512 |
-
|
513 |
@app.get("/chat_history/{user_id}")
|
514 |
async def get_chat_history(user_id: str):
|
515 |
async with async_session() as session:
|
|
|
49 |
price = Column(String, default="0")
|
50 |
status = Column(String, default="Pending Payment")
|
51 |
payment_reference = Column(String, nullable=True)
|
52 |
+
delivery_address = Column(String, default="") # New field for address
|
53 |
timestamp = Column(DateTime, default=datetime.utcnow)
|
54 |
|
55 |
class UserProfile(Base):
|
|
|
213 |
def process_order_flow(user_id: str, message: str) -> str:
|
214 |
"""
|
215 |
Implements an FSM-based order flow that:
|
216 |
+
- Step 1: Expects the user to mention a dish name (optionally with quantity)
|
217 |
+
- Step 2: Asks for quantity if not provided
|
218 |
+
- Step 3: Requests the delivery address
|
219 |
+
- Step 4: Asks for order confirmation (yes/no) and finalizes the order
|
220 |
"""
|
221 |
# Retrieve or initialize conversation state
|
222 |
state = user_state.get(user_id)
|
|
|
255 |
if dish.lower() in message.lower():
|
256 |
found_dish = dish
|
257 |
break
|
|
|
258 |
numbers = re.findall(r'\d+', message)
|
259 |
if found_dish:
|
260 |
state.data["dish"] = found_dish
|
|
|
263 |
if quantity <= 0:
|
264 |
return "Please enter a valid quantity (e.g., 1, 2, 3)."
|
265 |
state.data["quantity"] = quantity
|
266 |
+
state.step = 3 # move directly to address step
|
267 |
+
return f"You selected {found_dish} with {quantity} serving(s). Please provide your delivery address."
|
268 |
else:
|
269 |
state.step = 2 # ask for quantity
|
270 |
+
return f"You selected {found_dish}. How many servings would you like?"
|
271 |
else:
|
272 |
return "I couldn't identify the dish. Please type the dish name from our menu."
|
273 |
|
|
|
281 |
return "Please enter a valid quantity (e.g., 1, 2, 3)."
|
282 |
state.data["quantity"] = quantity
|
283 |
state.step = 3
|
284 |
+
return f"Got it. {quantity} serving(s) of {state.data.get('dish')}. Now, please provide your delivery address."
|
285 |
|
286 |
+
# --- Step 3: Requesting Delivery Address ---
|
287 |
if state.step == 3:
|
288 |
+
# Assume any text is a valid address
|
289 |
+
state.data["address"] = message
|
290 |
+
state.step = 4
|
291 |
+
return f"Thanks. Your delivery address is recorded as: {message}. Confirm order? (yes/no)"
|
292 |
+
|
293 |
+
# --- Step 4: Order Confirmation & Finalization ---
|
294 |
+
if state.step == 4:
|
295 |
+
if message.lower() in ["yes", "y"]:
|
296 |
+
order_id = f"ORD-{int(time.time())}"
|
297 |
+
state.data["order_id"] = order_id
|
298 |
+
price_per_serving = 1500 # fixed price per serving for demonstration
|
299 |
+
quantity = state.data.get("quantity", 1)
|
300 |
+
total_price = quantity * price_per_serving
|
301 |
+
state.data["price"] = str(total_price)
|
302 |
+
|
303 |
+
# Save the order asynchronously (including delivery_address)
|
304 |
+
async def save_order():
|
305 |
+
async with async_session() as session:
|
306 |
+
order = Order(
|
307 |
+
order_id=order_id,
|
308 |
+
user_id=user_id,
|
309 |
+
dish=state.data["dish"],
|
310 |
+
quantity=str(quantity),
|
311 |
+
price=str(total_price),
|
312 |
+
status="Pending Payment",
|
313 |
+
delivery_address=state.data.get("address", "")
|
314 |
+
)
|
315 |
+
session.add(order)
|
316 |
+
await session.commit()
|
317 |
+
asyncio.create_task(save_order())
|
318 |
+
|
319 |
+
email = "[email protected]" # Placeholder; retrieve from profile if available
|
320 |
+
payment_data = create_paystack_payment_link(email, total_price * 100, order_id)
|
321 |
+
dish_name = state.data.get("dish", "")
|
322 |
+
state.reset()
|
323 |
+
if user_id in user_state:
|
324 |
+
del user_state[user_id]
|
325 |
+
if payment_data.get("status"):
|
326 |
+
payment_link = payment_data["data"]["authorization_url"]
|
327 |
+
return (f"Thank you for your order of {quantity} serving(s) of {dish_name}! "
|
328 |
+
f"Your Order ID is {order_id}.\nPlease complete payment here: {payment_link}\n"
|
329 |
+
"You can track your order status using your Order ID.")
|
330 |
+
else:
|
331 |
+
return f"Your order has been placed with Order ID {order_id}, but we could not initialize payment. Please try again later."
|
332 |
else:
|
333 |
+
state.reset()
|
334 |
+
if user_id in user_state:
|
335 |
+
del user_state[user_id]
|
336 |
+
return "Order canceled. Let me know if you'd like to try again."
|
337 |
|
338 |
return ""
|
339 |
|
|
|
526 |
return StreamingResponse(stream_response(), media_type="text/plain")
|
527 |
|
528 |
# --- Other Endpoints (Chat History, Order Details, User Profile, Analytics, Voice, Payment Callback) ---
|
|
|
|
|
529 |
@app.get("/chat_history/{user_id}")
|
530 |
async def get_chat_history(user_id: str):
|
531 |
async with async_session() as session:
|