NLproductsearch / app.py
ghostai1's picture
Create app.py
aa16784 verified
import pandas as pd
from sentence_transformers import SentenceTransformer, util
import gradio as gr
# ─── Load catalog & compute embeddings ─────────────────────────
PRODUCTS_CSV = "products.csv"
df = pd.read_csv(PRODUCTS_CSV)
descriptions = df["description"].tolist()
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
embeddings = model.encode(descriptions, convert_to_tensor=True, normalize_embeddings=True)
# ─── Semantic-search function ─────────────────────────────────
def search_products(query: str, top_k: int = 5):
if not query.strip():
return pd.DataFrame(columns=df.columns.tolist() + ["score"])
q_emb = model.encode(query, convert_to_tensor=True, normalize_embeddings=True)
hits = util.cos_sim(q_emb, embeddings)[0].topk(k=top_k)
indices = hits.indices.cpu().tolist()
scores = [round(float(s), 3) for s in hits.values.cpu().tolist()]
results = df.iloc[indices].copy()
results["score"] = scores
return results.reset_index(drop=True)
# ─── Gradio UI ────────────────────────────────────────────────
with gr.Blocks(title="πŸ›οΈ Salon Catalog Semantic Search") as demo:
gr.Markdown("""
# πŸ›οΈ Salon Product Search
**Natural-language queries** β†’ **top matching products** via MiniLM embeddings
(Runs entirely on free CPU; no paid APIs)
""")
with gr.Row():
query_in = gr.Textbox(placeholder="e.g. sulfate-free shampoo under $15", label="Search query")
topk = gr.Slider(1, 10, value=5, step=1, label="Number of results")
search_btn = gr.Button("Search πŸ”", variant="primary")
table = gr.Dataframe(
headers=list(df.columns) + ["score"],
datatype=["number","str","str","str","number","number"],
interactive=False,
row_count= topk.value,
label="Results"
)
search_btn.click(search_products, [query_in, topk], table)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0")