Commit History

Update src/ocr_utils.py
d789f56
verified

theDavidGuy commited on

Update src/ocr_utils.py
9b62fe2
verified

theDavidGuy commited on

Update ocr_utils.py
ba9dd6c
verified

theDavidGuy commited on

Update ocr_utils.py
60de58e
verified

theDavidGuy commited on

Update ocr_utils.py
84c3056
verified

theDavidGuy commited on

Update ocr_utils.py
3a081c4
verified

theDavidGuy commited on

Create src/ocr_utils.py
9637293
verified

theDavidGuy commited on

Rename ocr to ocr_utils.py
50d1782
verified

theDavidGuy commited on

Update requirements.txt
53b8c5e
verified

theDavidGuy commited on

Update src/streamlit_app.py
6aa907d
verified

theDavidGuy commited on

Create ocr
b0cc733
verified

theDavidGuy commited on

Update Dockerfile
d1ab7c3
verified

theDavidGuy commited on

Update Dockerfile
a8548ca
verified

theDavidGuy commited on

Update Dockerfile
81d7dfc
verified

theDavidGuy commited on

Update requirements.txt
389199e
verified

theDavidGuy commited on

Update src/streamlit_app.py
199d49b
verified

theDavidGuy commited on

Update valuation
560ed18
verified

theDavidGuy commited on

Update requirements.txt
7914417
verified

theDavidGuy commited on

Update src/streamlit_app.py
bcac3a6
verified

theDavidGuy commited on

Update valuation
d2a7537
verified

theDavidGuy commited on

Update requirements.txt
90a4f9c
verified

theDavidGuy commited on

import re, os import pandas as pd from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.preprocessing import OneHotEncoder from sklearn.linear_model import Ridge # Seed comps (you can expand this later or swap for live sold comps) SEED = [ ("Nintendo Wii Console with controllers","Electronics","Nintendo","Used-Good",85), ("Vintage Pyrex mixing bowl set","Home & Kitchen","Pyrex","Used-Good",120), ("Levi's 501 jeans men's 34x32","Clothing","Levi's","Used-Good",28), ("Patagonia Synchilla fleece pullover M","Clothing","Patagonia","Used-Good",45), ("KitchenAid Artisan stand mixer","Home & Kitchen","KitchenAid","Used-Good",220), ("Bose QuietComfort 35 headphones","Electronics","Bose","Used-Good",140), ("Apple iPhone 11 128GB unlocked","Electronics","Apple","Used-Good",240), ("Herman Miller Aeron chair size B","Furniture","Herman Miller","Used-Good",500), ("Sony PlayStation 2 console slim","Electronics","Sony","Used-Good",75), ("Le Creuset dutch oven 5.5 qt","Home & Kitchen","Le Creuset","Used-Good",240), ("Sony Walkman cassette player","Electronics","Sony","Used-Good",95), ("All-Clad stainless pan 10 inch","Home & Kitchen","All-Clad","Used-Good",55), ("Coach leather handbag crossbody","Accessories","Coach","Used-Good",65), ("Seiko 5 automatic watch SNK809","Accessories","Seiko","Used-Good",95), ] def _seed_df(): return pd.DataFrame(SEED, columns=["title","category","brand","condition","price"]) class DealValuator: def __init__(self, df: pd.DataFrame = None): self.df = df if df is not None else _seed_df() self.model = self._train(self.df) def _train(self, df: pd.DataFrame): text_features = 'title' cat_features = ['category','brand','condition'] text_pipe = Pipeline([('tfidf', TfidfVectorizer(ngram_range=(1,2), min_df=1))]) cat_pipe = Pipeline([('ohe', OneHotEncoder(handle_unknown='ignore'))]) pre = ColumnTransformer([('t', text_pipe, text_features), ('c', cat_pipe, cat_features)]) model = Pipeline([('pre', pre), ('reg', Ridge(alpha=1.0))]) X = df[['title','category','brand','condition']] y = df['price'] model.fit(X, y) return model def predict_resale(self, title: str, category: str=None, brand: str=None, condition: str='Used-Good'): X = pd.DataFrame([{ 'title': title, 'category': category or 'Unknown', 'brand': brand or 'Unknown', 'condition': condition or 'Used-Good' }]) pred = float(self.model.predict(X)[0]) return max(5.0, round(pred, 2)) def deal_score(predicted_resale: float, ask: float, fee_rate: float=0.13, ship: float=12.0): fees = predicted_resale * fee_rate net = predicted_resale - fees - ship profit = net - ask margin = (profit / ask) if ask > 0 else 0.0 if profit >= 50 and margin >= 0.8: label = "Home Run" elif profit >= 25 and margin >= 0.5: label = "Great" elif profit >= 10 and margin >= 0.3: label = "Good" elif profit >= 5: label = "Meh" else: label = "Pass" return round(fees,2), round(net,2), round(profit,2), round(margin,2), label
096a2f5
verified

theDavidGuy commited on

Update requirements.txt
1b3a0ef
verified

theDavidGuy commited on

Update src/streamlit_app.py
b1d1fcb
verified

theDavidGuy commited on

