n8n-nodes-github-copilot 3.1.0 → 3.2.1
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/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.backup.d.ts +5 -0
- package/dist/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.backup.js +651 -0
- package/dist/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.js +105 -529
- package/dist/nodes/GitHubCopilotChatAPI/nodeProperties.d.ts +2 -0
- package/dist/nodes/GitHubCopilotChatAPI/nodeProperties.js +280 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/audioProcessor.d.ts +11 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/audioProcessor.js +86 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/helpers.d.ts +21 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/helpers.js +130 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/imageProcessor.d.ts +8 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/imageProcessor.js +101 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/index.d.ts +4 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/index.js +20 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/types.d.ts +45 -0
- package/dist/nodes/GitHubCopilotChatAPI/utils/types.js +2 -0
- package/package.json +1 -1
|
@@ -1,183 +1,55 @@
|
|
|
1
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 (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
3
|
exports.GitHubCopilotChatAPI = void 0;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
method: 'POST',
|
|
31
|
-
headers: {
|
|
32
|
-
'Authorization': `Bearer ${credentials.accessToken}`,
|
|
33
|
-
'Content-Type': 'application/json',
|
|
34
|
-
'User-Agent': 'n8n-github-copilot-chat/3.0.0',
|
|
35
|
-
},
|
|
36
|
-
body: JSON.stringify(body),
|
|
37
|
-
};
|
|
38
|
-
const response = await fetch(`https://api.githubcopilot.com${endpoint}`, options);
|
|
39
|
-
if (!response.ok) {
|
|
40
|
-
const errorText = await response.text();
|
|
41
|
-
throw new Error(`GitHub Copilot API error: ${response.status} ${response.statusText}. ${errorText}`);
|
|
42
|
-
}
|
|
43
|
-
return await response.json();
|
|
44
|
-
}
|
|
45
|
-
async function downloadFileFromUrl(url) {
|
|
46
|
-
const response = await fetch(url);
|
|
47
|
-
if (!response.ok) {
|
|
48
|
-
throw new Error(`Failed to download file from URL: ${response.status} ${response.statusText}`);
|
|
49
|
-
}
|
|
50
|
-
return Buffer.from(await response.arrayBuffer());
|
|
51
|
-
}
|
|
52
|
-
async function getFileFromBinary(context, itemIndex, propertyName) {
|
|
53
|
-
const items = context.getInputData();
|
|
54
|
-
const item = items[itemIndex];
|
|
55
|
-
if (!item.binary || !item.binary[propertyName]) {
|
|
56
|
-
throw new Error(`No binary data found in property "${propertyName}"`);
|
|
57
|
-
}
|
|
58
|
-
const binaryData = item.binary[propertyName];
|
|
59
|
-
if (binaryData.data) {
|
|
60
|
-
return Buffer.from(binaryData.data, 'base64');
|
|
61
|
-
}
|
|
62
|
-
else if (binaryData.id) {
|
|
63
|
-
return await context.helpers.getBinaryDataBuffer(itemIndex, propertyName);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
throw new Error(`Invalid binary data format in property "${propertyName}"`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
async function processAudioFile(context, itemIndex) {
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
const nodeProperties_1 = require("./nodeProperties");
|
|
6
|
+
async function processAudioFileLegacy(context, itemIndex) {
|
|
70
7
|
const audioSource = context.getNodeParameter('audioSource', itemIndex);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const item = items[itemIndex];
|
|
99
|
-
if (item.binary && item.binary[audioBinaryProperty] && item.binary[audioBinaryProperty].fileName) {
|
|
100
|
-
filename = item.binary[audioBinaryProperty].fileName || 'audio.mp3';
|
|
101
|
-
}
|
|
102
|
-
break;
|
|
103
|
-
default:
|
|
104
|
-
throw new Error(`Unknown audio source: ${audioSource}`);
|
|
8
|
+
try {
|
|
9
|
+
const audioFile = context.getNodeParameter('audioFile', itemIndex, '');
|
|
10
|
+
const audioUrl = context.getNodeParameter('audioUrl', itemIndex, '');
|
|
11
|
+
const audioProperty = context.getNodeParameter('audioBinaryProperty', itemIndex, '');
|
|
12
|
+
const result = await (0, utils_1.processAudioFile)(context, itemIndex, audioSource, audioFile, audioUrl, audioProperty);
|
|
13
|
+
const tokenValidation = (0, utils_1.validateTokenLimit)(result.estimatedTokens, 100000);
|
|
14
|
+
if (!tokenValidation.valid) {
|
|
15
|
+
return {
|
|
16
|
+
dataUrl: '',
|
|
17
|
+
description: (0, utils_1.createAudioSummary)(result.filename, result.size)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const optimized = (0, utils_1.optimizeAudioForTokens)(result.data, 80000);
|
|
21
|
+
let description = `Audio file: ${result.filename} (${Math.round(result.size / 1024)}KB)`;
|
|
22
|
+
if (optimized.truncated) {
|
|
23
|
+
description += ` - Compressed from ${optimized.originalTokens} to ${optimized.finalTokens} tokens`;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
dataUrl: `data:${result.mimeType};base64,${optimized.data}`,
|
|
27
|
+
description
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return {
|
|
32
|
+
dataUrl: '',
|
|
33
|
+
description: `Error processing audio: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
34
|
+
};
|
|
105
35
|
}
|
|
106
|
-
const mimeType = getAudioMimeType(filename);
|
|
107
|
-
return `data:${mimeType};base64,${audioBuffer.toString('base64')}`;
|
|
108
36
|
}
|
|
109
|
-
async function
|
|
37
|
+
async function processImageFileLegacy(context, itemIndex) {
|
|
110
38
|
const imageSource = context.getNodeParameter('imageSource', itemIndex);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
else {
|
|
123
|
-
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
124
|
-
imageBuffer = fs.readFileSync(imageFile);
|
|
125
|
-
filename = imageFile.split(/[\\\/]/).pop() || 'image.jpg';
|
|
126
|
-
}
|
|
127
|
-
break;
|
|
128
|
-
case 'url':
|
|
129
|
-
const imageUrl = context.getNodeParameter('imageUrl', itemIndex);
|
|
130
|
-
imageBuffer = await downloadFileFromUrl(imageUrl);
|
|
131
|
-
filename = imageUrl.split('/').pop() || 'image.jpg';
|
|
132
|
-
break;
|
|
133
|
-
case 'binary':
|
|
134
|
-
const imageBinaryProperty = context.getNodeParameter('imageBinaryProperty', itemIndex);
|
|
135
|
-
imageBuffer = await getFileFromBinary(context, itemIndex, imageBinaryProperty);
|
|
136
|
-
const items = context.getInputData();
|
|
137
|
-
const item = items[itemIndex];
|
|
138
|
-
if (item.binary && item.binary[imageBinaryProperty] && item.binary[imageBinaryProperty].fileName) {
|
|
139
|
-
filename = item.binary[imageBinaryProperty].fileName || 'image.jpg';
|
|
140
|
-
}
|
|
141
|
-
break;
|
|
142
|
-
default:
|
|
143
|
-
throw new Error(`Unknown image source: ${imageSource}`);
|
|
39
|
+
try {
|
|
40
|
+
const imageFile = context.getNodeParameter('imageFile', itemIndex, '');
|
|
41
|
+
const imageUrl = context.getNodeParameter('imageUrl', itemIndex, '');
|
|
42
|
+
const imageProperty = context.getNodeParameter('imageBinaryProperty', itemIndex, '');
|
|
43
|
+
const result = await (0, utils_1.processImageFile)(context, itemIndex, imageSource, imageFile, imageUrl, imageProperty);
|
|
44
|
+
const tokenValidation = (0, utils_1.validateTokenLimit)(result.estimatedTokens, 50000);
|
|
45
|
+
if (!tokenValidation.valid) {
|
|
46
|
+
throw new Error(`Image too large: ${result.estimatedTokens} estimated tokens. Please use a smaller image.`);
|
|
47
|
+
}
|
|
48
|
+
const optimizedData = (0, utils_1.compressImageToTokenLimit)(result.data, 40000);
|
|
49
|
+
return `data:${result.mimeType};base64,${optimizedData}`;
|
|
144
50
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
function getMimeType(filename) {
|
|
149
|
-
const ext = filename.toLowerCase().split('.').pop();
|
|
150
|
-
switch (ext) {
|
|
151
|
-
case 'jpg':
|
|
152
|
-
case 'jpeg':
|
|
153
|
-
return 'image/jpeg';
|
|
154
|
-
case 'png':
|
|
155
|
-
return 'image/png';
|
|
156
|
-
case 'webp':
|
|
157
|
-
return 'image/webp';
|
|
158
|
-
case 'gif':
|
|
159
|
-
return 'image/gif';
|
|
160
|
-
default:
|
|
161
|
-
return 'image/jpeg';
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
function getAudioMimeType(filename) {
|
|
165
|
-
const ext = filename.toLowerCase().split('.').pop();
|
|
166
|
-
switch (ext) {
|
|
167
|
-
case 'mp3':
|
|
168
|
-
return 'audio/mpeg';
|
|
169
|
-
case 'wav':
|
|
170
|
-
return 'audio/wav';
|
|
171
|
-
case 'm4a':
|
|
172
|
-
return 'audio/mp4';
|
|
173
|
-
case 'flac':
|
|
174
|
-
return 'audio/flac';
|
|
175
|
-
case 'ogg':
|
|
176
|
-
return 'audio/ogg';
|
|
177
|
-
case 'aac':
|
|
178
|
-
return 'audio/aac';
|
|
179
|
-
default:
|
|
180
|
-
return 'audio/mpeg';
|
|
51
|
+
catch (error) {
|
|
52
|
+
throw new Error(`Error processing image: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
181
53
|
}
|
|
182
54
|
}
|
|
183
55
|
class GitHubCopilotChatAPI {
|
|
@@ -201,384 +73,88 @@ class GitHubCopilotChatAPI {
|
|
|
201
73
|
required: true,
|
|
202
74
|
},
|
|
203
75
|
],
|
|
204
|
-
properties:
|
|
205
|
-
{
|
|
206
|
-
displayName: 'Operation',
|
|
207
|
-
name: 'operation',
|
|
208
|
-
type: 'options',
|
|
209
|
-
options: [
|
|
210
|
-
{
|
|
211
|
-
name: 'Chat Completion',
|
|
212
|
-
value: 'chatCompletion',
|
|
213
|
-
description: 'Send a message and get AI response using Copilot models',
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
name: 'Audio Transcription',
|
|
217
|
-
value: 'audioTranscription',
|
|
218
|
-
description: 'Transcribe audio file to text using Copilot',
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
name: 'Image Analysis',
|
|
222
|
-
value: 'imageAnalysis',
|
|
223
|
-
description: 'Analyze image with AI (vision models)',
|
|
224
|
-
},
|
|
225
|
-
],
|
|
226
|
-
default: 'chatCompletion',
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
displayName: 'Model',
|
|
230
|
-
name: 'model',
|
|
231
|
-
type: 'options',
|
|
232
|
-
options: [
|
|
233
|
-
{
|
|
234
|
-
name: 'GPT-5 (Latest)',
|
|
235
|
-
value: 'gpt-5',
|
|
236
|
-
description: 'OpenAI GPT-5 - Latest and most advanced model',
|
|
237
|
-
},
|
|
238
|
-
{
|
|
239
|
-
name: 'GPT-5 Mini',
|
|
240
|
-
value: 'gpt-5-mini',
|
|
241
|
-
description: 'OpenAI GPT-5 Mini - Faster and more efficient',
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
name: 'Claude Opus 4.1',
|
|
245
|
-
value: 'claude-opus-4.1',
|
|
246
|
-
description: 'Anthropic Claude Opus 4.1 - Advanced reasoning',
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
name: 'Gemini 2.5 Pro',
|
|
250
|
-
value: 'gemini-2.5-pro',
|
|
251
|
-
description: 'Google Gemini 2.5 Pro - Multimodal capabilities',
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
name: 'Grok Code Fast 1',
|
|
255
|
-
value: 'grok-code-fast-1',
|
|
256
|
-
description: 'xAI Grok - Optimized for coding tasks',
|
|
257
|
-
},
|
|
258
|
-
{
|
|
259
|
-
name: 'GPT-4.1 Copilot',
|
|
260
|
-
value: 'gpt-4.1-copilot',
|
|
261
|
-
description: 'GitHub Copilot optimized GPT-4.1 model',
|
|
262
|
-
},
|
|
263
|
-
],
|
|
264
|
-
default: 'gpt-5',
|
|
265
|
-
description: 'Choose the AI model from your Copilot subscription',
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
displayName: 'Message',
|
|
269
|
-
name: 'message',
|
|
270
|
-
type: 'string',
|
|
271
|
-
typeOptions: {
|
|
272
|
-
rows: 4,
|
|
273
|
-
},
|
|
274
|
-
default: '',
|
|
275
|
-
placeholder: 'Enter your message here...',
|
|
276
|
-
description: 'The message to send to the AI',
|
|
277
|
-
displayOptions: {
|
|
278
|
-
show: {
|
|
279
|
-
operation: ['chatCompletion', 'imageAnalysis'],
|
|
280
|
-
},
|
|
281
|
-
},
|
|
282
|
-
},
|
|
283
|
-
{
|
|
284
|
-
displayName: 'Audio Source',
|
|
285
|
-
name: 'audioSource',
|
|
286
|
-
type: 'options',
|
|
287
|
-
options: [
|
|
288
|
-
{ name: 'File Path or Base64', value: 'manual' },
|
|
289
|
-
{ name: 'Download from URL', value: 'url' },
|
|
290
|
-
{ name: 'From Previous Node Binary', value: 'binary' },
|
|
291
|
-
],
|
|
292
|
-
default: 'manual',
|
|
293
|
-
description: 'Choose how to provide the audio file',
|
|
294
|
-
displayOptions: {
|
|
295
|
-
show: {
|
|
296
|
-
operation: ['audioTranscription'],
|
|
297
|
-
},
|
|
298
|
-
},
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
displayName: 'Audio File',
|
|
302
|
-
name: 'audioFile',
|
|
303
|
-
type: 'string',
|
|
304
|
-
default: '',
|
|
305
|
-
placeholder: 'Path to audio file or base64 data',
|
|
306
|
-
description: 'Audio file to transcribe (supports MP3, WAV, M4A, FLAC, OGG)',
|
|
307
|
-
displayOptions: {
|
|
308
|
-
show: {
|
|
309
|
-
operation: ['audioTranscription'],
|
|
310
|
-
audioSource: ['manual'],
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
displayName: 'Audio URL',
|
|
316
|
-
name: 'audioUrl',
|
|
317
|
-
type: 'string',
|
|
318
|
-
default: '',
|
|
319
|
-
placeholder: 'https://example.com/audio.mp3',
|
|
320
|
-
description: 'URL to download audio file from',
|
|
321
|
-
displayOptions: {
|
|
322
|
-
show: {
|
|
323
|
-
operation: ['audioTranscription'],
|
|
324
|
-
audioSource: ['url'],
|
|
325
|
-
},
|
|
326
|
-
},
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
displayName: 'Binary Property Name',
|
|
330
|
-
name: 'audioBinaryProperty',
|
|
331
|
-
type: 'string',
|
|
332
|
-
default: 'data',
|
|
333
|
-
placeholder: 'data',
|
|
334
|
-
description: 'Name of the binary property containing the audio file',
|
|
335
|
-
displayOptions: {
|
|
336
|
-
show: {
|
|
337
|
-
operation: ['audioTranscription'],
|
|
338
|
-
audioSource: ['binary'],
|
|
339
|
-
},
|
|
340
|
-
},
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
displayName: 'Audio Language',
|
|
344
|
-
name: 'audioLanguage',
|
|
345
|
-
type: 'options',
|
|
346
|
-
options: [
|
|
347
|
-
{ name: 'Auto-detect', value: 'auto' },
|
|
348
|
-
{ name: 'Portuguese (Brazil)', value: 'pt' },
|
|
349
|
-
{ name: 'English', value: 'en' },
|
|
350
|
-
{ name: 'Spanish', value: 'es' },
|
|
351
|
-
{ name: 'French', value: 'fr' },
|
|
352
|
-
{ name: 'German', value: 'de' },
|
|
353
|
-
{ name: 'Italian', value: 'it' },
|
|
354
|
-
{ name: 'Japanese', value: 'ja' },
|
|
355
|
-
{ name: 'Chinese', value: 'zh' },
|
|
356
|
-
],
|
|
357
|
-
default: 'auto',
|
|
358
|
-
description: 'Language of the audio (helps with accuracy)',
|
|
359
|
-
displayOptions: {
|
|
360
|
-
show: {
|
|
361
|
-
operation: ['audioTranscription'],
|
|
362
|
-
},
|
|
363
|
-
},
|
|
364
|
-
},
|
|
365
|
-
{
|
|
366
|
-
displayName: 'Image Source',
|
|
367
|
-
name: 'imageSource',
|
|
368
|
-
type: 'options',
|
|
369
|
-
options: [
|
|
370
|
-
{ name: 'File Path or Base64', value: 'manual' },
|
|
371
|
-
{ name: 'Download from URL', value: 'url' },
|
|
372
|
-
{ name: 'From Previous Node Binary', value: 'binary' },
|
|
373
|
-
],
|
|
374
|
-
default: 'manual',
|
|
375
|
-
description: 'Choose how to provide the image file',
|
|
376
|
-
displayOptions: {
|
|
377
|
-
show: {
|
|
378
|
-
operation: ['imageAnalysis'],
|
|
379
|
-
},
|
|
380
|
-
},
|
|
381
|
-
},
|
|
382
|
-
{
|
|
383
|
-
displayName: 'Image File',
|
|
384
|
-
name: 'imageFile',
|
|
385
|
-
type: 'string',
|
|
386
|
-
default: '',
|
|
387
|
-
placeholder: 'Path to image file or base64 data',
|
|
388
|
-
description: 'Image file to analyze (supports JPG, PNG, WebP, GIF)',
|
|
389
|
-
displayOptions: {
|
|
390
|
-
show: {
|
|
391
|
-
operation: ['imageAnalysis'],
|
|
392
|
-
imageSource: ['manual'],
|
|
393
|
-
},
|
|
394
|
-
},
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
displayName: 'Image URL',
|
|
398
|
-
name: 'imageUrl',
|
|
399
|
-
type: 'string',
|
|
400
|
-
default: '',
|
|
401
|
-
placeholder: 'https://example.com/image.jpg',
|
|
402
|
-
description: 'URL to download image file from',
|
|
403
|
-
displayOptions: {
|
|
404
|
-
show: {
|
|
405
|
-
operation: ['imageAnalysis'],
|
|
406
|
-
imageSource: ['url'],
|
|
407
|
-
},
|
|
408
|
-
},
|
|
409
|
-
},
|
|
410
|
-
{
|
|
411
|
-
displayName: 'Binary Property Name',
|
|
412
|
-
name: 'imageBinaryProperty',
|
|
413
|
-
type: 'string',
|
|
414
|
-
default: 'data',
|
|
415
|
-
placeholder: 'data',
|
|
416
|
-
description: 'Name of the binary property containing the image file',
|
|
417
|
-
displayOptions: {
|
|
418
|
-
show: {
|
|
419
|
-
operation: ['imageAnalysis'],
|
|
420
|
-
imageSource: ['binary'],
|
|
421
|
-
},
|
|
422
|
-
},
|
|
423
|
-
},
|
|
424
|
-
{
|
|
425
|
-
displayName: 'System Prompt',
|
|
426
|
-
name: 'systemPrompt',
|
|
427
|
-
type: 'string',
|
|
428
|
-
typeOptions: {
|
|
429
|
-
rows: 2,
|
|
430
|
-
},
|
|
431
|
-
default: '',
|
|
432
|
-
placeholder: 'You are a helpful assistant...',
|
|
433
|
-
description: 'Optional system prompt to set AI behavior',
|
|
434
|
-
displayOptions: {
|
|
435
|
-
show: {
|
|
436
|
-
operation: ['chatCompletion', 'imageAnalysis'],
|
|
437
|
-
},
|
|
438
|
-
},
|
|
439
|
-
},
|
|
440
|
-
{
|
|
441
|
-
displayName: 'Temperature',
|
|
442
|
-
name: 'temperature',
|
|
443
|
-
type: 'number',
|
|
444
|
-
typeOptions: {
|
|
445
|
-
minValue: 0,
|
|
446
|
-
maxValue: 2,
|
|
447
|
-
numberStepSize: 0.1,
|
|
448
|
-
},
|
|
449
|
-
default: 1,
|
|
450
|
-
description: 'Controls randomness: 0 = focused, 2 = creative',
|
|
451
|
-
displayOptions: {
|
|
452
|
-
show: {
|
|
453
|
-
operation: ['chatCompletion', 'imageAnalysis'],
|
|
454
|
-
},
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
{
|
|
458
|
-
displayName: 'Max Tokens',
|
|
459
|
-
name: 'maxTokens',
|
|
460
|
-
type: 'number',
|
|
461
|
-
typeOptions: {
|
|
462
|
-
minValue: 1,
|
|
463
|
-
maxValue: 8192,
|
|
464
|
-
},
|
|
465
|
-
default: 2000,
|
|
466
|
-
description: 'Maximum tokens in response',
|
|
467
|
-
displayOptions: {
|
|
468
|
-
show: {
|
|
469
|
-
operation: ['chatCompletion', 'imageAnalysis'],
|
|
470
|
-
},
|
|
471
|
-
},
|
|
472
|
-
},
|
|
473
|
-
],
|
|
76
|
+
properties: nodeProperties_1.nodeProperties,
|
|
474
77
|
};
|
|
475
78
|
}
|
|
476
79
|
async execute() {
|
|
80
|
+
var _a, _b, _c;
|
|
477
81
|
const items = this.getInputData();
|
|
478
82
|
const returnData = [];
|
|
479
83
|
for (let i = 0; i < items.length; i++) {
|
|
480
84
|
try {
|
|
481
85
|
const operation = this.getNodeParameter('operation', i);
|
|
482
86
|
const model = this.getNodeParameter('model', i);
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
const
|
|
486
|
-
const
|
|
487
|
-
const
|
|
488
|
-
const
|
|
87
|
+
if (operation === 'chat') {
|
|
88
|
+
const userMessage = this.getNodeParameter('message', i);
|
|
89
|
+
const systemMessage = this.getNodeParameter('systemMessage', i, '');
|
|
90
|
+
const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
|
|
91
|
+
const includeImage = this.getNodeParameter('includeImage', i, false);
|
|
92
|
+
const includeAudio = this.getNodeParameter('includeAudio', i, false);
|
|
489
93
|
const messages = [];
|
|
490
|
-
if (
|
|
491
|
-
messages.push({
|
|
492
|
-
}
|
|
493
|
-
messages.push({ role: 'user', content: message });
|
|
494
|
-
const requestBody = {
|
|
495
|
-
model: model,
|
|
496
|
-
messages: messages,
|
|
497
|
-
temperature: temperature,
|
|
498
|
-
max_tokens: maxTokens,
|
|
499
|
-
stream: false,
|
|
500
|
-
};
|
|
501
|
-
const response = await makeApiRequest(this, '/chat/completions', requestBody);
|
|
502
|
-
result = {
|
|
503
|
-
response: response.choices[0].message.content,
|
|
504
|
-
model: model,
|
|
505
|
-
usage: response.usage,
|
|
506
|
-
finish_reason: response.choices[0].finish_reason,
|
|
507
|
-
timestamp: new Date().toISOString(),
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
else if (operation === 'audioTranscription') {
|
|
511
|
-
const language = this.getNodeParameter('audioLanguage', i);
|
|
512
|
-
const audioDataUrl = await processAudioFile(this, i);
|
|
513
|
-
const transcriptionPrompt = language === 'auto'
|
|
514
|
-
? `Please transcribe this audio file to text. Detect the language automatically and provide the transcription.`
|
|
515
|
-
: `Please transcribe this audio file to text. The audio is in ${language} language.`;
|
|
516
|
-
const messages = [
|
|
517
|
-
{
|
|
94
|
+
if (systemMessage) {
|
|
95
|
+
messages.push({
|
|
518
96
|
role: 'system',
|
|
519
|
-
content:
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
97
|
+
content: systemMessage,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
let userContent = userMessage;
|
|
101
|
+
if (includeImage || includeAudio) {
|
|
102
|
+
const contentArray = [];
|
|
103
|
+
if (userMessage.trim()) {
|
|
104
|
+
contentArray.push({
|
|
105
|
+
type: 'text',
|
|
106
|
+
text: userMessage,
|
|
107
|
+
});
|
|
524
108
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
messages.push({ role: 'system', content: systemPrompt });
|
|
109
|
+
if (includeImage) {
|
|
110
|
+
const imageDataUrl = await processImageFileLegacy(this, i);
|
|
111
|
+
contentArray.push({
|
|
112
|
+
type: 'image_url',
|
|
113
|
+
image_url: {
|
|
114
|
+
url: imageDataUrl,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (includeAudio) {
|
|
119
|
+
const audioResult = await processAudioFileLegacy(this, i);
|
|
120
|
+
if (audioResult.dataUrl) {
|
|
121
|
+
contentArray.push({
|
|
122
|
+
type: 'text',
|
|
123
|
+
text: `[Audio included: ${audioResult.description}]`,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
contentArray.push({
|
|
128
|
+
type: 'text',
|
|
129
|
+
text: `[Audio processing failed: ${audioResult.description}]`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
userContent = contentArray;
|
|
551
134
|
}
|
|
552
135
|
messages.push({
|
|
553
136
|
role: 'user',
|
|
554
|
-
content:
|
|
555
|
-
{ type: 'text', text: message },
|
|
556
|
-
{ type: 'image_url', image_url: { url: imageBase64 } }
|
|
557
|
-
]
|
|
137
|
+
content: userContent,
|
|
558
138
|
});
|
|
559
139
|
const requestBody = {
|
|
560
|
-
model
|
|
561
|
-
messages
|
|
562
|
-
temperature: temperature,
|
|
563
|
-
max_tokens: maxTokens,
|
|
140
|
+
model,
|
|
141
|
+
messages,
|
|
564
142
|
stream: false,
|
|
143
|
+
...advancedOptions,
|
|
565
144
|
};
|
|
566
|
-
const response = await makeApiRequest(this, '/chat/completions', requestBody);
|
|
567
|
-
result = {
|
|
568
|
-
|
|
569
|
-
model
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
145
|
+
const response = await (0, utils_1.makeApiRequest)(this, '/chat/completions', requestBody, includeImage);
|
|
146
|
+
const result = {
|
|
147
|
+
message: ((_b = (_a = response.choices[0]) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.content) || '',
|
|
148
|
+
model,
|
|
149
|
+
operation,
|
|
150
|
+
usage: response.usage || null,
|
|
151
|
+
finish_reason: ((_c = response.choices[0]) === null || _c === void 0 ? void 0 : _c.finish_reason) || 'unknown',
|
|
573
152
|
};
|
|
153
|
+
returnData.push({
|
|
154
|
+
json: result,
|
|
155
|
+
pairedItem: { item: i },
|
|
156
|
+
});
|
|
574
157
|
}
|
|
575
|
-
else {
|
|
576
|
-
throw new Error(`Unknown operation: ${operation}`);
|
|
577
|
-
}
|
|
578
|
-
returnData.push({
|
|
579
|
-
json: result,
|
|
580
|
-
pairedItem: { item: i },
|
|
581
|
-
});
|
|
582
158
|
}
|
|
583
159
|
catch (error) {
|
|
584
160
|
if (this.continueOnFail()) {
|