Inspiration
Small B2B sellers keep their sales history in exports and spreadsheets. They know their regulars, but rarely notice when one slips out of their usual ordering rhythm. Most "AI prediction" tools show a confident score and never say whether it was right before. We wanted a tool that checks itself first.
What it does
Upload a messy sales export. An LLM and built-in rules both propose a column mapping, code verifies it, and you confirm. Customers are ranked by how likely they are to reorder within 8 weeks and grouped as Due now, Slipping, Lapsed or Not due yet.
We do not show a made-up probability per customer. Each tier shows how often it was right in past test windows on your own data. Each customer gets a short explanation and a draft message, checked by code against their own orders.
The app audits itself against a simple "most recent buyers first" rule. If the model does not beat the rule on your data, the app says so and uses the rule. On our Indonesian sample it only ties in 2 of 3 windows, so it uses the rule.
How we built it
Python, pandas and scikit-learn for features, a logistic regression model and backtests. Streamlit for the app. Qwen2.5-7B-Instruct through Featherless for column mapping, explanations and drafts.
Code decides every number. The LLM only proposes, and code checks:
- the mapping (one customer and one date per invoice)
- the invoice numbers in explanations
- each draft (numbers, dates, products, blocked promises, currency symbols)
If a check fails, a template replaces the text.
Evidence (UCI Online Retail II, 5,878 customers, 36,969 invoices; locked 20% holdout, run once; paired bootstrap intervals). Model minus recency rule, top 20%:
- Oct 2011: +23 points (+16 to +31)
- Jul 2011: +13 points (+6 to +23)
- Apr 2011: +6 points (-2 to +16, not conclusive)
Challenges
Teaching the app to say no. In our own final check, the LLM invented a currency amount and a product name on a sample file with no product column. Our first verifier missed both. We fixed it by rejecting currency symbols and, without a product column, capitalized product-like names. It can still miss names that start a sentence or are lowercase, so drafts must be read before sending.
The LLM also put the invoice id in the wrong column in 2 of 5 mapping runs. Code now catches that, and the user always confirms the mapping.
Accomplishments that we're proud of
A tool that refuses to use its own model when the data does not support it, and shows its weakest result (the April window) instead of hiding it. A verifier that caught 15 of 15 hand-written bad drafts. Everything built solo during the event.
What we learned
Trust is a product feature. Showing measured hit rates and failing honestly was harder than building the model, and it is what makes the output usable.
What's next
- Test with real sellers' data (we have asked staff of a real shop, no reply yet)
- Get an independent rating of the 20 sample drafts
- Test whether contacting a customer actually causes a reorder, which we do not claim
Notes
Demo samples are synthetic. Evidence data: UCI Online Retail II, CC BY 4.0.
AI tools used: Claude (coding assistant, and automation of demo screen recording). LLM calls inside the app go through Featherless. Voice-over by the developer.
Built With
- featherless
- ffmpeg
- pandas
- playwright
- python
- qwen2.5
- scikit-learn
- streamlit
Log in or sign up for Devpost to join the conversation.