# GoodFind β€” Simple Online Demo (Docker/Streamlit one-file) import streamlit as st import base64 from datetime import datetime st.set_page_config(page_title="GoodFind (Simple)", page_icon="πŸ›’") st.title("πŸ›’ GoodFind β€” Simple Online Demo") st.caption("Zero-setup demo (no OCR/ML). Enter items & prices; I estimate fees/shipping and rank by profit.") # Simple keyword table (no external deps) PRICE_TABLE = { "wii": 85, "playstation": 120, "ps2": 75, "ps3": 110, "ps4": 160, "ps5": 350, "iphone": 240, "macbook": 450, "aeron": 500, "pyrex": 120, "le creuset": 240, "kitchenaid": 220, "bose": 140, "walkman": 95, "marantz": 400, "yeti": 18, "dansko": 40, "coach": 65, "levi": 28, "seiko": 95, "all-clad": 55, } DEFAULT_RESALE = 45.0 def quick_estimate(title: str) -> float: t = (title or "").lower() best = None for k, v in PRICE_TABLE.items(): if k in t: best = max(best or 0, v) return float(best if best else DEFAULT_RESALE) def score_deal(predicted_resale: float, ask: float, fee_rate: float = 0.13, ship: float = 12.0): fees = predicted_resale * fee_rate net = predicted_resale - fees - ship profit = net - ask margin = (profit / ask) if ask > 0 else 0.0 if profit >= 50 and margin >= 0.8: label = "Home Run" elif profit >= 25 and margin >= 0.5: label = "Great" elif profit >= 10 and margin >= 0.3: label = "Good" elif profit >= 5: label = "Meh" else: label = "Pass" return {"fees": round(fees, 2), "net_after_fees": round(net, 2), "profit": round(profit, 2), "margin": round(margin, 2), "label": label} # CSS for hover labels st.markdown(""" <style> .img-wrap{position:relative; display:inline-block; margin:8px; max-width:100%;} .img-wrap img{display:block; max-width:100%; height:auto; border-radius:6px; border:1px solid rgba(0,0,0,0.1);} .hover-label{ position:absolute; left:8px; top:8px; padding:4px 8px; border-radius:4px; background:rgba(0,0,0,0.65); color:#fff; font-size:0.9rem; opacity:0; transition:opacity .15s; pointer-events:none; } .img-wrap:hover .hover-label{opacity:1;} </style> """, unsafe_allow_html=True) tab1, tab2 = st.tabs(["Single check", "Group scan (manual)"]) # Single check with tab1: st.subheader("Quick deal check") title = st.text_input("Item title", placeholder="e.g., Nintendo Wii bundle with games") c1, c2, c3 = st.columns(3) with c1: ask = st.number_input("Asking price ($)", min_value=0.0, step=1.0, value=10.0) with c2: fees_rate = st.slider("Fees rate", 0.05, 0.20, 0.13, 0.01) with c3: ship = st.slider("Shipping estimate ($)", 0.0, 30.0, 12.0, 1.0) if st.button("Evaluate deal", type="primary"): resale = quick_estimate(title) s = score_deal(resale, ask, fees_rate, ship) st.markdown(f"### Estimated resale: **${resale:.2f}**") st.markdown(f"**Verdict:** {s['label']}") st.write({ "Fees ($)": s["fees"], "Net after fees+ship ($)": s["net_after_fees"], "Profit ($)": s["profit"], "Margin on ask": s["margin"], }) # Group scan (manual) with tab2: st.subheader("Group scan: upload photos, type names & prices") st.caption("No OCR in this simple demo. Enter a short name + price for each photo; I'll rank by profit.") fees_rate_g = st.slider("Fees rate (apply to all)", 0.05, 0.20, 0.13, 0.01, key="fees_group") ship_g = st.slider("Shipping estimate ($, apply to all)", 0.0, 30.0, 12.0, 1.0, key="ship_group") photos = st.file_uploader("Upload photos", type=["jpg","jpeg","png","webp"], accept_multiple_files=True) items = [] if photos: for i, img in enumerate(photos): data = img.read() with st.expander(f"Photo {i+1}"): st.image(data, use_column_width=True) c1, c2 = st.columns([2,1]) with c1: name = st.text_input(f"Item name #{i+1}", placeholder="e.g., Bose QC35 headphones", key=f"name_{i}") with c2: price_txt = st.text_input(f"Asking price #{i+1} ($)", placeholder="e.g., 25.00", key=f"price_{i}") items.append((name, price_txt, data, img.type or "image/jpeg")) if st.button("Evaluate group", type="primary"): rows = [] gallery_blocks = [] for idx, (name, price_txt, data, mime) in enumerate(items): if not (name and name.strip()): name = f"Item {idx+1}" try: ask_i = float(price_txt) if price_txt.strip() else 0.0 except: ask_i = 0.0 resale = quick_estimate(name) s = score_deal(resale, ask_i, fees_rate_g, ship_g) rows.append({"title": name, "ask": ask_i, "resale": resale, **s}) b64 = base64.b64encode(data).decode("utf-8") gallery_blocks.append(f""" <div class="img-wrap" title="{name}"> <img src="data:{mime};base64,{b64}" alt="{name}"/> <span class="hover-label">{name}</span> </div> """) if rows: rows.sort(key=lambda r: (r["profit"], r["resale"]), reverse=True) st.markdown("### Ranked results") st.table([ {"Title": r["title"], "Ask ($)": f"{r['ask']:.2f}", "Est. resale ($)": f"{r['resale']:.2f}", "Profit ($)": f"{r['profit']:.2f}", "Margin": f"{r['margin']:.2f}", "Verdict": r["label"]} for r in rows ]) top = rows[0] st.success(f"Top pick: **{top['title']}** β€” resale ${top['resale']:.0f}, profit ${top['profit']:.0f} ({top['label']})") st.markdown("### Hover over each image to see the item name") st.markdown("".join(gallery_blocks), unsafe_allow_html=True)
8c98941
verified

theDavidGuy commited on

initial commit
7c7acae
verified

theDavidGuy commited on

Duplicate from streamlit/streamlit-template-space
c3fc7ce
verified

theDavidGuy FranckAbgrall HF Staff commited on