Skip to content

Commit 115c811

Browse files
committed
Removed old prompt stuff, better types
1 parent 4e251be commit 115c811

3 files changed

Lines changed: 39 additions & 58 deletions

File tree

product-image-generator/app/actions.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
"use server";
22

33
import { auth, tasks } from "@trigger.dev/sdk";
4-
import type { generateAndUploadImage } from "../src/trigger/generate-image-and-upload";
4+
import type {
5+
generateAndUploadImage,
6+
StylePrompt,
7+
} from "../src/trigger/generate-image-and-upload";
58
import type { uploadImageToR2 } from "../src/trigger/upload-image-and-analyze";
69
import type { ProductAnalysis } from "./types/trigger";
710

@@ -13,7 +16,7 @@ export async function triggerUploadTask(payload: {
1316
try {
1417
const handle = await tasks.trigger<typeof uploadImageToR2>(
1518
"upload-image-and-analyze",
16-
payload,
19+
payload
1720
);
1821

1922
// Create a public access token for this specific run
@@ -37,15 +40,15 @@ export async function triggerUploadTask(payload: {
3740
}
3841

3942
export async function triggerGenerationTask(payload: {
40-
promptStyle: string;
43+
promptStyle: StylePrompt;
4144
baseImageUrl: string;
4245
productAnalysis: ProductAnalysis;
4346
customPrompt?: string;
4447
}) {
4548
try {
4649
const handle = await tasks.trigger<typeof generateAndUploadImage>(
4750
"generate-image-and-upload",
48-
payload,
51+
payload
4952
);
5053

5154
// Create a public access token for this specific run

product-image-generator/app/components/GeneratedCard.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,20 @@ import {
1414
import { useState, useEffect, useCallback } from "react";
1515
import { useRealtimeRun } from "@trigger.dev/react-hooks";
1616
import { triggerGenerationTask } from "../actions";
17-
import type { generateAndUploadImage } from "../../src/trigger/generate-image-and-upload";
17+
import type {
18+
generateAndUploadImage,
19+
StylePrompt,
20+
} from "../../src/trigger/generate-image-and-upload";
1821
import type { ProductAnalysis } from "../types/trigger";
1922

2023
interface GeneratedCardProps {
2124
baseImageUrl: string | null;
2225
productAnalysis: ProductAnalysis | null;
23-
promptId: string;
26+
promptId: StylePrompt;
2427
promptTitle: string;
2528
onGenerationComplete?: (
2629
runId: string,
27-
promptId: string,
30+
promptId: StylePrompt,
2831
promptTitle: string,
2932
imageUrl?: string
3033
) => void;

product-image-generator/src/trigger/generate-image-and-upload.ts

Lines changed: 26 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ type GeneratePayload = {
4545
customPrompt?: string; // User's custom prompt for "custom" style
4646
model?: "flux";
4747
size?: "1024x1792";
48-
strength?: number;
49-
guidance?: number;
50-
steps?: number;
51-
seed?: number;
5248
};
5349

5450
export const generateAndUploadImage = task({
@@ -62,10 +58,6 @@ export const generateAndUploadImage = task({
6258
customPrompt,
6359
model = aiModel,
6460
size = "1024x1792",
65-
strength = 0.2,
66-
guidance = 7, // From your settings
67-
steps = 20, // From your settings
68-
seed = Math.floor(Math.random() * 1000000), // Random seed for variety
6961
} = payload;
7062

7163
// Set initial metadata with 4 steps (no analysis needed)
@@ -81,7 +73,6 @@ export const generateAndUploadImage = task({
8173
baseImageUrl,
8274
productAnalysis,
8375
model,
84-
size,
8576
});
8677

8778
try {
@@ -93,24 +84,24 @@ export const generateAndUploadImage = task({
9384
});
9485

9586
// Build detailed product description from analysis with fallbacks
96-
const productDetails = [
97-
`Exact product: ${
98-
productAnalysis?.exact_product_name || "unknown product"
99-
}`,
100-
`Model number: ${productAnalysis?.model_number || "unknown model"}`,
101-
`Material: ${productAnalysis?.material || "unknown"}`,
102-
`Colors: ${productAnalysis?.colors?.join(", ") || "unknown"}`,
103-
`Shape: ${productAnalysis?.shape || "unknown"}`,
104-
`Proportions: ${productAnalysis?.size_proportions || "standard"}`,
105-
`Functional elements: ${
106-
productAnalysis?.functional_elements?.join(", ") || "standard"
107-
}`,
108-
`Surface finish: ${productAnalysis?.surface_finish || "standard"}`,
109-
`Text/branding: ${productAnalysis?.text_branding || "none"}`,
110-
`Unique features: ${
111-
productAnalysis?.unique_features?.join(", ") || "standard"
112-
}`,
113-
].join(". ");
87+
// const productDetails = [
88+
// `Exact product: ${
89+
// productAnalysis?.exact_product_name || "unknown product"
90+
// }`,
91+
// `Model number: ${productAnalysis?.model_number || "unknown model"}`,
92+
// `Material: ${productAnalysis?.material || "unknown"}`,
93+
// `Colors: ${productAnalysis?.colors?.join(", ") || "unknown"}`,
94+
// `Shape: ${productAnalysis?.shape || "unknown"}`,
95+
// `Proportions: ${productAnalysis?.size_proportions || "standard"}`,
96+
// `Functional elements: ${
97+
// productAnalysis?.functional_elements?.join(", ") || "standard"
98+
// }`,
99+
// `Surface finish: ${productAnalysis?.surface_finish || "standard"}`,
100+
// `Text/branding: ${productAnalysis?.text_branding || "none"}`,
101+
// `Unique features: ${
102+
// productAnalysis?.unique_features?.join(", ") || "standard"
103+
// }`,
104+
// ].join(". ");
114105

115106
// Style-specific prompts
116107
const baseStylePrompt =
@@ -119,7 +110,7 @@ export const generateAndUploadImage = task({
119110
stylePrompts["isolated-table"];
120111

121112
// Combine everything into one unambiguous prompt
122-
const enhancedPrompt = `${baseStylePrompt}. MANDATORY PRODUCT PRESERVATION: You MUST recreate the EXACT product from the reference image. Product specifications that are ABSOLUTELY REQUIRED: ${productDetails}. The product must be IDENTICAL to the reference image - same brand name, same exact model number, same exact colors and color combinations, same shape, same proportions, same text, same logos, same design elements, same materials, same finish. DO NOT change any colors, DO NOT substitute different models or color variants, DO NOT modify the product itself in any way. The product must be pixel-perfect identical. Only change the background, lighting, and camera angle. If you cannot preserve the exact product, do not generate the image.`;
113+
const enhancedPrompt = `${baseStylePrompt}. MANDATORY PRODUCT PRESERVATION: You MUST recreate the EXACT product from the reference image. The product must be IDENTICAL to the reference image - same brand name, same exact model number, same exact colors and color combinations, same shape, same proportions, same text, same logos, same design elements, same materials, same finish. DO NOT change any colors, DO NOT substitute different models or color variants, DO NOT modify the product itself in any way. The product must be pixel-perfect identical. Only change the background, lighting, and camera angle. If you cannot preserve the exact product, do not generate the image.`;
123114

124115
logger.log("Enhanced prompt created", {
125116
enhancedPrompt,
@@ -134,7 +125,7 @@ export const generateAndUploadImage = task({
134125
});
135126

136127
// Use Flux with structured prompt
137-
const output = await replicate.predictions.create({
128+
await replicate.predictions.create({
138129
model: "google/nano-banana",
139130
input: { prompt: enhancedPrompt, image_input: [baseImageUrl] },
140131
// pass the provided URL to Replicate's webhook, so they can "callback"
@@ -143,7 +134,6 @@ export const generateAndUploadImage = task({
143134
});
144135

145136
const prediction = await wait.forToken<Prediction>(token);
146-
147137
if (!prediction.ok) {
148138
throw new Error("Failed to create prediction");
149139
}
@@ -152,21 +142,6 @@ export const generateAndUploadImage = task({
152142

153143
const imageUrl = prediction.output.output;
154144

155-
// const { image } = await experimental_generateImage({
156-
// model: replicate.image(aiModel),
157-
// prompt: enhancedPrompt,
158-
// image: baseImageUrl, // Reference image for img2img
159-
// width: parseInt(size.split("x")[0]),
160-
// height: parseInt(size.split("x")[1]),
161-
// guidance_scale: guidance,
162-
// num_inference_steps: steps,
163-
// strength: strength,
164-
// seed: seed,
165-
// num_outputs: 1,
166-
// // Add negative prompt to prevent unwanted changes
167-
// negative_prompt:
168-
// "different product, wrong brand, different model, different colors, color variants, different shape, modified product, altered design, wrong text, different logo, fake product, generic product",
169-
// });
170145
logger.log("Image generated successfully");
171146

172147
// Step 4: Upload to storage
@@ -179,14 +154,14 @@ export const generateAndUploadImage = task({
179154
const image = await fetch(imageUrl);
180155
const imageBuffer = Buffer.from(await image.arrayBuffer());
181156

182-
const base64Image = Buffer.from(imageBuffer).toString("base64");
183-
184157
const timestamp = Date.now();
185-
const filename = `generated-${timestamp}.png`;
158+
const filename = `generated-${timestamp}.png`.replace(
159+
/[^a-zA-Z0-9.-]/g,
160+
"_"
161+
);
186162

187163
// Generate unique key for R2
188-
const sanitizedFileName = filename.replace(/[^a-zA-Z0-9.-]/g, "_");
189-
const r2Key = `uploaded-images/${timestamp}-${sanitizedFileName}`;
164+
const r2Key = `uploaded-images/${timestamp}-${filename}`;
190165

191166
const uploadParams = {
192167
Bucket: process.env.R2_BUCKET,
@@ -218,7 +193,7 @@ export const generateAndUploadImage = task({
218193
publicUrl,
219194
r2Key,
220195
fileSize: imageBuffer.length,
221-
fileName: sanitizedFileName,
196+
filename,
222197
};
223198

224199
// Complete

0 commit comments

Comments
 (0)