DEV Community

Aakash Mehta
Aakash Mehta

Posted on

ListingForge: a local Gemma tool that drafts shop listings from product photos

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission šŸ’ø

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle

What I Built

ListingForge helps a small online seller turn photos of one product into a first draft of a shop listing. You add 1 to 4 photos, choose Etsy or eBay, and optionally add a one-line note. Gemma 3 looks at the photos and drafts a title, a description of about 100 words, tags and a condition note. It also gives you a box called "Things only you can fill in", which lists everything a photo can't tell: size, material, price, shipping, and whether the item is handmade, vintage or mass-produced.

Who would pay for it: a small seller who lists a few items a week and finds writing listings tedious. I have not validated pricing with anyone, so I can't say what they would pay. I built the version that is cheap enough to run for free on a laptop.

It runs entirely on my computer. No account, no cloud, and the photos never leave the machine.

Demo

I don't have a hosted demo on purpose. The model runs locally through Ollama, so a public URL would defeat the point.

Screenshots from real runs on my laptop:

Code

ListingForge

What it is

ListingForge is a local-first web application that turns product photos into draft shop listings for online marketplaces. It runs entirely on your own computer using a local Ollama server and the Gemma 3 4B vision model. It uses standard Node.js and vanilla browser technologies, with no client-side frameworks, no build step, and no cloud API dependencies.

Who it is for

ListingForge is designed for small sellers on Etsy or eBay who find writing product listings tedious and repetitive, but who still want an honest, factual starting draft based strictly on what their photos show.

How it works

  1. Browser photo preparation: When you select or drop up to 4 product photos, the browser resizes them client-side using an HTML canvas to a maximum of 1024px on the longest side (JPEG at 0.8 quality). This keeps base64 payload sizes small and fast to process.
  2. Local server handling…

Setup: install Ollama, run ollama pull gemma3:4b, then npm install and npm start, and open http://localhost:3000.

How I Built It

  • Model: Gemma 3 4B (vision) through Ollama. It does two jobs: a quick "are these all the same product?" check, then the listing draft.
  • Server: Node.js and Express, with a small API for the health check, the same-product check and the listing.
  • Client: one plain HTML page. Photos are resized to 1024px JPEG in the browser before they are sent.
  • Structured output: every call asks Gemma for JSON, validates it, and retries once if it is invalid.
  • Built in stages: health check, photo upload, listing generation, then safety fixes, testing each stage before starting the next.

What Went Wrong, and How I Fixed It

My first test uploaded four different products at once. Gemma wrote one listing about two of them and dropped the other two. It also used words like "handmade", "hand-thrown" and "luxurious", which a photo can't prove. And the to-do box said "All essential details appear covered", which was false, because size, material and price never show in a photo.

I added instructions to the prompt, and the small model ignored the "detect mixed photos" rule. What worked was moving the rules into code:

  1. A separate yes/no check ("do all photos show the same product?") before any listing is written. With four different products it now names them and stops. With three different mugs it correctly says they are separate items.
  2. A list of words the draft may not use unless the seller's note says so, enforced in the prompt and again in code.
  3. A to-do list that is always added by the server: size, material, price, shipping, and whether the item is handmade, vintage or mass-produced.
  4. A last fix after a test on my own mouse: the draft said "wireless", but one photo can't show that, so features that can't be seen now go to the seller as questions.

What I Tested

  • One real product, one photo (my mouse, photographed by me): a plain, accurate draft that described only what was visible and used "appears to be" wording.
  • Four different products together (mug, wallet, earrings, candle): rejected, with the products named.
  • Three different mugs together: rejected as separate items.

Why Does Open Innovation Matter?

  1. Privacy. A seller's photos and product details stay on their own computer. A hosted API would receive every photo.
  2. Cost. There is no per-listing fee, so listing 500 items costs nothing beyond electricity. For a side hustle with thin margins, that decides whether the tool is worth using at all.
  3. Control. I could add checks around the model and swap it later without being locked into someone else's pricing or rules.

What It Does Not Do

  • It is a draft, not a finished listing. A seller must review every word. It never generates prices or sizes.
  • I have not had a first user yet, so I can't tell you what a real seller would pay or ask for next.
  • I tested one real product with real photos. The rest of my tests used other images, so the results are early.
  • A 4B model is imperfect. It can miss details, and the same-product check can be wrong on unusual photos. I tell the user when it can't decide.
  • I have not tested it on a phone.

AI Disclosure

I used Antigravity to help write the code, and a Claude assistant helped plan the build and write this post. The app itself runs on Gemma locally.

Prize Categories

Best Use of Gemma: Gemma 3 4B does the same-product check and the listing draft, entirely on the seller's own machine.

Top comments (1)

Collapse
 
amintacccp profile image
tamina •

The "wireless mouse" moment is the whole game with small local models — a photo can't prove a claim, and no amount of prompt wording reliably stops the model from inventing one. Moving that rule into code (a banned-words check, plus the separate same-product yes/no gate before any drafting happens) is exactly the right call. I also appreciate the honesty of the "things only you can fill in" box — most listing tools would rather hallucinate a size than admit the photo doesn't say.