giva-discovery / src /app.py
Gautham98's picture
GIVA Discovery: full app + vectors
73d02ec verified
Raw
History Blame Contribute Delete
3.23 kB
"""
app.py — Streamlit UI: prompt box + filters + product grid with "why this matches".
Run: streamlit run app.py
Prereq: run `python ingest.py` first to build ./chroma_db.
"""
import streamlit as st
from search import search
from llm import explain_matches
st.set_page_config(page_title="GIVA Discovery", page_icon="💍", layout="wide")
PLACEHOLDER_IMG = "https://via.placeholder.com/300x300?text=No+Image"
st.title("💍 GIVA — Describe it, find it")
st.caption("Type what you want in plain English. Searches GIVA's real inventory by meaning, not keywords.")
# ---- Search bar -----------------------------------------------------------
prompt = st.text_input(
"What are you looking for?",
placeholder="dainty flower ring in rose gold under 15000",
)
# ---- Filters --------------------------------------------------------------
with st.sidebar:
st.header("Refine")
material = st.selectbox("Material", ["Any", "Silver", "Gold"])
colour = st.selectbox(
"Colour", ["Any", "Silver", "Gold", "Rose Gold", "Yellow Gold"])
shop_for = st.selectbox("Shop for", ["Any", "Women", "Men", "Kids"])
solid_gold = st.checkbox("Solid gold only (9KT/14KT)")
price_range = st.slider("Budget (Rs.)", 0, 150000, (0, 15000), step=500)
top_n = st.slider("Results", 4, 24, 12)
use_llm = st.checkbox("Explain matches (Claude)", value=True)
filters = {}
if material != "Any":
filters["primary_category"] = material
if colour != "Any":
filters["colour"] = colour
if shop_for != "Any":
filters["shop_for"] = shop_for
if solid_gold:
filters["solid_gold_only"] = True
filters["min_price"] = price_range[0]
filters["max_price"] = price_range[1]
def render_card(r):
img = r.get("img") or PLACEHOLDER_IMG
st.image(img, use_container_width=True)
st.markdown(f"**{r.get('title', '')}**")
price = r.get("price")
cap = r.get("compare_at_price")
if isinstance(price, (int, float)) and price > 0:
if isinstance(cap, (int, float)) and cap > price:
st.markdown(f"**Rs.{price:,.0f}** ~~Rs.{cap:,.0f}~~")
else:
st.markdown(f"**Rs.{price:,.0f}**")
label = "Gold-plated silver" if (
r.get("primary_category") == "Silver"
and "gold" in str(r.get("colour", "")).lower()
) else r.get("primary_category", "")
st.caption(f"{label} · {r.get('colour','')} · {r.get('sku','')}")
if r.get("why"):
st.success(r["why"], icon="✨")
if prompt:
with st.spinner("Searching GIVA's catalogue..."):
results = search(prompt, filters, top_n=top_n)
if use_llm and results:
results = explain_matches(prompt, results)
if not results:
st.warning("No strong match for that. Try loosening the filters or rephrasing.")
else:
st.write(f"### {len(results)} matches")
cols_per_row = 4
for i in range(0, len(results), cols_per_row):
cols = st.columns(cols_per_row)
for col, r in zip(cols, results[i:i + cols_per_row]):
with col:
render_card(r)
else:
st.info("Try: *twin heart pendant for her* · *evil eye anklet in silver* "
"· *14KT gold diamond studs*")