chat_with_data / src /streamlit_app.py
Jurabek's picture
Update src/streamlit_app.py
20f50df verified
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)