(alt: SellCraft AI — a fully local Etsy/eBay listing writer with Gemma 4 and Ollama)
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
SellCraft AI is a listing writer that runs on the seller's laptop, not on anyone else's server. A handmade seller drops in up to four product photos, types the few facts only the maker knows — materials, size, price — picks a platform (Etsy or eBay) and a tone, and gets back a finished listing: a keyword-front-loaded title inside the platform's character limit, a 120–180 word description in the shop's own voice, and tags that respect Etsy's 13-tags-by-20-characters rule.
I built it for one specific person — the seller I kept picturing while writing it: forty active listings, a day job, a phone full of product photos. Photographing six new mugs takes an evening. Writing the six listings takes another evening, and that's the evening the box stays closed and the mugs stay unlisted. SellCraft turns each listing into about a minute of work — and it doesn't sound like a template, because it writes from the photos and the seller's own words instead of from a blank prompt box.
Would someone pay for it? I think so, and not much has to be true for that to hold: it saves a seller an evening a week, and it's sold as a flat one-time download. There's no API bill behind it, so there's no meter to hide inside a subscription — the seller can regenerate a description twenty times without watching a counter. Tooling for a side hustle shouldn't be one of the side hustle's fixed costs, and only a locally-running model makes that price possible.
Demo
There's no live link, deliberately. SellCraft's whole argument is that it runs on the seller's machine — a hosted demo would be a different, worse product. The honest demo is two commands:
ollama pull gemma4 # one-time: the model now lives on this machine
python sellcraft.py # opens http://127.0.0.1:8765
The repo ships three sample photos (a mug, soap bars, earrings), so you can go from clone to a finished listing in about a minute without hunting for product photos.
Code
Everything lives in one repo: https://github.com/Senthil455/Sell-Carft-AI
One Python file (~600 lines, standard library only), one plain HTML/CSS/JS front end, one SQLite file. No pip install, no build step, no framework, no account. Built end-to-end for this challenge.
How I Built It
A single-file backend, on purpose. The server is http.server + urllib + sqlite3 — every import is in Python's standard library. If you're going to ask a stranger to run AI on their own laptop, "you can read the entire backend in one sitting" is the feature. The trust story is the source code, not a policy page.
Gemma reads the photos. The app talks to Ollama on 127.0.0.1:11434 and runs Gemma's vision model. Seeing the photo is what makes or breaks the output: it has to recognize speckled stoneware with a chunky handle, because "handmade ceramic mug" is the listing every other seller already has. Any vision model you've pulled shows up in a dropdown, so a slower laptop can swap down.
The prompt is where the product actually lives. It's one carefully-built template with hard rules: never invent materials, sizes, prices or origins; work only from the seller's facts and what's clearly visible in the photos; plain text only; exactly four labelled sections (NOTES / TITLE / DESCRIPTION / TAGS). Each platform carries its own constraints — Etsy gets a 100–140 character title and 13 tags of ≤20 characters; eBay gets a keyword-first 80-character title and 8 keywords. My favourite part is NOTES: instead of inventing a size, the model says what it saw and asks about the one thing it couldn't read — "roughly how much does this hold?" A writer that asks is worth more than one that guesses.
Trust is enforced a second time, in code. Prompts drift, so every draft passes through a tidy_listing() cleanup before it reaches the UI: titles are truncated at a word boundary to the platform's limit, tags are deduplicated, lowercased and trimmed to 20 characters — and when trimming would gut a tag into nonsense, it's dropped instead of shipped broken. (Etsy silently ignores over-long tags, which is how sellers end up with nine working tags and no idea why.)
Streaming, because good writing feels written. The server relays Ollama's token stream to the browser, so you watch the title fill in, character counters tick against each platform's limits, and tags that run long light up red before Etsy ever sees them. A full draft lands in about [X] seconds at [Y] tok/s on my laptop — the app prints both numbers under every draft, so the machine is honest about its speed with the seller.
It learns the shop's voice, locally. Saved listings go into SQLite, and the last three are fed back into the next prompt as a style sample: match this voice, never copy it. The output sounds more like the shop with every listing — and the examples never leave the machine that wrote them. Revision works the same way: type "less flowery" or "make the description shorter", and the model receives the previous draft plus the instruction, and rewrites the whole thing.
Small kindnesses where they matter. Photos are downscaled in the browser to 1000 px before they hit the local model. The app opens its own tab on startup. When Ollama isn't running, the page says so in plain words and offers a re-check button instead of dying. And there's a one-click CSV export, because a seller's catalogue is their business, not my database.
What it deliberately doesn't do: it won't post to Etsy for you. The output is plain text with copy buttons, because holding a seller's marketplace credentials is a commitment a v1 shouldn't make. It's probably the first thing a real user will ask for — and that's a decision to make with a real user, not on their behalf.
Why Does Open Innovation Matter?
Privacy is the architecture, not a promise. The only hostname that appears anywhere in SellCraft's source is 127.0.0.1. A handmade seller's photos are their original work — often photographed before the listing exists anywhere — and their drafts contain pricing and positioning they haven't published yet. Running Gemma locally means there is no server to trust. That's a different category of claim from "we don't store your data": you can verify it by reading one file.
The business model only works because inference is local. With a closed API, every draft is a line item, and the builder pays for every user forever. That cost structure is exactly what pushes small tools into subscriptions, credit packs, and "fair use" limits. Gemma on the laptop makes the hundredth listing cost the same as the first — nothing — so the product can be sold as a flat one-time download. A price that works for a seller in a craft economy only exists because the marginal cost is zero.
Swapping models is a feature, not an escape hatch. The model dropdown is just "whatever you've pulled with Ollama." When a better open-weight vision model ships next month, a seller gets it with one command: no waitlist, no repricing, no migration project. Whole product roadmaps have been broken by a provider deprecating a single endpoint.
The agent's behaviour is a text file. "Never invent a size" is a visible rule in one f-string that a seller — or anyone forking the repo — can change in a line. Closed systems hand you a prompt box; open ones hand you the harness. And because Gemma's weights are open, the natural next step stays on the table instead of on a waitlist: fine-tuning a small model on a shop's own back catalogue, so the writer learns their catalogue the way a hired copywriter would.
It works with the Wi-Fi off. Once the model is pulled, SellCraft doesn't need the internet to write a listing — on a train, at a market stall, during an outage. That still feels slightly magic, and it's the property that most cleanly separates what open weights make possible from what closed APIs allow.
My Agent Session
My First User
Prize Categories
Best Use of Gemma. Gemma is the core of the product, running locally through Ollama: it reads the seller's photos and writes every word of the listing — the description, the title, the tags, and the questions it asks back. The default pull is gemma4:latest; any Gemma vision build works, and there is no other model or cloud API anywhere in the stack.
Top comments (0)