@push.rocks/smartai 0.13.3 → 2.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/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/index.d.ts +6 -11
- package/dist_ts/index.js +6 -12
- package/dist_ts/plugins.d.ts +10 -15
- package/dist_ts/plugins.js +13 -19
- package/dist_ts/smartai.classes.smartai.d.ts +7 -0
- package/dist_ts/smartai.classes.smartai.js +51 -0
- package/dist_ts/smartai.interfaces.d.ts +41 -0
- package/dist_ts/smartai.interfaces.js +2 -0
- package/dist_ts/smartai.middleware.anthropic.d.ts +7 -0
- package/dist_ts/smartai.middleware.anthropic.js +36 -0
- package/dist_ts/smartai.provider.ollama.d.ts +8 -0
- package/dist_ts/smartai.provider.ollama.js +378 -0
- package/dist_ts_audio/index.d.ts +9 -0
- package/dist_ts_audio/index.js +15 -0
- package/dist_ts_audio/plugins.d.ts +2 -0
- package/dist_ts_audio/plugins.js +3 -0
- package/dist_ts_document/index.d.ts +11 -0
- package/dist_ts_document/index.js +45 -0
- package/dist_ts_document/plugins.d.ts +3 -0
- package/dist_ts_document/plugins.js +4 -0
- package/dist_ts_image/index.d.ts +46 -0
- package/dist_ts_image/index.js +110 -0
- package/dist_ts_image/plugins.d.ts +3 -0
- package/dist_ts_image/plugins.js +4 -0
- package/dist_ts_research/index.d.ts +19 -0
- package/dist_ts_research/index.js +98 -0
- package/dist_ts_research/plugins.d.ts +2 -0
- package/dist_ts_research/plugins.js +3 -0
- package/dist_ts_vision/index.d.ts +8 -0
- package/dist_ts_vision/index.js +21 -0
- package/dist_ts_vision/plugins.d.ts +2 -0
- package/dist_ts_vision/plugins.js +3 -0
- package/package.json +50 -22
- package/readme.hints.md +34 -88
- package/readme.md +284 -547
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/index.ts +8 -11
- package/ts/plugins.ts +19 -35
- package/ts/smartai.classes.smartai.ts +51 -0
- package/ts/smartai.interfaces.ts +53 -0
- package/ts/smartai.middleware.anthropic.ts +38 -0
- package/ts/smartai.provider.ollama.ts +426 -0
- package/ts_audio/index.ts +24 -0
- package/ts_audio/plugins.ts +2 -0
- package/ts_document/index.ts +61 -0
- package/ts_document/plugins.ts +3 -0
- package/ts_image/index.ts +147 -0
- package/ts_image/plugins.ts +3 -0
- package/ts_research/index.ts +120 -0
- package/ts_research/plugins.ts +2 -0
- package/ts_vision/index.ts +29 -0
- package/ts_vision/plugins.ts +2 -0
- package/dist_ts/abstract.classes.multimodal.d.ts +0 -212
- package/dist_ts/abstract.classes.multimodal.js +0 -43
- package/dist_ts/classes.conversation.d.ts +0 -31
- package/dist_ts/classes.conversation.js +0 -150
- package/dist_ts/classes.smartai.d.ts +0 -59
- package/dist_ts/classes.smartai.js +0 -139
- package/dist_ts/classes.tts.d.ts +0 -6
- package/dist_ts/classes.tts.js +0 -10
- package/dist_ts/interfaces.d.ts +0 -1
- package/dist_ts/interfaces.js +0 -2
- package/dist_ts/paths.d.ts +0 -2
- package/dist_ts/paths.js +0 -4
- package/dist_ts/provider.anthropic.d.ts +0 -48
- package/dist_ts/provider.anthropic.js +0 -369
- package/dist_ts/provider.elevenlabs.d.ts +0 -43
- package/dist_ts/provider.elevenlabs.js +0 -64
- package/dist_ts/provider.exo.d.ts +0 -40
- package/dist_ts/provider.exo.js +0 -116
- package/dist_ts/provider.groq.d.ts +0 -39
- package/dist_ts/provider.groq.js +0 -178
- package/dist_ts/provider.mistral.d.ts +0 -61
- package/dist_ts/provider.mistral.js +0 -288
- package/dist_ts/provider.ollama.d.ts +0 -141
- package/dist_ts/provider.ollama.js +0 -529
- package/dist_ts/provider.openai.d.ts +0 -62
- package/dist_ts/provider.openai.js +0 -403
- package/dist_ts/provider.perplexity.d.ts +0 -37
- package/dist_ts/provider.perplexity.js +0 -215
- package/dist_ts/provider.xai.d.ts +0 -52
- package/dist_ts/provider.xai.js +0 -160
- package/ts/abstract.classes.multimodal.ts +0 -240
- package/ts/classes.conversation.ts +0 -176
- package/ts/classes.smartai.ts +0 -187
- package/ts/classes.tts.ts +0 -15
- package/ts/interfaces.ts +0 -0
- package/ts/paths.ts +0 -4
- package/ts/provider.anthropic.ts +0 -446
- package/ts/provider.elevenlabs.ts +0 -116
- package/ts/provider.exo.ts +0 -155
- package/ts/provider.groq.ts +0 -219
- package/ts/provider.mistral.ts +0 -352
- package/ts/provider.ollama.ts +0 -705
- package/ts/provider.openai.ts +0 -462
- package/ts/provider.perplexity.ts +0 -259
- package/ts/provider.xai.ts +0 -214
package/ts/provider.openai.ts
DELETED
|
@@ -1,462 +0,0 @@
|
|
|
1
|
-
import * as plugins from './plugins.js';
|
|
2
|
-
import * as paths from './paths.js';
|
|
3
|
-
import { Readable } from 'stream';
|
|
4
|
-
import { toFile } from 'openai';
|
|
5
|
-
|
|
6
|
-
// Custom type definition for chat completion messages
|
|
7
|
-
export type TChatCompletionRequestMessage = {
|
|
8
|
-
role: "system" | "user" | "assistant";
|
|
9
|
-
content: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
import { MultiModalModel } from './abstract.classes.multimodal.js';
|
|
13
|
-
import type {
|
|
14
|
-
ResearchOptions,
|
|
15
|
-
ResearchResponse,
|
|
16
|
-
ImageGenerateOptions,
|
|
17
|
-
ImageEditOptions,
|
|
18
|
-
ImageResponse
|
|
19
|
-
} from './abstract.classes.multimodal.js';
|
|
20
|
-
|
|
21
|
-
export interface IOpenaiProviderOptions {
|
|
22
|
-
openaiToken: string;
|
|
23
|
-
chatModel?: string;
|
|
24
|
-
audioModel?: string;
|
|
25
|
-
visionModel?: string;
|
|
26
|
-
researchModel?: string;
|
|
27
|
-
imageModel?: string;
|
|
28
|
-
enableWebSearch?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export class OpenAiProvider extends MultiModalModel {
|
|
32
|
-
private options: IOpenaiProviderOptions;
|
|
33
|
-
public openAiApiClient: plugins.openai.default;
|
|
34
|
-
|
|
35
|
-
constructor(optionsArg: IOpenaiProviderOptions) {
|
|
36
|
-
super();
|
|
37
|
-
this.options = optionsArg;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
public async start() {
|
|
41
|
-
await super.start();
|
|
42
|
-
this.openAiApiClient = new plugins.openai.default({
|
|
43
|
-
apiKey: this.options.openaiToken,
|
|
44
|
-
dangerouslyAllowBrowser: true,
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
public async stop() {
|
|
49
|
-
await super.stop();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
public async chatStream(input: ReadableStream<Uint8Array>): Promise<ReadableStream<string>> {
|
|
53
|
-
// Create a TextDecoder to handle incoming chunks
|
|
54
|
-
const decoder = new TextDecoder();
|
|
55
|
-
let buffer = '';
|
|
56
|
-
let currentMessage: {
|
|
57
|
-
role: "function" | "user" | "system" | "assistant" | "tool" | "developer";
|
|
58
|
-
content: string;
|
|
59
|
-
} | null = null;
|
|
60
|
-
|
|
61
|
-
// Create a TransformStream to process the input
|
|
62
|
-
const transform = new TransformStream<Uint8Array, string>({
|
|
63
|
-
transform: async (chunk, controller) => {
|
|
64
|
-
buffer += decoder.decode(chunk, { stream: true });
|
|
65
|
-
|
|
66
|
-
// Try to parse complete JSON messages from the buffer
|
|
67
|
-
while (true) {
|
|
68
|
-
const newlineIndex = buffer.indexOf('\n');
|
|
69
|
-
if (newlineIndex === -1) break;
|
|
70
|
-
|
|
71
|
-
const line = buffer.slice(0, newlineIndex);
|
|
72
|
-
buffer = buffer.slice(newlineIndex + 1);
|
|
73
|
-
|
|
74
|
-
if (line.trim()) {
|
|
75
|
-
try {
|
|
76
|
-
const message = JSON.parse(line);
|
|
77
|
-
currentMessage = {
|
|
78
|
-
role: (message.role || 'user') as "function" | "user" | "system" | "assistant" | "tool" | "developer",
|
|
79
|
-
content: message.content || '',
|
|
80
|
-
};
|
|
81
|
-
} catch (e) {
|
|
82
|
-
console.error('Failed to parse message:', e);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// If we have a complete message, send it to OpenAI
|
|
88
|
-
if (currentMessage) {
|
|
89
|
-
const messageToSend = { role: "user" as const, content: currentMessage.content };
|
|
90
|
-
const chatModel = this.options.chatModel ?? 'gpt-5-mini';
|
|
91
|
-
const requestParams: any = {
|
|
92
|
-
model: chatModel,
|
|
93
|
-
messages: [messageToSend],
|
|
94
|
-
stream: true,
|
|
95
|
-
};
|
|
96
|
-
// Temperature is omitted since the model does not support it.
|
|
97
|
-
const stream = await this.openAiApiClient.chat.completions.create(requestParams);
|
|
98
|
-
// Explicitly cast the stream as an async iterable to satisfy TypeScript.
|
|
99
|
-
const streamAsyncIterable = stream as unknown as AsyncIterableIterator<any>;
|
|
100
|
-
// Process each chunk from OpenAI
|
|
101
|
-
for await (const chunk of streamAsyncIterable) {
|
|
102
|
-
const content = chunk.choices[0]?.delta?.content;
|
|
103
|
-
if (content) {
|
|
104
|
-
controller.enqueue(content);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
currentMessage = null;
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
flush(controller) {
|
|
112
|
-
if (buffer) {
|
|
113
|
-
try {
|
|
114
|
-
const message = JSON.parse(buffer);
|
|
115
|
-
controller.enqueue(message.content || '');
|
|
116
|
-
} catch (e) {
|
|
117
|
-
console.error('Failed to parse remaining buffer:', e);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// Connect the input to our transform stream
|
|
124
|
-
return input.pipeThrough(transform);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Implementing the synchronous chat interaction
|
|
128
|
-
public async chat(optionsArg: {
|
|
129
|
-
systemMessage: string;
|
|
130
|
-
userMessage: string;
|
|
131
|
-
messageHistory: {
|
|
132
|
-
role: 'assistant' | 'user';
|
|
133
|
-
content: string;
|
|
134
|
-
}[];
|
|
135
|
-
}) {
|
|
136
|
-
const chatModel = this.options.chatModel ?? 'gpt-5-mini';
|
|
137
|
-
const requestParams: any = {
|
|
138
|
-
model: chatModel,
|
|
139
|
-
messages: [
|
|
140
|
-
{ role: 'system', content: optionsArg.systemMessage },
|
|
141
|
-
...optionsArg.messageHistory,
|
|
142
|
-
{ role: 'user', content: optionsArg.userMessage },
|
|
143
|
-
],
|
|
144
|
-
};
|
|
145
|
-
// Temperature parameter removed to avoid unsupported error.
|
|
146
|
-
const result = await this.openAiApiClient.chat.completions.create(requestParams);
|
|
147
|
-
return {
|
|
148
|
-
role: result.choices[0].message.role as 'assistant',
|
|
149
|
-
message: result.choices[0].message.content,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
public async audio(optionsArg: { message: string }): Promise<NodeJS.ReadableStream> {
|
|
154
|
-
const done = plugins.smartpromise.defer<NodeJS.ReadableStream>();
|
|
155
|
-
const result = await this.openAiApiClient.audio.speech.create({
|
|
156
|
-
model: this.options.audioModel ?? 'tts-1-hd',
|
|
157
|
-
input: optionsArg.message,
|
|
158
|
-
voice: 'nova',
|
|
159
|
-
response_format: 'mp3',
|
|
160
|
-
speed: 1,
|
|
161
|
-
});
|
|
162
|
-
const stream = result.body;
|
|
163
|
-
const nodeStream = Readable.fromWeb(stream as any);
|
|
164
|
-
done.resolve(nodeStream);
|
|
165
|
-
return done.promise;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
public async document(optionsArg: {
|
|
169
|
-
systemMessage: string;
|
|
170
|
-
userMessage: string;
|
|
171
|
-
pdfDocuments: Uint8Array[];
|
|
172
|
-
messageHistory: {
|
|
173
|
-
role: 'assistant' | 'user';
|
|
174
|
-
content: any;
|
|
175
|
-
}[];
|
|
176
|
-
}) {
|
|
177
|
-
// Ensure SmartPdf is initialized before processing documents
|
|
178
|
-
await this.ensureSmartpdfReady();
|
|
179
|
-
|
|
180
|
-
let pdfDocumentImageBytesArray: Uint8Array[] = [];
|
|
181
|
-
|
|
182
|
-
// Convert each PDF into one or more image byte arrays.
|
|
183
|
-
for (const pdfDocument of optionsArg.pdfDocuments) {
|
|
184
|
-
const documentImageArray = await this.smartpdfInstance!.convertPDFToPngBytes(pdfDocument);
|
|
185
|
-
pdfDocumentImageBytesArray = pdfDocumentImageBytesArray.concat(documentImageArray);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
console.log(`image smartfile array`);
|
|
189
|
-
console.log(pdfDocumentImageBytesArray.map((smartfile) => smartfile.length));
|
|
190
|
-
|
|
191
|
-
// Filter out any empty buffers to avoid sending invalid image URLs.
|
|
192
|
-
const validImageBytesArray = pdfDocumentImageBytesArray.filter(imageBytes => imageBytes && imageBytes.length > 0);
|
|
193
|
-
const imageAttachments = validImageBytesArray.map(imageBytes => ({
|
|
194
|
-
type: 'image_url',
|
|
195
|
-
image_url: {
|
|
196
|
-
url: 'data:image/png;base64,' + Buffer.from(imageBytes).toString('base64'),
|
|
197
|
-
},
|
|
198
|
-
}));
|
|
199
|
-
|
|
200
|
-
const chatModel = this.options.chatModel ?? 'gpt-5-mini';
|
|
201
|
-
const requestParams: any = {
|
|
202
|
-
model: chatModel,
|
|
203
|
-
messages: [
|
|
204
|
-
{ role: 'system', content: optionsArg.systemMessage },
|
|
205
|
-
...optionsArg.messageHistory,
|
|
206
|
-
{
|
|
207
|
-
role: 'user',
|
|
208
|
-
content: [
|
|
209
|
-
{ type: 'text', text: optionsArg.userMessage },
|
|
210
|
-
...imageAttachments,
|
|
211
|
-
],
|
|
212
|
-
},
|
|
213
|
-
],
|
|
214
|
-
};
|
|
215
|
-
// Temperature parameter removed.
|
|
216
|
-
const result = await this.openAiApiClient.chat.completions.create(requestParams);
|
|
217
|
-
return {
|
|
218
|
-
message: result.choices[0].message,
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
public async vision(optionsArg: { image: Buffer; prompt: string }): Promise<string> {
|
|
223
|
-
const visionModel = this.options.visionModel ?? '04-mini';
|
|
224
|
-
const requestParams: any = {
|
|
225
|
-
model: visionModel,
|
|
226
|
-
messages: [
|
|
227
|
-
{
|
|
228
|
-
role: 'user',
|
|
229
|
-
content: [
|
|
230
|
-
{ type: 'text', text: optionsArg.prompt },
|
|
231
|
-
{
|
|
232
|
-
type: 'image_url',
|
|
233
|
-
image_url: {
|
|
234
|
-
url: `data:image/jpeg;base64,${optionsArg.image.toString('base64')}`
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
]
|
|
238
|
-
}
|
|
239
|
-
],
|
|
240
|
-
max_tokens: 300
|
|
241
|
-
};
|
|
242
|
-
const result = await this.openAiApiClient.chat.completions.create(requestParams);
|
|
243
|
-
return result.choices[0].message.content || '';
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
public async research(optionsArg: ResearchOptions): Promise<ResearchResponse> {
|
|
247
|
-
// Determine which model to use - Deep Research API requires specific models
|
|
248
|
-
let model: string;
|
|
249
|
-
if (optionsArg.searchDepth === 'deep') {
|
|
250
|
-
model = this.options.researchModel || 'o4-mini-deep-research-2025-06-26';
|
|
251
|
-
} else {
|
|
252
|
-
// For basic/advanced, still use deep research models if web search is needed
|
|
253
|
-
if (optionsArg.includeWebSearch) {
|
|
254
|
-
model = this.options.researchModel || 'o4-mini-deep-research-2025-06-26';
|
|
255
|
-
} else {
|
|
256
|
-
model = this.options.chatModel || 'gpt-5-mini';
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const systemMessage = 'You are a research assistant. Provide comprehensive answers with citations and sources when available.';
|
|
261
|
-
|
|
262
|
-
// Prepare request parameters using Deep Research API format
|
|
263
|
-
const requestParams: any = {
|
|
264
|
-
model,
|
|
265
|
-
instructions: systemMessage,
|
|
266
|
-
input: optionsArg.query
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
// Add web search tool if requested
|
|
270
|
-
if (optionsArg.includeWebSearch || optionsArg.searchDepth === 'deep') {
|
|
271
|
-
requestParams.tools = [
|
|
272
|
-
{
|
|
273
|
-
type: 'web_search_preview',
|
|
274
|
-
search_context_size: optionsArg.searchDepth === 'deep' ? 'high' :
|
|
275
|
-
optionsArg.searchDepth === 'advanced' ? 'medium' : 'low'
|
|
276
|
-
}
|
|
277
|
-
];
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Add background flag for deep research
|
|
281
|
-
if (optionsArg.background && optionsArg.searchDepth === 'deep') {
|
|
282
|
-
requestParams.background = true;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
try {
|
|
286
|
-
// Execute the research request using Deep Research API
|
|
287
|
-
const result = await this.openAiApiClient.responses.create(requestParams);
|
|
288
|
-
|
|
289
|
-
// Extract the answer from output items
|
|
290
|
-
let answer = '';
|
|
291
|
-
const sources: Array<{ url: string; title: string; snippet: string }> = [];
|
|
292
|
-
const searchQueries: string[] = [];
|
|
293
|
-
|
|
294
|
-
// Process output items
|
|
295
|
-
for (const item of result.output || []) {
|
|
296
|
-
// Extract message content
|
|
297
|
-
if (item.type === 'message' && 'content' in item) {
|
|
298
|
-
const messageItem = item as any;
|
|
299
|
-
for (const contentItem of messageItem.content || []) {
|
|
300
|
-
if (contentItem.type === 'output_text' && 'text' in contentItem) {
|
|
301
|
-
answer += contentItem.text;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Extract web search queries
|
|
307
|
-
if (item.type === 'web_search_call' && 'action' in item) {
|
|
308
|
-
const searchItem = item as any;
|
|
309
|
-
if (searchItem.action && searchItem.action.type === 'search' && 'query' in searchItem.action) {
|
|
310
|
-
searchQueries.push(searchItem.action.query);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// Parse sources from markdown links in the answer
|
|
316
|
-
const urlRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
317
|
-
let match: RegExpExecArray | null;
|
|
318
|
-
|
|
319
|
-
while ((match = urlRegex.exec(answer)) !== null) {
|
|
320
|
-
sources.push({
|
|
321
|
-
title: match[1],
|
|
322
|
-
url: match[2],
|
|
323
|
-
snippet: ''
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return {
|
|
328
|
-
answer,
|
|
329
|
-
sources,
|
|
330
|
-
searchQueries: searchQueries.length > 0 ? searchQueries : undefined,
|
|
331
|
-
metadata: {
|
|
332
|
-
model,
|
|
333
|
-
searchDepth: optionsArg.searchDepth || 'basic',
|
|
334
|
-
tokensUsed: result.usage?.total_tokens
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
} catch (error) {
|
|
338
|
-
console.error('Research API error:', error);
|
|
339
|
-
throw new Error(`Failed to perform research: ${error.message}`);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Image generation using OpenAI's gpt-image-1 or DALL-E models
|
|
345
|
-
*/
|
|
346
|
-
public async imageGenerate(optionsArg: ImageGenerateOptions): Promise<ImageResponse> {
|
|
347
|
-
const model = optionsArg.model || this.options.imageModel || 'gpt-image-1';
|
|
348
|
-
|
|
349
|
-
try {
|
|
350
|
-
const requestParams: any = {
|
|
351
|
-
model,
|
|
352
|
-
prompt: optionsArg.prompt,
|
|
353
|
-
n: optionsArg.n || 1,
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
// Add gpt-image-1 specific parameters
|
|
357
|
-
if (model === 'gpt-image-1') {
|
|
358
|
-
if (optionsArg.quality) requestParams.quality = optionsArg.quality;
|
|
359
|
-
if (optionsArg.size) requestParams.size = optionsArg.size;
|
|
360
|
-
if (optionsArg.background) requestParams.background = optionsArg.background;
|
|
361
|
-
if (optionsArg.outputFormat) requestParams.output_format = optionsArg.outputFormat;
|
|
362
|
-
if (optionsArg.outputCompression !== undefined) requestParams.output_compression = optionsArg.outputCompression;
|
|
363
|
-
if (optionsArg.moderation) requestParams.moderation = optionsArg.moderation;
|
|
364
|
-
if (optionsArg.stream !== undefined) requestParams.stream = optionsArg.stream;
|
|
365
|
-
if (optionsArg.partialImages !== undefined) requestParams.partial_images = optionsArg.partialImages;
|
|
366
|
-
} else if (model === 'dall-e-3') {
|
|
367
|
-
// DALL-E 3 specific parameters
|
|
368
|
-
if (optionsArg.quality) requestParams.quality = optionsArg.quality;
|
|
369
|
-
if (optionsArg.size) requestParams.size = optionsArg.size;
|
|
370
|
-
if (optionsArg.style) requestParams.style = optionsArg.style;
|
|
371
|
-
requestParams.response_format = 'b64_json'; // Always use base64 for consistency
|
|
372
|
-
} else if (model === 'dall-e-2') {
|
|
373
|
-
// DALL-E 2 specific parameters
|
|
374
|
-
if (optionsArg.size) requestParams.size = optionsArg.size;
|
|
375
|
-
requestParams.response_format = 'b64_json';
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
const result = await this.openAiApiClient.images.generate(requestParams);
|
|
379
|
-
|
|
380
|
-
const images = (result.data || []).map(img => ({
|
|
381
|
-
b64_json: img.b64_json,
|
|
382
|
-
url: img.url,
|
|
383
|
-
revisedPrompt: img.revised_prompt
|
|
384
|
-
}));
|
|
385
|
-
|
|
386
|
-
return {
|
|
387
|
-
images,
|
|
388
|
-
metadata: {
|
|
389
|
-
model,
|
|
390
|
-
quality: result.quality,
|
|
391
|
-
size: result.size,
|
|
392
|
-
outputFormat: result.output_format,
|
|
393
|
-
tokensUsed: result.usage?.total_tokens
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
} catch (error) {
|
|
397
|
-
console.error('Image generation error:', error);
|
|
398
|
-
throw new Error(`Failed to generate image: ${error.message}`);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Image editing using OpenAI's gpt-image-1 or DALL-E 2 models
|
|
404
|
-
*/
|
|
405
|
-
public async imageEdit(optionsArg: ImageEditOptions): Promise<ImageResponse> {
|
|
406
|
-
const model = optionsArg.model || this.options.imageModel || 'gpt-image-1';
|
|
407
|
-
|
|
408
|
-
try {
|
|
409
|
-
// Convert Buffer to uploadable file format for OpenAI API
|
|
410
|
-
const imageFile = await toFile(optionsArg.image, 'image.png', { type: 'image/png' });
|
|
411
|
-
|
|
412
|
-
const requestParams: any = {
|
|
413
|
-
model,
|
|
414
|
-
image: imageFile,
|
|
415
|
-
prompt: optionsArg.prompt,
|
|
416
|
-
n: optionsArg.n || 1,
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
// Add mask if provided (also convert to file format)
|
|
420
|
-
if (optionsArg.mask) {
|
|
421
|
-
requestParams.mask = await toFile(optionsArg.mask, 'mask.png', { type: 'image/png' });
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Add gpt-image-1 specific parameters
|
|
425
|
-
if (model === 'gpt-image-1') {
|
|
426
|
-
if (optionsArg.quality) requestParams.quality = optionsArg.quality;
|
|
427
|
-
if (optionsArg.size) requestParams.size = optionsArg.size;
|
|
428
|
-
if (optionsArg.background) requestParams.background = optionsArg.background;
|
|
429
|
-
if (optionsArg.outputFormat) requestParams.output_format = optionsArg.outputFormat;
|
|
430
|
-
if (optionsArg.outputCompression !== undefined) requestParams.output_compression = optionsArg.outputCompression;
|
|
431
|
-
if (optionsArg.stream !== undefined) requestParams.stream = optionsArg.stream;
|
|
432
|
-
if (optionsArg.partialImages !== undefined) requestParams.partial_images = optionsArg.partialImages;
|
|
433
|
-
} else if (model === 'dall-e-2') {
|
|
434
|
-
// DALL-E 2 specific parameters
|
|
435
|
-
if (optionsArg.size) requestParams.size = optionsArg.size;
|
|
436
|
-
requestParams.response_format = 'b64_json';
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
const result = await this.openAiApiClient.images.edit(requestParams);
|
|
440
|
-
|
|
441
|
-
const images = (result.data || []).map(img => ({
|
|
442
|
-
b64_json: img.b64_json,
|
|
443
|
-
url: img.url,
|
|
444
|
-
revisedPrompt: img.revised_prompt
|
|
445
|
-
}));
|
|
446
|
-
|
|
447
|
-
return {
|
|
448
|
-
images,
|
|
449
|
-
metadata: {
|
|
450
|
-
model,
|
|
451
|
-
quality: result.quality,
|
|
452
|
-
size: result.size,
|
|
453
|
-
outputFormat: result.output_format,
|
|
454
|
-
tokensUsed: result.usage?.total_tokens
|
|
455
|
-
}
|
|
456
|
-
};
|
|
457
|
-
} catch (error) {
|
|
458
|
-
console.error('Image edit error:', error);
|
|
459
|
-
throw new Error(`Failed to edit image: ${error.message}`);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|