Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| from supervisor_agent import supervisor_agent | |
| from database import engine | |
| from sqlalchemy import text | |
| import uuid | |
| import pandas as pd | |
| import os | |
| from supabase import create_client | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| supabase = create_client(os.getenv("SUPABASE_URL"), os.getenv("SUPABASE_KEY")) | |
| def upload_file_to_supabase_gradio(file_path: str, order_id: str): | |
| """ | |
| Uploads a file to Supabase storage from a file path (Gradio format) | |
| Returns the public URL or None if upload fails | |
| """ | |
| if not file_path: | |
| return None | |
| try: | |
| with open(file_path, 'rb') as f: | |
| file_bytes = f.read() | |
| file_ext = os.path.splitext(file_path)[1].lstrip('.') | |
| if not file_ext: | |
| file_ext = 'bin' | |
| timestamp = str(uuid.uuid4().hex) | |
| storage_path = f"{order_id}_{timestamp}.{file_ext}" | |
| res = supabase.storage.from_("complaints").upload(storage_path, file_bytes) | |
| if isinstance(res, dict) and res.get("error"): | |
| print(f"Supabase upload error: {res.get('error')}") | |
| return None | |
| public_url = supabase.storage.from_("complaints").get_public_url(storage_path) | |
| print(f"File uploaded successfully: {public_url}") | |
| return public_url | |
| except Exception as e: | |
| print(f"Error uploading file to Supabase: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| return None | |
| def chat_with_agent(message, file, session_id): | |
| """Main chat function""" | |
| if not session_id: | |
| session_id = int(uuid.uuid4().int % 1000000) | |
| session_id = int(session_id) | |
| file_url = None | |
| if file is not None: | |
| print(f" File received: {file}") | |
| print(f" File type: {type(file)}") | |
| file_url = upload_file_to_supabase_gradio(file, order_id=str(session_id)) | |
| if file_url: | |
| print(f" File uploaded: {file_url}") | |
| else: | |
| print(" File upload failed, continuing without file") | |
| supervisor_input = f"Session ID: {session_id} | User Query: {message}" | |
| if file_url: | |
| supervisor_input += f" | FileURL: {file_url}" | |
| print(f"\n Sending to supervisor: {supervisor_input}\n") | |
| try: | |
| result = supervisor_agent.invoke( | |
| {"messages": [{"role": "user", "content": supervisor_input}]}, | |
| {"configurable": {"thread_id": str(session_id)}}, | |
| ) | |
| return result["messages"][-1].content, session_id | |
| except Exception as e: | |
| print(f" Error in chat_with_agent: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| return f"I apologize, but I encountered an error: {str(e)}", session_id | |
| def view_orders(user_id): | |
| """View all orders for a user""" | |
| try: | |
| if not user_id: | |
| return pd.DataFrame({"Message": ["Please enter a valid User ID"]}) | |
| with engine.connect() as conn: | |
| result = conn.execute( | |
| text( | |
| "SELECT order_id, product_name, created_at FROM orders WHERE user_id = :user_id ORDER BY created_at DESC"), | |
| {"user_id": int(user_id)} | |
| ) | |
| rows = result.fetchall() | |
| if not rows: | |
| return pd.DataFrame({"Message": ["No orders found for this User ID"]}) | |
| df = pd.DataFrame(rows, columns=["Order ID", "Product Name", "Order Date"]) | |
| return df | |
| except Exception as e: | |
| return pd.DataFrame({"Error": [str(e)]}) | |
| def check_complaints(user_id): | |
| """View all complaints for a user""" | |
| try: | |
| if not user_id: | |
| return pd.DataFrame({"Message": ["Please enter a valid User ID"]}) | |
| with engine.connect() as conn: | |
| result = conn.execute( | |
| text(""" | |
| SELECT order_id, product_name, complaint_text, complaint_file_url, created_at | |
| FROM orders | |
| WHERE user_id = :user_id AND is_complaint = 1 | |
| ORDER BY created_at DESC | |
| """), | |
| {"user_id": int(user_id)} | |
| ) | |
| rows = result.fetchall() | |
| if not rows: | |
| return pd.DataFrame({"Message": ["No complaints found for this User ID"]}) | |
| df = pd.DataFrame(rows, columns=["Order ID", "Product", "Complaint", "Evidence", "Date"]) | |
| return df | |
| except Exception as e: | |
| return pd.DataFrame({"Error": [str(e)]}) | |
| def upload_catalog(file, table_name): | |
| """Upload CSV/Excel to database""" | |
| if not file: | |
| return " Please select a file to upload" | |
| try: | |
| file_path = file if isinstance(file, str) else file.name | |
| if file_path.endswith('.csv'): | |
| df = pd.read_csv(file_path) | |
| elif file_path.endswith(('.xlsx', '.xls')): | |
| df = pd.read_excel(file_path) | |
| else: | |
| return " Please upload a CSV or Excel file" | |
| df.to_sql(table_name, con=engine, if_exists="replace", index=False) | |
| return f" Successfully uploaded {len(df)} rows to table '{table_name}'" | |
| except Exception as e: | |
| return f" Error: {str(e)}" | |
| custom_css = """ | |
| #title-box { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| padding: 30px; | |
| border-radius: 12px; | |
| margin-bottom: 25px; | |
| box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); | |
| text-align: center; | |
| width: 100%; | |
| } | |
| #title-box h1 { | |
| color: white !important; | |
| margin: 0 !important; | |
| font-size: 2.2em !important; | |
| text-shadow: 2px 2px 4px rgba(0,0,0,0.2); | |
| text-align: center !important; | |
| } | |
| /* Target all buttons with variant="primary" */ | |
| button[variant="primary"] { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; | |
| border: none !important; | |
| color: white !important; | |
| font-weight: 600 !important; | |
| border-radius: 8px !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| button[variant="primary"]:hover { | |
| background: linear-gradient(135deg, #764ba2 0%, #667eea 100%) !important; | |
| transform: translateY(-2px) !important; | |
| box-shadow: 0 5px 20px rgba(102, 126, 234, 0.5) !important; | |
| } | |
| /* Backup selectors for buttons */ | |
| .primary { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; | |
| border: none !important; | |
| color: white !important; | |
| } | |
| .primary:hover { | |
| background: linear-gradient(135deg, #764ba2 0%, #667eea 100%) !important; | |
| } | |
| """ | |
| with gr.Blocks() as demo: | |
| gr.HTML(""" | |
| <div id="title-box"> | |
| <h1>🛍️ E-commerce Customer Support System</h1> | |
| </div> | |
| """) | |
| session_state = gr.State(value=int(uuid.uuid4().int % 1000000)) | |
| with gr.Tabs(): | |
| with gr.Tab("💬 Chat with Support"): | |
| gr.Markdown("### Talk to our AI support agent") | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| chatbot = gr.Chatbot(height=400) | |
| msg_input = gr.Textbox( | |
| placeholder="Type your message here...", | |
| label="Your Message", | |
| lines=2 | |
| ) | |
| with gr.Row(): | |
| file_input = gr.File( | |
| label="Attach file (for complaints)", | |
| file_types=["image", "video", ".jpg", ".jpeg", ".png", ".mp4", ".mov"], | |
| scale=2 | |
| ) | |
| with gr.Column(scale=1): | |
| send_btn = gr.Button("Send", variant="primary", size="lg") | |
| clear_btn = gr.Button("Clear Chat", variant="secondary", size="lg") | |
| with gr.Column(scale=1): | |
| session_display = gr.Textbox( | |
| label="Your Session ID", | |
| value=session_state.value, | |
| interactive=False, | |
| lines=2 | |
| ) | |
| gr.Markdown(""" | |
| **Tips:** | |
| - Ask about products | |
| - Place orders | |
| - File complaints | |
| - Upload evidence for complaints | |
| **File Upload:** | |
| - Click "Attach file" button | |
| - Select image or video | |
| - Then send your message | |
| """) | |
| def respond(message, chat_history, file_path, session_id): | |
| """Handle user message and bot response""" | |
| if not message.strip(): | |
| return chat_history, session_id, None | |
| try: | |
| bot_response, updated_session = chat_with_agent(message, file_path, session_id) | |
| chat_history.append({"role": "user", "content": message}) | |
| chat_history.append({"role": "assistant", "content": bot_response}) | |
| return chat_history, updated_session, None | |
| except Exception as e: | |
| print(f"Error in respond function: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| error_msg = f"I apologize, but I encountered an error: {str(e)}" | |
| chat_history.append({"role": "user", "content": message}) | |
| chat_history.append({"role": "assistant", "content": error_msg}) | |
| return chat_history, session_id, None | |
| send_btn.click( | |
| respond, | |
| inputs=[msg_input, chatbot, file_input, session_state], | |
| outputs=[chatbot, session_state, file_input] | |
| ).then( | |
| lambda: "", | |
| outputs=[msg_input] | |
| ) | |
| msg_input.submit( | |
| respond, | |
| inputs=[msg_input, chatbot, file_input, session_state], | |
| outputs=[chatbot, session_state, file_input] | |
| ).then( | |
| lambda: "", | |
| outputs=[msg_input] | |
| ) | |
| clear_btn.click( | |
| lambda: ([], int(uuid.uuid4().int % 1000000)), | |
| outputs=[chatbot, session_state] | |
| ) | |
| with gr.Tab("📦 My Orders"): | |
| gr.Markdown("### View all your orders") | |
| user_id_orders = gr.Number( | |
| label="Enter Your User ID", | |
| precision=0 | |
| ) | |
| check_orders_btn = gr.Button("View My Orders", variant="primary") | |
| orders_output = gr.Dataframe( | |
| label="Your Orders", | |
| headers=["Order ID", "Product Name", "Order Date"] | |
| ) | |
| check_orders_btn.click( | |
| view_orders, | |
| inputs=[user_id_orders], | |
| outputs=[orders_output] | |
| ) | |
| with gr.Tab("⚠️ My Complaints"): | |
| gr.Markdown("### Track your complaint status") | |
| user_id_complaints = gr.Number( | |
| label="Enter Your User ID", | |
| precision=0 | |
| ) | |
| check_complaints_btn = gr.Button("View My Complaints", variant="primary") | |
| complaints_output = gr.Dataframe( | |
| label="Your Complaints", | |
| headers=["Order ID", "Product", "Complaint", "Evidence Files", "Date"] | |
| ) | |
| check_complaints_btn.click( | |
| check_complaints, | |
| inputs=[user_id_complaints], | |
| outputs=[complaints_output] | |
| ) | |
| with gr.Tab("📊 Upload Products (Admin)"): | |
| gr.Markdown("### Upload product catalog to database") | |
| gr.Markdown("⚠️ *Admin only - uploads CSV/Excel to database*") | |
| catalog_file = gr.File(label="Upload CSV or Excel") | |
| table_name_input = gr.Textbox( | |
| label="Table Name", | |
| value="Ecommerce_Data" | |
| ) | |
| upload_btn = gr.Button("Upload to Database", variant="primary") | |
| upload_status = gr.Textbox(label="Status") | |
| upload_btn.click( | |
| upload_catalog, | |
| inputs=[catalog_file, table_name_input], | |
| outputs=[upload_status] | |
| ) | |
| gr.Markdown(""" | |
| --- | |
| ### How to Use: | |
| 1. **Chat**: Talk to AI for product recommendations, place orders, or file complaints | |
| 2. **My Orders**: Check your order history using your User ID | |
| 3. **My Complaints**: Track complaint status and view evidence | |
| 4. **Upload Products** *(Admin)*: Add new products to the catalog | |
| ### Troubleshooting: | |
| - If file upload fails, check console logs for errors | |
| - Make sure SUPABASE_URL and SUPABASE_KEY are set in .env | |
| - Supported file types: JPG, PNG, MP4, MOV | |
| """) | |
| if __name__ == "__main__": | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| debug=True, | |
| css=custom_css | |
| ) |