genai-lite 0.4.3 → 0.5.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.
Files changed (49) hide show
  1. package/README.md +377 -16
  2. package/dist/adapters/image/ElectronDiffusionAdapter.d.ts +10 -0
  3. package/dist/adapters/image/ElectronDiffusionAdapter.js +11 -0
  4. package/dist/adapters/image/GenaiElectronImageAdapter.d.ts +69 -0
  5. package/dist/adapters/image/GenaiElectronImageAdapter.js +273 -0
  6. package/dist/adapters/image/MockImageAdapter.d.ts +23 -0
  7. package/dist/adapters/image/MockImageAdapter.js +55 -0
  8. package/dist/adapters/image/OpenAIImageAdapter.d.ts +62 -0
  9. package/dist/adapters/image/OpenAIImageAdapter.js +303 -0
  10. package/dist/config/image-presets.json +194 -0
  11. package/dist/config/llm-presets.json +326 -0
  12. package/dist/image/ImageService.d.ts +53 -0
  13. package/dist/image/ImageService.js +199 -0
  14. package/dist/image/config.d.ts +48 -0
  15. package/dist/image/config.js +221 -0
  16. package/dist/image/services/ImageAdapterRegistry.d.ts +61 -0
  17. package/dist/image/services/ImageAdapterRegistry.js +95 -0
  18. package/dist/image/services/ImageModelResolver.d.ts +26 -0
  19. package/dist/image/services/ImageModelResolver.js +98 -0
  20. package/dist/image/services/ImagePresetManager.d.ts +27 -0
  21. package/dist/image/services/ImagePresetManager.js +52 -0
  22. package/dist/image/services/ImageRequestValidator.d.ts +37 -0
  23. package/dist/image/services/ImageRequestValidator.js +133 -0
  24. package/dist/image/services/ImageSettingsResolver.d.ts +25 -0
  25. package/dist/image/services/ImageSettingsResolver.js +76 -0
  26. package/dist/index.d.ts +4 -2
  27. package/dist/index.js +5 -1
  28. package/dist/llm/LLMService.d.ts +3 -4
  29. package/dist/llm/LLMService.js +14 -4
  30. package/dist/llm/clients/AnthropicClientAdapter.js +2 -2
  31. package/dist/llm/clients/GeminiClientAdapter.js +2 -2
  32. package/dist/llm/clients/LlamaCppClientAdapter.d.ts +1 -1
  33. package/dist/llm/clients/LlamaCppClientAdapter.js +3 -3
  34. package/dist/llm/clients/OpenAIClientAdapter.js +2 -2
  35. package/dist/llm/config.js +4 -28
  36. package/dist/llm/services/ModelResolver.d.ts +6 -4
  37. package/dist/providers/fromEnvironment.d.ts +5 -1
  38. package/dist/providers/fromEnvironment.js +29 -4
  39. package/dist/shared/adapters/errorUtils.d.ts +26 -0
  40. package/dist/shared/adapters/errorUtils.js +107 -0
  41. package/dist/shared/services/AdapterRegistry.d.ts +89 -0
  42. package/dist/shared/services/AdapterRegistry.js +144 -0
  43. package/dist/shared/services/PresetManager.d.ts +33 -0
  44. package/dist/shared/services/PresetManager.js +56 -0
  45. package/dist/types/image.d.ts +399 -0
  46. package/dist/types/image.js +8 -0
  47. package/dist/types.d.ts +6 -0
  48. package/package.json +1 -1
  49. package/src/config/presets.json +0 -327
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ /**
3
+ * OpenAI Images API Adapter
4
+ *
5
+ * Adapter for OpenAI's image generation API (DALL-E and GPT-Image models).
6
+ * Supports the /v1/images/generations endpoint.
7
+ *
8
+ * Supported models:
9
+ * - gpt-image-1-mini (default): Fast, efficient, 32K char prompts
10
+ * - gpt-image-1: Highest quality, 32K char prompts, advanced features
11
+ * - dall-e-3: High quality, 4K char prompts, only n=1
12
+ * - dall-e-2: Standard quality, 1K char prompts
13
+ *
14
+ * Based on: https://platform.openai.com/docs/api-reference/images/create
15
+ */
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.OpenAIImageAdapter = void 0;
21
+ const openai_1 = __importDefault(require("openai"));
22
+ const errorUtils_1 = require("../../shared/adapters/errorUtils");
23
+ /**
24
+ * Prompt length limits per model
25
+ */
26
+ const PROMPT_LIMITS = {
27
+ 'gpt-image-1': 32000,
28
+ 'gpt-image-1-mini': 32000,
29
+ 'dall-e-3': 4000,
30
+ 'dall-e-2': 1000,
31
+ };
32
+ /**
33
+ * Adapter for OpenAI's image generation API
34
+ */
35
+ class OpenAIImageAdapter {
36
+ constructor(config) {
37
+ this.id = 'openai-images';
38
+ this.supports = {
39
+ supportsMultipleImages: true,
40
+ supportsB64Json: true,
41
+ supportsHostedUrls: true,
42
+ supportsProgressEvents: false,
43
+ supportsNegativePrompt: false,
44
+ defaultModelId: 'gpt-image-1-mini',
45
+ };
46
+ this.baseURL = config?.baseURL;
47
+ this.timeout = config?.timeout || 60000;
48
+ }
49
+ /**
50
+ * Validates OpenAI API key format
51
+ */
52
+ validateApiKey(apiKey) {
53
+ // OpenAI API keys typically start with 'sk-' and are at least 20 characters
54
+ return apiKey.startsWith('sk-') && apiKey.length >= 20;
55
+ }
56
+ /**
57
+ * Generates images using OpenAI's API
58
+ */
59
+ async generate(config) {
60
+ const { request, resolvedPrompt, settings, apiKey } = config;
61
+ if (!apiKey) {
62
+ throw new Error('OpenAI API key is required but was not provided');
63
+ }
64
+ try {
65
+ // Validate prompt length
66
+ this.validatePromptLength(resolvedPrompt, request.modelId);
67
+ // Validate dall-e-3 constraints
68
+ if (request.modelId === 'dall-e-3') {
69
+ const count = request.count || settings.n || 1;
70
+ if (count > 1) {
71
+ throw new Error('dall-e-3 only supports generating 1 image at a time (n=1)');
72
+ }
73
+ }
74
+ // Initialize OpenAI client
75
+ const client = new openai_1.default({
76
+ apiKey,
77
+ ...(this.baseURL && { baseURL: this.baseURL }),
78
+ timeout: this.timeout,
79
+ });
80
+ // Determine if this is a gpt-image-1 model
81
+ const isGptImageModel = request.modelId.startsWith('gpt-image-1');
82
+ // Build request parameters
83
+ const params = {
84
+ model: request.modelId,
85
+ prompt: resolvedPrompt,
86
+ n: request.count || settings.n || 1,
87
+ };
88
+ // Add model-specific parameters
89
+ if (isGptImageModel) {
90
+ // gpt-image-1 models: use new parameter format
91
+ this.addGptImageParams(params, settings);
92
+ }
93
+ else {
94
+ // dall-e-2/dall-e-3: use traditional parameters
95
+ this.addDalleParams(params, settings);
96
+ }
97
+ console.log(`OpenAI Image API call for model: ${request.modelId}`, {
98
+ model: params.model,
99
+ promptLength: resolvedPrompt.length,
100
+ n: params.n,
101
+ isGptImageModel,
102
+ });
103
+ // Make API call
104
+ const response = await client.images.generate(params);
105
+ if (!response.data || response.data.length === 0) {
106
+ throw new Error('OpenAI API returned no images in response');
107
+ }
108
+ console.log(`OpenAI Image API call successful, generated ${response.data.length} images`);
109
+ // Process response
110
+ return await this.processResponse(response, request, isGptImageModel);
111
+ }
112
+ catch (error) {
113
+ console.error('OpenAI Image API error:', error);
114
+ throw this.handleError(error, request);
115
+ }
116
+ }
117
+ /**
118
+ * Validates prompt length for the given model
119
+ */
120
+ validatePromptLength(prompt, modelId) {
121
+ const limit = PROMPT_LIMITS[modelId];
122
+ if (limit && prompt.length > limit) {
123
+ throw new Error(`Prompt too long for model ${modelId}: ${prompt.length} characters (max: ${limit})`);
124
+ }
125
+ }
126
+ /**
127
+ * Converts width and height to OpenAI size format (e.g., "1024x1024")
128
+ */
129
+ toSizeString(width, height) {
130
+ return `${width}x${height}`;
131
+ }
132
+ /**
133
+ * Adds gpt-image-1 specific parameters to the request
134
+ */
135
+ addGptImageParams(params, settings) {
136
+ // Size (supports auto, 1024x1024, 1536x1024, 1024x1536)
137
+ // Convert width/height to OpenAI's size format
138
+ params.size = this.toSizeString(settings.width, settings.height);
139
+ // Quality (auto, high, medium, low)
140
+ if (settings.quality) {
141
+ params.quality = settings.quality;
142
+ }
143
+ // For gpt-image-1, use settings.openai namespace
144
+ const openaiSettings = settings.openai;
145
+ if (openaiSettings) {
146
+ if (openaiSettings.outputFormat) {
147
+ params.output_format = openaiSettings.outputFormat;
148
+ }
149
+ if (openaiSettings.background) {
150
+ params.background = openaiSettings.background;
151
+ }
152
+ if (openaiSettings.moderation) {
153
+ params.moderation = openaiSettings.moderation;
154
+ }
155
+ if (openaiSettings.outputCompression !== undefined) {
156
+ params.output_compression = openaiSettings.outputCompression;
157
+ }
158
+ }
159
+ // User tracking
160
+ if (settings.user) {
161
+ params.user = settings.user;
162
+ }
163
+ // Note: gpt-image-1 always returns base64, no response_format parameter needed
164
+ }
165
+ /**
166
+ * Adds dall-e-2/dall-e-3 specific parameters to the request
167
+ */
168
+ addDalleParams(params, settings) {
169
+ // Size (model-specific options)
170
+ // Convert width/height to OpenAI's size format
171
+ params.size = this.toSizeString(settings.width, settings.height);
172
+ // Quality and Style are only supported by dall-e-3
173
+ const isDallE3 = params.model === 'dall-e-3';
174
+ if (isDallE3) {
175
+ // Quality (hd or standard for dall-e-3 only)
176
+ if (settings.quality) {
177
+ params.quality = settings.quality;
178
+ }
179
+ // Style (vivid or natural for dall-e-3 only)
180
+ if (settings.style) {
181
+ params.style = settings.style;
182
+ }
183
+ }
184
+ // Response format (url or b64_json)
185
+ // Default to b64_json for consistency (gpt-image-1 only returns base64)
186
+ if (settings.responseFormat === 'url') {
187
+ params.response_format = 'url';
188
+ }
189
+ else {
190
+ params.response_format = 'b64_json';
191
+ }
192
+ // User tracking
193
+ if (settings.user) {
194
+ params.user = settings.user;
195
+ }
196
+ }
197
+ /**
198
+ * Processes the OpenAI API response and converts to ImageGenerationResponse
199
+ */
200
+ async processResponse(response, request, isGptImageModel) {
201
+ const images = [];
202
+ for (let i = 0; i < response.data.length; i++) {
203
+ const item = response.data[i];
204
+ let imageBuffer;
205
+ let mimeType = 'image/png';
206
+ let imageUrl;
207
+ let b64String;
208
+ if (isGptImageModel) {
209
+ // gpt-image-1 models always return base64
210
+ if (!item.b64_json) {
211
+ throw new Error(`Expected b64_json in response for gpt-image-1 model, but got: ${JSON.stringify(item)}`);
212
+ }
213
+ const b64Data = item.b64_json;
214
+ b64String = b64Data;
215
+ imageBuffer = Buffer.from(b64Data, 'base64');
216
+ // Determine mime type from output_format parameter (if we have access to it)
217
+ // For now, default to PNG (most common)
218
+ mimeType = 'image/png';
219
+ }
220
+ else {
221
+ // dall-e-2/dall-e-3: can be url or b64_json
222
+ if (item.url) {
223
+ // Fetch image from URL
224
+ imageUrl = item.url;
225
+ const imageResponse = await fetch(item.url);
226
+ if (!imageResponse.ok) {
227
+ throw new Error(`Failed to fetch image from URL: ${imageResponse.statusText}`);
228
+ }
229
+ const arrayBuffer = await imageResponse.arrayBuffer();
230
+ imageBuffer = Buffer.from(arrayBuffer);
231
+ // Infer mime type from URL or default to PNG
232
+ if (item.url.includes('.jpeg') || item.url.includes('.jpg')) {
233
+ mimeType = 'image/jpeg';
234
+ }
235
+ else if (item.url.includes('.webp')) {
236
+ mimeType = 'image/webp';
237
+ }
238
+ }
239
+ else if (item.b64_json) {
240
+ // Base64 encoded
241
+ const b64Data = item.b64_json;
242
+ b64String = b64Data;
243
+ imageBuffer = Buffer.from(b64Data, 'base64');
244
+ mimeType = 'image/png';
245
+ }
246
+ else {
247
+ throw new Error('OpenAI response contained neither url nor b64_json');
248
+ }
249
+ }
250
+ images.push({
251
+ index: i,
252
+ mimeType,
253
+ data: imageBuffer,
254
+ ...(imageUrl && { url: imageUrl }),
255
+ ...(b64String && { b64Json: b64String }),
256
+ prompt: request.prompt,
257
+ // OpenAI doesn't return seed in the response
258
+ });
259
+ }
260
+ // Extract usage data if available
261
+ const usage = response.usage
262
+ ? {
263
+ inputTokens: response.usage.input_tokens,
264
+ outputTokens: response.usage.output_tokens,
265
+ }
266
+ : undefined;
267
+ return {
268
+ object: 'image.result',
269
+ created: response.created || Math.floor(Date.now() / 1000),
270
+ providerId: this.id,
271
+ modelId: request.modelId,
272
+ data: images,
273
+ ...(usage && { usage }),
274
+ };
275
+ }
276
+ /**
277
+ * Handles errors from OpenAI API and converts to standard format
278
+ */
279
+ handleError(error, request) {
280
+ // Use shared error mapping utility
281
+ const mapped = (0, errorUtils_1.getCommonMappedErrorDetails)(error);
282
+ // Enhance error message with context
283
+ let errorMessage = mapped.errorMessage;
284
+ // Add baseURL context for network errors
285
+ if (mapped.errorCode === 'NETWORK_ERROR') {
286
+ const baseUrl = this.baseURL || 'https://api.openai.com/v1';
287
+ errorMessage = `${errorMessage} (connecting to ${baseUrl})`;
288
+ }
289
+ // Add model-specific context for validation errors
290
+ if (mapped.errorType === 'invalid_request_error' && error.message) {
291
+ errorMessage = error.message;
292
+ }
293
+ // Create enhanced error with all details
294
+ const enhancedError = new Error(errorMessage);
295
+ enhancedError.code = mapped.errorCode;
296
+ enhancedError.type = mapped.errorType;
297
+ enhancedError.status = mapped.status;
298
+ enhancedError.providerId = this.id;
299
+ enhancedError.modelId = request.modelId;
300
+ return enhancedError;
301
+ }
302
+ }
303
+ exports.OpenAIImageAdapter = OpenAIImageAdapter;
@@ -0,0 +1,194 @@
1
+ [
2
+ {
3
+ "id": "openai-gpt-image-1-mini-default",
4
+ "displayName": "OpenAI - GPT-Image 1 Mini",
5
+ "description": "Fast and efficient image generation with GPT-Image (32K char prompts)",
6
+ "providerId": "openai-images",
7
+ "modelId": "gpt-image-1-mini",
8
+ "settings": {
9
+ "width": 1024,
10
+ "height": 1024,
11
+ "quality": "auto",
12
+ "responseFormat": "buffer",
13
+ "openai": {
14
+ "outputFormat": "png",
15
+ "background": "auto",
16
+ "moderation": "auto"
17
+ }
18
+ }
19
+ },
20
+ {
21
+ "id": "openai-gpt-image-1-quality",
22
+ "displayName": "OpenAI - GPT-Image 1 (High Quality)",
23
+ "description": "Highest quality OpenAI image model with advanced features (32K char prompts)",
24
+ "providerId": "openai-images",
25
+ "modelId": "gpt-image-1",
26
+ "settings": {
27
+ "width": 1024,
28
+ "height": 1024,
29
+ "quality": "high",
30
+ "responseFormat": "buffer",
31
+ "openai": {
32
+ "outputFormat": "png",
33
+ "background": "auto",
34
+ "moderation": "auto"
35
+ }
36
+ }
37
+ },
38
+ {
39
+ "id": "openai-dalle-3-hd",
40
+ "displayName": "OpenAI - DALL-E 3 HD",
41
+ "description": "High-quality DALL-E 3 with vivid style (4K char prompts)",
42
+ "providerId": "openai-images",
43
+ "modelId": "dall-e-3",
44
+ "settings": {
45
+ "width": 1024,
46
+ "height": 1024,
47
+ "quality": "hd",
48
+ "style": "vivid",
49
+ "responseFormat": "buffer"
50
+ }
51
+ },
52
+ {
53
+ "id": "openai-dalle-3-natural",
54
+ "displayName": "OpenAI - DALL-E 3 Natural",
55
+ "description": "DALL-E 3 with natural style for realistic photographs (4K char prompts)",
56
+ "providerId": "openai-images",
57
+ "modelId": "dall-e-3",
58
+ "settings": {
59
+ "width": 1024,
60
+ "height": 1024,
61
+ "quality": "standard",
62
+ "style": "natural",
63
+ "responseFormat": "buffer"
64
+ }
65
+ },
66
+ {
67
+ "id": "openai-dalle-2-default",
68
+ "displayName": "OpenAI - DALL-E 2",
69
+ "description": "Cost-effective DALL-E 2 generation (1K char prompts)",
70
+ "providerId": "openai-images",
71
+ "modelId": "dall-e-2",
72
+ "settings": {
73
+ "width": 1024,
74
+ "height": 1024,
75
+ "quality": "standard",
76
+ "responseFormat": "buffer"
77
+ }
78
+ },
79
+ {
80
+ "id": "openai-dalle-2-fast",
81
+ "displayName": "OpenAI - DALL-E 2 Fast",
82
+ "description": "Rapid prototyping with smaller image size (1K char prompts)",
83
+ "providerId": "openai-images",
84
+ "modelId": "dall-e-2",
85
+ "settings": {
86
+ "width": 512,
87
+ "height": 512,
88
+ "quality": "standard",
89
+ "responseFormat": "buffer"
90
+ }
91
+ },
92
+ {
93
+ "id": "genai-electron-sdxl-quality",
94
+ "displayName": "Local - SDXL Quality",
95
+ "description": "High-quality SDXL generation for final production images",
96
+ "providerId": "genai-electron-images",
97
+ "modelId": "stable-diffusion",
98
+ "settings": {
99
+ "width": 1024,
100
+ "height": 1024,
101
+ "responseFormat": "buffer",
102
+ "diffusion": {
103
+ "steps": 30,
104
+ "cfgScale": 7.5,
105
+ "sampler": "dpm++2m"
106
+ }
107
+ }
108
+ },
109
+ {
110
+ "id": "genai-electron-sdxl-balanced",
111
+ "displayName": "Local - SDXL Balanced",
112
+ "description": "Balanced quality and speed for general use",
113
+ "providerId": "genai-electron-images",
114
+ "modelId": "stable-diffusion",
115
+ "settings": {
116
+ "width": 768,
117
+ "height": 768,
118
+ "responseFormat": "buffer",
119
+ "diffusion": {
120
+ "steps": 20,
121
+ "cfgScale": 7.0,
122
+ "sampler": "euler_a"
123
+ }
124
+ }
125
+ },
126
+ {
127
+ "id": "genai-electron-sdxl-fast",
128
+ "displayName": "Local - SDXL Fast",
129
+ "description": "Quick iterations with reduced steps",
130
+ "providerId": "genai-electron-images",
131
+ "modelId": "stable-diffusion",
132
+ "settings": {
133
+ "width": 512,
134
+ "height": 512,
135
+ "responseFormat": "buffer",
136
+ "diffusion": {
137
+ "steps": 15,
138
+ "cfgScale": 6.5,
139
+ "sampler": "euler_a"
140
+ }
141
+ }
142
+ },
143
+ {
144
+ "id": "genai-electron-sdxl-portrait",
145
+ "displayName": "Local - SDXL Portrait",
146
+ "description": "Portrait-oriented image generation",
147
+ "providerId": "genai-electron-images",
148
+ "modelId": "stable-diffusion",
149
+ "settings": {
150
+ "width": 768,
151
+ "height": 1024,
152
+ "responseFormat": "buffer",
153
+ "diffusion": {
154
+ "steps": 20,
155
+ "cfgScale": 7.5,
156
+ "sampler": "dpm++2m"
157
+ }
158
+ }
159
+ },
160
+ {
161
+ "id": "genai-electron-sdxl-turbo",
162
+ "displayName": "Local - SDXL Turbo",
163
+ "description": "Real-time generation with SDXL Turbo (optimal at 512x512, 1-4 steps)",
164
+ "providerId": "genai-electron-images",
165
+ "modelId": "sdxl-turbo",
166
+ "settings": {
167
+ "width": 512,
168
+ "height": 512,
169
+ "responseFormat": "buffer",
170
+ "diffusion": {
171
+ "steps": 4,
172
+ "cfgScale": 1.0,
173
+ "sampler": "euler_a"
174
+ }
175
+ }
176
+ },
177
+ {
178
+ "id": "genai-electron-sdxl-lightning",
179
+ "displayName": "Local - SDXL Lightning",
180
+ "description": "Lightning-fast generation with quality (trained at 1024x1024, 2-8 steps)",
181
+ "providerId": "genai-electron-images",
182
+ "modelId": "sdxl-lightning",
183
+ "settings": {
184
+ "width": 1024,
185
+ "height": 1024,
186
+ "responseFormat": "buffer",
187
+ "diffusion": {
188
+ "steps": 8,
189
+ "cfgScale": 1.0,
190
+ "sampler": "euler_a"
191
+ }
192
+ }
193
+ }
194
+ ]