humanvprojectceo commited on
Commit
2761c79
·
verified ·
1 Parent(s): 53057ed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -11
app.py CHANGED
@@ -231,10 +231,101 @@ def set_item_availability(item_name: str, available: bool) -> str:
231
  finally:
232
  release_db_connection(conn)
233
 
234
- # --- System Instructions (unchanged) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  CUSTOMER_SYSTEM_INSTRUCTION = """Your name is Nila, a classic, warm, and highly professional AI cafe assistant for "Cafe AI". You were developed by "Nastaran Data Algorithm".
236
  ... (keep existing)"""
237
- ADMIN_SYSTEM_INSTRUCTION = """Your name is Nila, the smart cafe administrator assistant for "Cafe AI". ... (keep existing)"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
 
239
  # --- Routes ---
240
  @app.route('/')
@@ -299,7 +390,7 @@ def api_customer_chat_stream(table_number):
299
 
300
  response = chat.send_message(user_message)
301
 
302
- # Extract text
303
  if response.candidates and response.candidates[0].content and response.candidates[0].content.parts:
304
  parts = response.candidates[0].content.parts
305
  text_parts = [part.text for part in parts if hasattr(part, "text") and part.text]
@@ -431,7 +522,7 @@ def api_admin_chat():
431
 
432
  config = types.GenerateContentConfig(
433
  system_instruction=ADMIN_SYSTEM_INSTRUCTION,
434
- tools=[get_full_menu, set_item_availability],
435
  thinking_config=types.ThinkingConfig(thinking_budget=0)
436
  )
437
 
@@ -445,6 +536,48 @@ def api_admin_chat():
445
 
446
  response = chat.send_message(last_user_message)
447
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  admin_response_text = ""
449
  if response.candidates and response.candidates[0].content and response.candidates[0].content.parts:
450
  parts = response.candidates[0].content.parts
@@ -455,22 +588,20 @@ def api_admin_chat():
455
  try:
456
  admin_response_text = response.text or ""
457
  except (ValueError, AttributeError):
458
- admin_response_text = "تغییرات مورد نظر شما با موفقیت روی منو اعمال شد."
459
 
460
  return jsonify({"success": True, "response": admin_response_text})
461
  except Exception as e:
462
  return jsonify({"error": str(e)}), 500
463
 
464
- # --- Admin Menu CRUD ---
465
  @app.route('/api/admin/menu', methods=['GET'])
466
  def api_admin_get_menu():
467
- """Get full menu for admin panel."""
468
  menu = load_menu()
469
  return jsonify(menu)
470
 
471
  @app.route('/api/admin/menu/item', methods=['POST'])
472
  def api_admin_add_menu_item():
473
- """Add a new menu item manually."""
474
  data = request.json or {}
475
  name = data.get("name", "").strip()
476
  if not name:
@@ -497,12 +628,10 @@ def api_admin_add_menu_item():
497
 
498
  @app.route('/api/admin/menu/item/<int:item_id>', methods=['PUT'])
499
  def api_admin_update_menu_item(item_id):
500
- """Update a menu item's fields."""
501
  data = request.json or {}
502
  conn = get_db_connection()
503
  try:
504
  with conn.cursor() as cur:
505
- # Build dynamic SET clause
506
  allowed_fields = ["name", "description", "price", "available"]
507
  updates = []
508
  values = []
@@ -527,7 +656,6 @@ def api_admin_update_menu_item(item_id):
527
 
528
  @app.route('/api/admin/menu/item/<int:item_id>', methods=['DELETE'])
529
  def api_admin_delete_menu_item(item_id):
530
- """Delete a menu item."""
531
  conn = get_db_connection()
532
  try:
533
  with conn.cursor() as cur:
 
231
  finally:
232
  release_db_connection(conn)
233
 
