npm package: @gloobussoftwaredevelopment/apostrophecms-ai-alt-generator
Description: ApostropheCMS extension that uses OpenAI Vision (GPT-4o) to automatically generate accessible, SEO-friendly alt text for images — individually or in bulk.
Author: Andrei Mateas
Latest version: 1.1.0

# apostrophecms-ai-alt-generator

ApostropheCMS extension that uses the OpenAI Vision API (GPT-4o) to automatically generate descriptive, accessible alt text for images. Supports single-image generation with optional user context and bulk generation for all images missing alt text across the media library.

## Why

Images uploaded to the media library often lack alt text. Writing it manually for hundreds of images is time-consuming and frequently skipped, leaving gaps in accessibility and SEO. This module automates the process using AI vision analysis so every image gets a meaningful, screen-reader-friendly description.

## Features

### Single image generation

A **"Generate Alt Text with AI"** button is added to the image editor modal, directly above the `alt` field.

- Click the button, optionally enter context (e.g. *"Couple preparing for a scuba dive in the Maldives"*), and the AI analyzes the image and fills in the alt text automatically.
- User context is treated as ground truth and incorporated into the result, producing more accurate descriptions for domain-specific imagery.
- Uses `detail: auto` mode for maximum accuracy on individual images.
- SVG images are detected and rejected with a clear error message (OpenAI Vision does not support SVG).
- Inline success/error feedback is displayed below the button.

### Bulk generation

Available in **Global Settings > AI** tab.

- Processes all images in the media library that have an empty or missing `alt` field.
- Configurable **batch size** (1–500, default 20) via a stepper input with -10/+10 buttons.
- Automatically **skips SVG and archived images**.
- Uses `detail: low` mode to keep API costs minimal for bulk operations.
- Includes a 500ms delay between API requests to respect OpenAI rate limits.
- Updates both **draft and published** document versions directly.
- After processing, displays:
  - Summary stats (Processed / Failed / Remaining)
  - A results table showing each image title and its generated alt text
  - An error list for any failed images

### Global configuration

- **OpenAI API Key** is stored as a password field in Global Settings > AI tab (input is masked).
- The API key is automatically synced across all locales.
- No environment variables or `.env` changes required.

## Requirements

- ApostropheCMS 3.x
- Node.js 18+ (uses native `fetch`)
- An OpenAI API key with access to GPT-4o

No additional npm dependencies are installed.

## Installation

```bash
npm install @gloobussoftwaredevelopment/apostrophecms-ai-alt-generator
```

Register the module in your `app.js`:

```js
require('apostrophe')({
  modules: {
    '@gloobussoftwaredevelopment/apostrophecms-ai-alt-generator': {},
    // ... other modules
  }
});
```

Restart your dev server so the admin UI assets rebuild.

## Configuration

1. Go to **Global Settings > AI** tab in the admin bar.
2. Enter your OpenAI API key (get one from [platform.openai.com/api-keys](https://platform.openai.com/api-keys)).
3. **Save** the Global document — the API key must be persisted before generating alt text.

That's it. No other configuration is needed.

## Usage

### Single image

1. Open the media library and select an image.
2. Click **"Generate Alt Text with AI"** in the basics group.
3. Optionally enter context in the prompt dialog to guide the AI.
4. The `alt` field is populated automatically with the generated text.

### Bulk

1. Go to **Global Settings > AI** tab.
2. Set the desired batch size.
3. Click **"Generate Missing Alt Texts"** and confirm.
4. Review the results table once processing completes.
5. Run again if images remain — the "Remaining" count shows how many are left.

## How it works

The module registers two custom ApostropheCMS field types (`aiAltGenerator` and `aiAltBulkGenerator`) and two API routes:

| Route | Method | Description |
|-------|--------|-------------|
| `/api/v1/@gloobussoftwaredevelopment/apostrophecms-ai-alt-generator/generate` | POST | Generates alt text for a single image. Body: `{ imageDocId, prompt }` |
| `/api/v1/@gloobussoftwaredevelopment/apostrophecms-ai-alt-generator/generate-bulk` | POST | Generates alt text for a batch of images missing it. Body: `{ batchSize }` |

Images are read from disk, base64-encoded, and sent to OpenAI's chat completions endpoint with a system prompt tuned for accessibility. The AI is instructed to produce concise alt text under 125 characters, avoid phrases like "Image of", and incorporate any user-provided context as ground truth.

### Bundle structure

The package follows the official ApostropheCMS bundle pattern (same as `@apostrophecms/seo`):

```
apostrophecms-ai-alt-generator/
├── index.js                                    # Main module — field types, API routes, methods, bundle config
├── package.json
├── README.md
├── modules/
│   └── @apostrophecms/
│       ├── ai-alt-global/
│       │   └── index.js                        # Improves @apostrophecms/global — API key + bulk generator + AI tab
│       └── ai-alt-image/
│           └── index.js                        # Improves @apostrophecms/image — AI generator button in basics group
└── ui/
    └── apos/
        └── components/
            ├── AposInputAiAltGenerator.vue     # Single image generator UI
            └── AposInputAiAltBulkGenerator.vue # Bulk generator UI with batch controls
```

## Edge cases

- **Image file missing from disk** — reports an error per image without crashing the batch.
- **SVG image (single)** — shows a clear error message explaining SVGs are unsupported.
- **SVG/archived images (bulk)** — excluded from the database query entirely.
- **Empty or invalid API key** — surfaces a clear error message.
- **OpenAI API failure** — the original error message from OpenAI is displayed to the user.

## License

[MIT](LICENSE)