@crewdle/mist-connector-openai 1.0.14 → 1.0.15
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,12 +42,89 @@ 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);
|
|
@@ -54,6 +132,7 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
54
132
|
let outputTokens = 0;
|
|
55
133
|
let output = '';
|
|
56
134
|
while (true) {
|
|
135
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob', options.model.id);
|
|
57
136
|
const response = await this.client.responses.create({
|
|
58
137
|
model: options.model.id,
|
|
59
138
|
input: messages,
|
|
@@ -62,6 +141,7 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
62
141
|
text: responseFormat,
|
|
63
142
|
tools,
|
|
64
143
|
});
|
|
144
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJob response');
|
|
65
145
|
inputTokens += response.usage?.input_tokens ?? 0;
|
|
66
146
|
outputTokens += response.usage?.output_tokens ?? 0;
|
|
67
147
|
const promises = [];
|
|
@@ -96,10 +176,99 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
96
176
|
if (!options || !this.models.has(options.model.id)) {
|
|
97
177
|
throw new Error('Model not initialized');
|
|
98
178
|
}
|
|
179
|
+
if (options.model.taskType === GenerativeAITaskType.SpeechToText) {
|
|
180
|
+
if (typeof parameters.prompt === 'string') {
|
|
181
|
+
throw new Error('Prompt must be an array of messages');
|
|
182
|
+
}
|
|
183
|
+
let file;
|
|
184
|
+
for (const message of parameters.prompt) {
|
|
185
|
+
if (message.type === 'input_audio') {
|
|
186
|
+
const dataParts = message.input_audio.data.split(',');
|
|
187
|
+
const data = dataParts[1];
|
|
188
|
+
const type = dataParts[0].replace('data:', '').replace(';base64', '');
|
|
189
|
+
const byteArray = Uint8Array.from(Buffer.from(data, 'base64'));
|
|
190
|
+
const blob = new Blob([byteArray], { type });
|
|
191
|
+
file = new File([blob], `audio.${message.input_audio.format}`, { type });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (!file) {
|
|
195
|
+
throw new Error('No file found');
|
|
196
|
+
}
|
|
197
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream audio transcription');
|
|
198
|
+
const stream = await this.client.audio.transcriptions.create({
|
|
199
|
+
model: options.model.id,
|
|
200
|
+
file,
|
|
201
|
+
response_format: 'json',
|
|
202
|
+
stream: true,
|
|
203
|
+
});
|
|
204
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream audio transcription response');
|
|
205
|
+
for await (const chunk of stream) {
|
|
206
|
+
yield {
|
|
207
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
208
|
+
output: chunk.type === 'transcript.text.delta' ? chunk.delta : '',
|
|
209
|
+
inputTokens: chunk.type === 'transcript.text.done' ? 0 : chunk.usage?.input_tokens ?? 0,
|
|
210
|
+
outputTokens: chunk.type === 'transcript.text.done' ? 0 : chunk.usage?.output_tokens ?? 0,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (options.model.taskType === GenerativeAITaskType.ImageGeneration) {
|
|
216
|
+
const images = [];
|
|
217
|
+
let prompt = parameters.prompt;
|
|
218
|
+
if (typeof parameters.prompt !== 'string') {
|
|
219
|
+
for (const message of parameters.prompt) {
|
|
220
|
+
if (message.type === 'image_url') {
|
|
221
|
+
const parts = message.image_url.url.split(',');
|
|
222
|
+
const data = parts[1];
|
|
223
|
+
const type = parts[0].replace('data:', '').replace(';base64', '');
|
|
224
|
+
const byteArray = Uint8Array.from(Buffer.from(data, 'base64'));
|
|
225
|
+
const blob = new Blob([byteArray], { type });
|
|
226
|
+
images.push(new File([blob], `image.${type.split('/')[1]}`, { type }));
|
|
227
|
+
}
|
|
228
|
+
if (message.type === 'text') {
|
|
229
|
+
prompt = message.text;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (images.length === 0) {
|
|
234
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream images.length === 0');
|
|
235
|
+
const response = await this.client.images.generate({
|
|
236
|
+
model: options.model.id,
|
|
237
|
+
prompt,
|
|
238
|
+
});
|
|
239
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream images.length === 0 response');
|
|
240
|
+
yield {
|
|
241
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
242
|
+
output: '',
|
|
243
|
+
resultFile: `data:image/png;base64,${response.data?.[0]?.b64_json ?? ''}`,
|
|
244
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
245
|
+
outputTokens: response.usage?.output_tokens ?? 0,
|
|
246
|
+
};
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream images.length > 0');
|
|
251
|
+
const response = await this.client.images.edit({
|
|
252
|
+
model: options.model.id,
|
|
253
|
+
image: images.length === 1 ? images[0] : images,
|
|
254
|
+
prompt,
|
|
255
|
+
});
|
|
256
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream images.length > 0 response');
|
|
257
|
+
yield {
|
|
258
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
259
|
+
output: '',
|
|
260
|
+
resultFile: `data:image/png;base64,${response.data?.[0]?.b64_json ?? ''}`,
|
|
261
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
262
|
+
outputTokens: response.usage?.output_tokens ?? 0,
|
|
263
|
+
};
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
99
267
|
const responseFormat = this.getResponseFormat(parameters);
|
|
100
268
|
const tools = this.getTools(parameters);
|
|
101
269
|
const messages = this.getMessages(parameters);
|
|
102
270
|
while (true) {
|
|
271
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream', options.model.id);
|
|
103
272
|
const stream = await this.client.responses.create({
|
|
104
273
|
model: options.model.id,
|
|
105
274
|
input: messages,
|
|
@@ -109,6 +278,7 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
109
278
|
tools,
|
|
110
279
|
stream: true,
|
|
111
280
|
});
|
|
281
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processJobStream response');
|
|
112
282
|
const promises = [];
|
|
113
283
|
for await (const chunk of stream) {
|
|
114
284
|
if (chunk.type === 'response.output_text.delta') {
|
|
@@ -166,12 +336,15 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
166
336
|
if (input === '') {
|
|
167
337
|
input = '{}';
|
|
168
338
|
}
|
|
339
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processToolCall', toolName, input);
|
|
169
340
|
const result = func.callback(JSON.parse(input));
|
|
170
341
|
if (result instanceof Promise) {
|
|
342
|
+
const output = await result;
|
|
343
|
+
console.log('OpenAIGenerativeAIWorkerConnector.processToolCall result');
|
|
171
344
|
messages.push({
|
|
172
345
|
type: 'function_call_output',
|
|
173
346
|
call_id: toolCallId,
|
|
174
|
-
output
|
|
347
|
+
output,
|
|
175
348
|
});
|
|
176
349
|
}
|
|
177
350
|
else {
|
|
@@ -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.15",
|
|
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.48",
|
|
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
|
}
|