How to Batch Generate Images Using Structured Prompt Protocols with Awesome GPT Image 2

Batch generate images using structured prompt protocols by leveraging the apimartClient.js client to submit parallel generation tasks, poll for completion, and retrieve results from the APIMart service.

The awesome-gpt-image-2 repository provides a production-ready JavaScript client for orchestrating large-scale image generation workflows. By utilizing structured prompt protocols—detailed, reusable prompt templates stored in src/image25/realCases.js—you can batch generate images with consistent layout, composition, and visual language across hundreds of tasks. The architecture separates prompt definition from execution logic, enabling you to queue multiple generations simultaneously while monitoring their progress through a unified polling mechanism.

Core Workflow for Batch Image Generation

The batch generation process follows a four-phase pipeline implemented across the client's utility modules. Each phase handles a specific concern: payload construction, request submission, status monitoring, and result normalization.

Building the Payload

Before submitting any request, prompts must be sanitized and wrapped with metadata. The buildApimartGenerationPayload() function in shared/apimart.js (line 7) handles this transformation, adding the specified language code, optional webhook URL, and cleaning the prompt string for transmission.

import { buildApimartGenerationPayload } from './shared/apimart.js';

const payload = buildApimartGenerationPayload(
  "Create a premium beverage campaign poster...",
  'en',
  'https://your-webhook.com/notify'
);

Submitting Generation Requests

The submitPersonalGeneration() method in src/apimartClient.js (line 103) initiates the generation by sending a POST request to /v1/images/generations. It returns a taskId that serves as the unique identifier for tracking the job.

import { submitPersonalGeneration } from './src/apimartClient.js';

const { taskId } = await submitPersonalGeneration(prompt, apiKey, language);

Polling Task Status

Once submitted, tasks require polling until they reach a terminal state. The fetchPersonalTask() function (line 125 in src/apimartClient.js) retrieves the current status, while isTerminalApimartStatus (from shared/apimart.js) determines if the task has completed successfully or failed.

import { fetchPersonalTask } from './src/apimartClient.js';

const task = await fetchPersonalTask(taskId, apiKey, language);
if (task.status === 'succeeded') {
  return task.output; // Contains image URL(s)
}

Retrieving Final Results

Completed tasks are normalized using normalizeApimartTask() (found in api/_lib/apimart.js, line 52). This function standardizes the response format, extracting image URLs and error information into a consistent structure regardless of the raw API response format.

Structured Prompt Architecture

The repository distinguishes between free-form prompts and structured prompt protocols—detailed specifications that encode layout directives, subject consistency rules, and branding constraints. These protocols are stored in src/image25/realCases.js and designed for batch reuse.

Composition and Layout Directives

Unlike simple text descriptions, structured prompts define technical parameters such as grid size, panel count, and character consistency requirements. An example entry specifies:

{
  "prompt": "Create a Cannes-level premium summer beverage campaign poster...",
  "en": "Six-panel structure, character consistency, LIMORA text and prompt adherence"
}

These self-contained recipes ensure that when you batch generate images, each output adheres to the same visual grammar, making them suitable for multi-panel advertisements or themed galleries.

Importing the Prompt Library

To use the built-in structured prompts, import the realCases array and pass subsets to your batch processor:

import { realCases } from './src/image25/realCases.js';

// Filter for specific campaign types
const beveragePrompts = realCases.filter(p => p.en.includes('beverage'));
await batchGenerate(beveragePrompts);

Implementing the Batch Generation Pattern

Combine the core workflow functions with Promise-based concurrency to process multiple structured prompts efficiently. The following pattern demonstrates how to manage parallel submissions while respecting API constraints.

import { submitPersonalGeneration, fetchPersonalTask } from '../src/apimartClient.js';
import { realCases } from '../src/image25/realCases.js';

const API_KEY = 'YOUR_APIMART_KEY';
const LANGUAGE = 'en';
const MAX_CONCURRENT = 5; // Adjust based on rate limits

