Inspiration

I design print-on-demand artwork (my VELQAR catalog). The design work is the fun part; the listing work is the chore. Each marketplace has different rules - Etsy: up to 13 tags of at most 20 characters each, and a title up to 140 characters (https://help.etsy.com/hc/en-us/articles/360000336307-How-to-Use-Tags-to-Get-Found-in-Search and https://help.etsy.com/hc/en-us/articles/115015628707-How-to-Create-a-Listing, accessed Oct 6, 2026). Redbubble: up to 15 tags of 50 characters (https://help.redbubble.com/hc/en-us/articles/360047166432-How-do-I-tag-my-designs, updated Jan 22, 2026, accessed Oct 6, 2026). TeePublic: one designated main tag weighted heavily in search, plus supporting tags (TeePublic's own tagging guidance, https://www.teepublic.com/blog/tagging-101, accessed Oct 26, 2026). Writing those by hand for every design is repetitive, and tags written from memory age badly.

What it does

POD Listing Writer turns one uploaded design image into draft listings:

  1. NVIDIA Nemotron 3.5 Super VL, served on Nebius Token Factory, reads the artwork - subject, style, and the text printed on the design.
  2. NVIDIA Nemotron-3-Super-120B-A12B (nvidia/nemotron-3-super-120b-a12b), served on Nebius Token Factory, writes the title, tags, and description per platform. The prompt tells the model the design is artwork printed on a blank garment, so listings describe the artwork itself, not garment construction the printed product does not have.
  3. A rule layer trims every output to the platform's limits (tag count, tag length, title length) and scans the text against a small starter list of commonly protected brand terms - a basic heuristic warning, not legal advice.

Demo URL: https://pod-seo-tool.magpro369.workers.dev

How we built it

The backend is a single Cloudflare Worker. One browser request orchestrates the pipeline: a vision call to NVIDIA Nemotron 3.5 Super VL and a writing call to NVIDIA Nemotron-3-Super-120B-A12B on Nebius Token Factory's OpenAI-compatible endpoint - so the whole AI pipeline runs on NVIDIA Nemotron models (both model IDs verified in the Token Factory catalog on Oct 26, 2026; dated snapshot at docs/nebius-tokenfactory-model-catalog-2026-10-26.md, included in the public repo). The frontend is a static page served by the same worker. A Cloudflare Durable Object (SQLite) enforces budgets atomically before any paid backend call: a global daily generation limit, a per-connection (per-IP) daily limit, a lifetime generation cap, and a lifetime measured-cost budget (reserved before each call from a conservative estimate, settled to actual API usage after) sized from verified Token Factory rates - and it fails closed if the budget service itself errors. The worker also rejects oversized images server-side (JPEG/PNG only, byte and dimension caps), because the browser-side resize can be bypassed and image size is what drives vision token cost. If a Token Factory call fails at the transport level, the worker falls back to smaller Cloudflare Workers AI models; that fallback is a degraded mode and the results page always names the exact models that produced the output, so fallback text is never presented as Nemotron output. Empty model output is treated as an explicit error, never as a reason to quietly swap engines.

Challenges

  • Platform rules are stricter than model habits: models love 25-character tags and Etsy rejects them. Limits are enforced in code after generation, not just asked for in the prompt. The code never pads tag lists to hit a count - fewer, better tags are returned as-is.
  • Reasoning models hide a billing trap: their reasoning tokens count toward max_tokens, so a tight budget returns empty content. Measured: a vision call capped at 120 tokens spent all 120 on reasoning and returned nothing; the same call at 600 tokens used 374 (326 reasoning) and answered fully. Worse, long structured "OCR-style" prompts made the vision model reason without terminating - it returned empty content even at a 2000-token budget (recorded twice). The fix was prompt shape, not budget: a short conversational prompt terminates reliably (~400-600 tokens), and the writer model honors reasoning_effort="low" (the vision model ignores that parameter - measured). Production budgets are 2000 (vision) and 2400 (writer), and empty output is an explicit error.
  • A POD design sheet depicts a garment, but the product sold is the printed artwork on a blank garment. An early run described physical construction from the sheet (pockets, drawstrings) as product features - wrong for a print listing. The writer prompt now states the artwork-vs-garment distinction explicitly, and the verified output frames everything as artwork ("Artwork featuring...") instead.

Accomplishments

  • Every listing is trimmed to the platform's real limits in code - Etsy: at most 13 tags of 20 characters; Redbubble: at most 15 of 50 - verified in local mock-backed tests (offline) and in a live local end-to-end run (Oct 29: 97-character Etsy title, 6 tags, 15 Redbubble tags, TeePublic main tag, all within limits).
  • One OpenAI-compatible client integration covers both the vision and the writing model on Token Factory; switching models is a one-line change.
  • The demo's exposure to API costs is limited by design: before any paid call, an atomic guard reserves a worst-case cost estimated from the actual image dimensions and hard output caps, and after each call the reservation is settled to the measured token usage from the API response - so the lifetime budget tracks real spend. Combined with a lifetime generation cap and daily limits, this is intended to keep recorded demo spend within a small budget. These limits reduce exposure; they are not a guarantee.

What we learned

A few lines of enforcement code beat long prompts for hard constraints. And on reasoning models, max_tokens is a reasoning budget first and an output budget second - size it accordingly, and keep prompts short so the reasoning terminates.

What's next

Bulk CSV generation for whole catalogs, direct marketplace publishing, per-shop tone memory.

Verified public demo

On October 29 the deployed app completed a real browser upload-to-results generation using both Nebius Nemotron models. Live trend search is disabled and the result labels that clearly. The public GitHub repository is a recreated web import, not the original local commit history.

Built With

Share this project:

Updates

Submission history