{"slug": "etsy-listing-writer-with-gemma-4-it-reads-your-photos-and-won-t-make-stuff-up", "title": "Etsy listing writer with Gemma 4: it reads your photos and won't make stuff up", "summary": "A developer built listwright, an open-source tool that generates Etsy listing titles, 13 tags and descriptions from product photos using the open-weight Gemma 4 model, defaulting to a local Ollama instance. A dependency-free Python checker in rules.py validates output against Etsy's character and tag limits and flags any number or risky claim word (such as \"framed\" or \"personalised\") not present in the seller-supplied facts, returning hard failures to the model for up to three retries. In testing on 12 real shop listings run twice each, seven outputs required confirmation, five of them because the model pulled details like \"A5 to A2\" from photos rather than stated facts.", "body_md": "*This is a submission for the [Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle](https://dev.to/challenges/hacktoberfest-week2-2026-10-12)*\n\nI run a tiny Etsy shop on the side. Moon posters, word prints, that sort of thing. The making bit is fun. Writing the listing is not. Every product wants a title that fits in 140 characters with the search words first, exactly 13 tags of 20 characters or less, and a description that doesn't sound like a robot wrote it.\n\nSo I built **listwright**. You give it your product photos and a line or two about what's true, and it gives you back the title, the 13 tags and the description, using Gemma 4.\n\nThe bit I actually care about is what happens next. Before you see anything, a dead simple Python checker reads the listing and sorts it into one of three:\n\nWho'd pay for it? Anyone with more than a handful of listings and better things to do on a Sunday. It costs a fraction of a penny per listing to run, or nothing at all on your own box, so even a cheap hosted version for sellers who don't want to touch a terminal would be nearly all profit.\n\nHere's a real run on one of my listings, with the kind of one-line facts you'd actually type when you're knackered:\n\nDecent title, all 13 tags, sensible description. But it's slipped \"personalized gift\" and \"custom name art\" into the tags. That product isn't personalised. You buy the letters and spell the name yourself. On Etsy, \"personalised\" means the buyer expects to send you a name, so that's an awkward message waiting to happen. The checker didn't fix it. It asked me.\n\nThen I ran it on 12 real listings from the shop, each one twice. Once with the shop's full description as the facts, once with a lazy one-liner:\n\nThe 7 \"confirm\" ones were all fair questions. Five were the lazy runs picking up things like \"A5 to A2\" and \"November 2027\" from the photos. True, as it happens, but I never said them, and on another shop that's a mockup frame turning into \"arrives framed\". The other two were that \"personalised\" print above, once with each set of facts.\n\nEtsy listings from your product photos, written by an open-weight model you can run yourself and checked so it can't sell something you don't make.\n\n```\nlistwright draft photo1.jpg photo2.jpg --facts \"Birmingham moon poster. Instant digital download.\"\n```\n\nYou get a title (140 chars max, search words first), exactly 13 tags (20 chars max each) and a three-paragraph description. Then a plain Python checker reads it before you do:\n\n| Result | Means | \n|---|---|\n| `✓ ready` | inside Etsy's limits and says nothing you didn't tell it | \n| `? confirm` | it states something you didn't say: a number, or a claim like *framed* ,*handmade* ,*personalised* . Usually it read it off your photo and it's true. Sometimes it's a mockup frame and a refund waiting to happen. You decide. | \n| `✗ not ready` | still breaks a hard rule after 3 tries (too long, wrong tag count, a misspelt place name) | \n\nOnly hard failures go back…\n\nPython, no dependencies. `pip install git+https://github.com/casareanderson/listwright` and then:\n\n```\nlistwright draft photo1.jpg photo2.jpg --facts \"Birmingham moon poster. Instant digital download.\"\n```\n\nThree small files that matter:\n\n`model.py` makes one call to anything that speaks the OpenAI chat API with images. The default is Ollama on your own machine with `gemma4`. Point one environment variable somewhere else and nothing else changes.`draft.py` sends the photos and your facts, gets JSON back, and checks it. If it breaks a hard rule it goes back to the model with the list of what's wrong, up to 3 tries.`rules.py` is the checker. No AI in it at all. Character limits, tag counts, every number has to be in your facts, a list of risky claim words, and misspelt place names.\nGetting the checker right took longer than the model bit, honestly. Some things I got wrong first:\n\nWhat it doesn't do: it doesn't know if a tag is a *good* tag. It tagged one moon poster \"astrology art\". Wrong shelf completely. Read your tags.\n\nTwo reasons, and one of them happened to me today.\n\nThe plan was to run all of this on my own little GPU box with Gemma 4 locally. Photos never leave the house, no subscription, nobody can put the price up on you. This morning that box had other ideas. A graphics driver update had gone in without a reboot, so the card wasn't being used at all, and Gemma sat there for ten minutes without answering.\n\nWith a closed API I'd have been stuck or rewriting. Because it's an open model, I changed one setting and pointed it at a hosted copy of the same Gemma 4 family, and carried on. The demo numbers above are from that hosted 26B version. I haven't re-run all 24 on the local 8B yet, so I'm not going to claim it does just as well.\n\nThe second reason is cost. All 24 drafts cost $0.0035 in total. That's the difference between a tool that has to charge you every month to pay its AI bill and one that basically costs nothing to run.\n\nMy own shop, if I'm honest. Nobody's paid for it. But it found real problems in my real listings on its first afternoon, and that's more than most of my side projects manage.\n\nBest Use of Gemma: Gemma 4 does all the writing, reads the product photos, and runs locally through Ollama by default.\n\n🤖 *Drafted with AI assistance from my own notes and test runs, then reviewed and edited before publishing.*", "url": "https://wpnews.pro/news/etsy-listing-writer-with-gemma-4-it-reads-your-photos-and-won-t-make-stuff-up", "canonical_source": "https://dev.to/iam-tech/etsy-listing-writer-with-gemma-4-it-reads-your-photos-and-wont-make-stuff-up-3bgc", "published_at": "2026-10-18 08:06:04+00:00", "updated_at": "2026-10-18 08:14:36.117185+00:00", "lang": "en", "topics": ["ai-tools", "generative-ai", "large-language-models", "ai-products", "developer-tools"], "entities": ["Etsy", "Gemma 4", "Ollama", "listwright", "GitHub"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/etsy-listing-writer-with-gemma-4-it-reads-your-photos-and-won-t-make-stuff-up", "markdown": "https://wpnews.pro/news/etsy-listing-writer-with-gemma-4-it-reads-your-photos-and-won-t-make-stuff-up.md", "text": "https://wpnews.pro/news/etsy-listing-writer-with-gemma-4-it-reads-your-photos-and-won-t-make-stuff-up.txt", "jsonld": "https://wpnews.pro/news/etsy-listing-writer-with-gemma-4-it-reads-your-photos-and-won-t-make-stuff-up.jsonld"}}