import random import uuid import logging from datetime import datetime, timedelta import streamlit as st from openai import OpenAI # ================================================== # LOGGING # ================================================== logging.basicConfig( level=logging.INFO, format="%(asctime)s | %(levelname)s | %(message)s" ) logger = logging.getLogger("AI-Agent") # ================================================== # RAW DATA (600+ ROWS WITH DATE) # ================================================== @st.cache_data def generate_data(rows: int = 600): random.seed(42) today = datetime.today().date() data = [] for i in range(1, rows + 1): data.append({ "order_id": i, "order_date": today - timedelta(days=random.randint(0, 30)), "supplier": random.choice( ["Supplier A", "Supplier B", "Supplier C", "Supplier D"] ), "product": random.choice( ["Tomato", "Cheese", "Flour", "Oil", "Meat"] ), "quantity": random.randint(1, 100), "price": round(random.uniform(5, 50), 2), "delivery_days": random.randint(1, 14), "status": random.choice( ["Delivered", "Pending", "Delayed"] ) }) logger.info("Generated %d rows of data", len(data)) return data DATA = generate_data() # ================================================== # UTILS: FORMAT RESPONSE AS TEXT # ================================================== def format_rows_as_text(rows): lines = [] for r in rows: lines.append( f"๐Ÿงพ Order #{r['order_id']} | {r['order_date']}\n" f" Product: {r['product']}\n" f" Supplier: {r['supplier']}\n" f" Qty: {r['quantity']} | Price: ${r['price']}\n" f" Delivery: {r['delivery_days']} days | Status: {r['status']}\n" ) return "\n".join(lines) # ================================================== # TOOLS # ================================================== def tool_get_stats(): prices = [x["price"] for x in DATA] days = [x["delivery_days"] for x in DATA] logger.info("Tool โ†’ get_stats") return { "rows": len(DATA), "avg_price": round(sum(prices) / len(prices), 2), "avg_delivery_days": round(sum(days) / len(days), 2), } def tool_query_product(product: str): logger.info("Tool โ†’ query_product(%s)", product) return [x for x in DATA if x["product"].lower() == product.lower()][:5] def tool_query_last_days(days: int): logger.info("Tool โ†’ query_last_days(%d)", days) cutoff = datetime.today().date() - timedelta(days=days) return [x for x in DATA if x["order_date"] >= cutoff][:5] def tool_create_support_ticket(text: str): ticket_id = str(uuid.uuid4())[:8] logger.info("Tool โ†’ create_support_ticket (%s)", ticket_id) return ticket_id # ================================================== # SAFETY # ================================================== def is_dangerous(text: str): blocked = ["delete", "drop", "truncate", "remove"] return any(b in text.lower() for b in blocked) # ================================================== # AGENT # ================================================== def agent(user_input: str, openai_client: OpenAI): logger.info("User input: %s", user_input) if is_dangerous(user_input): return "โŒ Dangerous operations are not allowed." text = user_input.lower() # ---- STATS ---- if "stats" in text or "summary" in text: s = tool_get_stats() return ( "๐Ÿ“Š Business Overview\n" f"- Total rows: {s['rows']}\n" f"- Average price: ${s['avg_price']}\n" f"- Average delivery days: {s['avg_delivery_days']}" ) # ---- LAST N DAYS ---- if "last" in text and "day" in text: try: days = int([x for x in text.split() if x.isdigit()][0]) except: days = 3 rows = tool_query_last_days(days) if not rows: return f"No data found for last {days} days." return f"๐Ÿ“ฆ Orders from last {days} days:\n\n" + format_rows_as_text(rows) # ---- PRODUCT ---- if text.startswith("show"): product = user_input.replace("show", "").strip() rows = tool_query_product(product) if not rows: return "No records found. Would you like me to create a support ticket?" return f"๐Ÿ“ฆ Showing orders for **{product}**:\n\n" + format_rows_as_text(rows) # ---- SUPPORT ---- if "support" in text or "ticket" in text: ticket_id = tool_create_support_ticket(user_input) return ( "๐ŸŽซ Support Ticket Created\n" f"- Ticket ID: {ticket_id}\n" "- System: GitHub Issues (mock)" ) # ---- OPENAI FALLBACK ---- logger.info("LLM fallback via OpenAI") response = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[ { "role": "system", "content": ( "You are an AI procurement assistant. " "You do NOT have access to raw data." ) }, {"role": "user", "content": user_input} ], max_tokens=150, temperature=0.3 ) return response.choices[0].message.content # ================================================== # STREAMLIT UI # ================================================== st.set_page_config(page_title="AI Procurement Agent", layout="wide") st.title("๐Ÿค– AI Procurement Agent (OpenAI)") # ---- SIDEBAR ---- st.sidebar.header("๐Ÿ”‘ OpenAI Configuration") api_key = st.sidebar.text_input( "OpenAI API Key", type="password", help="Paste your OpenAI API key here" ) stats = tool_get_stats() st.sidebar.header("๐Ÿ“Š Business Information") st.sidebar.metric("Rows", stats["rows"]) st.sidebar.metric("Avg Price", f"${stats['avg_price']}") st.sidebar.metric("Avg Delivery Days", stats["avg_delivery_days"]) st.sidebar.markdown("### Sample queries") st.sidebar.code( "show tomato\n" "last 3 days\n" "database stats\n" "create support ticket" ) if not api_key: st.warning("Please enter your OpenAI API key to continue.") st.stop() openai_client = OpenAI(api_key=api_key) # ---- CHAT ---- if "messages" not in st.session_state: st.session_state.messages = [] user_input = st.chat_input("Ask the procurement agent...") if user_input: st.session_state.messages.append(("user", user_input)) reply = agent(user_input, openai_client) st.session_state.messages.append(("assistant", reply)) for role, message in st.session_state.messages: st.chat_message(role).write(message)