Ichlibitiche's picture
Add RoasterDB sample explorer app
fe941e5 verified
Raw
History Blame Contribute Delete
4.03 kB
import gradio as gr
import pandas as pd
# Load the free sample directly from the public Hugging Face dataset
DATA_URL = "hf://datasets/Ichlibitiche/roasterdb-specialty-coffee-sample/roasterdb_sample.csv"
df = pd.read_csv(DATA_URL)
DISPLAY_COLS = {
"source_roaster": "Roaster",
"title": "Coffee",
"origin_country": "Origin",
"process_method": "Process",
"roast_level": "Roast",
"weight_grams": "Weight (g)",
"price_value": "Price (USD)",
"tasting_notes_sca_nodes": "SCA Flavor Notes",
"source_url": "Source URL",
}
def choices(col):
vals = df[col].dropna().astype(str)
vals = sorted(v for v in vals.unique() if v.strip() and v != "Unknown")
return ["All"] + vals
PRICE_MAX = float(df["price_value"].max())
def explore(roaster, country, process, roast, flavor, max_price):
d = df
if roaster != "All":
d = d[d["source_roaster"] == roaster]
if country != "All":
d = d[d["origin_country"] == country]
if process != "All":
d = d[d["process_method"] == process]
if roast != "All":
d = d[d["roast_level"] == roast]
if flavor and flavor.strip():
d = d[d["tasting_notes_sca_nodes"].fillna("").str.contains(flavor.strip(), case=False, regex=False)]
if max_price < PRICE_MAX:
d = d[d["price_value"].fillna(PRICE_MAX + 1) <= max_price]
summary = (
f"**{len(d)} coffees** from **{d['source_roaster'].nunique()} roasters** match — "
f"out of {len(df)} records in the free sample. "
f"The full RoasterDB has **8,000+ products from 280+ roasters**."
)
table = d[list(DISPLAY_COLS)].rename(columns=DISPLAY_COLS).sort_values("Price (USD)")
return summary, table
with gr.Blocks(title="RoasterDB Sample Explorer") as demo:
gr.Markdown("# ☕ RoasterDB: Specialty Coffee Sample Explorer")
gr.Markdown(f"""Explore **{len(df)} verified specialty coffees from {df['source_roaster'].nunique()} artisan roasters** — tasting notes normalized to the **SCA Flavor Wheel**, with a verifiable source URL on every record.
---
### 🌐 This is the free sample. The full RoasterDB has 8,000+ products from 280+ roasters.
* **🔗 Official Portal (full dataset, $99 snapshot):** [roasterdb.net](https://specialty-coffee-roasterdb.pages.dev)
* **🤗 Free Sample Dataset (Download CSV):** [Ichlibitiche/roasterdb-specialty-coffee-sample](https://huggingface.co/datasets/Ichlibitiche/roasterdb-specialty-coffee-sample)
* **🏆 Kaggle Dataset:** [RoasterDB Specialty Coffee Sample](https://www.kaggle.com/datasets/ahtiticheamine/roasterdb-specialty-coffee-sample)
* **🔄 Live Self-Serve Scraping:** [Specialty Coffee Roaster Scraper on Apify](https://apify.com/dataengineered/specialty-coffee-roaster-scraper)
---""")
with gr.Row():
roaster_dd = gr.Dropdown(choices=choices("source_roaster"), value="All", label="Roaster")
country_dd = gr.Dropdown(choices=choices("origin_country"), value="All", label="Origin Country")
process_dd = gr.Dropdown(choices=choices("process_method"), value="All", label="Process Method")
roast_dd = gr.Dropdown(choices=choices("roast_level"), value="All", label="Roast Level")
with gr.Row():
flavor_tb = gr.Textbox(label="SCA Flavor Search", placeholder="e.g. Berry, Chocolate, Floral, Peach...")
price_sl = gr.Slider(minimum=0, maximum=PRICE_MAX, value=PRICE_MAX, step=1, label="Max Price (USD)")
btn = gr.Button("Explore Coffees", variant="primary")
out_text = gr.Markdown()
out_table = gr.Dataframe(label="Matching Coffees", wrap=True)
inputs = [roaster_dd, country_dd, process_dd, roast_dd, flavor_tb, price_sl]
btn.click(fn=explore, inputs=inputs, outputs=[out_text, out_table])
demo.load(fn=explore, inputs=inputs, outputs=[out_text, out_table])
gr.Markdown("""---
*Sample data © RoasterDB under CC BY-NC 4.0. Full dataset commercially licensed at [roasterdb.net](https://specialty-coffee-roasterdb.pages.dev) · contact RoasterDB@proton.me*""")
demo.launch()