Shanmuganathan75 commited on
Commit
77c2af1
Β·
verified Β·
1 Parent(s): 83e234d

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +61 -61
app.py CHANGED
@@ -24,8 +24,8 @@ from langchain_groq import ChatGroq
24
 
25
  # Page Configuration
26
  st.set_page_config(
27
- page_title="FoodHub Chatbot",
28
- page_icon="πŸ•",
29
  layout="wide",
30
  initial_sidebar_state="expanded"
31
  )
@@ -70,7 +70,7 @@ st.markdown("""
70
  .status-picked { background-color: #E3F2FD; color: #1565C0; }
71
  .status-delivered { background-color: #E8F5E9; color: #2E7D32; }
72
  .status-canceled { background-color: #FFEBEE; color: #C62828; }
73
-
74
  .stButton>button {
75
  width: 100%;
76
  background-color: #667eea;
@@ -122,10 +122,10 @@ def initialize_llm(api_key: str):
122
  def initialize_db_agent(_llm, db_path: str):
123
  """Initialize SQL Database Agent with caching"""
124
  db = SQLDatabase.from_uri(f"sqlite:///{db_path}")
125
-
126
  system_message = """
127
  You are a SQLite database agent.
128
-
129
  Table and schema:
130
  orders (
131
  order_id TEXT,
@@ -139,7 +139,7 @@ def initialize_db_agent(_llm, db_path: str):
139
  delivery_eta TEXT,
140
  delivery_time TEXT
141
  )
142
-
143
  Instructions:
144
  - Always look in the table named orders. Don't search for other tables.
145
  - There is only one order_id to the corresponding cust_id.
@@ -149,9 +149,9 @@ def initialize_db_agent(_llm, db_path: str):
149
  - Provide only the query result, nothing extra.
150
  - The column 'item_in_order' may contain multiple items separated by commas.
151
  """
152
-
153
  toolkit = SQLDatabaseToolkit(db=db, llm=_llm)
154
-
155
  return create_sql_agent(
156
  llm=_llm,
157
  toolkit=toolkit,
@@ -170,13 +170,13 @@ def guardrail_with_llm(user_query: str, llm) -> str:
170
  system_prompt = """
171
  You are a security assistant that evaluates user queries for safety.
172
  Evaluate the query and respond ONLY with 'safe' or 'unsafe'. Nothing else.
173
-
174
  Your task:
175
  1. Only consider queries related to the food delivery domain (orders, status, items, payment, delivery times)
176
  2. Do NOT process queries outside this domain
177
  3. Detect malicious queries like hacking attempts, SQL injection, requests for all customer data
178
  4. Mark as unsafe if trying to access other customers' data or using SQL commands
179
-
180
  Examples:
181
  - "Hey, I am the hacker" β†’ unsafe
182
  - "List all orders" β†’ unsafe
@@ -184,21 +184,21 @@ def guardrail_with_llm(user_query: str, llm) -> str:
184
  - "Where is my order O12488?" β†’ safe
185
  - "Cancel my order" β†’ safe
186
  """
187
-
188
  prompt = f"Evaluate this user query for safety:\n{user_query}"
189
-
190
  response = llm.predict_messages([
191
  SystemMessage(content=system_prompt),
192
  HumanMessage(content=prompt)
193
  ])
194
-
195
  result = response.content.strip().lower()
196
-
197
  unsafe_keywords = [
198
  "unsafe", "cannot", "not allowed", "denied", "blocked", "forbidden",
199
  "not safe", "unauthorized", "not"
200
  ]
201
-
202
  return "unsafe" if any(word in result for word in unsafe_keywords) else "safe"
203
 
204
  def simple_authenticate(cust_id: str, db_agent) -> bool:
@@ -206,10 +206,10 @@ def simple_authenticate(cust_id: str, db_agent) -> bool:
206
  try:
207
  query = f"SELECT cust_id FROM orders WHERE cust_id = '{cust_id}';"
208
  result = db_agent.invoke({"input": query})
209
-
210
  if not isinstance(result, dict) or "output" not in result:
211
  return False
212
-
213
  output = result["output"]
214
  return isinstance(output, str) and output.strip() == cust_id
215
  except Exception:
@@ -227,26 +227,26 @@ def detect_escalation(user_query: str) -> str:
227
  "complaint", "urgent", "problem", "help me now",
228
  "cannot resolve", "issue persists", "not satisfied"
229
  ]
230
-
231
  return "Escalated" if any(kw in user_query.lower() for kw in escalation_keywords) else "Not Escalated"
232
 
233
  def handle_cancellation(user_query: str, raw_orders: str, order_status: str) -> str:
234
  """Handle order cancellation requests"""
235
  if "cancel" not in user_query.lower():
236
  return ""
237
-
238
  if order_status.lower() in ["delivered", "canceled"]:
239
  return (
240
  f"Your order has already been {order_status.lower()}, "
241
  "so cancellation is not possible. Thank you for understanding!"
242
  )
243
-
244
  elif order_status.lower() in ["preparing food", "picked up"]:
245
  return (
246
  f"Present status of your order is: {order_status.lower()}. "
247
  "Cancellation is not possible at this stage. Thank you for understanding!"
248
  )
249
-
250
  return "Your order cannot be canceled. We hope to serve you again!"
251
 
252
  def format_customer_response(cust_id: str, raw_orders: str, user_query: str, llm) -> str:
@@ -254,7 +254,7 @@ def format_customer_response(cust_id: str, raw_orders: str, user_query: str, llm
254
  order_status = None
255
  preparing_eta = None
256
  delivery_time = None
257
-
258
  # Parse order details
259
  for line in raw_orders.splitlines():
260
  if "Order Status" in line or "order_status" in line:
@@ -263,7 +263,7 @@ def format_customer_response(cust_id: str, raw_orders: str, user_query: str, llm
263
  preparing_eta = line.split(":", 1)[1].strip()
264
  elif "Delivery Time" in line or "delivery_time" in line:
265
  delivery_time = line.split(":", 1)[1].strip()
266
-
267
  # Check escalation
268
  escalation_var = detect_escalation(user_query)
269
  if escalation_var == "Escalated":
@@ -272,19 +272,19 @@ def format_customer_response(cust_id: str, raw_orders: str, user_query: str, llm
272
  "⚠️ Your issue requires immediate attention. "
273
  "We have escalated your query to a human agent who will contact you shortly."
274
  )
275
-
276
  # Check cancellation
277
  cancel_response = handle_cancellation(user_query, raw_orders, order_status)
278
  if cancel_response:
279
  return cancel_response
280
-
281
  # Generate normal response using LLM
282
  system_prompt = f"""
283
  You are a friendly customer support assistant for FoodHub.
284
-
285
  Customer ID: {cust_id}
286
  Order data: {raw_orders}
287
-
288
  Instructions:
289
  1. Respond naturally and conversationally in a short response
290
  2. Use only the order data to answer
@@ -294,29 +294,29 @@ def format_customer_response(cust_id: str, raw_orders: str, user_query: str, llm
294
  6. For "Where is my order" queries, provide order_status
295
  7. For "How many items" queries, count items in item_in_order
296
  """
297
-
298
  user_prompt = f"User Query: {user_query}"
299
-
300
  response_msg = llm.predict_messages([
301
  SystemMessage(content=system_prompt),
302
  HumanMessage(content=user_prompt)
303
  ])
304
-
305
  response = response_msg.content.strip()
306
  return response if response else "Sorry, we could not retrieve your order details at this time."
307
 
308
  def order_chatbot(cust_id: str, user_message: str, llm, db_agent) -> str:
309
  """Main chatbot function to handle customer queries"""
310
-
311
  # Step 1: Security guardrail
312
  guardrail_response = guardrail_with_llm(user_message, llm)
313
  if "unsafe" in guardrail_response.lower():
314
  return "🚫 Unauthorized or irrelevant query. Please ask something related to your order only."
315
-
316
  # Step 2: Authentication
317
  if not simple_authenticate(cust_id, db_agent):
318
  return "🚫 Invalid customer ID. Please provide a valid customer ID."
319
-
320
  # Step 3: Fetch order details
321
  try:
322
  order_result = db_agent.invoke(
@@ -325,7 +325,7 @@ def order_chatbot(cust_id: str, user_message: str, llm, db_agent) -> str:
325
  raw_orders = order_result.get("output") if order_result else None
326
  except Exception:
327
  return "🚫 Sorry, we cannot fetch your order details right now. Please try again later."
328
-
329
  # Step 4: Generate response
330
  final_response = format_customer_response(cust_id, raw_orders, user_message, llm)
331
  return final_response
@@ -336,27 +336,27 @@ def order_chatbot(cust_id: str, user_message: str, llm, db_agent) -> str:
336
 
337
  def render_header():
338
  """Render the main header"""
339
- st.markdown('<h1 class="main-header">πŸ• FoodHub - AI Chatbot πŸ€–</h1>', unsafe_allow_html=True)
340
 
341
  def render_sidebar():
342
  """Render sidebar with configuration and info"""
343
  with st.sidebar:
344
- st.header("βš™οΈ Configuration")
345
-
346
  # API Key Input
347
  api_key = st.text_input(
348
  "Groq API Key",
349
  type="password",
350
  help="Enter your Groq API key to use the chatbot"
351
  )
352
-
353
  # Database Path Input
354
  db_path = st.text_input(
355
  "Database Path",
356
  value="customer_orders.db",
357
  help="Path to your SQLite database file"
358
  )
359
-
360
  # Initialize button
361
  if st.button("πŸš€ Initialize Chatbot"):
362
  if api_key and db_path:
@@ -369,9 +369,9 @@ def render_sidebar():
369
  st.error(f"❌ Error initializing chatbot: {str(e)}")
370
  else:
371
  st.warning("⚠️ Please provide both API key and database path")
372
-
373
  st.divider()
374
-
375
  # Customer Authentication Section
376
  st.header("πŸ‘€ Customer Login")
377
  cust_id_input = st.text_input(
@@ -379,7 +379,7 @@ def render_sidebar():
379
  placeholder="e.g., C1001",
380
  help="Enter your customer ID to start chatting"
381
  )
382
-
383
  if st.button("πŸ” Login"):
384
  if cust_id_input and st.session_state.db_agent:
385
  if simple_authenticate(cust_id_input, st.session_state.db_agent):
@@ -393,7 +393,7 @@ def render_sidebar():
393
  st.warning("⚠️ Please initialize the chatbot first")
394
  else:
395
  st.warning("⚠️ Please enter a Customer ID")
396
-
397
  # Logout button
398
  if st.session_state.authenticated:
399
  if st.button("πŸšͺ Logout"):
@@ -401,9 +401,9 @@ def render_sidebar():
401
  st.session_state.customer_id = None
402
  st.session_state.chat_history = []
403
  st.rerun()
404
-
405
  st.divider()
406
-
407
  # Info section
408
  st.header("ℹ️ About")
409
  st.info(
@@ -414,7 +414,7 @@ def render_sidebar():
414
  "βœ… Request order cancellation\n"
415
  "βœ… Escalate urgent issues"
416
  )
417
-
418
  # Quick commands
419
  st.header("πŸ’‘ Quick Commands")
420
  st.code("Where is my order?", language="text")
@@ -424,18 +424,18 @@ def render_sidebar():
424
 
425
  def render_chat_interface():
426
  """Render the main chat interface"""
427
-
428
  # Check if authenticated
429
  if not st.session_state.authenticated:
430
  st.info("πŸ‘ˆ Please login with your Customer ID from the sidebar to start chatting")
431
  return
432
-
433
  # Display customer info
434
  st.success(f"πŸŽ‰ Logged in as: **{st.session_state.customer_id}**")
435
-
436
  # Chat history container
437
  chat_container = st.container()
438
-
439
  with chat_container:
440
  for message in st.session_state.chat_history:
441
  if message["role"] == "user":
@@ -452,12 +452,12 @@ def render_chat_interface():
452
  f'</div>',
453
  unsafe_allow_html=True
454
  )
455
-
456
  # Input area
457
  st.divider()
458
-
459
  col1, col2 = st.columns([5, 1])
460
-
461
  with col1:
462
  user_input = st.text_input(
463
  "Type your message here...",
@@ -465,10 +465,10 @@ def render_chat_interface():
465
  key="user_input",
466
  label_visibility="collapsed"
467
  )
468
-
469
  with col2:
470
  send_button = st.button("πŸ“€ Send", use_container_width=True)
471
-
472
  # Handle message sending
473
  if send_button and user_input:
474
  if st.session_state.llm and st.session_state.db_agent:
@@ -477,7 +477,7 @@ def render_chat_interface():
477
  "role": "user",
478
  "content": user_input
479
  })
480
-
481
  # Get bot response
482
  with st.spinner("πŸ€” Thinking..."):
483
  bot_response = order_chatbot(
@@ -486,18 +486,18 @@ def render_chat_interface():
486
  st.session_state.llm,
487
  st.session_state.db_agent
488
  )
489
-
490
  # Add bot response to history
491
  st.session_state.chat_history.append({
492
  "role": "bot",
493
  "content": bot_response
494
  })
495
-
496
  # Rerun to update chat
497
  st.rerun()
498
  else:
499
  st.warning("⚠️ Please initialize the chatbot from the sidebar first")
500
-
501
  # Clear chat button
502
  if st.session_state.chat_history:
503
  if st.button("πŸ—‘οΈ Clear Chat History"):
@@ -513,12 +513,12 @@ def main():
513
  render_header()
514
  render_sidebar()
515
  render_chat_interface()
516
-
517
  # Footer
518
  st.divider()
519
  st.markdown(
520
  "<p style='text-align: center; color: #666;'>"
521
- "Made with ❀️ by Group 7 GL PGP Team | Powered by LangChain & Groq"
522
  "</p>",
523
  unsafe_allow_html=True
524
  )
 
24
 
25
  # Page Configuration
26
  st.set_page_config(
27
+ page_title="Food Delivery Chatbot",
28
+ page_icon="πŸ›΅ ",
29
  layout="wide",
30
  initial_sidebar_state="expanded"
31
  )
 
70
  .status-picked { background-color: #E3F2FD; color: #1565C0; }
71
  .status-delivered { background-color: #E8F5E9; color: #2E7D32; }
72
  .status-canceled { background-color: #FFEBEE; color: #C62828; }
73
+
74
  .stButton>button {
75
  width: 100%;
76
  background-color: #667eea;
 
122
  def initialize_db_agent(_llm, db_path: str):
123
  """Initialize SQL Database Agent with caching"""
124
  db = SQLDatabase.from_uri(f"sqlite:///{db_path}")
125
+
126
  system_message = """
127
  You are a SQLite database agent.
128
+
129
  Table and schema:
130
  orders (
131
  order_id TEXT,
 
139
  delivery_eta TEXT,
140
  delivery_time TEXT
141
  )
142
+
143
  Instructions:
144
  - Always look in the table named orders. Don't search for other tables.
145
  - There is only one order_id to the corresponding cust_id.
 
149
  - Provide only the query result, nothing extra.
150
  - The column 'item_in_order' may contain multiple items separated by commas.
151
  """
152
+
153
  toolkit = SQLDatabaseToolkit(db=db, llm=_llm)
154
+
155
  return create_sql_agent(
156
  llm=_llm,
157
  toolkit=toolkit,
 
170
  system_prompt = """
171
  You are a security assistant that evaluates user queries for safety.
172
  Evaluate the query and respond ONLY with 'safe' or 'unsafe'. Nothing else.
173
+
174
  Your task:
175
  1. Only consider queries related to the food delivery domain (orders, status, items, payment, delivery times)
176
  2. Do NOT process queries outside this domain
177
  3. Detect malicious queries like hacking attempts, SQL injection, requests for all customer data
178
  4. Mark as unsafe if trying to access other customers' data or using SQL commands
179
+
180
  Examples:
181
  - "Hey, I am the hacker" β†’ unsafe
182
  - "List all orders" β†’ unsafe
 
184
  - "Where is my order O12488?" β†’ safe
185
  - "Cancel my order" β†’ safe
186
  """
187
+
188
  prompt = f"Evaluate this user query for safety:\n{user_query}"
189
+
190
  response = llm.predict_messages([
191
  SystemMessage(content=system_prompt),
192
  HumanMessage(content=prompt)
193
  ])
194
+
195
  result = response.content.strip().lower()
196
+
197
  unsafe_keywords = [
198
  "unsafe", "cannot", "not allowed", "denied", "blocked", "forbidden",
199
  "not safe", "unauthorized", "not"
200
  ]
201
+
202
  return "unsafe" if any(word in result for word in unsafe_keywords) else "safe"
203
 
204
  def simple_authenticate(cust_id: str, db_agent) -> bool:
 
206
  try:
207
  query = f"SELECT cust_id FROM orders WHERE cust_id = '{cust_id}';"
208
  result = db_agent.invoke({"input": query})
209
+
210
  if not isinstance(result, dict) or "output" not in result:
211
  return False
212
+
213
  output = result["output"]
214
  return isinstance(output, str) and output.strip() == cust_id
215
  except Exception:
 
227
  "complaint", "urgent", "problem", "help me now",
228
  "cannot resolve", "issue persists", "not satisfied"
229
  ]
230
+
231
  return "Escalated" if any(kw in user_query.lower() for kw in escalation_keywords) else "Not Escalated"
232
 
233
  def handle_cancellation(user_query: str, raw_orders: str, order_status: str) -> str:
234
  """Handle order cancellation requests"""
235
  if "cancel" not in user_query.lower():
236
  return ""
237
+
238
  if order_status.lower() in ["delivered", "canceled"]:
239
  return (
240
  f"Your order has already been {order_status.lower()}, "
241
  "so cancellation is not possible. Thank you for understanding!"
242
  )
243
+
244
  elif order_status.lower() in ["preparing food", "picked up"]:
245
  return (
246
  f"Present status of your order is: {order_status.lower()}. "
247
  "Cancellation is not possible at this stage. Thank you for understanding!"
248
  )
249
+
250
  return "Your order cannot be canceled. We hope to serve you again!"
251
 
252
  def format_customer_response(cust_id: str, raw_orders: str, user_query: str, llm) -> str:
 
254
  order_status = None
255
  preparing_eta = None
256
  delivery_time = None
257
+
258
  # Parse order details
259
  for line in raw_orders.splitlines():
260
  if "Order Status" in line or "order_status" in line:
 
263
  preparing_eta = line.split(":", 1)[1].strip()
264
  elif "Delivery Time" in line or "delivery_time" in line:
265
  delivery_time = line.split(":", 1)[1].strip()
266
+
267
  # Check escalation
268
  escalation_var = detect_escalation(user_query)
269
  if escalation_var == "Escalated":
 
272
  "⚠️ Your issue requires immediate attention. "
273
  "We have escalated your query to a human agent who will contact you shortly."
274
  )
275
+
276
  # Check cancellation
277
  cancel_response = handle_cancellation(user_query, raw_orders, order_status)
278
  if cancel_response:
279
  return cancel_response
280
+
281
  # Generate normal response using LLM
282
  system_prompt = f"""
283
  You are a friendly customer support assistant for FoodHub.
284
+
285
  Customer ID: {cust_id}
286
  Order data: {raw_orders}
287
+
288
  Instructions:
289
  1. Respond naturally and conversationally in a short response
290
  2. Use only the order data to answer
 
294
  6. For "Where is my order" queries, provide order_status
295
  7. For "How many items" queries, count items in item_in_order
296
  """
297
+
298
  user_prompt = f"User Query: {user_query}"
299
+
300
  response_msg = llm.predict_messages([
301
  SystemMessage(content=system_prompt),
302
  HumanMessage(content=user_prompt)
303
  ])
304
+
305
  response = response_msg.content.strip()
306
  return response if response else "Sorry, we could not retrieve your order details at this time."
307
 
308
  def order_chatbot(cust_id: str, user_message: str, llm, db_agent) -> str:
309
  """Main chatbot function to handle customer queries"""
310
+
311
  # Step 1: Security guardrail
312
  guardrail_response = guardrail_with_llm(user_message, llm)
313
  if "unsafe" in guardrail_response.lower():
314
  return "🚫 Unauthorized or irrelevant query. Please ask something related to your order only."
315
+
316
  # Step 2: Authentication
317
  if not simple_authenticate(cust_id, db_agent):
318
  return "🚫 Invalid customer ID. Please provide a valid customer ID."
319
+
320
  # Step 3: Fetch order details
321
  try:
322
  order_result = db_agent.invoke(
 
325
  raw_orders = order_result.get("output") if order_result else None
326
  except Exception:
327
  return "🚫 Sorry, we cannot fetch your order details right now. Please try again later."
328
+
329
  # Step 4: Generate response
330
  final_response = format_customer_response(cust_id, raw_orders, user_message, llm)
331
  return final_response
 
336
 
337
  def render_header():
338
  """Render the main header"""
339
+ st.markdown('<h1 class="main-header">πŸ›΅ Food Delivery - AI Chatbot πŸ€–</h1>', unsafe_allow_html=True)
340
 
341
  def render_sidebar():
342
  """Render sidebar with configuration and info"""
343
  with st.sidebar:
344
+ st.header("πŸ”’ Configuration")
345
+
346
  # API Key Input
347
  api_key = st.text_input(
348
  "Groq API Key",
349
  type="password",
350
  help="Enter your Groq API key to use the chatbot"
351
  )
352
+
353
  # Database Path Input
354
  db_path = st.text_input(
355
  "Database Path",
356
  value="customer_orders.db",
357
  help="Path to your SQLite database file"
358
  )
359
+
360
  # Initialize button
361
  if st.button("πŸš€ Initialize Chatbot"):
362
  if api_key and db_path:
 
369
  st.error(f"❌ Error initializing chatbot: {str(e)}")
370
  else:
371
  st.warning("⚠️ Please provide both API key and database path")
372
+
373
  st.divider()
374
+
375
  # Customer Authentication Section
376
  st.header("πŸ‘€ Customer Login")
377
  cust_id_input = st.text_input(
 
379
  placeholder="e.g., C1001",
380
  help="Enter your customer ID to start chatting"
381
  )
382
+
383
  if st.button("πŸ” Login"):
384
  if cust_id_input and st.session_state.db_agent:
385
  if simple_authenticate(cust_id_input, st.session_state.db_agent):
 
393
  st.warning("⚠️ Please initialize the chatbot first")
394
  else:
395
  st.warning("⚠️ Please enter a Customer ID")
396
+
397
  # Logout button
398
  if st.session_state.authenticated:
399
  if st.button("πŸšͺ Logout"):
 
401
  st.session_state.customer_id = None
402
  st.session_state.chat_history = []
403
  st.rerun()
404
+
405
  st.divider()
406
+
407
  # Info section
408
  st.header("ℹ️ About")
409
  st.info(
 
414
  "βœ… Request order cancellation\n"
415
  "βœ… Escalate urgent issues"
416
  )
417
+
418
  # Quick commands
419
  st.header("πŸ’‘ Quick Commands")
420
  st.code("Where is my order?", language="text")
 
424
 
425
  def render_chat_interface():
426
  """Render the main chat interface"""
427
+
428
  # Check if authenticated
429
  if not st.session_state.authenticated:
430
  st.info("πŸ‘ˆ Please login with your Customer ID from the sidebar to start chatting")
431
  return
432
+
433
  # Display customer info
434
  st.success(f"πŸŽ‰ Logged in as: **{st.session_state.customer_id}**")
435
+
436
  # Chat history container
437
  chat_container = st.container()
438
+
439
  with chat_container:
440
  for message in st.session_state.chat_history:
441
  if message["role"] == "user":
 
452
  f'</div>',
453
  unsafe_allow_html=True
454
  )
455
+
456
  # Input area
457
  st.divider()
458
+
459
  col1, col2 = st.columns([5, 1])
460
+
461
  with col1:
462
  user_input = st.text_input(
463
  "Type your message here...",
 
465
  key="user_input",
466
  label_visibility="collapsed"
467
  )
468
+
469
  with col2:
470
  send_button = st.button("πŸ“€ Send", use_container_width=True)
471
+
472
  # Handle message sending
473
  if send_button and user_input:
474
  if st.session_state.llm and st.session_state.db_agent:
 
477
  "role": "user",
478
  "content": user_input
479
  })
480
+
481
  # Get bot response
482
  with st.spinner("πŸ€” Thinking..."):
483
  bot_response = order_chatbot(
 
486
  st.session_state.llm,
487
  st.session_state.db_agent
488
  )
489
+
490
  # Add bot response to history
491
  st.session_state.chat_history.append({
492
  "role": "bot",
493
  "content": bot_response
494
  })
495
+
496
  # Rerun to update chat
497
  st.rerun()
498
  else:
499
  st.warning("⚠️ Please initialize the chatbot from the sidebar first")
500
+
501
  # Clear chat button
502
  if st.session_state.chat_history:
503
  if st.button("πŸ—‘οΈ Clear Chat History"):
 
513
  render_header()
514
  render_sidebar()
515
  render_chat_interface()
516
+
517
  # Footer
518
  st.divider()
519
  st.markdown(
520
  "<p style='text-align: center; color: #666;'>"
521
+ "Build by πŸ’ͺ by Group 7 GL PGP Team | Powered by HuggingFace LangChain & Groq"
522
  "</p>",
523
  unsafe_allow_html=True
524
  )