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()