Skip to main content

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

ModelKeySpeedUse Case
Nano-Banananano-banana~5sFast iterations
Nano-Banana Pronano-banana-pro~15sFinal designs
Nano-Banana Pro 4Knano-banana-pro-4k~25sPrint-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