ecom_Chat / app.py
Saurabh502's picture
Upload 6 files
078556c verified
import gradio as gr
import data_manager
import gemini_client
import re
import os
import pandas as pd # For displaying data in a table
import datetime
# --- Functions copied/adapted from chatbot.py ---
def extract_order_id(query):
"""Attempts to extract an order ID (assumed to be a number) from the query."""
match = re.search(r'\b\d+\b', query)
if match:
return int(match.group(0))
return None
def format_prompt(query, order_details=None, order_items=None, recent_orders=None):
"""Formats the prompt for the Gemini API, including context."""
prompt = f"You are an e-commerce customer support assistant. Answer the user's query based *only* on the provided information. If the information is insufficient, say so.\n\nUser Query: \"{query}\"\n\n"
if order_details:
prompt += "--- Order Information ---\n"
prompt += f"Order ID: {order_details.get('order_id')}\n"
prompt += f"Customer: {order_details.get('user_name')} ({order_details.get('email')})\n"
prompt += f"Date: {order_details.get('order_date')}\n"
prompt += f"Status: {order_details.get('status')}\n"
prompt += f"Total: ${order_details.get('total_amount'):.2f}\n"
if order_items:
prompt += "\n--- Items in Order ---\n"
for item in order_items:
prompt += f"- {item.get('product_name')} (Qty: {item.get('quantity')}, Price/Unit: ${item.get('price_per_unit'):.2f})\n"
if recent_orders:
prompt += "\n--- Recent Orders ---\n"
for order in recent_orders:
prompt += f"- Order ID: {order.get('order_id')}, Date: {order.get('order_date')}, Status: {order.get('status')}, Total: ${order.get('total_amount'):.2f}\n"
prompt += "\n---\nAssistant Response:"
return prompt
# --- Data Management Functions ---
def get_product_dataframe():
"""Fetches all products and returns them as a Pandas DataFrame."""
products = data_manager.get_all_products()
if products:
return pd.DataFrame(products)
else:
return pd.DataFrame({"message": ["No products found"]}) # Empty DataFrame with a message
def get_user_dataframe():
"""Fetches all users and returns them as a Pandas DataFrame."""
users = data_manager.get_all_users()
if users:
return pd.DataFrame(users)
else:
return pd.DataFrame({"message": ["No users found"]})
def get_order_dataframe():
"""Fetches all orders and returns them as a Pandas DataFrame."""
orders = data_manager.get_all_orders()
if orders:
return pd.DataFrame(orders)
else:
return pd.DataFrame({"message": ["No orders found"]})
def get_order_item_dataframe():
"""Fetches all order items and returns them as a Pandas DataFrame."""
order_items = data_manager.get_all_order_details()
if order_items:
return pd.DataFrame(order_items)
else:
return pd.DataFrame({"message": ["No order items found"]})
def add_product_interface(name, description, price, stock):
"""Adds a product using the data_manager function and returns a message."""
try:
price = float(price)
stock = int(stock)
if not all([name, description, price >= 0, stock >= 0]):
return "Error: Please fill all fields correctly. Price and stock must be non-negative.", get_product_dataframe()
product_id = data_manager.add_product(name, description, price, stock)
if product_id:
return "Product added successfully. Refreshing data...", get_product_dataframe()
else:
return "Error: Could not add product.", get_product_dataframe()
except ValueError:
return "Error: Invalid price or stock value.", get_product_dataframe()
def remove_product_interface(product_id):
"""Removes a product using the data_manager function and returns a message."""
try:
product_id = int(product_id)
if product_id <= 0:
return "Error: Product ID must be a positive integer.", get_product_dataframe()
removed = data_manager.remove_product(product_id)
if removed:
return f"Product with ID {product_id} removed successfully.", get_product_dataframe()
else:
return f"Error: Could not remove product with ID {product_id} (product not found or in use).", get_product_dataframe()
except ValueError:
return "Error: Invalid product ID.", get_product_dataframe()
def add_user_interface(name, email, address):
"""Adds a user using the data_manager function."""
user_id = data_manager.add_user(name, email, address)
if user_id:
return f"User added successfully with ID: {user_id}", get_user_dataframe()
else:
return "Error: Could not add user.", get_user_dataframe()
def add_order_interface(user_id, order_date, status, total_amount):
"""Adds an order using the data_manager function."""
try:
user_id = int(user_id)
total_amount = float(total_amount)
datetime.datetime.strptime(order_date, '%Y-%m-%d') # Validate date format
if status not in ['Pending', 'Processing', 'Shipped', 'Delivered', 'Cancelled']:
return "Error: Invalid order status.", get_order_dataframe()
order_id = data_manager.add_order(user_id, order_date, status, total_amount)
if order_id:
return f"Order added successfully with ID: {order_id}", get_order_dataframe()
else:
return "Error: Could not add order.", get_order_dataframe()
except ValueError:
return "Error: Invalid user ID or total amount.", get_order_dataframe()
except ValueError:
return "Error: Invalid date format. Use YYYY-MM-DD.", get_order_dataframe()
def add_order_item_interface(order_id, product_id, quantity, price_per_unit):
"""Adds an order item using the data_manager function."""
try:
order_id = int(order_id)
product_id = int(product_id)
quantity = int(quantity)
price_per_unit = float(price_per_unit)
order_item_id = data_manager.add_order_item(order_id, product_id, quantity, price_per_unit)
if order_item_id:
return f"Order item added successfully with ID: {order_item_id}", get_order_item_dataframe()
else:
return "Error: Could not add order item.", get_order_item_dataframe()
except ValueError:
return "Error: Invalid order ID, product ID, quantity, or price per unit.", get_order_item_dataframe()
def remove_user_interface(user_id):
"""Removes a user using the data_manager function and returns a message."""
try:
user_id = int(user_id)
if user_id <= 0:
return "Error: User ID must be a positive integer.", get_user_dataframe()
removed = data_manager.remove_user(user_id)
if removed:
return f"User with ID {user_id} removed successfully.", get_user_dataframe()
else:
return f"Error: Could not remove user with ID {user_id} (user not found or in use).", get_user_dataframe()
except ValueError:
return "Error: Invalid user ID.", get_user_dataframe()
def remove_order_interface(order_id):
"""Removes an order using the data_manager function and returns a message."""
try:
order_id = int(order_id)
if order_id <= 0:
return "Error: Order ID must be a positive integer.", get_order_dataframe()
removed = data_manager.remove_order(order_id)
if removed:
return f"Order with ID {order_id} removed successfully.", get_order_dataframe()
else:
return f"Error: Could not remove order with ID {order_id} (order not found or in use).", get_order_dataframe()
except ValueError:
return "Error: Invalid order ID.", get_order_dataframe()
def remove_order_item_interface(order_id, product_id):
"""Removes an order item using the data_manager function and returns a message."""
try:
order_id = int(order_id)
product_id = int(product_id)
if order_id <= 0 or product_id <= 0:
return "Error: IDs must be positive integers.", get_order_item_dataframe()
conn = data_manager.get_db_connection()
cursor = conn.cursor()
try:
cursor.execute("DELETE FROM order_items WHERE order_id = ? AND product_id = ?",
(order_id, product_id))
conn.commit()
removed = cursor.rowcount > 0
conn.close()
if removed:
return f"Order item (Order: {order_id}, Product: {product_id}) removed successfully.", get_order_item_dataframe()
else:
return f"Error: Could not remove order item (Order: {order_id}, Product: {product_id}) - not found.", get_order_item_dataframe()
except sqlite3.Error as e:
conn.rollback()
conn.close()
return f"Database error: {e}", get_order_item_dataframe()
except ValueError:
return "Error: Invalid order ID or product ID.", get_order_item_dataframe()
# --- Chatbot Functions ---
def get_chatbot_response(user_email, query):
"""Handles the chatbot logic for the Gradio interface."""
if not user_email:
return "Error: Please enter your email address."
user_info = data_manager.get_user_by_email(user_email)
if not user_info:
return f"Error: User with email {user_email} not found."
user_id = user_info['user_id']
order_id = extract_order_id(query)
order_details = None
order_items = None
recent_orders = None
response_message = ""
try:
# Determine context based on query and extracted info
if order_id:
order_details = data_manager.get_order_details(order_id)
if order_details:
# Security check: Ensure the order belongs to the logged-in user
if order_details['email'] != user_email:
response_message = f"Order {order_id} does not belong to user {user_email}."
order_details = None # Clear details if not authorized
else:
# Fetch items only if order details are valid and authorized
order_items = data_manager.get_order_items(order_id)
else:
response_message = f"Order ID {order_id} not found."
# Check for recent orders query (simple keyword check)
elif "recent orders" in query.lower() or "my orders" in query.lower():
recent_orders = data_manager.get_user_recent_orders(user_id)
if not recent_orders:
response_message = "You have no recent orders."
# Construct and send prompt if we have relevant context
if order_details or recent_orders:
prompt = format_prompt(query, order_details, order_items, recent_orders)
# print("\nAssistant thinking...") # No console print in Gradio func
response = gemini_client.get_gemini_response(prompt)
response_message = response
elif order_id and not order_details and not response_message:
# Already handled the "not found" or "not authorized" message above
pass # response_message already set
elif not response_message: # If no context found and no error message yet
response_message = "Please specify an order ID (e.g., 'status for order 123') or ask about 'recent orders'."
return response_message
except FileNotFoundError as e:
return f"Error: Database not found at {data_manager.DB_PATH}. Please ensure it exists."
except Exception as e:
# Log the full error for debugging if needed, but return a user-friendly message
print(f"An unexpected error occurred: {e}") # Log to console where Gradio runs
return f"An unexpected error occurred. Please try again later."
# --- Database Check ---
if not os.path.exists(data_manager.DB_PATH):
print(f"Database not found at {data_manager.DB_PATH}.")
print("Please run 'python generate_data.py' first to create and populate the database.")
# Optionally, exit or prevent Gradio launch
# exit() # Uncomment to stop if DB is missing
# --- Gradio Interface ---
with gr.Blocks(title="E-commerce Management") as iface:
gr.Markdown("# E-commerce Chatbot and Data Management")
with gr.Tab("Chatbot"):
email_input = gr.Textbox(label="Your Email Address")
query_input = gr.Textbox(label="Your Query", placeholder="e.g., 'What is the status of order 1?' or 'Show my recent orders'")
chatbot_output = gr.Textbox(label="Assistant Response")
chatbot_button = gr.Button("Submit")
chatbot_button.click(
fn=get_chatbot_response,
inputs=[email_input, query_input],
outputs=chatbot_output
)
with gr.Tab("Data Management"):
with gr.Tabs():
with gr.Tab("Products"):
gr.Markdown("## Product Data")
product_table = gr.DataFrame(get_product_dataframe(), interactive=False, label="Current Products")
with gr.Accordion("Add New Product", open=False):
new_name_input = gr.Textbox(label="Product Name")
new_description_input = gr.Textbox(label="Description")
new_price_input = gr.Number(label="Price")
new_stock_input = gr.Number(label="Stock")
add_product_button = gr.Button("Add Product")
add_product_output = gr.Textbox()
add_product_button.click(
fn=add_product_interface,
inputs=[new_name_input, new_description_input, new_price_input, new_stock_input],
outputs=[add_product_output, product_table]
)
with gr.Accordion("Remove Product", open=False):
remove_id_input = gr.Number(label="Product ID to Remove")
remove_product_button = gr.Button("Remove Product")
remove_product_output = gr.Textbox()
remove_product_button.click(
fn=remove_product_interface,
inputs=[remove_id_input],
outputs=[remove_product_output, product_table]
)
with gr.Tab("Users"):
gr.Markdown("## User Data")
user_table = gr.DataFrame(get_user_dataframe(), interactive=False, label="Current Users")
with gr.Accordion("Add User", open=False):
new_user_name_input = gr.Textbox(label="User Name")
new_user_email_input = gr.Textbox(label="Email")
new_user_address_input = gr.Textbox(label="Address")
add_user_button = gr.Button("Add User")
add_user_output = gr.Textbox()
add_user_button.click(
fn=add_user_interface,
inputs=[new_user_name_input, new_user_email_input, new_user_address_input],
outputs=[add_user_output, user_table]
)
with gr.Accordion("Remove User", open=False):
remove_user_id_input = gr.Number(label="User ID to Remove")
remove_user_button = gr.Button("Remove User")
remove_user_output = gr.Textbox()
remove_user_button.click(
fn=remove_user_interface,
inputs=[remove_user_id_input],
outputs=[remove_user_output, user_table]
)
with gr.Tab("Orders"):
gr.Markdown("## Order Data")
order_table = gr.DataFrame(get_order_dataframe(), interactive=False, label="Current Orders")
with gr.Accordion("Add Order", open=False):
new_order_user_id_input = gr.Number(label="User ID")
new_order_date_input = gr.Textbox(label="Order Date (YYYY-MM-DD)")
new_order_status_input = gr.Dropdown(label="Status", choices=['Pending', 'Processing', 'Shipped', 'Delivered', 'Cancelled'])
new_order_total_amount_input = gr.Number(label="Total Amount")
add_order_button = gr.Button("Add Order")
add_order_output = gr.Textbox()
add_order_button.click(
fn=add_order_interface,
inputs=[new_order_user_id_input, new_order_date_input, new_order_status_input, new_order_total_amount_input],
outputs=[add_order_output, order_table]
)
with gr.Accordion("Remove Order", open=False):
remove_order_id_input = gr.Number(label="Order ID to Remove")
remove_order_button = gr.Button("Remove Order")
remove_order_output = gr.Textbox()
remove_order_button.click(
fn=remove_order_interface,
inputs=[remove_order_id_input],
outputs=[remove_order_output, order_table]
)
with gr.Tab("Order Items"):
gr.Markdown("## Order Item Data")
order_item_table = gr.DataFrame(get_order_item_dataframe(), interactive=False, label="Current Order Items")
with gr.Accordion("Add Order Item", open=False):
new_order_item_order_id_input = gr.Number(label="Order ID")
new_order_item_product_id_input = gr.Number(label="Product ID")
new_order_item_quantity_input = gr.Number(label="Quantity")
new_order_item_price_per_unit_input = gr.Number(label="Price per Unit")
add_order_item_button = gr.Button("Add Order Item")
add_order_item_output = gr.Textbox()
add_order_item_button.click(
fn=add_order_item_interface,
inputs=[new_order_item_order_id_input, new_order_item_product_id_input, new_order_item_quantity_input, new_order_item_price_per_unit_input],
outputs=[add_order_item_output, order_item_table]
)
with gr.Accordion("Remove Order Item", open=False):
remove_order_id_input = gr.Number(label="Order ID")
remove_product_id_input = gr.Number(label="Product ID")
remove_order_item_button = gr.Button("Remove Order Item")
remove_order_item_output = gr.Textbox()
remove_order_item_button.click(
fn=remove_order_item_interface,
inputs=[remove_order_id_input, remove_product_id_input],
outputs=[remove_order_item_output, order_item_table]
)
if __name__ == "__main__":
if os.path.exists(data_manager.DB_PATH):
print("Launching Gradio interface...")
iface.launch(share=True)
else:
print("Gradio interface not launched because the database is missing.")