AI Generation
Garmint uses fal.ai (primary) and Replicate for AI image generation, background removal, and upscaling.
Overview
Generation
Design graphics with nano-banana models
Background Removal
High-quality extraction with recraft-ai
Upscaling
Enhance resolution with Real-ESRGAN
Configuration
REPLICATE_API_KEY=r8_xxxxxxxxxxxxxxxxxxxxxxxxxx
Get your API key at replicate.com.
Available Models
Generation Models
| Model | Key | Speed | Use Case |
|---|
| Nano-Banana | nano-banana | ~5s | Fast iterations |
| Nano-Banana Pro | nano-banana-pro | ~15s | Final designs |
| Nano-Banana Pro 4K | nano-banana-pro-4k | ~25s | Print-ready output |
// lib/ai/mockup.ts
export const AI_MODELS = {
"nano-banana": {
name: "Fast",
description: "Quick iterations, good for exploration",
tokens: 12,
},
"nano-banana-pro": {
name: "Quality",
description: "Higher quality for final designs",
tokens: 45,
},
"nano-banana-pro-4k": {
name: "Print Ready",
description: "4K resolution for production",
tokens: 90,
},
};
Background Removal
const REMOVE_BG_MODEL = "recraft-ai/recraft-remove-background";
// Tokens: 3
Upscaling
const UPSCALE_MODEL = "nightmareai/real-esrgan";
// Tokens: 1
Image Generation
Basic Generation
import Replicate from "replicate";
const replicate = new Replicate({
auth: process.env.REPLICATE_API_KEY,
});
const output = await replicate.run("google/nano-banana", {
input: {
prompt: "vintage surf logo with palm trees",
aspect_ratio: "1:1",
num_outputs: 1,
},
});
// Returns array of image URLs
const imageUrl = output[0];
Two-Step Generation (Design + Mockup)
Garmint uses a two-step process for better control:
// lib/ai/mockup.ts
export async function generateUnified({
prompt,
referenceImages,
garmentUrls,
designUrls,
mockupCount,
modelKey,
}) {
// Step 1: Generate isolated design graphic
const designPrompt = buildDesignPrompt(prompt);
const graphicResult = await generateWithReplicate({
prompt: designPrompt,
referenceImages: designUrls,
});
const graphicUrl = graphicResult.images[0];
// Step 2: Composite onto garment (if garment provided)
if (garmentUrls?.length) {
const mockupPrompt = buildMockupPrompt(prompt);
const mockupResult = await generateWithReplicate({
prompt: mockupPrompt,
referenceImages: [graphicUrl, ...garmentUrls],
});
return {
graphicUrl,
mockups: mockupResult.images,
jobId: mockupResult.jobId,
provider: "replicate",
};
}
return {
graphicUrl,
mockups: [],
jobId: graphicResult.jobId,
provider: "replicate",
};
}
Background Removal
Extract designs for print production:
// lib/ai/replicate.ts
export async function removeBackground({ imageUrl }) {
const replicate = new Replicate({
auth: process.env.REPLICATE_API_KEY,
});
const output = await replicate.run(
"recraft-ai/recraft-remove-background",
{ input: { image: imageUrl } }
);
// Returns URL of transparent PNG
return {
imageUrl: String(output),
provider: "replicate",
};
}
Usage:
// Remove background from AI-generated design
const result = await removeBackground({
imageUrl: generatedDesign.url,
});
// result.imageUrl is transparent PNG
const printAsset = await uploadImage(result.imageUrl, "print-asset.png", {
preserveAlpha: true,
});
Upscaling
Enhance image resolution:
export async function upscaleImage({ imageUrl, scale = 2 }) {
const replicate = new Replicate({
auth: process.env.REPLICATE_API_KEY,
});
const output = await replicate.run(
"nightmareai/real-esrgan:f121d640bd...",
{
input: {
image: imageUrl,
scale: scale, // 2x or 4x
face_enhance: false,
},
}
);
return {
imageUrl: String(output),
provider: "replicate",
};
}
Reference Image Handling
The system supports multiple reference types:
// Build Replicate input with references
function buildReplicateInput(prompt, referenceImages) {
const input: Record<string, unknown> = {
prompt,
aspect_ratio: "1:1",
num_outputs: 1,
output_format: "png",
};
// Add image references if provided
if (referenceImages?.length) {
// nano-banana supports image prompt
input.image_prompt = referenceImages[0];
// Additional images as style reference
if (referenceImages.length > 1) {
input.style_reference = referenceImages[1];
}
}
return input;
}
fal.ai Fallback
If Replicate fails, fall back to fal.ai:
// lib/ai/mockup.ts
export async function generateMockup(params) {
try {
return await generateWithReplicate(params);
} catch (error) {
if (hasFal) {
console.warn("Replicate failed, trying fal.ai fallback");
return await generateWithFal(params);
}
throw error;
}
}
async function generateWithFal({ prompt, referenceImages }) {
const result = await fal.subscribe("fal-ai/flux-pro/v1.1", {
input: {
prompt,
image_size: "square",
num_images: 1,
},
});
return {
images: result.images.map(img => img.url),
jobId: result.request_id,
provider: "fal",
};
}
Error Handling
try {
const output = await replicate.run(modelSlug, { input });
return processOutput(output);
} catch (error) {
if (error.message?.includes("rate limit")) {
// Wait and retry
await sleep(2000);
return replicate.run(modelSlug, { input });
}
if (error.message?.includes("model not found")) {
console.error("Model unavailable:", modelSlug);
throw new Error("AI generation temporarily unavailable");
}
throw error;
}
Token Costs
Track generation costs with tokens:
const TOKEN_COSTS = {
ai_generation: {
"nano-banana": 12,
"nano-banana-pro": 45,
"nano-banana-pro-4k": 90,
},
background_removal: 3,
upscale: 1,
};
// Deduct tokens after successful generation
await recordUsage({
userId,
eventType: "ai_generation",
tokens: TOKEN_COSTS.ai_generation[modelKey],
model: modelKey,
});
Best Practices
Use nano-banana for fast iterations during design exploration, then switch to nano-banana-pro for final outputs.
Always remove backgrounds before creating print assets to ensure clean edges.
Replicate API keys are billed. Monitor usage at replicate.com/account.
Models may update. Pin to specific versions in production for consistency.
Debugging
Enable verbose logging:
// Log all API calls
console.log("[replicate] Model:", modelSlug);
console.log("[replicate] Input:", JSON.stringify(input, null, 2));
console.log("[replicate] Output:", JSON.stringify(output, null, 2));
Check model status:
# Using Replicate CLI
replicate models get google/nano-banana