@crewdle/mist-connector-openai 1.0.14 → 1.0.16
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.
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
|
+
import { GenerativeAIEngineType, GenerativeAITaskType } from '@crewdle/web-sdk-types';
|
|
2
3
|
export class OpenAIGenerativeAIWorkerConnector {
|
|
3
4
|
models = new Map();
|
|
4
5
|
apiKey;
|
|
@@ -22,7 +23,7 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
22
23
|
this.models.clear();
|
|
23
24
|
}
|
|
24
25
|
getEngineType() {
|
|
25
|
-
return
|
|
26
|
+
return GenerativeAIEngineType.OpenAI;
|
|
26
27
|
}
|
|
27
28
|
async processJob(parameters, options) {
|
|
28
29
|
if (!this.client) {
|
|
@@ -31,7 +32,7 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
31
32
|
if (!options || !this.models.has(options.model.id)) {
|
|
32
33
|
throw new Error('Model not initialized');
|
|
33
34
|
}
|
|
34
|
-
if (options.model.
|
|
35
|
+
if (options.model.taskType === GenerativeAITaskType.Embeddings) {
|
|
35
36
|
const response = await this.client.embeddings.create({
|
|
36
37
|
model: options.model.id,
|
|
37
38
|
input: parameters.prompt,
|
|
@@ -41,19 +42,98 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
41
42
|
throw new Error('No response data');
|
|
42
43
|
}
|
|
43
44
|
return {
|
|
44
|
-
type:
|
|
45
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
45
46
|
output: response.data[0].embedding,
|
|
46
47
|
inputTokens: response.usage?.prompt_tokens ?? 0,
|
|
47
48
|
outputTokens: 0,
|
|
48
49
|
};
|
|
49
50
|
}
|
|
51
|
+
if (options.model.taskType === GenerativeAITaskType.SpeechToText) {
|
|
52
|
+
if (typeof parameters.prompt === 'string') {
|
|
53
|
+
throw new Error('Prompt must be an array of messages');
|
|
54
|
+
}
|
|
55
|
+
let file;
|
|
56
|
+
for (const message of parameters.prompt) {
|
|
57
|
+
if (message.type === 'input_audio') {
|
|
58
|
+
file = new File([message.input_audio.data], 'audio.mp3', { type: message.input_audio.format });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!file) {
|
|
62
|
+
throw new Error('No file found');
|
|
63
|
+
}
|
|
64
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob audio transcription');
|
|
65
|
+
const response = await this.client.audio.transcriptions.create({
|
|
66
|
+
model: options.model.id,
|
|
67
|
+
file,
|
|
68
|
+
response_format: 'json',
|
|
69
|
+
});
|
|
70
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob audio transcription response');
|
|
71
|
+
return {
|
|
72
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
73
|
+
output: response.text,
|
|
74
|
+
inputTokens: response.usage?.type === 'tokens' ? response.usage.input_tokens : 0,
|
|
75
|
+
outputTokens: response.usage?.type === 'tokens' ? response.usage.output_tokens : 0,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (options.model.taskType === GenerativeAITaskType.ImageGeneration) {
|
|
79
|
+
const images = [];
|
|
80
|
+
let prompt = parameters.prompt;
|
|
81
|
+
if (typeof parameters.prompt !== 'string') {
|
|
82
|
+
for (const message of parameters.prompt) {
|
|
83
|
+
if (message.type === 'image_url') {
|
|
84
|
+
const parts = message.image_url.url.split(',');
|
|
85
|
+
const data = parts[1];
|
|
86
|
+
const type = parts[0].replace('data:', '').replace(';base64', '');
|
|
87
|
+
const byteArray = Uint8Array.from(Buffer.from(data, 'base64'));
|
|
88
|
+
const blob = new Blob([byteArray], { type });
|
|
89
|
+
images.push(new File([blob], `image.${type.split('/')[1]}`, { type }));
|
|
90
|
+
}
|
|
91
|
+
if (message.type === 'text') {
|
|
92
|
+
prompt = message.text;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (images.length === 0) {
|
|
97
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob image generation');
|
|
98
|
+
const response = await this.client.images.generate({
|
|
99
|
+
model: options.model.id,
|
|
100
|
+
prompt,
|
|
101
|
+
});
|
|
102
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob image generation response');
|
|
103
|
+
return {
|
|
104
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
105
|
+
output: '',
|
|
106
|
+
resultFile: `data:image/png;base64,${response.data?.[0]?.b64_json ?? ''}`,
|
|
107
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
108
|
+
outputTokens: response.usage?.output_tokens ?? 0,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob image edit');
|
|
113
|
+
const response = await this.client.images.edit({
|
|
114
|
+
model: options.model.id,
|
|
115
|
+
image: images.length === 1 ? images[0] : images,
|
|
116
|
+
prompt,
|
|
117
|
+
});
|
|
118
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob image edit response');
|
|
119
|
+
return {
|
|
120
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
121
|
+
output: '',
|
|
122
|
+
resultFile: `data:image/png;base64,${response.data?.[0]?.b64_json ?? ''}`,
|
|
123
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
124
|
+
outputTokens: response.usage?.output_tokens ?? 0,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
50
128
|
const responseFormat = this.getResponseFormat(parameters);
|
|
51
129
|
const tools = this.getTools(parameters);
|
|
52
130
|
const messages = this.getMessages(parameters);
|
|
53
131
|
let inputTokens = 0;
|
|
54
132
|
let outputTokens = 0;
|
|
55
133
|
let output = '';
|
|
134
|
+
let resultFile;
|
|
56
135
|
while (true) {
|
|
136
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob', options.model.id);
|
|
57
137
|
const response = await this.client.responses.create({
|
|
58
138
|
model: options.model.id,
|
|
59
139
|
input: messages,
|
|
@@ -62,6 +142,7 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
62
142
|
text: responseFormat,
|
|
63
143
|
tools,
|
|
64
144
|
});
|
|
145
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob response');
|
|
65
146
|
inputTokens += response.usage?.input_tokens ?? 0;
|
|
66
147
|
outputTokens += response.usage?.output_tokens ?? 0;
|
|
67
148
|
const promises = [];
|
|
@@ -73,6 +154,9 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
73
154
|
}
|
|
74
155
|
}
|
|
75
156
|
}
|
|
157
|
+
if (content.type === 'image_generation_call' && content.result) {
|
|
158
|
+
resultFile = `data:image/png;base64,${content.result}`;
|
|
159
|
+
}
|
|
76
160
|
if (content.type === 'function_call') {
|
|
77
161
|
promises.push(this.processToolCall(parameters, messages, content.name, content.call_id, content.arguments));
|
|
78
162
|
}
|
|
@@ -84,6 +168,7 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
84
168
|
return {
|
|
85
169
|
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
86
170
|
output,
|
|
171
|
+
resultFile,
|
|
87
172
|
inputTokens,
|
|
88
173
|
outputTokens,
|
|
89
174
|
};
|
|
@@ -96,10 +181,99 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
96
181
|
if (!options || !this.models.has(options.model.id)) {
|
|
97
182
|
throw new Error('Model not initialized');
|
|
98
183
|
}
|
|
184
|
+
if (options.model.taskType === GenerativeAITaskType.SpeechToText) {
|
|
185
|
+
if (typeof parameters.prompt === 'string') {
|
|
186
|
+
throw new Error('Prompt must be an array of messages');
|
|
187
|
+
}
|
|
188
|
+
let file;
|
|
189
|
+
for (const message of parameters.prompt) {
|
|
190
|
+
if (message.type === 'input_audio') {
|
|
191
|
+
const dataParts = message.input_audio.data.split(',');
|
|
192
|
+
const data = dataParts[1];
|
|
193
|
+
const type = dataParts[0].replace('data:', '').replace(';base64', '');
|
|
194
|
+
const byteArray = Uint8Array.from(Buffer.from(data, 'base64'));
|
|
195
|
+
const blob = new Blob([byteArray], { type });
|
|
196
|
+
file = new File([blob], `audio.${message.input_audio.format}`, { type });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (!file) {
|
|
200
|
+
throw new Error('No file found');
|
|
201
|
+
}
|
|
202
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream audio transcription');
|
|
203
|
+
const stream = await this.client.audio.transcriptions.create({
|
|
204
|
+
model: options.model.id,
|
|
205
|
+
file,
|
|
206
|
+
response_format: 'json',
|
|
207
|
+
stream: true,
|
|
208
|
+
});
|
|
209
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream audio transcription response');
|
|
210
|
+
for await (const chunk of stream) {
|
|
211
|
+
yield {
|
|
212
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
213
|
+
output: chunk.type === 'transcript.text.delta' ? chunk.delta : '',
|
|
214
|
+
inputTokens: chunk.type === 'transcript.text.done' ? 0 : chunk.usage?.input_tokens ?? 0,
|
|
215
|
+
outputTokens: chunk.type === 'transcript.text.done' ? 0 : chunk.usage?.output_tokens ?? 0,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (options.model.taskType === GenerativeAITaskType.ImageGeneration) {
|
|
221
|
+
const images = [];
|
|
222
|
+
let prompt = parameters.prompt;
|
|
223
|
+
if (typeof parameters.prompt !== 'string') {
|
|
224
|
+
for (const message of parameters.prompt) {
|
|
225
|
+
if (message.type === 'image_url') {
|
|
226
|
+
const parts = message.image_url.url.split(',');
|
|
227
|
+
const data = parts[1];
|
|
228
|
+
const type = parts[0].replace('data:', '').replace(';base64', '');
|
|
229
|
+
const byteArray = Uint8Array.from(Buffer.from(data, 'base64'));
|
|
230
|
+
const blob = new Blob([byteArray], { type });
|
|
231
|
+
images.push(new File([blob], `image.${type.split('/')[1]}`, { type }));
|
|
232
|
+
}
|
|
233
|
+
if (message.type === 'text') {
|
|
234
|
+
prompt = message.text;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (images.length === 0) {
|
|
239
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream images.length === 0');
|
|
240
|
+
const response = await this.client.images.generate({
|
|
241
|
+
model: options.model.id,
|
|
242
|
+
prompt,
|
|
243
|
+
});
|
|
244
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream images.length === 0 response');
|
|
245
|
+
yield {
|
|
246
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
247
|
+
output: '',
|
|
248
|
+
resultFile: `data:image/png;base64,${response.data?.[0]?.b64_json ?? ''}`,
|
|
249
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
250
|
+
outputTokens: response.usage?.output_tokens ?? 0,
|
|
251
|
+
};
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream images.length > 0');
|
|
256
|
+
const response = await this.client.images.edit({
|
|
257
|
+
model: options.model.id,
|
|
258
|
+
image: images.length === 1 ? images[0] : images,
|
|
259
|
+
prompt,
|
|
260
|
+
});
|
|
261
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream images.length > 0 response');
|
|
262
|
+
yield {
|
|
263
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
264
|
+
output: '',
|
|
265
|
+
resultFile: `data:image/png;base64,${response.data?.[0]?.b64_json ?? ''}`,
|
|
266
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
267
|
+
outputTokens: response.usage?.output_tokens ?? 0,
|
|
268
|
+
};
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
99
272
|
const responseFormat = this.getResponseFormat(parameters);
|
|
100
273
|
const tools = this.getTools(parameters);
|
|
101
274
|
const messages = this.getMessages(parameters);
|
|
102
275
|
while (true) {
|
|
276
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream', options.model.id);
|
|
103
277
|
const stream = await this.client.responses.create({
|
|
104
278
|
model: options.model.id,
|
|
105
279
|
input: messages,
|
|
@@ -109,6 +283,7 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
109
283
|
tools,
|
|
110
284
|
stream: true,
|
|
111
285
|
});
|
|
286
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream response');
|
|
112
287
|
const promises = [];
|
|
113
288
|
for await (const chunk of stream) {
|
|
114
289
|
if (chunk.type === 'response.output_text.delta') {
|
|
@@ -131,6 +306,15 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
131
306
|
if (chunk.item.type === 'function_call') {
|
|
132
307
|
promises.push(this.processToolCall(parameters, messages, chunk.item.name, chunk.item.call_id, chunk.item.arguments));
|
|
133
308
|
}
|
|
309
|
+
if (chunk.item.type === 'image_generation_call' && chunk.item.result) {
|
|
310
|
+
yield {
|
|
311
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
312
|
+
output: '',
|
|
313
|
+
resultFile: `data:image/png;base64,${chunk.item.result}`,
|
|
314
|
+
inputTokens: 0,
|
|
315
|
+
outputTokens: 0,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
134
318
|
}
|
|
135
319
|
}
|
|
136
320
|
if (promises.length > 0) {
|
|
@@ -166,12 +350,15 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
166
350
|
if (input === '') {
|
|
167
351
|
input = '{}';
|
|
168
352
|
}
|
|
353
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processToolCall', toolName, input);
|
|
169
354
|
const result = func.callback(JSON.parse(input));
|
|
170
355
|
if (result instanceof Promise) {
|
|
356
|
+
const output = await result;
|
|
357
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processToolCall result');
|
|
171
358
|
messages.push({
|
|
172
359
|
type: 'function_call_output',
|
|
173
360
|
call_id: toolCallId,
|
|
174
|
-
output
|
|
361
|
+
output,
|
|
175
362
|
});
|
|
176
363
|
}
|
|
177
364
|
else {
|
|
@@ -246,6 +433,18 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
246
433
|
}
|
|
247
434
|
const tools = [];
|
|
248
435
|
for (const [name, func] of parameters.functions) {
|
|
436
|
+
if (func.type === 'mcp') {
|
|
437
|
+
tools.push(func);
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
if (func.type === 'code_interpreter') {
|
|
441
|
+
tools.push(func);
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (func.type === 'image_generation') {
|
|
445
|
+
tools.push(func);
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
249
448
|
let params = null;
|
|
250
449
|
if (func.params) {
|
|
251
450
|
params = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
|
+
import { GenerativeAIEngineType } from '@crewdle/web-sdk-types';
|
|
2
3
|
export class OpenAISpeechConnector {
|
|
3
4
|
client;
|
|
4
5
|
constructor(apiKey) {
|
|
@@ -6,13 +7,13 @@ export class OpenAISpeechConnector {
|
|
|
6
7
|
apiKey,
|
|
7
8
|
});
|
|
8
9
|
}
|
|
9
|
-
async speak(model, text, voice, instructions) {
|
|
10
|
+
async speak(model, text, voice, format, instructions) {
|
|
10
11
|
const response = await this.client.audio.speech.create({
|
|
11
12
|
model,
|
|
12
13
|
voice: voice,
|
|
13
14
|
input: text,
|
|
14
15
|
instructions,
|
|
15
|
-
response_format:
|
|
16
|
+
response_format: format,
|
|
16
17
|
});
|
|
17
18
|
if (!response.body) {
|
|
18
19
|
throw new Error('No response body');
|
|
@@ -30,6 +31,6 @@ export class OpenAISpeechConnector {
|
|
|
30
31
|
});
|
|
31
32
|
}
|
|
32
33
|
getEngineType() {
|
|
33
|
-
return
|
|
34
|
+
return GenerativeAIEngineType.OpenAI;
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -2,6 +2,6 @@ import { GenerativeAIEngineType, IGenerativeAISpeechConnector } from '@crewdle/w
|
|
|
2
2
|
export declare class OpenAISpeechConnector implements IGenerativeAISpeechConnector {
|
|
3
3
|
private client;
|
|
4
4
|
constructor(apiKey: string);
|
|
5
|
-
speak(model: string, text: string, voice: string, instructions?: string): Promise<ReadableStream>;
|
|
5
|
+
speak(model: string, text: string, voice: string, format: string, instructions?: string): Promise<ReadableStream>;
|
|
6
6
|
getEngineType(): GenerativeAIEngineType;
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewdle/mist-connector-openai",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"dist/"
|
|
16
16
|
],
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@crewdle/web-sdk-types": "^1.0.
|
|
18
|
+
"@crewdle/web-sdk-types": "^1.0.50",
|
|
19
19
|
"@types/node": "^22.13.9",
|
|
20
20
|
"typescript": "^5.8.2"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"openai": "^5.
|
|
23
|
+
"openai": "^5.8.2"
|
|
24
24
|
}
|
|
25
25
|
}
|