234
+ # --- NEW: Full CRUD tools for admin chat ---
235
+ def get_menu_items() -> str:
236
+ """
237
+ Returns the complete menu with IDs, names, descriptions, prices, and availability statuses.
238
+ """
239
+ menu = load_menu()
240
+ return json.dumps(menu, ensure_ascii=False)
241
+
242
+ def add_menu_item(name: str, description: str = "", price: str = "", available: bool = True) -> str:
243
+ """
244
+ Add a new item to the cafe menu. Returns confirmation message.
245
+ """
246
+ conn = get_db_connection()
247
+ try:
248
+ with conn.cursor() as cur:
249
+ cur.execute(
250
+ "INSERT INTO menu (name, description, price, available) VALUES (%s, %s, %s, %s) RETURNING id;",
251
+ (name.strip(), description.strip(), price.strip(), available)
252
+ )
253
+ new_id = cur.fetchone()[0]
254
+ conn.commit()
255
+ return f"آیتم '{name}' با شناسه {new_id} با موفقیت اضافه شد."
256
+ except Exception as e:
257
+ conn.rollback()
258
+ return f"خطا در افزودن آیتم: {str(e)}"
259
+ finally:
260
+ release_db_connection(conn)
261
+
262
+ def update_menu_item(item_id: int, name: str = None, description: str = None, price: str = None, available: bool = None) -> str:
263
+ """
264
+ Update an existing menu item by ID. Only provided fields are updated.
265
+ """
266
+ conn = get_db_connection()
267
+ try:
268
+ updates = {}
269
+ if name is not None:
270
+ updates["name"] = name.strip()
271
+ if description is not None:
272
+ updates["description"] = description.strip()
273
+ if price is not None:
274
+ updates["price"] = price.strip()
275
+ if available is not None:
276
+ updates["available"] = available
277
+ if not updates:
278
+ return "هیچ فیلدی برای بروزرسانی ارسال نشده است."
279
+ with conn.cursor() as cur:
280
+ set_clause = ", ".join([f"{field} = %s" for field in updates])
281
+ values = list(updates.values()) + [item_id]
282
+ cur.execute(f"UPDATE menu SET {set_clause} WHERE id = %s;", values)
283
+ conn.commit()
284
+ if cur.rowcount == 0:
285
+ return f"آیتم با شناسه {item_id} یافت نشد."
286
+ return f"آیتم {item_id} با موفقیت بروزرسانی شد."
287
+ except Exception as e:
288
+ conn.rollback()
289
+ return f"خطا در بروزرسانی آیتم: {str(e)}"
290
+ finally:
291
+ release_db_connection(conn)
292
+
293
+ def delete_menu_item(item_id: int) -> str:
294
+ """
295
+ Delete a menu item by ID.
296
+ """
297
+ conn = get_db_connection()
298
+ try:
299
+ with conn.cursor() as cur:
300
+ cur.execute("DELETE FROM menu WHERE id = %s;", (item_id,))
301
+ conn.commit()
302
+ if cur.rowcount == 0:
303
+ return f"آیتم با شناسه {item_id} یافت نشد."
304
+ return f"آیتم {item_id} با موفقیت حذف شد."
305
+ except Exception as e:
306
+ conn.rollback()
307
+ return f"خطا در حذف آیتم: {str(e)}"
308
+ finally:
309
+ release_db_connection(conn)
310
+
311
+ # --- System Instructions ---
312
  CUSTOMER_SYSTEM_INSTRUCTION = """Your name is Nila, a classic, warm, and highly professional AI cafe assistant for "Cafe AI". You were developed by "Nastaran Data Algorithm".
313
  ... (keep existing)"""
314
+
315
+ ADMIN_SYSTEM_INSTRUCTION = """Your name is Nila, the smart cafe administrator assistant for "Cafe AI". You manage the cafe menu in real time.
316
+ You can view, add, update, delete menu items, and change availability using the following tools:
317
+ - **get_menu_items()**: fetch the full menu with IDs, names, descriptions, prices, and availability.
318
+ - **add_menu_item(name, description, price, available)**: add a new item (description and price optional, available is True by default).
319
+ - **update_menu_item(item_id, name, description, price, available)**: update any fields of an existing item by its ID (only pass the fields you want to change).
320
+ - **delete_menu_item(item_id)**: permanently remove an item.
321
+ - **set_item_availability(item_name, available)**: quickly toggle availability of an item by its exact name.
322
+
323
+ When the user asks to see the menu, use get_menu_items and show a nicely formatted list.
324
+ When asked to add an item, ask for the necessary details and then call add_menu_item.
325
+ For modifications, first get the menu to find the item ID, then use update_menu_item.
326
+ For removals, use delete_menu_item with the correct ID.
327
+ Always confirm every change clearly. Communicate primarily in Persian (Farsi), but you can understand English commands as well.
328
+ Be polite, precise, and efficient."""
329
 
