Fantasy Faces - AI Portrait Product
Product
AI-generated fantasy character portraits from user-uploaded photos. Users upload photos, select DnD-themed character classes, and receive portraits that preserve their likeness. Full SaaS product with authentication, payments, ML training pipeline, and email delivery. Live at fantasyfaces.app. People's Choice winner, QLD AI Hub Launch AI 2023 cohort.
Origin
The market was validated on Fiverr before the product was built - personalised D&D portraits and professional LinkedIn headshots. D&D was an underserved category with clear demand. The motivation was to build a product company around a promising technology, not a deep connection to the domain. That distinction mattered later.
Architecture
Each paid order triggers a per-user model fine-tune - not inference against a shared model.
- User uploads subject photos to S3 via presigned URLs
- Stripe payment webhook creates a Character record
- User selects character configuration (name, gender, classes)
- Next.js API triggers an Airflow DAG on EC2
- Airflow fine-tunes a Dreambooth/Stable Diffusion model on the user's photos and generates images across classes and styles
- Airflow calls back to the web application with generated outputs
- Application discovers output images from S3 and creates records in PostgreSQL
- SendGrid delivers completion notification to the user
Technical Challenges
Per-User Model Training
Each order spins up a dedicated training job - not a shared model, not inference. Airflow on EC2 orchestrates the pipeline, managing compute allocation and job scheduling across concurrent users.
Likeness Tuning
The product promise is that portraits look like the person. Dreambooth parameters - learning rate, training steps, regularisation strength - determine likeness quality without overfitting or losing style transfer. Weights & Biases tracked experimental runs across parameter combinations and converged on settings that reliably produced recognisable outputs across character classes.
Async Pipeline Coordination
The user-facing experience is synchronous (upload, pay, configure). The backend is fully asynchronous. Airflow processes the training job, then calls back to the Next.js application with a shared secret. The callback discovers generated images from S3 (organised as {env}/{user_id}/{character_id}/output_images/{class}/{style}), bulk-creates database records, and triggers email notification. Failure at any step leaves the user without output or feedback.
S3 as Storage and Communication Layer
S3 serves as both file storage and inter-service communication. User photos are uploaded via presigned URLs. Airflow writes generated images to a structured folder hierarchy. The callback endpoint reads S3 to discover outputs, parses folder paths to extract class and style metadata, and writes structured records to the database.
Retrospective
The product worked technically. Commercially, it didn't gain traction. A few things became clear in hindsight.
- Distribution needed the same effort as the build. Months went into refining the technology. Making the product visible received a fraction of that attention.
- The project was two products. A Dreambooth fine-tuning and inference API, and a niche consumer application built on top of it. Either could have been pursued independently - using an existing API to focus on the consumer product, or exposing the API as a platform for others to build on. Doing both diluted focus on each.
- Market selection matters. The D&D market was picked because it was available and underserved, not out of genuine interest in the domain. That affected how much energy went into distribution, how quickly problems were addressed, and how long the project sustained attention.
Stack
Next.js, TypeScript, Prisma, PostgreSQL, Stripe, SendGrid, AWS S3, Apache Airflow, Stable Diffusion (Dreambooth), Weights & Biases.
Next
AI Voice Agent - Queensland Automotive Group
Production voice agent handling 50+ inbound service calls per day at under $500/month.
Relevant to a problem you're working on?
The first conversation is free.