Overview
Chitron AI is the generative engine behind PhotoFox, an e-commerce and creative photography platform. A seller or creator uploads a single raw snapshot — a flat-lay, a product on a desk, a selfie — and gets back a professional asset: a styled hero image, a lifestyle scene, a virtual try-on, an upscaled print-ready file, or a short video. There is no prompt engineering to learn; the system turns a plain request into a finished result.
Under the hood, that simplicity is a Nuxt 3 single-page studio talking to a Node/Express API that orchestrates six best-in-class generative models across Replicate and fal. The engineering thesis is the same one that runs through every product we build: let the models synthesise the pixels, and keep everything a customer is billed for in plain, deterministic code. This study covers both halves — the front-end studio and the back-end orchestration, training, and commerce layers that make it a reliable product rather than a demo.
Business Challenges
- A Studio Shoot for Every SKU Doesn't Scale – Sellers and creators need a high-end hero image, a styled lifestyle scene, and often a short video for every product — but a photographer, a set, and an editor cost more time and money than most catalogs can justify per listing.
- The Tooling Is Scattered Across a Dozen Apps – Generate an image in one tool, retouch in another, upscale in a third, cut a video in a fourth, remove a background somewhere else. Each hand-off loses context and adds friction between an idea and a finished asset.
- Raw Prompt Boxes Don't Serve Real Users – Most consumers and small merchants can't — and shouldn't have to — write a paragraph of model-tuned prompt engineering to get a usable photo. The product has to turn a single snapshot and a plain request into a professional result.
Technical Challenges
- One Product, Many Generative Models – Editing, product scenes, virtual try-on, portraits, upscaling, and video each map to a different best-in-class model across Replicate and fal. The app needs a single request shape and a single result contract — the front-end should never care which vendor ran the job.
- Models Refuse, Providers Wobble – A safety filter trips, a provider times out, a hosted model is briefly down. On a paid, user-facing job that cannot surface as a raw error — the system needs deterministic fallbacks so a hiccup on one model quietly succeeds on another.
- Long GPU Jobs Behind a Snappy UI – Training and generation run for seconds to minutes on GPU queues. The interface has to feel instant and never block, which means an async submit-poll-deliver lifecycle rather than a request that hangs waiting for pixels.
- Every Pixel Costs Money — Billing Can't Guess – Each generation burns GPU credits, and customers pay by subscription tier, lifetime plan, or credit pack. Entitlement, metering, watermarking, and refunds on failure all have to be exact and auditable — never left to a model's judgement.
Our Approach
The design philosophy was “models make pixels, code makes promises.” Image synthesis is the one place a generative model is genuinely irreplaceable — so the models write the pixels. Everything a customer depends on downstream of that — which model runs, what happens when it refuses, whether the account has credits, how much a job costs, what gets refunded on failure, which tier gets a watermark — is handled by ordinary, testable code. The creative step is flexible and vendor-swappable; the parts a customer pays for are boring, predictable, and auditable.
Discipline & Contributions
| Discipline | Contributions |
|---|---|
| Business Analysis | A credit model spanning subscription tiers, lifetime plans, and top-up packs; per-feature GPU cost mapping; and multi-tenant org/team billing with seat invitations. |
| Backend Engineering | A modular Express API, MongoDB data layer, Firebase-verified auth, Stripe webhook reconciliation, Sharp watermarking, tiered rate limiting, and Slack error alerting. |
| AI Engineering | Multi-provider model orchestration with automatic fallback, FLUX LoRA training pipelines, GPT-4o-mini prompt enhancement and image-to-prompt vision, and async job polling. |
The Front-End: A Studio, Not a Prompt Box
PhotoFox ships as a client-rendered Nuxt 3 SPA — fast to navigate, installable as a PWA, and structured around tasks rather than a single blank text field. Each surface — magic mode, product and fashion photography, the human builder, upscaling, and video — is its own focused studio, but they all share the same underlying job machinery.
- Task-shaped surfaces. Instead of asking users to describe everything, each page collects just what its job needs — an upload, a style, a dimension, a garment — and a Pinia store holds the signed-in user, their credits, and in-flight jobs across every page.
- An interface that never blocks. Generations kick off behind skeleton loaders and toast feedback, so a minute-long GPU job feels responsive; results drop into a gallery the moment they are ready.
- Compare and export built in. A before/after slider lets users judge a result against the original in-browser, and JSZip powers one-click bulk download of an entire batch.
- Firebase-secured, growth-instrumented. Auth is handled by Firebase; PostHog, GTM, the Meta pixel, and a first-party analytics proxy give the team clean product and acquisition signal without leaking it to third parties on the critical path.
The Back-End: One Contract Over Six Models
The centrepiece of the API is a model-orchestration layer. Every generation — an edit, a product scene, a try-on, a portrait — enters with the same request shape and leaves with the same result contract, no matter which vendor actually ran it. Adding or swapping a model is a change inside the orchestrator, not a change the front-end ever sees.
- Intent enhancement first.A user’s plain request and any reference images are passed through
GPT-4o-minivision, which returns a terse, safety-tuned prompt — low temperature for consistency, and automatically retried across models if one refuses. - A model router, not a hard-coded call. The chosen job is dispatched to the right generator —
nano-banana-2for fast edits,seedream-4.5for product scenes,flux-kontext-profor high-fidelity work — behind one function signature. - Deterministic fallback. When a model refuses or a provider wobbles, the orchestrator retries on FLUX Kontext and alerts the team via Slack — a single-provider hiccup quietly succeeds instead of surfacing to a paying user as an error.
- A uniform result handler.Whatever ran, the output is stored to Firebase Cloud Storage, watermarked by the account’s tier with Sharp, and reconciled against the credit ledger in one place.
Training a Private Model of Your Subject
Editing a photo is one thing; generating new photos of a specific product or person, consistently, is another. For that, Chitron trains a private FLUX LoRA per subject from a handful of uploads — so the same shoe, bottle, or face renders faithfully across any prompt the user later types.
- A few photos in, a private model out. Ten to twenty images are zipped, pushed to storage, and used to create a privatetraining destination on Replicate — one account’s subject is never visible to another.
- Fast or standard training. The pipeline offers a quick trainer for speed and a full LoRA trainer for quality, with auto-captioning and a pinned trigger word so inference stays on-subject.
- Polled to completion, reconciled on failure. Training status is polled; on success the trained version id is bound to the subject in MongoDB, and on failure or cancellation the spent credits are refunded rather than silently lost.
- Consistent generation thereafter. Once trained, the subject can be generated on demand in any style, aspect ratio, or batch size, with its identity preserved across every image.
Making a Minute-Long GPU Job Feel Instant
Generation and training run on GPU queues for seconds to minutes. Rather than hold a request open and hope, every heavy job runs through an async submit-poll-deliver lifecycle — the tab stays interactive, and credits are only committed when pixels actually arrive.
- Submit and hold.The API verifies the caller’s Firebase token, checks and holds the required credits, enqueues the job on Replicate or fal, and hands back a request id — all behind a strict rate limit on the expensive endpoints.
- Poll, don’t hang. The SPA polls by request id and keeps a skeleton loader on screen, so nothing blocks while the GPU works.
- Commit or refund. On success the result is stored, watermarked, and the held credits are committed; on error the hold is released and the user is told plainly — a failed job never costs anything.
- Deliver and export. Finished assets land in the gallery for in-browser compare and single or JSZip batch download.
The Commerce Layer the Model Never Touches
Because every generation burns real GPU money, entitlement and metering can’t be approximate. PhotoFox’s billing is deterministic code end to end: Stripe drives subscription tiers, lifetime plans, and credit packs, and webhooks reconcile every payment event— checkout, recurring renewal, and failure — back into an account’s tier and credit balance in MongoDB. Watermarks are applied by tier with Sharp, teams are supported through orgs and seat invitations, and transactional email runs through Brevo and Resend. The generative models decide what an image looks like; they never decide what a customer is allowed to do or owe.
The Whole System, End to End
The orchestration, training, and billing paths sit inside a complete product — a Nuxt 3 studio, a Firebase-secured Express API with modular routers, a MongoDB data layer, and a fleet of generative models behind a single contract.
- Modular API surface. Person, model, image-editor, fit (try-on), upscale, video, gallery, upload, org, invitations, automation, prompt, and payment each live as their own Express router behind shared authenticate / authorize middleware.
- Resilient by default. A CORS allowlist, tiered rate limits, Slack error reporting, and a first-party analytics proxy keep the platform stable and observable under production load.
- Multi-tenant ready. Organizations, seat invitations, and per-account credit ledgers mean the same engine serves a solo creator and a team from one codebase.
Technology Stack
- Frontend & UI: Nuxt 3 (client-rendered SPA), Vue 3, Pinia, Tailwind CSS, vue3-compare-image, vue3-toastify, JSZip, PWA (@vite-pwa/nuxt)
- Backend API: Node.js, Express, modular routers behind authenticate / authorize middleware, express-rate-limit, CORS allowlist, express-http-proxy
- Generative AI: Replicate (nano-banana-2, seedream-4.5, flux-kontext-pro, FLUX LoRA trainer, seedance video), fal (clarity-upscaler, FASHN try-on), OpenAI GPT-4o-mini vision
- Data & Storage: MongoDB, Firebase Cloud Storage for uploads and outputs, Sharp for tier-based watermarking, Multer + Archiver for batch handling
- Platform & Growth: Firebase Authentication, Stripe (subscriptions, lifetime, credits) with webhooks, Brevo / Resend email, PostHog, GTM, Meta Conversions API, Docker + Cloud Build
Results & Outcomes
Takeaways
- Abstract the vendor behind a contract.One request shape and one result contract over six models means best-in-class quality per task and painless model swaps — the product isn’t coupled to any single provider.
- Fallbacks are a feature. Models refuse and providers wobble; a deterministic retry path turns those failures into quiet successes instead of customer-facing errors.
- Async is the only honest UX for GPU work. Submit-poll-deliver with held credits keeps the UI instant and guarantees a failed job never costs a user anything.
- Keep billing out of the model. Entitlement, metering, watermarking, and refunds are plain, auditable code — the generative layer stays purely creative, exactly where it belongs.
