-
-
`OFFLINE=1 pytest -v` real output: 19 passed in 0.48s.
-
One real API call: POST /campaigns returns the whole batch — manifest_verified: true, ranked top-3, and winner reasons.
-
Close frame: 19 tests green · deterministic explainable ranking · verified provenance — with the OFFLINE/mock-images honesty note.
-
"One ad is a guess — a salvo is a decision": brief in → N scored variants out → best three ship (brand hook frame).
-
Live `/console` full view: brief + N in, verified manifest hash out, top-3 and full batch below (OFFLINE demo, mock placeholder images).
-
Live /console top-3 grid — each variant's score + full reason breakdown; engagement is a content-hash stand-in, not real click data.
💡 Inspiration
Generative tools make it trivial to produce one ad. The real work is producing many and knowing which to ship — and being able to explain why. Most "generate N variants" tools hand you a wall of images with no ranking, no provenance, and no reproducibility. We wanted a small, honest pipeline that turns a brief into a batch, scores every variant on transparent signals, and surfaces the best three — with the reasoning shown, not hidden.
⚙️ What it does
Give Salvo a creative brief and a count N. It fans out N ad-image variants through one real Genblaze Pipeline, stores each variant with a verified provenance manifest, scores them with an explainable, deterministic ranking, and surfaces the top 3 to ship — each score accompanied by a plain-English breakdown of exactly how it was reached.
Every variant is scored on three transparent signals:
| Signal | Weight | What it measures |
|---|---|---|
| Brief coverage | 0.45 | how many of the brief's keywords the headline uses |
| Headline length | 0.25 | closeness to a 22–42 char scannable sweet spot |
| Engagement index | 0.30 | a deterministic pseudo-signal seeded from the content hash |
Honesty note. The engagement index is not real click/CTR data — it's a deterministic stand-in seeded from the content hash so the ranking is reproducible offline, and every reason string says so.
🏗️ How we built it
- Engine — Genblaze: a real
Pipeline.astream(max_concurrency=N)batch fan-out, one step per variant, stored through anObjectStorageSinkover aLocalDirBackend(a real subclass of Genblaze's documentedStorageBackendinterface), with provenance read back viaread_manifest(verify=True). - Storage — Backblaze B2: OFFLINE uses the local backend; setting B2 credentials switches storage to a real Backblaze B2 bucket via Genblaze's
S3StorageBackend(auto-detected at startup). - App: a FastAPI backend with an operator console (
/console), a dependency-free raw-PNG encoder (no Pillow/ffmpeg), and an in-memory campaign store. Packaged withuv, containerized with Docker, deployed on Railway. - Ranking: deterministic and explainable — same brief + variant always yields the same score and the same reasons.
🧗 Challenges we ran into
- Explainability without a real model in the loop. We wanted honest, reproducible scores in an offline demo, so we designed the ranking around transparent, deterministic signals and made the "engagement" signal explicitly a content-hash stand-in — labeled as such everywhere — rather than fabricating fake CTR numbers.
- A real batch pipeline, not a loop of fakes. The variants flow through a genuine Genblaze
Pipelinefan-out and are provenance-verified, so the "batch factory" claim is backed by real SDK code paths, not a for-loop. - Zero-dependency images. To keep the OFFLINE path fast and portable (no Pillow, no ffmpeg), we wrote a tiny raw-PNG encoder for the mock variant images.
🏆 Accomplishments that we're proud of
- A working, honest batch-and-rank pipeline on real Genblaze code paths, deployed live, in a focused build.
- Explainable ranking: every score ships with its reasoning, and the one non-real signal is labeled as such — no fabricated metrics presented as real.
- 37 tests, OFFLINE-by-default (zero credentials), Dockerized and live on Railway.
📚 What we learned
- The valuable part of "generate N" isn't the generation — it's the selection, and selection is only trustworthy if it's explainable and reproducible.
- Genblaze's
Pipeline+StorageBackendabstractions make a real batch pipeline with verified provenance small to build.
🚀 What's next for Salvo
- Swap the mock image provider for real generation (GMI FLUX / DALL·E) behind the same pipeline — the seam already exists.
- Real Backblaze B2 storage + a promotion-on-storage-event delivery step (approved variant → webhook).
- Richer ranking signals (brand-safety, visual diversity) and a live A/B feedback loop to replace the seeded engagement stand-in.
Log in or sign up for Devpost to join the conversation.