tsrivallabh commited on
Commit
62d7f74
Β·
verified Β·
1 Parent(s): a38e4b0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +497 -500
app.py CHANGED
@@ -1,500 +1,497 @@
1
- import streamlit as st
2
- from openai import OpenAI
3
- import sqlite3
4
- import pandas as pd
5
- import re
6
- import json
7
- from sticky import sticky_container
8
- import chromadb
9
- from sentence_transformers import SentenceTransformer
10
- from transformers import pipeline
11
- import hashlib
12
- import inspect
13
- from tools import *
14
- from var import SCHEMA_DESCRIPTIONS, SchemaVectorDB, FullVectorDB
15
- import os
16
- from dotenv import load_dotenv
17
- load_dotenv()
18
-
19
- # Set your Groq API key
20
- GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
21
-
22
- # Initialize Groq's OpenAI-compatible client
23
- client = OpenAI(
24
- api_key=GROQ_API_KEY,
25
- base_url="https://api.groq.com/openai/v1"
26
- )
27
-
28
- # --- Load prompt templates from prompts folder ---
29
- with open("prompts/determine_intent.txt", "r", encoding="utf-8") as f:
30
- determine_intent_prompt = f.read()
31
-
32
- with open("prompts/generate_reservation_conversation.txt", "r", encoding="utf-8") as f:
33
- generate_reservation_conversation_prompt = f.read()
34
-
35
- with open("prompts/interpret_sql_result.txt", "r", encoding="utf-8") as f:
36
- interpret_sql_result_prompt = f.read()
37
-
38
- with open("prompts/schema_prompt.txt", "r", encoding="utf-8") as f:
39
- schema_prompt = f.read()
40
-
41
- with open("prompts/store_user_info.txt", "r", encoding="utf-8") as f:
42
- store_user_info_prompt = f.read()
43
-
44
-
45
-
46
- st.set_page_config(page_title="FoodieSpot Assistant", layout="wide")
47
-
48
-
49
- # --- Initialize State ---
50
- if 'chat_history' not in st.session_state:
51
- st.session_state.chat_history = []
52
-
53
- if 'user_data' not in st.session_state:
54
- st.session_state.user_data = {
55
- "restaurant_name": None,
56
- "user_name": None,
57
- "contact": None,
58
- "party_size": None,
59
- "time": None
60
- }
61
- if 'vector_db' not in st.session_state:
62
- st.session_state.vector_db = SchemaVectorDB()
63
- vector_db = st.session_state.vector_db
64
- if 'full_vector_db' not in st.session_state:
65
- st.session_state.full_vector_db = FullVectorDB()
66
- # Track last assistant reply for context
67
- if 'last_assistant_reply' not in st.session_state:
68
- st.session_state.last_assistant_reply = ""
69
- # Fixed container at top for title + reservation
70
- reservation_box = sticky_container(mode="top", border=False,z=999)
71
-
72
- with reservation_box:
73
- st.text("")
74
- st.text("")
75
- st.title("🍽️ FoodieSpot Assistant")
76
- cols = st.columns([3, 3, 3, 2, 2, 1])
77
-
78
- with cols[0]:
79
- restaurant_name = st.text_input(
80
- "Restaurant Name",
81
- value=st.session_state.user_data.get("restaurant_name") or "",
82
- key="restaurant_name_input"
83
- )
84
- if restaurant_name!="":
85
- st.session_state.user_data["restaurant_name"] = restaurant_name
86
-
87
- with cols[1]:
88
- user_name = st.text_input(
89
- "Your Name",
90
- value=st.session_state.user_data.get("user_name") or "",
91
- key="user_name_input"
92
- )
93
- if user_name!="":
94
- st.session_state.user_data["user_name"] = user_name
95
-
96
- with cols[2]:
97
- contact = st.text_input(
98
- "Contact",
99
- value=st.session_state.user_data.get("contact") or "",
100
- key="contact_input"
101
- )
102
- if contact!="":
103
- st.session_state.user_data["contact"] = contact
104
-
105
- with cols[3]:
106
- party_size = st.number_input(
107
- "Party Size",
108
- value=st.session_state.user_data.get("party_size") or 0,
109
- key="party_size_input"
110
- )
111
- if party_size!=0:
112
- st.session_state.user_data["party_size"] = party_size
113
-
114
- with cols[4]:
115
- time = st.number_input(
116
- "Time(24hr form, 9-20, 8 ~ null)",
117
- min_value=8,
118
- max_value=20,
119
- value=st.session_state.user_data.get("time") or 8,
120
- key="time_input"
121
- )
122
- if time!=8:
123
- st.session_state.user_data["time"] = time
124
- # Place the BOOK button in the last column
125
- with cols[5]:
126
- st.text("")
127
- st.text("")
128
- book_clicked = st.button("BOOK", type="primary")
129
- # Add a green BOOK button (primary style)
130
- # book_clicked = st.button("BOOK", type="primary")
131
-
132
- if book_clicked:
133
- # Check if all required fields are filled
134
- required_keys = ["restaurant_name", "user_name", "contact", "party_size", "time"]
135
- if all(st.session_state.user_data.get(k) not in [None, "", 0, 8] for k in required_keys):
136
- booking_conn = None
137
- try:
138
- user_data = st.session_state.user_data
139
- party_size = int(user_data["party_size"])
140
- tables_needed = -(-party_size // 4)
141
-
142
- booking_conn = sqlite3.connect("db/restaurant_reservation.db")
143
- booking_cursor = booking_conn.cursor()
144
-
145
- booking_cursor.execute("SELECT id FROM restaurants WHERE LOWER(name) = LOWER(?)", (user_data["restaurant_name"],))
146
- restaurant_row = booking_cursor.fetchone()
147
- if not restaurant_row:
148
- raise Exception("Restaurant not found.")
149
- restaurant_id = restaurant_row[0]
150
-
151
- booking_cursor.execute("""
152
- SELECT t.id AS table_id, s.id AS slot_id
153
- FROM tables t
154
- JOIN slots s ON t.id = s.table_id
155
- WHERE t.restaurant_id = ?
156
- AND s.hour = ?
157
- AND s.date = '2025-05-12'
158
- AND s.is_reserved = 0
159
- LIMIT ?
160
- """, (restaurant_id, user_data["time"], tables_needed))
161
- available = booking_cursor.fetchall()
162
-
163
- if len(available) < tables_needed:
164
- raise Exception("Not enough available tables.")
165
-
166
- booking_cursor.execute("""
167
- INSERT INTO reservations (restaurant_id, user_name, contact, date, time, party_size)
168
- VALUES (?, ?, ?, '2025-05-12', ?, ?)
169
- """, (restaurant_id, user_data["user_name"], user_data["contact"], user_data["time"], party_size))
170
- reservation_id = booking_cursor.lastrowid
171
-
172
- for table_id, _ in available:
173
- booking_cursor.execute("INSERT INTO reservation_tables (reservation_id, table_id) VALUES (?, ?)", (reservation_id, table_id))
174
-
175
- slot_ids = [slot_id for _, slot_id in available]
176
- booking_cursor.executemany("UPDATE slots SET is_reserved = 1 WHERE id = ?", [(sid,) for sid in slot_ids])
177
-
178
- booking_conn.commit()
179
-
180
- booking_cursor.execute("SELECT name FROM restaurants WHERE id = ?", (restaurant_id,))
181
- restaurant_name = booking_cursor.fetchone()[0]
182
-
183
- confirmation_msg = (
184
- f"βœ… Booking processed successfully!\n\n"
185
- f"πŸ“ Restaurant: **{restaurant_name}**\n"
186
- f"⏰ Time: **{user_data['time']} on 2025-05-12**\n"
187
- f"🍽️ Tables Booked: **{tables_needed}**\n"
188
- f"πŸ†” Reservation ID: **{reservation_id}**\n\n"
189
- f"πŸ‘‰ Please mention this Reservation ID at the restaurant reception when you arrive."
190
- )
191
-
192
- st.success(confirmation_msg)
193
- st.session_state.chat_history.append({'role': 'assistant', 'message': confirmation_msg})
194
- st.session_state.user_data["restaurant_name"] = None
195
- st.session_state.user_data["party_size"] = None
196
- st.session_state.user_data["time"] = None
197
- st.session_state.last_assistant_reply = ""
198
- except Exception as e:
199
- if booking_conn:
200
- booking_conn.rollback()
201
- st.error(f"❌ Booking failed: {e}")
202
- finally:
203
- if booking_conn:
204
- booking_cursor = None
205
- booking_conn.close()
206
- else:
207
- st.warning("⚠️ Missing user information. Please provide all booking details first.")
208
- st.text("")
209
- # Inject custom CSS for smaller font and tighter layout
210
- st.markdown("""
211
- <style>
212
- .element-container:has(.streamlit-expander) {
213
- margin-bottom: 0.5rem;
214
- }
215
- .streamlit-expanderHeader {
216
- font-size: 0.9rem;
217
- }
218
- .streamlit-expanderContent {
219
- font-size: 0.85rem;
220
- padding: 0.5rem 1rem;
221
- }
222
- </style>
223
- """, unsafe_allow_html=True)
224
-
225
- with st.container():
226
- col1, col2, col3 = st.columns(3)
227
-
228
- with col1:
229
- with st.expander("🍽️ Restaurants"):
230
- st.markdown("""
231
- - Bella Italia
232
- - Spice Symphony
233
- - Tokyo Ramen House
234
- - Saffron Grill
235
- - El Toro Loco
236
- - Noodle Bar
237
- - Le Petit Bistro
238
- - Tandoori Nights
239
- - Green Leaf Cafe
240
- - Ocean Pearl
241
- - Mama Mia Pizza
242
- - The Dumpling Den
243
- - Bangkok Express
244
- - Curry Kingdom
245
- - The Garden Table
246
- - Skyline Dine
247
- - Pasta Republic
248
- - Street Tacos Co
249
- - Miso Hungry
250
- - Chez Marie
251
- """)
252
-
253
- with col2:
254
- with st.expander("🌎 Cuisines"):
255
- st.markdown("""
256
- - Italian
257
- - French
258
- - Chinese
259
- - Japanese
260
- - Indian
261
- - Mexican
262
- - Thai
263
- - Healthy
264
- - Fusion
265
- """)
266
-
267
- with col3:
268
- with st.expander("✨ Special Features"):
269
- st.markdown("""
270
- - Pet-Friendly
271
- - Live Music
272
- - Rooftop View
273
- - Outdoor Seating
274
- - Private Dining
275
- """)
276
-
277
-
278
-
279
-
280
- # --- Display previous chat history (before new input) ---
281
-
282
- for msg in st.session_state.chat_history:
283
- # Check if both 'role' and 'message' are not None
284
- if msg['role'] is not None and msg['message'] is not None:
285
- with st.chat_message(msg['role']):
286
- st.markdown(msg['message'])
287
-
288
- user_input = st.chat_input("Ask something about restaurants or reservations(eg. Tell me some best rated Italian cuisine restaurants)...")
289
- if user_input:
290
- # Show user message instantly
291
- with st.chat_message("user"):
292
- st.markdown(user_input)
293
- st.session_state.chat_history.append({'role': 'user', 'message': user_input})
294
-
295
- # Prepare conversation context
296
- history_prompt = st.session_state.last_assistant_reply
297
-
298
- # Store possible user info
299
- user_info = store_user_info(user_input,history_prompt,store_user_info_prompt,client)
300
- if user_info:
301
- st.session_state.user_data.update(user_info)
302
- # st.rerun()
303
-
304
- # Detect intent
305
- intent = determine_intent(user_input,determine_intent_prompt,client)
306
- # st.write(intent)
307
- if intent == "RUBBISH":
308
- # Display user data for confirmation instead of invoking LLM
309
- with st.chat_message("assistant"):
310
- st.markdown("❌ Sorry, I didn't understand that. Could you rephrase your request?")
311
- st.session_state.chat_history.append({
312
- 'role': 'assistant',
313
- 'message': "❌ Sorry, I didn't understand that. Could you rephrase your request?"
314
- })
315
-
316
- st.stop()
317
-
318
- # Generate assistant reply
319
- required_keys = ["restaurant_name", "user_name", "contact", "party_size", "time"]
320
- user_data_complete = all(
321
- k in st.session_state.user_data and st.session_state.user_data[k] not in [None, "", "NULL"]
322
- for k in required_keys
323
- )
324
-
325
-
326
- if user_data_complete and intent != "BOOK":
327
-
328
- # Format user data as a Markdown bullet list
329
- user_details = "\n".join([f"- **{key.capitalize()}**: {value}" for key, value in st.session_state.user_data.items()])
330
-
331
- with st.chat_message("assistant"):
332
- st.markdown("βœ… I have all the details needed for your reservation:")
333
- st.markdown(user_details)
334
- st.markdown("If everything looks good, please type **`book`** to confirm the reservation.")
335
-
336
- st.session_state.chat_history.append({
337
- 'role': 'assistant',
338
- 'message': f"βœ… I have all the details needed for your reservation:\n{user_details}\nPlease type **`book`** to confirm."
339
- })
340
- st.session_state.last_assistant_reply = "I have all the reservation details. Waiting for confirmation..."
341
- st.rerun()
342
- st.stop()
343
-
344
-
345
-
346
-
347
- response_summary = None
348
-
349
- if intent == "SELECT":
350
- response_summary=handle_query(user_input, st.session_state.full_vector_db, client)
351
-
352
- # First try semantic search
353
- semantic_results = {}
354
-
355
- # Search across all collections
356
- restaurant_results = st.session_state.full_vector_db.semantic_search(user_input, "restaurants")
357
- table_results = st.session_state.full_vector_db.semantic_search(user_input, "tables")
358
- slot_results = st.session_state.full_vector_db.semantic_search(user_input, "slots")
359
-
360
- if not is_large_output_request(user_input) and any([restaurant_results, table_results, slot_results]):
361
- semantic_results = {
362
- "restaurants": restaurant_results,
363
- "tables": table_results,
364
- "slots": slot_results
365
- }
366
- # Format semantic results
367
- summary = []
368
- for category, items in semantic_results.items():
369
- if items:
370
- summary.append(f"Found {len(items)} relevant {category}:")
371
- summary.extend([f"- {item['name']}" if 'name' in item else f"- {item}"
372
- for item in items[:3]])
373
- st.write("### Semantic Search used")
374
- response_summary = "\n".join(summary)
375
- else:
376
- # Fall back to SQL generation for large or exact output requests
377
- sql = generate_sql_query_v2(user_input,SCHEMA_DESCRIPTIONS, history_prompt, vector_db, client)
378
- result = execute_query(sql)
379
- response_summary = interpret_result_v2(result, user_input, sql)
380
-
381
-
382
-
383
- # sql = generate_sql_query_v2(user_input,history_prompt, vector_db, client)
384
- # result = execute_query(sql)
385
- # response_summary=interpret_result_v2(result, user_input, sql)
386
- # if isinstance(result, pd.DataFrame):
387
- # response_summary = interpret_sql_result(user_input, sql_query, result)
388
-
389
-
390
- elif intent == "BOOK":
391
- required_keys = ["restaurant_name", "user_name", "contact", "party_size", "time"]
392
- if all(st.session_state.user_data.get(k) is not None for k in required_keys):
393
- booking_conn = None
394
- try:
395
- user_data = st.session_state.user_data
396
- party_size = int(user_data["party_size"])
397
- tables_needed = -(-party_size // 4)
398
-
399
- booking_conn = sqlite3.connect("db/restaurant_reservation.db")
400
- booking_cursor = booking_conn.cursor()
401
-
402
- booking_cursor.execute("SELECT id FROM restaurants WHERE LOWER(name) = LOWER(?)", (user_data["restaurant_name"],))
403
- restaurant_row = booking_cursor.fetchone()
404
- if not restaurant_row:
405
- raise Exception("Restaurant not found.")
406
- restaurant_id = restaurant_row[0]
407
-
408
- booking_cursor.execute("""
409
- SELECT t.id AS table_id, s.id AS slot_id
410
- FROM tables t
411
- JOIN slots s ON t.id = s.table_id
412
- WHERE t.restaurant_id = ?
413
- AND s.hour = ?
414
- AND s.date = '2025-05-12'
415
- AND s.is_reserved = 0
416
- LIMIT ?
417
- """, (restaurant_id, user_data["time"], tables_needed))
418
- available = booking_cursor.fetchall()
419
- # Debugging output
420
-
421
- if len(available) < tables_needed:
422
- raise Exception("Not enough available tables.")
423
-
424
- booking_cursor.execute("""
425
- INSERT INTO reservations (restaurant_id, user_name, contact, date, time, party_size)
426
- VALUES (?, ?, ?, '2025-05-12', ?, ?)
427
- """, (restaurant_id, user_data["user_name"], user_data["contact"], user_data["time"], party_size))
428
- reservation_id = booking_cursor.lastrowid
429
-
430
- for table_id, _ in available:
431
- booking_cursor.execute("INSERT INTO reservation_tables (reservation_id, table_id) VALUES (?, ?)", (reservation_id, table_id))
432
-
433
- slot_ids = [slot_id for _, slot_id in available]
434
- booking_cursor.executemany("UPDATE slots SET is_reserved = 1 WHERE id = ?", [(sid,) for sid in slot_ids])
435
-
436
- booking_conn.commit()
437
- # Fetch the restaurant name to confirm
438
- booking_cursor.execute("SELECT name FROM restaurants WHERE id = ?", (restaurant_id,))
439
- restaurant_name = booking_cursor.fetchone()[0]
440
-
441
- # Prepare confirmation details
442
- confirmation_msg = (
443
- f"βœ… Booking processed successfully!\n\n"
444
- f"πŸ“ Restaurant: **{restaurant_name}**\n"
445
- f"⏰ Time: **{user_data['time']} on 2025-05-12**\n"
446
- f"🍽️ Tables Booked: **{tables_needed}**\n"
447
- f"πŸ†” Reservation ID: **{reservation_id}**\n\n"
448
- f"πŸ‘‰ Please mention this Reservation ID at the restaurant reception when you arrive."
449
- )
450
-
451
- response_summary = confirmation_msg
452
- st.success(response_summary)
453
- st.session_state.chat_history.append({'role': 'assistant', 'message': response_summary})
454
- response_summary="βœ… Booking processed successfully."
455
- st.session_state.user_data["restaurant_name"]=None
456
- st.session_state.user_data["party_size"]=None
457
- st.session_state.user_data["time"]=None
458
- st.session_state.last_assistant_reply=""
459
- except Exception as e:
460
- if booking_conn:
461
- booking_conn.rollback()
462
- response_summary = f"❌ Booking failed: {e}"
463
- st.error(response_summary)
464
- finally:
465
- if booking_conn:
466
- booking_cursor=None
467
- booking_conn.close()
468
- else:
469
- st.markdown("⚠️ Missing user information. Please provide all booking details first.")
470
- response_summary = "⚠️ Missing user information. Please provide all booking details first."
471
-
472
-
473
- elif intent == "GREET":
474
- response_summary = "πŸ‘‹ Hello! How can I help you with your restaurant reservation today?"
475
-
476
- elif intent == "RUBBISH":
477
- response_summary = "❌ Sorry, I didn't understand that. Could you rephrase your request?"
478
-
479
- # Generate assistant reply
480
- if response_summary!="βœ… Booking processed successfully.":
481
- follow_up = generate_reservation_conversation(
482
- user_input,
483
- history_prompt,
484
- response_summary or "Info stored.",
485
- json.dumps(st.session_state.user_data),generate_reservation_conversation_prompt,client
486
- )
487
- else:
488
- follow_up="Thanks for booking with FoodieSpot restaurant chain, I could assist you in new booking, also I could tell about restaurant features, pricing, etc... "
489
-
490
- # Show assistant reply instantly
491
- with st.chat_message("assistant"):
492
- st.markdown(follow_up)
493
-
494
- st.session_state.chat_history.append({'role': 'assistant', 'message': follow_up})
495
- # Update it after assistant speaks
496
- st.session_state.last_assistant_reply = follow_up
497
- st.rerun()
498
- # Reset if booking done
499
-
500
-
 
1
+ import streamlit as st
2
+ from openai import OpenAI
3
+ import sqlite3
4
+ import pandas as pd
5
+ import re
6
+ import json
7
+ from sticky import sticky_container
8
+ import chromadb
9
+ from sentence_transformers import SentenceTransformer
10
+ from transformers import pipeline
11
+ import hashlib
12
+ import inspect
13
+ from tools import *
14
+ from var import SCHEMA_DESCRIPTIONS, SchemaVectorDB, FullVectorDB
15
+ import os
16
+ # Set your Groq API key
17
+ GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
18
+
19
+ # Initialize Groq's OpenAI-compatible client
20
+ client = OpenAI(
21
+ api_key=GROQ_API_KEY,
22
+ base_url="https://api.groq.com/openai/v1"
23
+ )
24
+
25
+ # --- Load prompt templates from prompts folder ---
26
+ with open("prompts/determine_intent.txt", "r", encoding="utf-8") as f:
27
+ determine_intent_prompt = f.read()
28
+
29
+ with open("prompts/generate_reservation_conversation.txt", "r", encoding="utf-8") as f:
30
+ generate_reservation_conversation_prompt = f.read()
31
+
32
+ with open("prompts/interpret_sql_result.txt", "r", encoding="utf-8") as f:
33
+ interpret_sql_result_prompt = f.read()
34
+
35
+ with open("prompts/schema_prompt.txt", "r", encoding="utf-8") as f:
36
+ schema_prompt = f.read()
37
+
38
+ with open("prompts/store_user_info.txt", "r", encoding="utf-8") as f:
39
+ store_user_info_prompt = f.read()
40
+
41
+
42
+
43
+ st.set_page_config(page_title="FoodieSpot Assistant", layout="wide")
44
+
45
+
46
+ # --- Initialize State ---
47
+ if 'chat_history' not in st.session_state:
48
+ st.session_state.chat_history = []
49
+
50
+ if 'user_data' not in st.session_state:
51
+ st.session_state.user_data = {
52
+ "restaurant_name": None,
53
+ "user_name": None,
54
+ "contact": None,
55
+ "party_size": None,
56
+ "time": None
57
+ }
58
+ if 'vector_db' not in st.session_state:
59
+ st.session_state.vector_db = SchemaVectorDB()
60
+ vector_db = st.session_state.vector_db
61
+ if 'full_vector_db' not in st.session_state:
62
+ st.session_state.full_vector_db = FullVectorDB()
63
+ # Track last assistant reply for context
64
+ if 'last_assistant_reply' not in st.session_state:
65
+ st.session_state.last_assistant_reply = ""
66
+ # Fixed container at top for title + reservation
67
+ reservation_box = sticky_container(mode="top", border=False,z=999)
68
+
69
+ with reservation_box:
70
+ st.text("")
71
+ st.text("")
72
+ st.title("🍽️ FoodieSpot Assistant")
73
+ cols = st.columns([3, 3, 3, 2, 2, 1])
74
+
75
+ with cols[0]:
76
+ restaurant_name = st.text_input(
77
+ "Restaurant Name",
78
+ value=st.session_state.user_data.get("restaurant_name") or "",
79
+ key="restaurant_name_input"
80
+ )
81
+ if restaurant_name!="":
82
+ st.session_state.user_data["restaurant_name"] = restaurant_name
83
+
84
+ with cols[1]:
85
+ user_name = st.text_input(
86
+ "Your Name",
87
+ value=st.session_state.user_data.get("user_name") or "",
88
+ key="user_name_input"
89
+ )
90
+ if user_name!="":
91
+ st.session_state.user_data["user_name"] = user_name
92
+
93
+ with cols[2]:
94
+ contact = st.text_input(
95
+ "Contact",
96
+ value=st.session_state.user_data.get("contact") or "",
97
+ key="contact_input"
98
+ )
99
+ if contact!="":
100
+ st.session_state.user_data["contact"] = contact
101
+
102
+ with cols[3]:
103
+ party_size = st.number_input(
104
+ "Party Size",
105
+ value=st.session_state.user_data.get("party_size") or 0,
106
+ key="party_size_input"
107
+ )
108
+ if party_size!=0:
109
+ st.session_state.user_data["party_size"] = party_size
110
+
111
+ with cols[4]:
112
+ time = st.number_input(
113
+ "Time(24hr form, 9-20, 8 ~ null)",
114
+ min_value=8,
115
+ max_value=20,
116
+ value=st.session_state.user_data.get("time") or 8,
117
+ key="time_input"
118
+ )
119
+ if time!=8:
120
+ st.session_state.user_data["time"] = time
121
+ # Place the BOOK button in the last column
122
+ with cols[5]:
123
+ st.text("")
124
+ st.text("")
125
+ book_clicked = st.button("BOOK", type="primary")
126
+ # Add a green BOOK button (primary style)
127
+ # book_clicked = st.button("BOOK", type="primary")
128
+
129
+ if book_clicked:
130
+ # Check if all required fields are filled
131
+ required_keys = ["restaurant_name", "user_name", "contact", "party_size", "time"]
132
+ if all(st.session_state.user_data.get(k) not in [None, "", 0, 8] for k in required_keys):
133
+ booking_conn = None
134
+ try:
135
+ user_data = st.session_state.user_data
136
+ party_size = int(user_data["party_size"])
137
+ tables_needed = -(-party_size // 4)
138
+
139
+ booking_conn = sqlite3.connect("db/restaurant_reservation.db")
140
+ booking_cursor = booking_conn.cursor()
141
+
142
+ booking_cursor.execute("SELECT id FROM restaurants WHERE LOWER(name) = LOWER(?)", (user_data["restaurant_name"],))
143
+ restaurant_row = booking_cursor.fetchone()
144
+ if not restaurant_row:
145
+ raise Exception("Restaurant not found.")
146
+ restaurant_id = restaurant_row[0]
147
+
148
+ booking_cursor.execute("""
149
+ SELECT t.id AS table_id, s.id AS slot_id
150
+ FROM tables t
151
+ JOIN slots s ON t.id = s.table_id
152
+ WHERE t.restaurant_id = ?
153
+ AND s.hour = ?
154
+ AND s.date = '2025-05-12'
155
+ AND s.is_reserved = 0
156
+ LIMIT ?
157
+ """, (restaurant_id, user_data["time"], tables_needed))
158
+ available = booking_cursor.fetchall()
159
+
160
+ if len(available) < tables_needed:
161
+ raise Exception("Not enough available tables.")
162
+
163
+ booking_cursor.execute("""
164
+ INSERT INTO reservations (restaurant_id, user_name, contact, date, time, party_size)
165
+ VALUES (?, ?, ?, '2025-05-12', ?, ?)
166
+ """, (restaurant_id, user_data["user_name"], user_data["contact"], user_data["time"], party_size))
167
+ reservation_id = booking_cursor.lastrowid
168
+
169
+ for table_id, _ in available:
170
+ booking_cursor.execute("INSERT INTO reservation_tables (reservation_id, table_id) VALUES (?, ?)", (reservation_id, table_id))
171
+
172
+ slot_ids = [slot_id for _, slot_id in available]
173
+ booking_cursor.executemany("UPDATE slots SET is_reserved = 1 WHERE id = ?", [(sid,) for sid in slot_ids])
174
+
175
+ booking_conn.commit()
176
+
177
+ booking_cursor.execute("SELECT name FROM restaurants WHERE id = ?", (restaurant_id,))
178
+ restaurant_name = booking_cursor.fetchone()[0]
179
+
180
+ confirmation_msg = (
181
+ f"βœ… Booking processed successfully!\n\n"
182
+ f"πŸ“ Restaurant: **{restaurant_name}**\n"
183
+ f"⏰ Time: **{user_data['time']} on 2025-05-12**\n"
184
+ f"🍽️ Tables Booked: **{tables_needed}**\n"
185
+ f"πŸ†” Reservation ID: **{reservation_id}**\n\n"
186
+ f"πŸ‘‰ Please mention this Reservation ID at the restaurant reception when you arrive."
187
+ )
188
+
189
+ st.success(confirmation_msg)
190
+ st.session_state.chat_history.append({'role': 'assistant', 'message': confirmation_msg})
191
+ st.session_state.user_data["restaurant_name"] = None
192
+ st.session_state.user_data["party_size"] = None
193
+ st.session_state.user_data["time"] = None
194
+ st.session_state.last_assistant_reply = ""
195
+ except Exception as e:
196
+ if booking_conn:
197
+ booking_conn.rollback()
198
+ st.error(f"❌ Booking failed: {e}")
199
+ finally:
200
+ if booking_conn:
201
+ booking_cursor = None
202
+ booking_conn.close()
203
+ else:
204
+ st.warning("⚠️ Missing user information. Please provide all booking details first.")
205
+ st.text("")
206
+ # Inject custom CSS for smaller font and tighter layout
207
+ st.markdown("""
208
+ <style>
209
+ .element-container:has(.streamlit-expander) {
210
+ margin-bottom: 0.5rem;
211
+ }
212
+ .streamlit-expanderHeader {
213
+ font-size: 0.9rem;
214
+ }
215
+ .streamlit-expanderContent {
216
+ font-size: 0.85rem;
217
+ padding: 0.5rem 1rem;
218
+ }
219
+ </style>
220
+ """, unsafe_allow_html=True)
221
+
222
+ with st.container():
223
+ col1, col2, col3 = st.columns(3)
224
+
225
+ with col1:
226
+ with st.expander("🍽️ Restaurants"):
227
+ st.markdown("""
228
+ - Bella Italia
229
+ - Spice Symphony
230
+ - Tokyo Ramen House
231
+ - Saffron Grill
232
+ - El Toro Loco
233
+ - Noodle Bar
234
+ - Le Petit Bistro
235
+ - Tandoori Nights
236
+ - Green Leaf Cafe
237
+ - Ocean Pearl
238
+ - Mama Mia Pizza
239
+ - The Dumpling Den
240
+ - Bangkok Express
241
+ - Curry Kingdom
242
+ - The Garden Table
243
+ - Skyline Dine
244
+ - Pasta Republic
245
+ - Street Tacos Co
246
+ - Miso Hungry
247
+ - Chez Marie
248
+ """)
249
+
250
+ with col2:
251
+ with st.expander("🌎 Cuisines"):
252
+ st.markdown("""
253
+ - Italian
254
+ - French
255
+ - Chinese
256
+ - Japanese
257
+ - Indian
258
+ - Mexican
259
+ - Thai
260
+ - Healthy
261
+ - Fusion
262
+ """)
263
+
264
+ with col3:
265
+ with st.expander("✨ Special Features"):
266
+ st.markdown("""
267
+ - Pet-Friendly
268
+ - Live Music
269
+ - Rooftop View
270
+ - Outdoor Seating
271
+ - Private Dining
272
+ """)
273
+
274
+
275
+
276
+
277
+ # --- Display previous chat history (before new input) ---
278
+
279
+ for msg in st.session_state.chat_history:
280
+ # Check if both 'role' and 'message' are not None
281
+ if msg['role'] is not None and msg['message'] is not None:
282
+ with st.chat_message(msg['role']):
283
+ st.markdown(msg['message'])
284
+
285
+ user_input = st.chat_input("Ask something about restaurants or reservations(eg. Tell me some best rated Italian cuisine restaurants)...")
286
+ if user_input:
287
+ # Show user message instantly
288
+ with st.chat_message("user"):
289
+ st.markdown(user_input)
290
+ st.session_state.chat_history.append({'role': 'user', 'message': user_input})
291
+
292
+ # Prepare conversation context
293
+ history_prompt = st.session_state.last_assistant_reply
294
+
295
+ # Store possible user info
296
+ user_info = store_user_info(user_input,history_prompt,store_user_info_prompt,client)
297
+ if user_info:
298
+ st.session_state.user_data.update(user_info)
299
+ # st.rerun()
300
+
301
+ # Detect intent
302
+ intent = determine_intent(user_input,determine_intent_prompt,client)
303
+ # st.write(intent)
304
+ if intent == "RUBBISH":
305
+ # Display user data for confirmation instead of invoking LLM
306
+ with st.chat_message("assistant"):
307
+ st.markdown("❌ Sorry, I didn't understand that. Could you rephrase your request?")
308
+ st.session_state.chat_history.append({
309
+ 'role': 'assistant',
310
+ 'message': "❌ Sorry, I didn't understand that. Could you rephrase your request?"
311
+ })
312
+
313
+ st.stop()
314
+
315
+ # Generate assistant reply
316
+ required_keys = ["restaurant_name", "user_name", "contact", "party_size", "time"]
317
+ user_data_complete = all(
318
+ k in st.session_state.user_data and st.session_state.user_data[k] not in [None, "", "NULL"]
319
+ for k in required_keys
320
+ )
321
+
322
+
323
+ if user_data_complete and intent != "BOOK":
324
+
325
+ # Format user data as a Markdown bullet list
326
+ user_details = "\n".join([f"- **{key.capitalize()}**: {value}" for key, value in st.session_state.user_data.items()])
327
+
328
+ with st.chat_message("assistant"):
329
+ st.markdown("βœ… I have all the details needed for your reservation:")
330
+ st.markdown(user_details)
331
+ st.markdown("If everything looks good, please type **`book`** to confirm the reservation.")
332
+
333
+ st.session_state.chat_history.append({
334
+ 'role': 'assistant',
335
+ 'message': f"βœ… I have all the details needed for your reservation:\n{user_details}\nPlease type **`book`** to confirm."
336
+ })
337
+ st.session_state.last_assistant_reply = "I have all the reservation details. Waiting for confirmation..."
338
+ st.rerun()
339
+ st.stop()
340
+
341
+
342
+
343
+
344
+ response_summary = None
345
+
346
+ if intent == "SELECT":
347
+ response_summary=handle_query(user_input, st.session_state.full_vector_db, client)
348
+
349
+ # First try semantic search
350
+ semantic_results = {}
351
+
352
+ # Search across all collections
353
+ restaurant_results = st.session_state.full_vector_db.semantic_search(user_input, "restaurants")
354
+ table_results = st.session_state.full_vector_db.semantic_search(user_input, "tables")
355
+ slot_results = st.session_state.full_vector_db.semantic_search(user_input, "slots")
356
+
357
+ if not is_large_output_request(user_input) and any([restaurant_results, table_results, slot_results]):
358
+ semantic_results = {
359
+ "restaurants": restaurant_results,
360
+ "tables": table_results,
361
+ "slots": slot_results
362
+ }
363
+ # Format semantic results
364
+ summary = []
365
+ for category, items in semantic_results.items():
366
+ if items:
367
+ summary.append(f"Found {len(items)} relevant {category}:")
368
+ summary.extend([f"- {item['name']}" if 'name' in item else f"- {item}"
369
+ for item in items[:3]])
370
+ st.write("### Semantic Search used")
371
+ response_summary = "\n".join(summary)
372
+ else:
373
+ # Fall back to SQL generation for large or exact output requests
374
+ sql = generate_sql_query_v2(user_input,SCHEMA_DESCRIPTIONS, history_prompt, vector_db, client)
375
+ result = execute_query(sql)
376
+ response_summary = interpret_result_v2(result, user_input, sql)
377
+
378
+
379
+
380
+ # sql = generate_sql_query_v2(user_input,history_prompt, vector_db, client)
381
+ # result = execute_query(sql)
382
+ # response_summary=interpret_result_v2(result, user_input, sql)
383
+ # if isinstance(result, pd.DataFrame):
384
+ # response_summary = interpret_sql_result(user_input, sql_query, result)
385
+
386
+
387
+ elif intent == "BOOK":
388
+ required_keys = ["restaurant_name", "user_name", "contact", "party_size", "time"]
389
+ if all(st.session_state.user_data.get(k) is not None for k in required_keys):
390
+ booking_conn = None
391
+ try:
392
+ user_data = st.session_state.user_data
393
+ party_size = int(user_data["party_size"])
394
+ tables_needed = -(-party_size // 4)
395
+
396
+ booking_conn = sqlite3.connect("db/restaurant_reservation.db")
397
+ booking_cursor = booking_conn.cursor()
398
+
399
+ booking_cursor.execute("SELECT id FROM restaurants WHERE LOWER(name) = LOWER(?)", (user_data["restaurant_name"],))
400
+ restaurant_row = booking_cursor.fetchone()
401
+ if not restaurant_row:
402
+ raise Exception("Restaurant not found.")
403
+ restaurant_id = restaurant_row[0]
404
+
405
+ booking_cursor.execute("""
406
+ SELECT t.id AS table_id, s.id AS slot_id
407
+ FROM tables t
408
+ JOIN slots s ON t.id = s.table_id
409
+ WHERE t.restaurant_id = ?
410
+ AND s.hour = ?
411
+ AND s.date = '2025-05-12'
412
+ AND s.is_reserved = 0
413
+ LIMIT ?
414
+ """, (restaurant_id, user_data["time"], tables_needed))
415
+ available = booking_cursor.fetchall()
416
+ # Debugging output
417
+
418
+ if len(available) < tables_needed:
419
+ raise Exception("Not enough available tables.")
420
+
421
+ booking_cursor.execute("""
422
+ INSERT INTO reservations (restaurant_id, user_name, contact, date, time, party_size)
423
+ VALUES (?, ?, ?, '2025-05-12', ?, ?)
424
+ """, (restaurant_id, user_data["user_name"], user_data["contact"], user_data["time"], party_size))
425
+ reservation_id = booking_cursor.lastrowid
426
+
427
+ for table_id, _ in available:
428
+ booking_cursor.execute("INSERT INTO reservation_tables (reservation_id, table_id) VALUES (?, ?)", (reservation_id, table_id))
429
+
430
+ slot_ids = [slot_id for _, slot_id in available]
431
+ booking_cursor.executemany("UPDATE slots SET is_reserved = 1 WHERE id = ?", [(sid,) for sid in slot_ids])
432
+
433
+ booking_conn.commit()
434
+ # Fetch the restaurant name to confirm
435
+ booking_cursor.execute("SELECT name FROM restaurants WHERE id = ?", (restaurant_id,))
436
+ restaurant_name = booking_cursor.fetchone()[0]
437
+
438
+ # Prepare confirmation details
439
+ confirmation_msg = (
440
+ f"βœ… Booking processed successfully!\n\n"
441
+ f"πŸ“ Restaurant: **{restaurant_name}**\n"
442
+ f"⏰ Time: **{user_data['time']} on 2025-05-12**\n"
443
+ f"🍽️ Tables Booked: **{tables_needed}**\n"
444
+ f"πŸ†” Reservation ID: **{reservation_id}**\n\n"
445
+ f"πŸ‘‰ Please mention this Reservation ID at the restaurant reception when you arrive."
446
+ )
447
+
448
+ response_summary = confirmation_msg
449
+ st.success(response_summary)
450
+ st.session_state.chat_history.append({'role': 'assistant', 'message': response_summary})
451
+ response_summary="βœ… Booking processed successfully."
452
+ st.session_state.user_data["restaurant_name"]=None
453
+ st.session_state.user_data["party_size"]=None
454
+ st.session_state.user_data["time"]=None
455
+ st.session_state.last_assistant_reply=""
456
+ except Exception as e:
457
+ if booking_conn:
458
+ booking_conn.rollback()
459
+ response_summary = f"❌ Booking failed: {e}"
460
+ st.error(response_summary)
461
+ finally:
462
+ if booking_conn:
463
+ booking_cursor=None
464
+ booking_conn.close()
465
+ else:
466
+ st.markdown("⚠️ Missing user information. Please provide all booking details first.")
467
+ response_summary = "⚠️ Missing user information. Please provide all booking details first."
468
+
469
+
470
+ elif intent == "GREET":
471
+ response_summary = "πŸ‘‹ Hello! How can I help you with your restaurant reservation today?"
472
+
473
+ elif intent == "RUBBISH":
474
+ response_summary = "❌ Sorry, I didn't understand that. Could you rephrase your request?"
475
+
476
+ # Generate assistant reply
477
+ if response_summary!="βœ… Booking processed successfully.":
478
+ follow_up = generate_reservation_conversation(
479
+ user_input,
480
+ history_prompt,
481
+ response_summary or "Info stored.",
482
+ json.dumps(st.session_state.user_data),generate_reservation_conversation_prompt,client
483
+ )
484
+ else:
485
+ follow_up="Thanks for booking with FoodieSpot restaurant chain, I could assist you in new booking, also I could tell about restaurant features, pricing, etc... "
486
+
487
+ # Show assistant reply instantly
488
+ with st.chat_message("assistant"):
489
+ st.markdown(follow_up)
490
+
491
+ st.session_state.chat_history.append({'role': 'assistant', 'message': follow_up})
492
+ # Update it after assistant speaks
493
+ st.session_state.last_assistant_reply = follow_up
494
+ st.rerun()
495
+ # Reset if booking done
496
+
497
+