This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
SalesWhy tells a small shop owner why their sales dropped — in plain English (or Telugu), backed by actual numbers, in about 20 seconds.
Picture the person this is for: she runs a little Etsy shop selling candles and ceramics on the side. Tuesday's sales were fine. Thursday they fell off a cliff. She has no idea why, and no time to become a data analyst to find out. Was it the weather? A competitor? Did she mess something up? Right now her only options are "stare at a spreadsheet" or "guess."
SalesWhy takes her orders CSV — whatever export her platform gives her, no reformatting required — and gives her three things:
- A chart of what sales actually did vs. what they should have done, with the rough weeks shaded and labeled.
- A ranked list of likely causes (price went up, shipping got more expensive, something went out of stock — or, honestly, "not sure, might be something outside this file").
- A three-sentence explanation she can actually read, plus a shareable "ledger slip" PNG she can screenshot to WhatsApp a supplier or business partner.
Who'd pay for this? Anyone running a one-person storefront who doesn't have, and can't afford, a data analyst — which is most of them. $5-10/month to stop guessing about your own numbers is an easy sell.
Demo
Try it live: [https://saleswhy.onrender.com]
Or run it in 3 commands (needs Ollama for local explanations):
git clone https://github.com/Yasaswini-ch/SalesWhy.git && cd SalesWhy
pip install -r requirements.txt && ollama pull gemma3:4b
python app.py
Open http://127.0.0.1:8000 and click "Try sample shop" — no upload needed to see it work end to end.
Code
SalesWhy
Why did your sales drop? SalesWhy tells you — in plain words, backed by numbers.
Upload an orders CSV from Shopify, Etsy, or any small shop export. SalesWhy predicts what sales should have been, finds the days where they fell short (or jumped), names the most likely cause, and explains it in a short, plain-language note — in English or Telugu.
Built for the DEV Hacktoberfest Open-Source AI Challenge — Week 2 ("Side Hustle").
Live demo: saleswhy.onrender.com — click "Try sample shop," no upload needed.
What it does
- Upload an orders CSV (or click "Try sample shop" to see it work instantly).
- SalesWhy auto-maps your columns (date, amount, quantity, product) and lets you confirm or fix the guess.
- It predicts expected daily revenue with TabPFN, trained on your own earlier data.
- It flags windows where actual revenue was well above or below expected, and deterministically ranks price, shipping…
How I Built It
The whole thing rests on one rule I didn't let myself break: a language model is never allowed to decide the cause of a sales drop. It only phrases a decision that's already been made by plain arithmetic. Here's the pipeline:
- TabPFN (local, open-weight) predicts what daily revenue should have been, trained on a seller's own earlier days — no hyperparameter tuning, which is TabPFN's whole premise and exactly what makes it workable for a tool that has to retrain itself on a stranger's CSV in a few seconds.
- A small deterministic function flags windows where actual revenue falls well below (or jumps well above) that prediction for 2+ consecutive days.
- For each flagged window, I compare price, shipping cost, and active-product-count inside the window against a 14-day baseline before it, and rank which one moved the most. If nothing moved enough, it says "not sure" — out loud, not silently.
- Only then does Gemma 3 (4B), running locally through Ollama, get involved — and only to turn
{"cause": "stockout", "change_pct": 43.5}into three readable sentences, in English or Telugu.
Everything else — the CSV column auto-mapper (so it works on Shopify, Etsy, or a raw transaction export without asking the user to reformat anything), the what-if estimator (re-predicts with a counterfactual price to say "if you hadn't raised the price, sales would've been about X"), the product drill-down, and the ledger-slip PNG export — is plain Python and a FastAPI endpoint. No agent framework, because this didn't need one.
I evaluated it properly, not just vibes: injected 30 synthetic drops with known causes (price hike, stockout, freight spike) into real seller data from the Olist e-commerce dataset, then checked whether SalesWhy named the right one. Full table and discussion in results/eval.md.
Why Does Open Innovation Matter?
Three concrete things open models bought me that a closed API wouldn't have, plus one honest surprise.
Cost that actually makes the business work. A shop owner checking "why did my sales drop" a few times a week, forever, needs a per-query cost near zero or the product doesn't exist. Local Gemma costs nothing beyond the laptop it's already running on.
Privacy that's actually true, not just claimed. TabPFN and Gemma both run on the same machine the CSV was uploaded to. The footer of the app states exactly what ran where, read from the live config — not a marketing claim, a fact I can check.
And here's the part I didn't expect going in. To build a fair baseline, I gave a generic LLM (Gemini, via API — the one closed piece in this whole evaluation, used only as a comparison point) the exact same raw data and asked it one plain, unstructured question: "why did sales drop?" I expected my engineered, deterministic pipeline to win easily. It didn't — the raw LLM call scored 53.3% accuracy against my pipeline's 36.7%, on the same 30 synthetic drops. (This post on why LLMs struggle with tabular prediction is about the opposite claim, and reading it after my own result made me take the surprise more seriously, not less.)
It wasn't all good news for the generic LLM, though — it does something SalesWhy's deterministic pipeline structurally can't: it sometimes gives a confidently wrong answer, blaming "orders fell" (true, but a symptom) instead of the price change that caused the orders to fall (the actual cause). SalesWhy can only ever name price, freight, stock, or say "not sure" — it can't invent a plausible-sounding non-answer. Whether 17 points of accuracy is worth that guardrail is a genuinely open question, and I'd rather report that honestly than quietly bury the number that didn't flatter my own design. (Full breakdown, including a grading bug I caught in myself mid-evaluation — my keyword classifier was marking the LLM wrong because it said "zero active products" instead of my expected word "stock" — is in results/eval.md.)
That's the open-innovation case in one sentence: because every piece of this ran somewhere I could inspect it, I could catch my own tool being outperformed, understand exactly why, and write about it instead of hiding it behind an API I couldn't see inside.
My Agent Session
The full build log — including every bug, every wrong turn, and the exact moment the generic-LLM baseline beat my own pipeline — is in DEVLOG.md in the repo. (Agent session embed/link to be added — see DevRelay session saving.)
My First User
Not an external customer yet — this was built solo against a tight deadline. But the closest thing to a first user so far: I put the running app in front of myself fresh, without pre-explaining the UI, and used it like a stranger would. First reaction: "the UI looks too boring." That's genuinely useful feedback, and it's the reason the finished app has the stamp-mark header, color-coded ledger rows, and a custom-styled chart instead of the plain bordered boxes I shipped first. The next real test is putting it in front of an actual Etsy or Shopify seller — that's the honest next step, not a fabricated success story.
Prize Categories
- Best Use of TabPFN
- Best Use of Gemma

Top comments (0)