330
  # --- Routes ---
331
  @app.route('/')
 
390
 
391
  response = chat.send_message(user_message)
392
 
393
+ # Extract text (ignore possible function calls in this simplified customer flow)
394
  if response.candidates and response.candidates[0].content and response.candidates[0].content.parts:
395
  parts = response.candidates[0].content.parts
396
  text_parts = [part.text for part in parts if hasattr(part, "text") and part.text]
 
522
 
523
  config = types.GenerateContentConfig(
524
  system_instruction=ADMIN_SYSTEM_INSTRUCTION,
525
+ tools=[get_menu_items, add_menu_item, update_menu_item, delete_menu_item, set_item_availability],
526
  thinking_config=types.ThinkingConfig(thinking_budget=0)
527
  )
528
 
 
536
 
537
  response = chat.send_message(last_user_message)
538
 
539
+ # Handle function calls loop
540
+ max_iterations = 10 # safety net
541
+ while max_iterations > 0:
542
+ function_calls = []
543
+ if response.candidates and response.candidates[0].content and response.candidates[0].content.parts:
544
+ for part in response.candidates[0].content.parts:
545
+ if hasattr(part, "function_call") and part.function_call:
546
+ function_calls.append(part.function_call)
547
+ if not function_calls:
548
+ break
549
+
550
+ # Execute functions and build response
551
+ function_response_parts = []
552
+ for fc in function_calls:
553
+ func_name = fc.name
554
+ args = dict(fc.args) if hasattr(fc, "args") else {}
555
+ print(f"Admin function call: {func_name}({args})")
556
+ try:
557
+ if func_name == "get_menu_items":
558
+ result = get_menu_items()
559
+ elif func_name == "add_menu_item":
560
+ result = add_menu_item(**args)
561
+ elif func_name == "update_menu_item":
562
+ result = update_menu_item(**args)
563
+ elif func_name == "delete_menu_item":
564
+ result = delete_menu_item(**args)
565
+ elif func_name == "set_item_availability":
566
+ result = set_item_availability(**args)
567
+ else:
568
+ result = f"Unknown function: {func_name}"
569
+ except Exception as e:
570
+ result = f"Error executing {func_name}: {str(e)}"
571
+ function_response_parts.append(
572
+ types.Part.from_function_response(name=func_name, response={"result": result})
573
+ )
574
+ # Send function responses back to the model
575
+ response = chat.send_message(
576
+ types.Content(role="user", parts=function_response_parts)
577
+ )
578
+ max_iterations -= 1
579
+
580
+ # Extract final text
581
  admin_response_text = ""
582
  if response.candidates and response.candidates[0].content and response.candidates[0].content.parts:
583
  parts = response.candidates[0].content.parts
 
588
  try:
589
  admin_response_text = response.text or ""
590
  except (ValueError, AttributeError):
591
+ admin_response_text = "تغییرات مورد نظر شما با موفقیت اعمال شد."
592
 
593
  return jsonify({"success": True, "response": admin_response_text})
594
  except Exception as e:
595
  return jsonify({"error": str(e)}), 500
596
 
597
+ # --- Admin Menu CRUD (manual REST endpoints, kept for the admin UI table) ---
598
  @app.route('/api/admin/menu', methods=['GET'])
599
  def api_admin_get_menu():
 
600
  menu = load_menu()
601
  return jsonify(menu)
602
 
603
  @app.route('/api/admin/menu/item', methods=['POST'])
604
  def api_admin_add_menu_item():
 
605
  data = request.json or {}
606
  name = data.get("name", "").strip()
607
  if not name:
 
628
 
629
  @app.route('/api/admin/menu/item/<int:item_id>', methods=['PUT'])
630
  def api_admin_update_menu_item(item_id):
 
631
  data = request.json or {}
632
  conn = get_db_connection()
633
  try:
634
  with conn.cursor() as cur:
 
635
  allowed_fields = ["name", "description", "price", "available"]
636
  updates = []
637
  values = []
 
656
 
657
  @app.route('/api/admin/menu/item/<int:item_id>', methods=['DELETE'])
658
  def api_admin_delete_menu_item(item_id):
 
659
  conn = get_db_connection()
660
  try:
661
  with conn.cursor() as cur: