How to Generate Product Images with GPT-Image2: A Complete Technical Guide

To generate product images with GPT-Image2, send a POST request to the /api/generate-image endpoint with a prompt and caseId; the system validates authentication, reserves credits via PostgreSQL, calls the Ciyuan upstream service, and returns a base64-encoded JPEG data URI.

The freestylefly/awesome-gpt-image-2 repository provides a production-ready React and Node.js stack for creating product images using the GPT-Image2 model. This implementation acts as a sophisticated orchestration layer that manages user sessions, credit balances, and communication with the external Ciyuan image-generation service while enforcing strict validation rules.

Architecture of the GPT-Image2 Generation Flow

Frontend Request Initialization

When a user initiates generation, the React frontend in src/main.jsx constructs a POST request to the internal /api/generate-image endpoint. The payload requires two parameters: prompt (the image description) and caseId (a numeric identifier for the generation context).

const response = await fetch('/api/generate-image', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ prompt, caseId })
});

API Handler and Validation Logic

The core logic resides in api/generate-image.js, which implements a six-stage pipeline:

  1. Method Validation – Accepts only GET and POST requests
  2. Configuration Check – Verifies CIYUAN_API_KEY and Supabase credentials; returns SERVER_NOT_CONFIGURED if missing
  3. Authentication – Uses getAuthContext from api/_lib/supabase.js to extract Supabase sessions; POST requires authenticated users while GET allows anonymous access
  4. Input Validation – Enforces non-empty prompts ≤ 6000 characters and finite numeric caseId values (returns INVALID_PROMPT on failure)
  5. Credit Reservation – Calls reserveGeneration for regular users or reserveCreditGeneration for super-admins, both invoking the PostgreSQL function reserve_generation_usage
  6. Upstream Generation – Executes generateImage(prompt) to contact https://ciyuan.today/v1/images/generations using the gpt-image-2 model

Response Handling and Cleanup

The handler returns a structured JSON object containing the generated image:

{
  "ok": true,
  "image": "data:image/jpeg;base64,....",
  "user": { "credits": 47, "tier": "pro" }
}

If generation succeeds, completeGenerationReservation finalizes the credit deduction. On any failure, releaseGenerationReservation immediately returns credits to prevent erroneous billing. Upstream errors such as UPSTREAM_BUSY or GENERATION_FAILED propagate as descriptive error messages.

Implementation Examples

Browser-Based Integration

Use this pattern in React or vanilla JavaScript to request images and render them directly:

async function generateProductImage(prompt, caseId) {
  const resp = await fetch('/api/generate-image', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ prompt, caseId })
  });

  const data = await resp.json();
  if (!data.ok) throw new Error(data.error);
  return data.image; // Data-URI ready for <img src=...>
}

// Usage example:
generateProductImage('A sleek smartwatch on a marble table', 42)
  .then(img => document.querySelector('#result').src = img)
  .catch(err => console.error(err));

Testing with cURL

For backend validation or CI/CD pipelines, use cURL to verify the endpoint:

curl -X POST https://your-site.com/api/generate-image \
  -H "Content-Type: application/json" \
  -d '{"prompt":"A futuristic electric scooter in a neon cityscape","caseId":7}' \
  | jq -r '.image' > result.txt

Server-Side Node.js Consumption

When calling from another Node.js service or serverless function:

import fetch from 'node-fetch';

async function requestImage(prompt) {
  const res = await fetch('http://localhost:3000/api/generate-image', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ prompt, caseId: 1 })
  });
  const json = await res.json();
  if (!json.ok) throw new Error(json.error);
  return json.image; // Base64 JPEG data URI
}

Validation Rules and Error Codes

The API enforces strict constraints to prevent abuse and ensure quality:

  • Prompt Length: Maximum 6000 characters; empty strings rejected with INVALID_PROMPT
  • Case ID: Must be a finite number (not Infinity, NaN, or non-numeric)
  • Credit Requirements: Returns HTTP 402 (CREDITS_REQUIRED) when users lack sufficient balance
  • Upstream Status: Returns UPSTREAM_BUSY when the Ciyuan service is at capacity

Key Source Files and Functions

File Purpose Critical Functions
api/generate-image.js Core API handler orchestrating the entire flow generateImage(), reserveGeneration(), completeGenerationReservation()
src/main.jsx React UI for prompt submission and image display Fetch call to /api/generate-image
api/_lib/supabase.js Authentication and session management getAuthContext(), getProfileById()
src/supabaseClient.js Supabase client initialization Client configuration
data/style-library.json Prompt templates and style taxonomy Style definitions and templates

Summary

  • Endpoint: POST to /api/generate-image with JSON body containing prompt (≤6000 chars) and caseId (finite number)
  • Authentication: Required for POST requests via Supabase session; handled by getAuthContext in api/_lib/supabase.js
  • Credit System: Uses PostgreSQL function reserve_generation_usage with automatic cleanup on failure via releaseGenerationReservation
  • Upstream Service: Communicates with Ciyuan API at https://ciyuan.today/v1/images/generations using model gpt-image-2
  • Response Format: Returns base64 JPEG as data URI in image field, ready for immediate DOM insertion
  • Error Handling: Distinguishes between validation errors (INVALID_PROMPT), payment issues (CREDITS_REQUIRED), and upstream failures (UPSTREAM_BUSY)

Frequently Asked Questions

What is the maximum prompt length for GPT-Image2?

The API enforces a hard limit of 6000 characters for the prompt field. Requests exceeding this length or containing empty strings return the INVALID_PROMPT error code immediately, before consuming any credits or contacting the upstream service.

How does the credit reservation system work?

When a user initiates generation, the system calls reserveGeneration (or reserveCreditGeneration for super-admins), which executes the PostgreSQL function reserve_generation_usage. This atomically deducts credits from the user's balance and creates a reservation record. If generation succeeds, completeGenerationReservation finalizes the transaction; if any error occurs, releaseGenerationReservation immediately restores the credits to prevent billing for failed attempts.

Can I use the API without authentication?

GET requests to /api/generate-image accept anonymous access according to the getAuthContext implementation, but POST requests require a signed-in Supabase user. The handler validates the session token and rejects unauthenticated POST attempts, ensuring that only registered users with valid credit balances can consume generation resources.

What image format does the API return?

The endpoint returns a base64-encoded JPEG formatted as a data URI (data:image/jpeg;base64,...). This format allows immediate rendering in HTML <img> tags without additional processing or temporary file storage. The raw base64 string is available in the b64_json field of the upstream Ciyuan response and passed through to the client in the image property.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →