|
1 | | -# AI Product Image Generator |
| 1 | +# Product Image Generator using Trigger.dev and Replicate |
2 | 2 |
|
3 | | -Transform product photos into professional marketing materials using AI-powered image generation. |
| 3 | +AI-powered product image generator that transforms basic product photos into professional marketing shots using Replicate's image generation models and Trigger.dev for task orchestration. |
4 | 4 |
|
5 | | -Upload a product image and automatically generate three marketing variations: isolated table shots, lifestyle scenes, and hero presentations. Built with Next.js, Trigger.dev, and OpenAI's DALL-E 3. |
6 | | -Upload a product image and automatically generate three marketing variations: isolated table shots, lifestyle scenes, and hero presentations. Built with Next.js, Trigger.dev, and the AI SDK (Replicate Flux for image generation, OpenAI for analysis). |
| 5 | +## Tech stack |
7 | 6 |
|
8 | | -## Features |
| 7 | +- [**Next.js**](https://nextjs.org/) – frontend React framework |
| 8 | +- [**Replicate**](https://replicate.com/docs) – AI image generation |
| 9 | +- [**Trigger.dev**](https://trigger.dev/docs) – background task orchestration |
| 10 | +- [**UploadThing**](https://uploadthing.com/) – file upload handling |
| 11 | +- [**Cloudflare R2**](https://developers.cloudflare.com/r2/) – image storage |
9 | 12 |
|
10 | | -- Real-time progress tracking with WebSocket subscriptions |
11 | | -- Product-focused AI prompts that maintain identical product appearance |
12 | | -- Responsive design with portrait-oriented image cards |
13 | | -- Automatic upload to Cloudflare R2 with public URLs |
14 | | -- Individual retry mechanisms for failed generations |
15 | | -- One-click download functionality |
16 | | -- Parallel processing for multiple image generations |
| 13 | +## Setup & Running locally |
17 | 14 |
|
18 | | -## Architecture |
| 15 | +1. **Clone the repository** |
19 | 16 |
|
20 | | -### Task Structure |
| 17 | + ```bash |
| 18 | + git clone <repository-url> |
| 19 | + cd product-image-generator |
| 20 | + ``` |
21 | 21 |
|
22 | | -``` |
23 | | -uploadImageToR2 |
24 | | -├── Handles user image uploads to Cloudflare R2 storage |
25 | | -├── Analyzes the product with OpenAI (structured JSON) |
26 | | -├── 5-step progress tracking via metadata |
| 22 | +2. **Install dependencies** |
27 | 23 |
|
28 | | -generateAndUploadImage |
29 | | -├── Generates an image using Replicate Flux (img2img) |
30 | | -├── Uploads result to R2 storage |
31 | | -├── 4-step progress tracking via metadata |
32 | | -``` |
| 24 | + ```bash |
| 25 | + pnpm install |
| 26 | + ``` |
33 | 27 |
|
34 | | -### Component Architecture |
| 28 | +3. **Copy environment variables and configure** |
35 | 29 |
|
36 | | -``` |
37 | | -UploadCard (aspect-[3/4]) |
38 | | -├── Drag & drop image upload |
39 | | -├── Progress tracking via run subscription |
40 | | -├── On completion, parent triggers 3 individual generations |
| 30 | + ```bash |
| 31 | + cp env.example .env |
| 32 | + ``` |
41 | 33 |
|
42 | | -GeneratedCard (aspect-[3/4]) |
43 | | -├── Individual task progress tracking |
44 | | -├── Real-time image display via subscription |
45 | | -├── Download and retry functionality |
| 34 | + Fill in the required variables: |
46 | 35 |
|
47 | | -CustomPromptCard (aspect-[3/4]) |
48 | | -├── Lets user enter a freeform scene prompt |
49 | | -├── Triggers a single generation reusing the product analysis |
| 36 | + - `TRIGGER_SECRET_KEY` – Get from [Trigger.dev dashboard](https://trigger.dev/) |
| 37 | + - `REPLICATE_API_TOKEN` – Get from [Replicate](https://replicate.com/account/api-tokens) |
| 38 | + - `UPLOADTHING_TOKEN` – Get from [UploadThing](https://uploadthing.com/) |
| 39 | + - `R2_ACCOUNT_ID`, `R2_BUCKET`, `R2_ENDPOINT`, `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `R2_PUBLIC_URL` – Configure Cloudflare R2 storage |
| 40 | + - `OPENAI_API_KEY` – Get from [OpenAI](https://platform.openai.com/api-keys) (optional, for future features) |
50 | 41 |
|
51 | | -Main Page |
52 | | -├── Grid layout: 1 upload + 3 generated cards (top) + 4 custom slots (bottom) |
53 | | -├── State for run IDs/access tokens for each card |
54 | | -├── Triggers generations and handles retries |
55 | | -``` |
| 42 | +4. **Add Trigger.dev project reference** |
56 | 43 |
|
57 | | -## Getting Started |
| 44 | + Update `trigger.config.ts` with your project ref: |
58 | 45 |
|
59 | | -### Prerequisites |
| 46 | + ```typescript |
| 47 | + project: "your_project_ref_here"; |
| 48 | + ``` |
60 | 49 |
|
61 | | -- Node.js 18+ and pnpm |
62 | | -- Trigger.dev account and project |
63 | | -- OpenAI API key (for product analysis) |
64 | | -- Replicate API token (for Flux image generation) |
65 | | -- Cloudflare R2 bucket for image storage |
| 50 | +5. **Start development servers** |
66 | 51 |
|
67 | | -### Environment Variables |
| 52 | + ```bash |
| 53 | + # Terminal 1: Start Next.js dev server |
| 54 | + pnpm dev |
68 | 55 |
|
69 | | -```env |
70 | | -# Trigger.dev |
71 | | -TRIGGER_SECRET_KEY=tr_dev_your_secret_key_here |
| 56 | + # Terminal 2: Start Trigger.dev CLI |
| 57 | + npx trigger.dev@latest dev |
| 58 | + ``` |
72 | 59 |
|
73 | | -# OpenAI |
74 | | -OPENAI_API_KEY=sk-your_openai_api_key_here |
| 60 | +## How it works |
75 | 61 |
|
76 | | -# Replicate |
77 | | -REPLICATE_API_TOKEN=your_replicate_api_token |
| 62 | +Trigger.dev orchestrates the image generation workflow through two main tasks: |
78 | 63 |
|
79 | | -# Cloudflare R2 Storage |
80 | | -R2_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com |
81 | | -R2_ACCESS_KEY_ID=your_r2_access_key |
82 | | -R2_SECRET_ACCESS_KEY=your_r2_secret_key |
83 | | -R2_BUCKET=your-bucket-name |
84 | | -R2_PUBLIC_URL=https://your-public-domain.com |
85 | | -``` |
| 64 | +1. **`generateImages`** – Batch coordinator that triggers multiple individual image generations ([`app/trigger/generate-images.ts`](app/trigger/generate-images.ts)) |
| 65 | +2. **`generateImage`** – Individual image processor that: |
| 66 | + - Enhances prompts with style-specific instructions |
| 67 | + - Calls Replicate's `google/nano-banana` model |
| 68 | + - Creates waitpoint tokens for async webhook handling |
| 69 | + - Waits for Replicate completion via webhook callbacks |
| 70 | + - Uploads generated images to Cloudflare R2 |
| 71 | + - Returns public URLs for display |
86 | 72 |
|
87 | | -### Installation |
| 73 | +**Process flow:** |
88 | 74 |
|
89 | | -```bash |
90 | | -# Install dependencies |
91 | | -pnpm install |
| 75 | +1. User selects and uploads product image to the website |
| 76 | +2. Image is uploaded to UploadThing cloud storage |
| 77 | +3. UploadThing's `onUploadComplete` callback triggers batch generation for 3 preset styles |
| 78 | +4. Each style runs as separate Trigger.dev task with waitpoints for Replicate webhooks |
| 79 | +5. Frontend receives real-time progress updates via Trigger.dev React hooks |
| 80 | +6. Generated images are stored in Cloudflare R2 and displayed with download options |
92 | 81 |
|
93 | | -# Start development server |
94 | | -pnpm dev |
| 82 | +**Style presets:** |
95 | 83 |
|
96 | | -# Start Trigger.dev dev server (separate terminal) |
97 | | -pnpm dlx trigger.dev@latest dev |
98 | | -``` |
| 84 | +- **Clean Product Shot** – Professional white background with studio lighting |
| 85 | +- **Lifestyle Scene** – Person holding product with natural lighting |
| 86 | +- **Hero Shot** – Elegant hands presenting product with dramatic lighting |
99 | 87 |
|
100 | | -### Quickstart (happy path) |
| 88 | +## Relevant code |
101 | 89 |
|
102 | | -```bash |
103 | | -cp .env.example .env # if provided, otherwise create .env with the vars above |
104 | | -pnpm install |
105 | | -pnpm dev & |
106 | | -pnpm dlx trigger.dev@latest dev |
107 | | -``` |
| 90 | +- **Image generation tasks** – Batch processing with waitpoints for Replicate webhook callbacks ([`app/trigger/generate-images.ts`](app/trigger/generate-images.ts)) |
| 91 | +- **Upload handler** – UploadThing integration that triggers batch generation for 3 preset styles ([`app/api/uploadthing/core.ts`](app/api/uploadthing/core.ts)) |
| 92 | +- **Real-time progress UI** – Live task updates using Trigger.dev React hooks ([`app/components/GeneratedCard.tsx`](app/components/GeneratedCard.tsx)) |
| 93 | +- **Custom prompt interface** – User-defined style generation with custom prompts ([`app/components/CustomPromptCard.tsx`](app/components/CustomPromptCard.tsx)) |
| 94 | +- **Main app component** – Layout and state management with professional style presets ([`app/ProductImageGenerator.tsx`](app/ProductImageGenerator.tsx)) |
| 95 | +- **Trigger.dev configuration** – Project settings and task directories ([`trigger.config.ts`](trigger.config.ts)) |
108 | 96 |
|
109 | | -## Usage |
| 97 | +## Learn more |
110 | 98 |
|
111 | | -1. Upload a product image via drag & drop or file selection |
112 | | -2. The upload task runs with 5-step progress and returns a public URL + analysis |
113 | | -3. The page triggers three `generateAndUploadImage` tasks (table, lifestyle, hero) |
114 | | -4. Each `GeneratedCard` subscribes to its run and shows progress |
115 | | -5. When a run completes, the image auto-appears, with expand/download actions |
116 | | -6. You can retry any failed generation individually |
117 | | -7. After the top row completes, use custom cards to generate extra scenes |
118 | | - |
119 | | -## Technical Implementation |
120 | | - |
121 | | -### AI Prompt Engineering |
122 | | - |
123 | | -Each generation builds an enhanced prompt from the structured product analysis. It enforces: |
124 | | - |
125 | | -- Product consistency: EXACT same product as the reference (brand, model, colors, text) |
126 | | -- Preservation: shape/proportions/materials/logos must be unchanged |
127 | | -- Variation: only background, lighting, and camera angle may change |
128 | | - |
129 | | -### Progress Tracking Implementation |
130 | | - |
131 | | -- Upload Task: 5 steps (prepare → process → upload → analyze → complete) |
132 | | -- Generation Task: 4 steps (prepare → prompt → generate → upload/complete) |
133 | | -- Real-time updates via `useRealtimeRun()` or `runs.subscribeToRun()` using public access tokens |
134 | | - |
135 | | -### Image Processing |
136 | | - |
137 | | -- Size: Defaults to 1024x1024 (configurable) |
138 | | -- Display: `object-cover` in generated cards |
139 | | -- Storage: Cloudflare R2 with automatic public URL generation |
140 | | - |
141 | | -## Project Structure |
142 | | - |
143 | | -``` |
144 | | -src/ |
145 | | -├── trigger/ |
146 | | -│ ├── image-upload.ts # Upload to R2 + structured product analysis (OpenAI) |
147 | | -│ └── generate-image-and-upload.ts # Flux generation (Replicate) + R2 upload |
148 | | -├── app/ |
149 | | -│ ├── actions.ts # Server actions: trigger tasks + public tokens |
150 | | -│ ├── components/ |
151 | | -│ │ ├── UploadCard.tsx # Upload with realtime progress |
152 | | -│ │ ├── GeneratedCard.tsx # Generated image display + progress |
153 | | -│ │ └── CustomPromptCard.tsx # Freeform prompt generation (post-upload) |
154 | | -│ └── page.tsx # Main application interface |
155 | | -└── trigger.config.ts # Trigger.dev configuration |
156 | | -``` |
157 | | - |
158 | | -## Task Flow Details |
159 | | - |
160 | | -### Upload Flow |
161 | | - |
162 | | -1. `UploadCard` calls `uploadImageToR2Action` (server action) |
163 | | -2. Server action triggers `uploadImageToR2` task and creates a public token |
164 | | -3. Client subscribes to the run using the token; task uploads to R2 |
165 | | -4. Task performs structured product analysis (OpenAI GPT-4o) |
166 | | -5. On completion, the page receives `publicUrl` and `productAnalysis` |
167 | | - |
168 | | -### Generation Flow |
169 | | - |
170 | | -1. The page calls `generateSingleImageAction` three times (table/lifestyle/hero) |
171 | | -2. Each task builds an enhanced prompt from `productAnalysis` |
172 | | -3. Flux (Replicate) generates an img2img output referencing the base image URL |
173 | | -4. The task uploads the result to R2 and sets `metadata.result.publicUrl` |
174 | | -5. `GeneratedCard` subscribes and renders the image on completion |
175 | | - |
176 | | -### Error Handling |
177 | | - |
178 | | -- Individual task failures don't affect other generations |
179 | | -- Retry triggers only that specific style |
180 | | -- Errors are surfaced via run metadata and UI messages |
181 | | - |
182 | | -## Customization |
183 | | - |
184 | | -### Adding Generation Styles |
185 | | - |
186 | | -Add a new style key in `generate-image-and-upload.ts` inside `stylePrompts` and wire a corresponding button/card in `app/page.tsx`. |
187 | | - |
188 | | -### Modifying Image Dimensions |
189 | | - |
190 | | -Pass a different `size` when triggering `generateAndUploadImage` via the server action (e.g., `"1792x1024"` or `"1024x1792"`). |
191 | | - |
192 | | -### Custom Progress Messages |
193 | | - |
194 | | -Update `metadata.set("progress", ...)` in the respective task to change UX copy. |
195 | | - |
196 | | -## Deployment |
197 | | - |
198 | | -### Production Deployment |
199 | | - |
200 | | -```bash |
201 | | -# Deploy tasks to Trigger.dev |
202 | | -pnpm dlx trigger.dev@latest deploy |
203 | | - |
204 | | -# Deploy frontend (e.g., Vercel) |
205 | | -vercel deploy |
206 | | -``` |
207 | | - |
208 | | -### Environment Configuration |
209 | | - |
210 | | -- Add all environment variables to deployment platform |
211 | | -- Configure R2 bucket CORS for production domain |
212 | | -- Update `R2_PUBLIC_URL` for production storage access |
213 | | -- Ensure OpenAI API key has sufficient credits and rate limits |
214 | | - |
215 | | -## Development Notes |
216 | | - |
217 | | -### Key Implementation Details |
218 | | - |
219 | | -- Uses public access tokens to enable client-side run subscriptions |
220 | | -- `aspect-[3/4]` Tailwind class for portrait card layout |
221 | | -- Metadata carries progress + final result for robust UI updates |
222 | | - |
223 | | -### Performance Considerations |
224 | | - |
225 | | -- Parallel task execution for multiple image generations |
226 | | -- Cloud storage with aggressive cache headers for assets |
227 | | -- Consider API quotas for Replicate/OpenAI |
228 | | - |
229 | | -## License |
230 | | - |
231 | | -MIT License - see LICENSE file for details. |
| 99 | +- [**Trigger.dev waitpoints**](https://trigger.dev/docs/wait-for-token) – pause tasks for async webhook callbacks |
| 100 | +- [**Trigger.dev React hooks**](https://trigger.dev/docs/frontend/react-hooks) – real-time task updates and frontend integration |
| 101 | +- [**Trigger.dev batch operations**](https://trigger.dev/docs/tasks/batch-trigger) – parallel task execution patterns |
| 102 | +- [**Replicate API**](https://replicate.com/docs/get-started/nextjs) – AI model integration and webhook handling |
| 103 | +- [**UploadThing**](https://docs.uploadthing.com/) – file upload handling and server callbacks |
0 commit comments