← All projectsKylan Thomson

Generative AI · Content Operations

AI Stock Image Factory

A demand-driven generative pipeline that turns search-volume data into upload-ready stock imagery, earning royalties on a marketplace where discovery is the whole game.

Role
Sole engineer — pipeline, prompt system, and metadata engineering
Status
Shipped · earning royalties
Period
2024 – present
5,110
Downloads sold
$3,840
Royalties earned
72
House styles
4
Model calls per asset

Overview

What it does

Stock marketplaces pay per download, and downloads follow search. So the system starts from demand rather than taste: it reads search-volume exports, samples a keyword in proportion to how often buyers actually search it, and generates an image aimed squarely at that term.

The interesting problem is not making a picture. Image models made that cheap, which is exactly why it stopped being the differentiator — an asset nobody can find earns nothing. The real work is the metadata: a title and an ordered keyword list engineered against the marketplace's own ranking behaviour, where the leading terms carry disproportionate weight.

Every asset costs a few cents and four model calls to produce, so the economics only work if the sell-through rate justifies the batch. That constraint drove the architecture more than any aesthetic decision did.

Architecture

Six-stage pipeline

01Sample02Style03Prompt04Generate05Describe06Rank
  1. 01

    Sample

    Draw a target keyword at random, weighted by monthly search volume, after dropping terms below a minimum demand floor.

  2. 02

    Style

    Pick one of 72 named house styles so a batch varies visually without drifting away from a coherent identity.

  3. 03

    Prompt

    A small chat model writes the image prompt, constrained by fixed core instructions that the style is layered on top of.

  4. 04

    Generate

    The image model renders a wide-format asset and returns it inline, so there is no expiring URL to race against.

  5. 05

    Describe

    Two more model calls produce a title and a raw keyword list, each held to the marketplace's character and count limits.

  6. 06

    Rank

    Keywords are deduplicated, re-ranked by similarity to the target term, filtered, and appended to the batch-upload manifest.

Selection

Production follows demand

Keywords are not worked through in order. Each image draws a target term with probability proportional to its search volume, so output distributes itself across the demand curve instead of piling onto whichever term happens to sit at the top of the file.

SEARCH DEMANDSHARE OF DRAWSTop demand12,000 /mo41%High8,000 /mo28%Mid4,000 /mo14%Low3,000 /mo10%Long tail2,000 /mo7%Terms below a minimum monthly volume are dropped before sampling.

Approach

How it works

Demand-weighted sampling, not a queue

Keywords are drawn with probability proportional to their monthly search volume, so a term searched ten thousand times a month is picked far more often than one searched a few hundred. Anything under ▓▓▓ is dropped outright. Working a list top-down would over-produce for the head and never reach the tail; sampling covers the whole distribution while still spending most of the budget where the buyers are.

A style library instead of a prompt

72 named house styles are held separately from the core instructions, and one is drawn per image. The core stays fixed, so output varies in look without varying in quality or subject discipline. Keeping the two apart also made the system model-agnostic — the core instructions carry no vendor-specific phrasing, which is what let the image model be swapped later as a config edit.

Metadata is the product

On a stock marketplace the image is the good but the keywords are the storefront. The marketplace weights the earliest terms in a keyword list far more heavily than the rest, which turns ordering into a ranking problem rather than a labelling one. Most of the engineering budget went here, not into image quality.

Embedding re-ranking for slot position

Raw model output arrives in whatever order the model felt like. Each candidate term is embedded and scored by cosine similarity against the target keyword, then sorted, so the terms most related to actual search intent land in the weighted leading slots. This is the single highest-leverage step in the metadata path.

A blacklist that catches the model, not just the content

▓▓▓ banned entries cover the obvious marketplace-prohibited vocabulary — and also the failure mode where a model narrates instead of answering, emitting scaffolding like "Here are the keywords for your image" straight into a keyword field. Filtering the generator's own tells matters as much as filtering the subject matter.

Config-driven model stack

Every model is a configuration entry rather than a literal in code, and each stage picks its own tier: a cheap model writes prompts, a cheaper one writes metadata, and only image generation pays for quality. Re-tuning cost against quality is a config edit, and the migration to a newer image model touched no code at all.

Skip-and-continue batching

Batches are rate-limited and failure-isolated: an API error on one asset is logged and skipped rather than killing the run. For an unattended generator this is the difference between a partial batch and a wasted night, and a row is only written to the manifest once its image is confirmed on disk.

Discoverability

From raw terms to ranked keywords

What the model returns is a bag of words. What the marketplace rewards is an ordered list whose leading entries match search intent — so the last stage of the pipeline is a ranking problem wearing a labelling problem's clothes.

Model returns raw termsunordered, some noiseNormalize + dedupecasing, plurals, repeatsRe-rank by embedding similaritycosine vs the target keywordBlacklist filterbanned terms + model artifactsOrdered keyword listorder is the deliverableleading terms — weighted mostremainder

Rigor

Measuring it honestly

Unit economics as the primary metric

Cost per asset is known to the cent and quality tiers are selectable, so the question is never "is this a good image" in the abstract — it is whether expected downloads clear the generation cost. At the lower quality tier an asset breaks even on a small number of downloads, which sets how aggressively a batch can be run.

Sell-through, not output volume

Images generated is a vanity number; downloads per image is the one that matters. 5,110 downloads is the figure that validates the approach, because it measures buyers choosing these assets over everything else surfaced for the same search.

Marketplace acceptance as a hard gate

Every asset is validated against the upload schema before it ships — title length, keyword count, category codes, release fields. The marketplace rejects malformed submissions, so schema conformance is checked as part of generation rather than discovered at upload time.

Provenance kept end to end

Each row records the keyword that motivated it and the style that rendered it, which is what makes a feedback loop possible: sales reports can be joined back to styles and terms to learn what actually sells rather than what seems likely to.

Trade-offs

Why it's built this way

Generate for demand, not for taste

The keyword list drives the system. It is a less romantic way to make images and a much better way to sell them — the alternative is producing work nobody searches for and calling the marketplace broken.

Spend the engineering on discoverability

Given a fixed budget, effort went into keyword ranking rather than prompt artistry. Image quality has a floor the marketplace enforces and a ceiling buyers barely notice; discoverability has neither.

Local embeddings first, hosted embeddings for scale

Re-ranking began with a locally loaded transformer, which was free per call but added gigabytes to any container image and slowed cold starts badly. Moving to a hosted embedding endpoint costs a rounding error per asset and shrinks the deployable artifact by an order of magnitude — the right trade once this runs serverless rather than on a workstation.

Upload stays manual, deliberately

The pipeline produces an upload manifest rather than pushing to the marketplace directly. A fully autonomous loop between a generative model and a live storefront is a reputational risk with no upside; a human reviewing the batch costs minutes and prevents the category of mistake that gets contributor accounts closed.

Built with

Stack & data sources

Generation

  • Python
  • OpenAI image + chat models
  • Pillow
  • Config-driven model registry

Metadata

  • Transformer embeddings
  • Cosine re-ranking
  • pandas
  • Blacklist filtering

Operations

  • Retry with backoff
  • Rate-limited batch loop
  • Cloud Run (in progress)

Demand signal

  • Google Keyword Planner exports
  • Monthly search volume

Marketplace contract

  • Adobe Stock batch-upload schema
  • Category taxonomy
  • Title + keyword limits
← All projectsTalk about this work