async function batchGenerate(prompts) {
  // Phase 1: Submit all generation requests in parallel
  const pendingTasks = prompts.map(p => 
    submitPersonalGeneration(p.prompt, API_KEY, LANGUAGE)
  );
  const submittedTasks = await Promise.all(pendingTasks);
  
  // Phase 2: Poll each task until completion
  const results = await Promise.all(
    submittedTasks.map(async ({ taskId }) => {
      // Validate task ID before polling
      while (true) {
        const task = await fetchPersonalTask(taskId, API_KEY, LANGUAGE);
        
        if (task.status === 'succeeded') {
          return task.output; // Array of image URLs
        }
        if (task.status === 'failed') {
          throw new Error(`Task ${taskId} failed: ${task.error}`);
        }
        
        // Wait 2 seconds before next poll
        await new Promise(resolve => setTimeout(resolve, 2000));
      }
    })
  );
  
  return results;
}

// Execute batch on structured prompt library
batchGenerate(realCases)
  .then(images => console.log('Generated images:', images))
  .catch(err => console.error('Batch failed:', err));

This implementation uses Promise.all to launch parallel requests, significantly reducing total processing time compared to sequential generation.

Handling Rate Limits and Validation

Production batch workflows must gracefully handle API rate limiting and input validation. The client provides specific utilities for these concerns.

Rate Limit Back-off

When the API returns a 429 status or similar error, the responseError helper (line 81 in apimartClient.js) attaches a retryAfterMs field indicating the required wait time. Implement exponential back-off using this value:

try {
  await submitPersonalGeneration(prompt, apiKey, language);
} catch (error) {
  if (error.retryAfterMs) {
    await new Promise(resolve => setTimeout(resolve, error.retryAfterMs));
    // Retry logic here
  }
}

Task ID Validation

Before entering polling loops, validate task IDs using isValidApimartTaskId() from shared/apimart.js (line 8). This prevents unnecessary API calls with malformed identifiers:

import { isValidApimartTaskId } from './shared/apimart.js';

if (!isValidApimartTaskId(taskId)) {
  throw new Error(`Invalid task ID format: ${taskId}`);
}

Summary

  • Batch generate images by mapping structured prompts to submitPersonalGeneration() calls and awaiting the results with Promise.all.
  • Use buildApimartGenerationPayload() in shared/apimart.js to ensure consistent request formatting across all batch items.
  • Monitor task completion through fetchPersonalTask(), checking for the succeeded status to retrieve image URLs.
  • Leverage the realCases.js library for production-ready structured prompts that include layout and composition directives.
  • Implement retryAfterMs handling to respect rate limits when processing large batches concurrently.
  • Validate task IDs with isValidApimartTaskId() before polling to eliminate invalid network requests.

Frequently Asked Questions

What defines a structured prompt protocol?

A structured prompt protocol is a detailed, reusable text template that encodes specific visual constraints such as panel layouts, character consistency rules, and branding requirements. According to the awesome-gpt-image-2 source code, these protocols are stored in src/image25/realCases.js and include both the generation prompt and metadata describing structural requirements like "Six-panel structure" or "Cannes-level premium" styling.

How does the batch generation handle API rate limits?

The client implements automatic error handling through the responseError helper in src/apimartClient.js (line 81), which extracts retryAfterMs values from API responses. When a 429 status occurs, your batch processor should catch this error and wait the specified duration before retrying, preventing account throttling while maintaining throughput.

Can I mix custom prompts with the built-in real cases library?

Yes. The batchGenerate() function accepts any array of objects containing a prompt property. You can combine entries from realCases.js with custom objects, filter the library by category using string matching on the en field, or pass entirely user-defined prompts while maintaining the same execution workflow.

While the repository does not enforce a hard limit, the example implementation sets MAX_CONCURRENT = 5 as a conservative default. You should adjust this value based on your APIMart subscription tier's rate limits. Monitor for 429 responses and implement the retryAfterMs back-off strategy to dynamically adapt to current API capacity.

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 →