alt-images-ai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +186 -0
- package/dist/client.d.ts +33 -0
- package/dist/client.js +117 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +47 -0
- package/dist/providers/gemini.d.ts +8 -0
- package/dist/providers/gemini.js +95 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +7 -0
- package/dist/providers/openai.d.ts +8 -0
- package/dist/providers/openai.js +96 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.js +2 -0
- package/dist/utils/html.d.ts +18 -0
- package/dist/utils/html.js +53 -0
- package/dist/utils/image.d.ts +8 -0
- package/dist/utils/image.js +137 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +8 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# alt-images-ai
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/alt-images-ai)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
|
|
7
|
+
Generate accessible alt text for images using AI. Supports **OpenAI** (GPT-4o) and **Google Gemini**.
|
|
8
|
+
|
|
9
|
+
Zero runtime dependencies — uses only Node.js built-in modules. Full TypeScript support.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Multiple AI providers** — OpenAI and Google Gemini out of the box
|
|
14
|
+
- **Flexible image input** — URLs, local files, base64 data URIs, or Buffers
|
|
15
|
+
- **HTML processing** — Automatically scan and add `alt` attributes to `<img>` tags
|
|
16
|
+
- **Batch processing** — Generate alt text for multiple images in parallel
|
|
17
|
+
- **Multi-language** — Generate descriptions in any language
|
|
18
|
+
- **Configurable** — Custom prompts, max length, model selection
|
|
19
|
+
- **TypeScript** — Full type definitions included
|
|
20
|
+
- **Lightweight** — Zero runtime dependencies
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install alt-images-ai
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { AltImageClient } from "alt-images-ai";
|
|
32
|
+
|
|
33
|
+
const client = new AltImageClient({
|
|
34
|
+
provider: "openai", // or "gemini"
|
|
35
|
+
apiKey: "your-api-key",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const alt = await client.generateAlt("https://example.com/photo.jpg");
|
|
39
|
+
console.log(alt);
|
|
40
|
+
// "Golden retriever running across a sunlit meadow"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### Create a Client
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { AltImageClient } from "alt-images-ai";
|
|
49
|
+
|
|
50
|
+
const client = new AltImageClient({
|
|
51
|
+
provider: "openai", // "openai" | "gemini"
|
|
52
|
+
apiKey: "sk-...",
|
|
53
|
+
language: "es", // optional — default: "en"
|
|
54
|
+
maxLength: 125, // optional — max characters for alt text
|
|
55
|
+
model: "gpt-4o", // optional — override default model
|
|
56
|
+
customPrompt: "...", // optional — fully custom AI prompt
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Generate Alt Text for a Single Image
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// From a URL
|
|
64
|
+
const alt = await client.generateAlt("https://example.com/photo.jpg");
|
|
65
|
+
|
|
66
|
+
// From a local file
|
|
67
|
+
const alt = await client.generateAlt("./images/hero.png");
|
|
68
|
+
|
|
69
|
+
// From a Buffer
|
|
70
|
+
import fs from "fs";
|
|
71
|
+
const buffer = fs.readFileSync("photo.jpg");
|
|
72
|
+
const alt = await client.generateAlt(buffer);
|
|
73
|
+
|
|
74
|
+
// With per-call overrides
|
|
75
|
+
const alt = await client.generateAlt("photo.jpg", {
|
|
76
|
+
language: "fr",
|
|
77
|
+
maxLength: 100,
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Batch Processing
|
|
82
|
+
|
|
83
|
+
Process multiple images in parallel. Failed images are collected in the `errors` array without stopping the rest.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const { results, errors } = await client.generateAltBatch([
|
|
87
|
+
"https://example.com/img1.jpg",
|
|
88
|
+
"https://example.com/img2.jpg",
|
|
89
|
+
"./local-image.png",
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
for (const { src, alt } of results) {
|
|
93
|
+
console.log(`${src} → ${alt}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (const { src, error } of errors) {
|
|
97
|
+
console.error(`${src} failed: ${error.message}`);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Process HTML
|
|
102
|
+
|
|
103
|
+
Scan an HTML string, find `<img>` tags missing alt text, and automatically generate it:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const html = `
|
|
107
|
+
<div>
|
|
108
|
+
<img src="hero.jpg">
|
|
109
|
+
<img src="team.jpg" alt="">
|
|
110
|
+
<img src="logo.png" alt="Company logo">
|
|
111
|
+
</div>
|
|
112
|
+
`;
|
|
113
|
+
|
|
114
|
+
const result = await client.processHTML(html);
|
|
115
|
+
// hero.jpg → gets AI-generated alt
|
|
116
|
+
// team.jpg → gets AI-generated alt (empty alt counts as missing)
|
|
117
|
+
// logo.png → left unchanged (already has alt text)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### HTML Processing Options
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const result = await client.processHTML(html, {
|
|
124
|
+
onlyMissing: true, // only process images without alt (default: true)
|
|
125
|
+
overrideExisting: false, // replace existing alt values (default: false)
|
|
126
|
+
language: "es", // override language for this call
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### One-liner
|
|
131
|
+
|
|
132
|
+
Generate alt text without creating a client first:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { generateAlt } from "alt-images-ai";
|
|
136
|
+
|
|
137
|
+
const alt = await generateAlt("photo.jpg", {
|
|
138
|
+
provider: "openai",
|
|
139
|
+
apiKey: "sk-...",
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Providers
|
|
144
|
+
|
|
145
|
+
| Provider | Default Model | Documentation |
|
|
146
|
+
| -------- | ---------------- | -------------------------------------------------------------- |
|
|
147
|
+
| `openai` | `gpt-4o-mini` | [OpenAI Vision](https://platform.openai.com/docs/guides/vision) |
|
|
148
|
+
| `gemini` | `gemini-2.0-flash` | [Google Gemini](https://ai.google.dev/docs) |
|
|
149
|
+
|
|
150
|
+
## API Reference
|
|
151
|
+
|
|
152
|
+
### `new AltImageClient(options)`
|
|
153
|
+
|
|
154
|
+
| Option | Type | Required | Default | Description |
|
|
155
|
+
| -------------- | ------------------------ | -------- | ---------------- | ---------------------------------- |
|
|
156
|
+
| `provider` | `"openai" \| "gemini"` | Yes | — | AI provider to use |
|
|
157
|
+
| `apiKey` | `string` | Yes | — | API key for the provider |
|
|
158
|
+
| `model` | `string` | No | Provider default | Override the default model |
|
|
159
|
+
| `language` | `string` | No | `"en"` | Language for generated alt text |
|
|
160
|
+
| `maxLength` | `number` | No | — | Maximum character length |
|
|
161
|
+
| `customPrompt` | `string` | No | — | Fully custom prompt for the AI |
|
|
162
|
+
|
|
163
|
+
### `client.generateAlt(image, options?): Promise<string>`
|
|
164
|
+
|
|
165
|
+
Generate alt text for a single image. Accepts a URL, file path, data URI, or Buffer.
|
|
166
|
+
|
|
167
|
+
### `client.generateAltBatch(images, options?): Promise<BatchResult>`
|
|
168
|
+
|
|
169
|
+
Generate alt text for multiple images in parallel. Returns `{ results, errors }`.
|
|
170
|
+
|
|
171
|
+
### `client.processHTML(html, options?): Promise<string>`
|
|
172
|
+
|
|
173
|
+
Parse HTML, find `<img>` tags, and add AI-generated alt attributes. Returns the modified HTML string.
|
|
174
|
+
|
|
175
|
+
### `generateAlt(image, options): Promise<string>`
|
|
176
|
+
|
|
177
|
+
Standalone function that creates a client internally — useful for one-off calls.
|
|
178
|
+
|
|
179
|
+
## Requirements
|
|
180
|
+
|
|
181
|
+
- Node.js >= 18
|
|
182
|
+
- An API key from [OpenAI](https://platform.openai.com/api-keys) or [Google AI Studio](https://aistudio.google.com/apikey)
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AltImageClientOptions, BatchResult, GenerateAltOptions, ProcessHTMLOptions } from "./types";
|
|
2
|
+
export declare class AltImageClient {
|
|
3
|
+
private provider;
|
|
4
|
+
private language;
|
|
5
|
+
private maxLength;
|
|
6
|
+
private customPrompt;
|
|
7
|
+
constructor(options: AltImageClientOptions);
|
|
8
|
+
/**
|
|
9
|
+
* Generate alt text for a single image.
|
|
10
|
+
*
|
|
11
|
+
* @param image - URL, file path, data URI, or Buffer
|
|
12
|
+
* @param options - Override default language, maxLength, or prompt
|
|
13
|
+
* @returns The generated alt text string
|
|
14
|
+
*/
|
|
15
|
+
generateAlt(image: string | Buffer, options?: GenerateAltOptions): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Generate alt text for multiple images in parallel.
|
|
18
|
+
*
|
|
19
|
+
* @param images - Array of URLs, file paths, data URIs, or Buffers
|
|
20
|
+
* @param options - Override default language, maxLength, or prompt
|
|
21
|
+
* @returns Object with results array and errors array
|
|
22
|
+
*/
|
|
23
|
+
generateAltBatch(images: (string | Buffer)[], options?: GenerateAltOptions): Promise<BatchResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Process an HTML string: find <img> tags and generate alt text for them.
|
|
26
|
+
*
|
|
27
|
+
* @param html - HTML string to process
|
|
28
|
+
* @param options - Configure which images to process and generation options
|
|
29
|
+
* @returns The HTML string with alt attributes added/updated
|
|
30
|
+
*/
|
|
31
|
+
processHTML(html: string, options?: ProcessHTMLOptions): Promise<string>;
|
|
32
|
+
private buildPrompt;
|
|
33
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AltImageClient = void 0;
|
|
4
|
+
const openai_1 = require("./providers/openai");
|
|
5
|
+
const gemini_1 = require("./providers/gemini");
|
|
6
|
+
const image_1 = require("./utils/image");
|
|
7
|
+
const html_1 = require("./utils/html");
|
|
8
|
+
class AltImageClient {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
if (!options.apiKey) {
|
|
11
|
+
throw new Error("apiKey is required");
|
|
12
|
+
}
|
|
13
|
+
this.language = options.language ?? "en";
|
|
14
|
+
this.maxLength = options.maxLength;
|
|
15
|
+
this.customPrompt = options.customPrompt;
|
|
16
|
+
switch (options.provider) {
|
|
17
|
+
case "openai":
|
|
18
|
+
this.provider = new openai_1.OpenAIProvider(options.apiKey, options.model);
|
|
19
|
+
break;
|
|
20
|
+
case "gemini":
|
|
21
|
+
this.provider = new gemini_1.GeminiProvider(options.apiKey, options.model);
|
|
22
|
+
break;
|
|
23
|
+
default:
|
|
24
|
+
throw new Error(`Unsupported provider: ${options.provider}. Use "openai" or "gemini".`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Generate alt text for a single image.
|
|
29
|
+
*
|
|
30
|
+
* @param image - URL, file path, data URI, or Buffer
|
|
31
|
+
* @param options - Override default language, maxLength, or prompt
|
|
32
|
+
* @returns The generated alt text string
|
|
33
|
+
*/
|
|
34
|
+
async generateAlt(image, options) {
|
|
35
|
+
const { base64, mimeType } = await (0, image_1.resolveImage)(image);
|
|
36
|
+
const prompt = this.buildPrompt(options);
|
|
37
|
+
let alt = await this.provider.generateAlt(base64, mimeType, prompt);
|
|
38
|
+
const maxLen = options?.maxLength ?? this.maxLength;
|
|
39
|
+
if (maxLen && alt.length > maxLen) {
|
|
40
|
+
alt = alt.substring(0, maxLen - 3).trimEnd() + "...";
|
|
41
|
+
}
|
|
42
|
+
return alt;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Generate alt text for multiple images in parallel.
|
|
46
|
+
*
|
|
47
|
+
* @param images - Array of URLs, file paths, data URIs, or Buffers
|
|
48
|
+
* @param options - Override default language, maxLength, or prompt
|
|
49
|
+
* @returns Object with results array and errors array
|
|
50
|
+
*/
|
|
51
|
+
async generateAltBatch(images, options) {
|
|
52
|
+
const results = [];
|
|
53
|
+
const errors = [];
|
|
54
|
+
const promises = images.map(async (image) => {
|
|
55
|
+
const src = Buffer.isBuffer(image) ? "[Buffer]" : image;
|
|
56
|
+
try {
|
|
57
|
+
const alt = await this.generateAlt(image, options);
|
|
58
|
+
results.push({ alt, src });
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
errors.push({
|
|
62
|
+
src,
|
|
63
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
await Promise.all(promises);
|
|
68
|
+
return { results, errors };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Process an HTML string: find <img> tags and generate alt text for them.
|
|
72
|
+
*
|
|
73
|
+
* @param html - HTML string to process
|
|
74
|
+
* @param options - Configure which images to process and generation options
|
|
75
|
+
* @returns The HTML string with alt attributes added/updated
|
|
76
|
+
*/
|
|
77
|
+
async processHTML(html, options) {
|
|
78
|
+
const onlyMissing = options?.onlyMissing ?? true;
|
|
79
|
+
const overrideExisting = options?.overrideExisting ?? false;
|
|
80
|
+
const imgTags = (0, html_1.extractImgTags)(html);
|
|
81
|
+
let result = html;
|
|
82
|
+
for (const tag of imgTags) {
|
|
83
|
+
const shouldProcess = !tag.hasAlt || (overrideExisting && !onlyMissing) || (tag.hasAlt && tag.alt === "");
|
|
84
|
+
if (!shouldProcess && onlyMissing)
|
|
85
|
+
continue;
|
|
86
|
+
if (tag.hasAlt && !overrideExisting && tag.alt !== "")
|
|
87
|
+
continue;
|
|
88
|
+
try {
|
|
89
|
+
const alt = await this.generateAlt(tag.src, options);
|
|
90
|
+
result = (0, html_1.setImgAlt)(result, tag, alt);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Skip images that fail — keep existing HTML intact
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
buildPrompt(options) {
|
|
99
|
+
const custom = options?.customPrompt ?? this.customPrompt;
|
|
100
|
+
if (custom)
|
|
101
|
+
return custom;
|
|
102
|
+
const lang = options?.language ?? this.language;
|
|
103
|
+
const maxLen = options?.maxLength ?? this.maxLength;
|
|
104
|
+
let prompt = "Generate a concise, descriptive alt text for this image. " +
|
|
105
|
+
"The alt text should be useful for screen readers and accessibility. " +
|
|
106
|
+
"Describe the key visual content without starting with 'Image of' or 'Picture of'. " +
|
|
107
|
+
"Return ONLY the alt text, no quotes, no explanation.";
|
|
108
|
+
if (lang !== "en") {
|
|
109
|
+
prompt += ` Write the alt text in ${lang}.`;
|
|
110
|
+
}
|
|
111
|
+
if (maxLen) {
|
|
112
|
+
prompt += ` Keep it under ${maxLen} characters.`;
|
|
113
|
+
}
|
|
114
|
+
return prompt;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.AltImageClient = AltImageClient;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { AltImageClient } from "./client";
|
|
2
|
+
export type { Provider, ImageInput, AltImageClientOptions, GenerateAltOptions, ProcessHTMLOptions, AltResult, BatchResult, BatchError, AIProvider, } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Convenience function: create a client and generate alt text in one call.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateAlt(image: string | Buffer, options: {
|
|
7
|
+
provider: "openai" | "gemini";
|
|
8
|
+
apiKey: string;
|
|
9
|
+
model?: string;
|
|
10
|
+
language?: string;
|
|
11
|
+
maxLength?: number;
|
|
12
|
+
customPrompt?: string;
|
|
13
|
+
}): Promise<string>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.AltImageClient = void 0;
|
|
37
|
+
exports.generateAlt = generateAlt;
|
|
38
|
+
var client_1 = require("./client");
|
|
39
|
+
Object.defineProperty(exports, "AltImageClient", { enumerable: true, get: function () { return client_1.AltImageClient; } });
|
|
40
|
+
/**
|
|
41
|
+
* Convenience function: create a client and generate alt text in one call.
|
|
42
|
+
*/
|
|
43
|
+
async function generateAlt(image, options) {
|
|
44
|
+
const { AltImageClient: Client } = await Promise.resolve().then(() => __importStar(require("./client")));
|
|
45
|
+
const client = new Client(options);
|
|
46
|
+
return client.generateAlt(image, options);
|
|
47
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AIProvider } from "../types";
|
|
2
|
+
export declare class GeminiProvider implements AIProvider {
|
|
3
|
+
private apiKey;
|
|
4
|
+
private model;
|
|
5
|
+
constructor(apiKey: string, model?: string);
|
|
6
|
+
generateAlt(imageBase64: string, mimeType: string, prompt: string): Promise<string>;
|
|
7
|
+
private request;
|
|
8
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.GeminiProvider = void 0;
|
|
37
|
+
const https = __importStar(require("https"));
|
|
38
|
+
class GeminiProvider {
|
|
39
|
+
constructor(apiKey, model) {
|
|
40
|
+
this.apiKey = apiKey;
|
|
41
|
+
this.model = model ?? "gemini-2.0-flash";
|
|
42
|
+
}
|
|
43
|
+
async generateAlt(imageBase64, mimeType, prompt) {
|
|
44
|
+
const body = JSON.stringify({
|
|
45
|
+
contents: [
|
|
46
|
+
{
|
|
47
|
+
parts: [
|
|
48
|
+
{ text: prompt },
|
|
49
|
+
{
|
|
50
|
+
inline_data: {
|
|
51
|
+
mime_type: mimeType,
|
|
52
|
+
data: imageBase64,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
generationConfig: {
|
|
59
|
+
maxOutputTokens: 300,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
const response = await this.request(body);
|
|
63
|
+
const data = JSON.parse(response);
|
|
64
|
+
if (data.error) {
|
|
65
|
+
throw new Error(`Gemini API error: ${data.error.message}`);
|
|
66
|
+
}
|
|
67
|
+
const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
68
|
+
if (!text) {
|
|
69
|
+
throw new Error("Gemini returned an empty response");
|
|
70
|
+
}
|
|
71
|
+
return text.trim();
|
|
72
|
+
}
|
|
73
|
+
request(body) {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const req = https.request({
|
|
76
|
+
hostname: "generativelanguage.googleapis.com",
|
|
77
|
+
path: `/v1beta/models/${this.model}:generateContent?key=${this.apiKey}`,
|
|
78
|
+
method: "POST",
|
|
79
|
+
headers: {
|
|
80
|
+
"Content-Type": "application/json",
|
|
81
|
+
},
|
|
82
|
+
}, (res) => {
|
|
83
|
+
let data = "";
|
|
84
|
+
res.on("data", (chunk) => {
|
|
85
|
+
data += chunk.toString();
|
|
86
|
+
});
|
|
87
|
+
res.on("end", () => resolve(data));
|
|
88
|
+
});
|
|
89
|
+
req.on("error", reject);
|
|
90
|
+
req.write(body);
|
|
91
|
+
req.end();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.GeminiProvider = GeminiProvider;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GeminiProvider = exports.OpenAIProvider = void 0;
|
|
4
|
+
var openai_1 = require("./openai");
|
|
5
|
+
Object.defineProperty(exports, "OpenAIProvider", { enumerable: true, get: function () { return openai_1.OpenAIProvider; } });
|
|
6
|
+
var gemini_1 = require("./gemini");
|
|
7
|
+
Object.defineProperty(exports, "GeminiProvider", { enumerable: true, get: function () { return gemini_1.GeminiProvider; } });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AIProvider } from "../types";
|
|
2
|
+
export declare class OpenAIProvider implements AIProvider {
|
|
3
|
+
private apiKey;
|
|
4
|
+
private model;
|
|
5
|
+
constructor(apiKey: string, model?: string);
|
|
6
|
+
generateAlt(imageBase64: string, mimeType: string, prompt: string): Promise<string>;
|
|
7
|
+
private request;
|
|
8
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.OpenAIProvider = void 0;
|
|
37
|
+
const https = __importStar(require("https"));
|
|
38
|
+
class OpenAIProvider {
|
|
39
|
+
constructor(apiKey, model) {
|
|
40
|
+
this.apiKey = apiKey;
|
|
41
|
+
this.model = model ?? "gpt-4o-mini";
|
|
42
|
+
}
|
|
43
|
+
async generateAlt(imageBase64, mimeType, prompt) {
|
|
44
|
+
const body = JSON.stringify({
|
|
45
|
+
model: this.model,
|
|
46
|
+
messages: [
|
|
47
|
+
{
|
|
48
|
+
role: "user",
|
|
49
|
+
content: [
|
|
50
|
+
{ type: "text", text: prompt },
|
|
51
|
+
{
|
|
52
|
+
type: "image_url",
|
|
53
|
+
image_url: {
|
|
54
|
+
url: `data:${mimeType};base64,${imageBase64}`,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
max_tokens: 300,
|
|
61
|
+
});
|
|
62
|
+
const response = await this.request(body);
|
|
63
|
+
const data = JSON.parse(response);
|
|
64
|
+
if (data.error) {
|
|
65
|
+
throw new Error(`OpenAI API error: ${data.error.message}`);
|
|
66
|
+
}
|
|
67
|
+
const text = data.choices?.[0]?.message?.content;
|
|
68
|
+
if (!text) {
|
|
69
|
+
throw new Error("OpenAI returned an empty response");
|
|
70
|
+
}
|
|
71
|
+
return text.trim();
|
|
72
|
+
}
|
|
73
|
+
request(body) {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const req = https.request({
|
|
76
|
+
hostname: "api.openai.com",
|
|
77
|
+
path: "/v1/chat/completions",
|
|
78
|
+
method: "POST",
|
|
79
|
+
headers: {
|
|
80
|
+
"Content-Type": "application/json",
|
|
81
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
82
|
+
},
|
|
83
|
+
}, (res) => {
|
|
84
|
+
let data = "";
|
|
85
|
+
res.on("data", (chunk) => {
|
|
86
|
+
data += chunk.toString();
|
|
87
|
+
});
|
|
88
|
+
res.on("end", () => resolve(data));
|
|
89
|
+
});
|
|
90
|
+
req.on("error", reject);
|
|
91
|
+
req.write(body);
|
|
92
|
+
req.end();
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.OpenAIProvider = OpenAIProvider;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** Supported AI providers */
|
|
2
|
+
export type Provider = "openai" | "gemini";
|
|
3
|
+
/** Image input: URL, local file path, or base64-encoded string */
|
|
4
|
+
export type ImageInput = string | Buffer;
|
|
5
|
+
/** Configuration for creating an AltImageClient */
|
|
6
|
+
export interface AltImageClientOptions {
|
|
7
|
+
/** AI provider to use */
|
|
8
|
+
provider: Provider;
|
|
9
|
+
/** API key for the chosen provider */
|
|
10
|
+
apiKey: string;
|
|
11
|
+
/** Model to use (defaults to provider's recommended vision model) */
|
|
12
|
+
model?: string;
|
|
13
|
+
/** Language for the generated alt text (e.g. "en", "es", "fr") */
|
|
14
|
+
language?: string;
|
|
15
|
+
/** Maximum character length for the alt text */
|
|
16
|
+
maxLength?: number;
|
|
17
|
+
/** Custom prompt to guide the AI generation */
|
|
18
|
+
customPrompt?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Options for a single generateAlt call (overrides client defaults) */
|
|
21
|
+
export interface GenerateAltOptions {
|
|
22
|
+
/** Language for the generated alt text */
|
|
23
|
+
language?: string;
|
|
24
|
+
/** Maximum character length for the alt text */
|
|
25
|
+
maxLength?: number;
|
|
26
|
+
/** Custom prompt to guide the AI generation */
|
|
27
|
+
customPrompt?: string;
|
|
28
|
+
}
|
|
29
|
+
/** Options for HTML processing */
|
|
30
|
+
export interface ProcessHTMLOptions extends GenerateAltOptions {
|
|
31
|
+
/** Only process <img> tags that are missing alt attributes (default: true) */
|
|
32
|
+
onlyMissing?: boolean;
|
|
33
|
+
/** Override existing alt attributes (default: false) */
|
|
34
|
+
overrideExisting?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Result of a single alt text generation */
|
|
37
|
+
export interface AltResult {
|
|
38
|
+
/** The generated alt text */
|
|
39
|
+
alt: string;
|
|
40
|
+
/** The image source that was processed */
|
|
41
|
+
src: string;
|
|
42
|
+
}
|
|
43
|
+
/** Result of a batch operation */
|
|
44
|
+
export interface BatchResult {
|
|
45
|
+
/** Successfully generated results */
|
|
46
|
+
results: AltResult[];
|
|
47
|
+
/** Errors encountered during processing */
|
|
48
|
+
errors: BatchError[];
|
|
49
|
+
}
|
|
50
|
+
/** Error from a batch operation */
|
|
51
|
+
export interface BatchError {
|
|
52
|
+
/** The image source that failed */
|
|
53
|
+
src: string;
|
|
54
|
+
/** The error that occurred */
|
|
55
|
+
error: Error;
|
|
56
|
+
}
|
|
57
|
+
/** Internal interface for AI provider implementations */
|
|
58
|
+
export interface AIProvider {
|
|
59
|
+
/** Generate alt text for an image */
|
|
60
|
+
generateAlt(imageBase64: string, mimeType: string, prompt: string): Promise<string>;
|
|
61
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ImgTag {
|
|
2
|
+
/** Full match of the <img> tag */
|
|
3
|
+
fullMatch: string;
|
|
4
|
+
/** Value of the src attribute */
|
|
5
|
+
src: string;
|
|
6
|
+
/** Value of the alt attribute (undefined if missing) */
|
|
7
|
+
alt: string | undefined;
|
|
8
|
+
/** Whether the tag has an alt attribute at all */
|
|
9
|
+
hasAlt: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Extract all <img> tags from an HTML string.
|
|
13
|
+
*/
|
|
14
|
+
export declare function extractImgTags(html: string): ImgTag[];
|
|
15
|
+
/**
|
|
16
|
+
* Replace an <img> tag's alt attribute in HTML, or add one if missing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function setImgAlt(html: string, imgTag: ImgTag, altText: string): string;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractImgTags = extractImgTags;
|
|
4
|
+
exports.setImgAlt = setImgAlt;
|
|
5
|
+
const IMG_REGEX = /<img\s[^>]*?>/gi;
|
|
6
|
+
const SRC_REGEX = /src\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+))/i;
|
|
7
|
+
const ALT_REGEX = /alt\s*=\s*(?:"([^"]*)"|'([^']*)')/i;
|
|
8
|
+
/**
|
|
9
|
+
* Extract all <img> tags from an HTML string.
|
|
10
|
+
*/
|
|
11
|
+
function extractImgTags(html) {
|
|
12
|
+
const tags = [];
|
|
13
|
+
let match;
|
|
14
|
+
while ((match = IMG_REGEX.exec(html)) !== null) {
|
|
15
|
+
const fullMatch = match[0];
|
|
16
|
+
const srcMatch = SRC_REGEX.exec(fullMatch);
|
|
17
|
+
const altMatch = ALT_REGEX.exec(fullMatch);
|
|
18
|
+
const src = srcMatch
|
|
19
|
+
? srcMatch[1] ?? srcMatch[2] ?? srcMatch[3] ?? ""
|
|
20
|
+
: "";
|
|
21
|
+
const hasAlt = altMatch !== null;
|
|
22
|
+
const alt = hasAlt
|
|
23
|
+
? altMatch[1] ?? altMatch[2] ?? ""
|
|
24
|
+
: undefined;
|
|
25
|
+
if (src) {
|
|
26
|
+
tags.push({ fullMatch, src, alt, hasAlt });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return tags;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Replace an <img> tag's alt attribute in HTML, or add one if missing.
|
|
33
|
+
*/
|
|
34
|
+
function setImgAlt(html, imgTag, altText) {
|
|
35
|
+
const escaped = escapeAttrValue(altText);
|
|
36
|
+
let newTag;
|
|
37
|
+
if (imgTag.hasAlt) {
|
|
38
|
+
// Replace existing alt attribute
|
|
39
|
+
newTag = imgTag.fullMatch.replace(ALT_REGEX, `alt="${escaped}"`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Add alt attribute after <img
|
|
43
|
+
newTag = imgTag.fullMatch.replace(/^<img/i, `<img alt="${escaped}"`);
|
|
44
|
+
}
|
|
45
|
+
return html.replace(imgTag.fullMatch, newTag);
|
|
46
|
+
}
|
|
47
|
+
function escapeAttrValue(value) {
|
|
48
|
+
return value
|
|
49
|
+
.replace(/&/g, "&")
|
|
50
|
+
.replace(/"/g, """)
|
|
51
|
+
.replace(/</g, "<")
|
|
52
|
+
.replace(/>/g, ">");
|
|
53
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.resolveImage = resolveImage;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const https = __importStar(require("https"));
|
|
39
|
+
const http = __importStar(require("http"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const MIME_TYPES = {
|
|
42
|
+
".jpg": "image/jpeg",
|
|
43
|
+
".jpeg": "image/jpeg",
|
|
44
|
+
".png": "image/png",
|
|
45
|
+
".gif": "image/gif",
|
|
46
|
+
".webp": "image/webp",
|
|
47
|
+
".bmp": "image/bmp",
|
|
48
|
+
".svg": "image/svg+xml",
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Resolves an image input (URL, file path, base64, or Buffer) to base64 + mimeType.
|
|
52
|
+
*/
|
|
53
|
+
async function resolveImage(input) {
|
|
54
|
+
if (Buffer.isBuffer(input)) {
|
|
55
|
+
return {
|
|
56
|
+
base64: input.toString("base64"),
|
|
57
|
+
mimeType: detectMimeFromBuffer(input),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// Base64 data URI
|
|
61
|
+
if (input.startsWith("data:")) {
|
|
62
|
+
const match = input.match(/^data:(image\/[^;]+);base64,(.+)$/);
|
|
63
|
+
if (!match) {
|
|
64
|
+
throw new Error("Invalid data URI format");
|
|
65
|
+
}
|
|
66
|
+
return { base64: match[2], mimeType: match[1] };
|
|
67
|
+
}
|
|
68
|
+
// URL
|
|
69
|
+
if (input.startsWith("http://") || input.startsWith("https://")) {
|
|
70
|
+
return downloadImage(input);
|
|
71
|
+
}
|
|
72
|
+
// File path
|
|
73
|
+
return readImageFile(input);
|
|
74
|
+
}
|
|
75
|
+
function readImageFile(filePath) {
|
|
76
|
+
if (!fs.existsSync(filePath)) {
|
|
77
|
+
throw new Error(`File not found: ${filePath}`);
|
|
78
|
+
}
|
|
79
|
+
const buffer = fs.readFileSync(filePath);
|
|
80
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
81
|
+
const mimeType = MIME_TYPES[ext] ?? detectMimeFromBuffer(buffer);
|
|
82
|
+
return {
|
|
83
|
+
base64: buffer.toString("base64"),
|
|
84
|
+
mimeType,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function downloadImage(url) {
|
|
88
|
+
const client = url.startsWith("https://") ? https : http;
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
client.get(url, (res) => {
|
|
91
|
+
if (res.statusCode &&
|
|
92
|
+
res.statusCode >= 300 &&
|
|
93
|
+
res.statusCode < 400 &&
|
|
94
|
+
res.headers.location) {
|
|
95
|
+
downloadImage(res.headers.location).then(resolve, reject);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
99
|
+
reject(new Error(`Failed to download image: HTTP ${res.statusCode}`));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const chunks = [];
|
|
103
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
104
|
+
res.on("end", () => {
|
|
105
|
+
const buffer = Buffer.concat(chunks);
|
|
106
|
+
const contentType = res.headers["content-type"] ?? "";
|
|
107
|
+
const mimeType = contentType.startsWith("image/")
|
|
108
|
+
? contentType.split(";")[0]
|
|
109
|
+
: detectMimeFromBuffer(buffer);
|
|
110
|
+
resolve({
|
|
111
|
+
base64: buffer.toString("base64"),
|
|
112
|
+
mimeType,
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
res.on("error", reject);
|
|
116
|
+
}).on("error", reject);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function detectMimeFromBuffer(buffer) {
|
|
120
|
+
if (buffer[0] === 0xff && buffer[1] === 0xd8)
|
|
121
|
+
return "image/jpeg";
|
|
122
|
+
if (buffer[0] === 0x89 &&
|
|
123
|
+
buffer[1] === 0x50 &&
|
|
124
|
+
buffer[2] === 0x4e &&
|
|
125
|
+
buffer[3] === 0x47)
|
|
126
|
+
return "image/png";
|
|
127
|
+
if (buffer[0] === 0x47 &&
|
|
128
|
+
buffer[1] === 0x49 &&
|
|
129
|
+
buffer[2] === 0x46)
|
|
130
|
+
return "image/gif";
|
|
131
|
+
if (buffer[0] === 0x52 &&
|
|
132
|
+
buffer[1] === 0x49 &&
|
|
133
|
+
buffer[2] === 0x46 &&
|
|
134
|
+
buffer[3] === 0x46)
|
|
135
|
+
return "image/webp";
|
|
136
|
+
return "image/jpeg"; // fallback
|
|
137
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setImgAlt = exports.extractImgTags = exports.resolveImage = void 0;
|
|
4
|
+
var image_1 = require("./image");
|
|
5
|
+
Object.defineProperty(exports, "resolveImage", { enumerable: true, get: function () { return image_1.resolveImage; } });
|
|
6
|
+
var html_1 = require("./html");
|
|
7
|
+
Object.defineProperty(exports, "extractImgTags", { enumerable: true, get: function () { return html_1.extractImgTags; } });
|
|
8
|
+
Object.defineProperty(exports, "setImgAlt", { enumerable: true, get: function () { return html_1.setImgAlt; } });
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "alt-images-ai",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Generate accessible alt text for images using AI (OpenAI, Google Gemini). Process single images, batch operations, or full HTML documents.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"alt-text",
|
|
16
|
+
"accessibility",
|
|
17
|
+
"a11y",
|
|
18
|
+
"images",
|
|
19
|
+
"ai",
|
|
20
|
+
"openai",
|
|
21
|
+
"gemini",
|
|
22
|
+
"gpt-4-vision",
|
|
23
|
+
"image-description",
|
|
24
|
+
"wcag",
|
|
25
|
+
"aria",
|
|
26
|
+
"html",
|
|
27
|
+
"seo"
|
|
28
|
+
],
|
|
29
|
+
"author": "kreent",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/kreent/alt-images-ai"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18.0.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^25.2.2",
|
|
40
|
+
"typescript": "^5.4.0"
|
|
41
|
+
}
|
|
42
|
+
}
|