n8n-nodes-github-copilot 3.1.0 → 3.2.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.
@@ -1,183 +1,54 @@
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
- async function makeApiRequest(context, endpoint, body) {
28
- const credentials = await context.getCredentials('githubApi');
29
- const options = {
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
+ async function processAudioFileLegacy(context, itemIndex) {
70
6
  const audioSource = context.getNodeParameter('audioSource', itemIndex);
71
- let audioBuffer;
72
- let filename = 'audio.mp3';
73
- switch (audioSource) {
74
- case 'manual':
75
- const audioFile = context.getNodeParameter('audioFile', itemIndex);
76
- if (audioFile.startsWith('data:audio/')) {
77
- const base64Data = audioFile.split(',')[1];
78
- audioBuffer = Buffer.from(base64Data, 'base64');
79
- }
80
- else if (audioFile.match(/^[A-Za-z0-9+/=]+$/)) {
81
- audioBuffer = Buffer.from(audioFile, 'base64');
82
- }
83
- else {
84
- const fs = await Promise.resolve().then(() => __importStar(require('fs')));
85
- audioBuffer = fs.readFileSync(audioFile);
86
- filename = audioFile.split(/[\\\/]/).pop() || 'audio.mp3';
87
- }
88
- break;
89
- case 'url':
90
- const audioUrl = context.getNodeParameter('audioUrl', itemIndex);
91
- audioBuffer = await downloadFileFromUrl(audioUrl);
92
- filename = audioUrl.split('/').pop() || 'audio.mp3';
93
- break;
94
- case 'binary':
95
- const audioBinaryProperty = context.getNodeParameter('audioBinaryProperty', itemIndex);
96
- audioBuffer = await getFileFromBinary(context, itemIndex, audioBinaryProperty);
97
- const items = context.getInputData();
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}`);
7
+ try {
8
+ const audioFile = context.getNodeParameter('audioFile', itemIndex, '');
9
+ const audioUrl = context.getNodeParameter('audioUrl', itemIndex, '');
10
+ const audioProperty = context.getNodeParameter('audioBinaryProperty', itemIndex, '');
11
+ const result = await (0, utils_1.processAudioFile)(context, itemIndex, audioSource, audioFile, audioUrl, audioProperty);
12
+ const tokenValidation = (0, utils_1.validateTokenLimit)(result.estimatedTokens, 100000);
13
+ if (!tokenValidation.valid) {
14
+ return {
15
+ dataUrl: '',
16
+ description: (0, utils_1.createAudioSummary)(result.filename, result.size)
17
+ };
18
+ }
19
+ const optimized = (0, utils_1.optimizeAudioForTokens)(result.data, 80000);
20
+ let description = `Audio file: ${result.filename} (${Math.round(result.size / 1024)}KB)`;
21
+ if (optimized.truncated) {
22
+ description += ` - Compressed from ${optimized.originalTokens} to ${optimized.finalTokens} tokens`;
23
+ }
24
+ return {
25
+ dataUrl: `data:${result.mimeType};base64,${optimized.data}`,
26
+ description
27
+ };
105
28
  }
106
- const mimeType = getAudioMimeType(filename);
107
- return `data:${mimeType};base64,${audioBuffer.toString('base64')}`;
108
- }
109
- async function processImageFile(context, itemIndex) {
110
- const imageSource = context.getNodeParameter('imageSource', itemIndex);
111
- let imageBuffer;
112
- let filename = 'image.jpg';
113
- switch (imageSource) {
114
- case 'manual':
115
- const imageFile = context.getNodeParameter('imageFile', itemIndex);
116
- if (imageFile.startsWith('data:image/')) {
117
- return imageFile;
118
- }
119
- else if (imageFile.match(/^[A-Za-z0-9+/=]+$/)) {
120
- imageBuffer = Buffer.from(imageFile, 'base64');
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}`);
29
+ catch (error) {
30
+ return {
31
+ dataUrl: '',
32
+ description: `Error processing audio: ${error instanceof Error ? error.message : 'Unknown error'}`
33
+ };
144
34
  }
145
- const mimeType = getMimeType(filename);
146
- return `data:${mimeType};base64,${imageBuffer.toString('base64')}`;
147
35
  }
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';
36
+ async function processImageFileLegacy(context, itemIndex) {
37
+ const imageSource = context.getNodeParameter('imageSource', itemIndex);
38
+ try {
39
+ const imageFile = context.getNodeParameter('imageFile', itemIndex, '');
40
+ const imageUrl = context.getNodeParameter('imageUrl', itemIndex, '');
41
+ const imageProperty = context.getNodeParameter('imageBinaryProperty', itemIndex, '');
42
+ const result = await (0, utils_1.processImageFile)(context, itemIndex, imageSource, imageFile, imageUrl, imageProperty);
43
+ const tokenValidation = (0, utils_1.validateTokenLimit)(result.estimatedTokens, 50000);
44
+ if (!tokenValidation.valid) {
45
+ throw new Error(`Image too large: ${result.estimatedTokens} estimated tokens. Please use a smaller image.`);
46
+ }
47
+ const optimizedData = (0, utils_1.compressImageToTokenLimit)(result.data, 40000);
48
+ return `data:${result.mimeType};base64,${optimizedData}`;
162
49
  }
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';
50
+ catch (error) {
51
+ throw new Error(`Error processing image: ${error instanceof Error ? error.message : 'Unknown error'}`);
181
52
  }
182
53
  }
183
54
  class GitHubCopilotChatAPI {
@@ -206,24 +77,15 @@ class GitHubCopilotChatAPI {
206
77
  displayName: 'Operation',
207
78
  name: 'operation',
208
79
  type: 'options',
80
+ noDataExpression: true,
209
81
  options: [
210
82
  {
211
83
  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)',
84
+ value: 'chat',
85
+ description: 'Send messages to GitHub Copilot Chat API',
224
86
  },
225
87
  ],
226
- default: 'chatCompletion',
88
+ default: 'chat',
227
89
  },
228
90
  {
229
91
  displayName: 'Model',
@@ -231,38 +93,38 @@ class GitHubCopilotChatAPI {
231
93
  type: 'options',
232
94
  options: [
233
95
  {
234
- name: 'GPT-5 (Latest)',
96
+ name: 'GPT-5',
235
97
  value: 'gpt-5',
236
- description: 'OpenAI GPT-5 - Latest and most advanced model',
98
+ description: 'OpenAI GPT-5 (Latest and most capable)',
237
99
  },
238
100
  {
239
101
  name: 'GPT-5 Mini',
240
102
  value: 'gpt-5-mini',
241
- description: 'OpenAI GPT-5 Mini - Faster and more efficient',
103
+ description: 'OpenAI GPT-5 Mini (Faster, cost-effective)',
242
104
  },
243
105
  {
244
106
  name: 'Claude Opus 4.1',
245
107
  value: 'claude-opus-4.1',
246
- description: 'Anthropic Claude Opus 4.1 - Advanced reasoning',
108
+ description: 'Anthropic Claude Opus 4.1 (Advanced reasoning)',
247
109
  },
248
110
  {
249
111
  name: 'Gemini 2.5 Pro',
250
112
  value: 'gemini-2.5-pro',
251
- description: 'Google Gemini 2.5 Pro - Multimodal capabilities',
113
+ description: 'Google Gemini 2.5 Pro (Multimodal capabilities)',
252
114
  },
253
115
  {
254
116
  name: 'Grok Code Fast 1',
255
117
  value: 'grok-code-fast-1',
256
- description: 'xAI Grok - Optimized for coding tasks',
118
+ description: 'xAI Grok Code Fast 1 (Optimized for coding)',
257
119
  },
258
120
  {
259
121
  name: 'GPT-4.1 Copilot',
260
122
  value: 'gpt-4.1-copilot',
261
- description: 'GitHub Copilot optimized GPT-4.1 model',
123
+ description: 'OpenAI GPT-4.1 specialized for coding assistance',
262
124
  },
263
125
  ],
264
- default: 'gpt-5',
265
- description: 'Choose the AI model from your Copilot subscription',
126
+ default: 'gpt-5-mini',
127
+ description: 'Select AI model to use',
266
128
  },
267
129
  {
268
130
  displayName: 'Message',
@@ -272,313 +134,302 @@ class GitHubCopilotChatAPI {
272
134
  rows: 4,
273
135
  },
274
136
  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
- },
137
+ placeholder: 'What can I help you with?',
138
+ description: 'The message to send to the AI model',
282
139
  },
283
140
  {
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',
141
+ displayName: 'System Message',
142
+ name: 'systemMessage',
303
143
  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
- },
144
+ typeOptions: {
145
+ rows: 3,
312
146
  },
313
- },
314
- {
315
- displayName: 'Audio URL',
316
- name: 'audioUrl',
317
- type: 'string',
318
147
  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
- },
148
+ placeholder: 'You are a helpful assistant...',
149
+ description: 'System message to set the behavior of the AI model',
327
150
  },
328
151
  {
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
- },
152
+ displayName: 'Include Image',
153
+ name: 'includeImage',
154
+ type: 'boolean',
155
+ default: false,
156
+ description: 'Whether to include an image in the message',
341
157
  },
342
158
  {
343
- displayName: 'Audio Language',
344
- name: 'audioLanguage',
159
+ displayName: 'Image Source',
160
+ name: 'imageSource',
345
161
  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
162
  displayOptions: {
360
163
  show: {
361
- operation: ['audioTranscription'],
164
+ includeImage: [true],
362
165
  },
363
166
  },
364
- },
365
- {
366
- displayName: 'Image Source',
367
- name: 'imageSource',
368
- type: 'options',
369
167
  options: [
370
- { name: 'File Path or Base64', value: 'manual' },
371
- { name: 'Download from URL', value: 'url' },
372
- { name: 'From Previous Node Binary', value: 'binary' },
168
+ {
169
+ name: 'Manual Input',
170
+ value: 'manual',
171
+ description: 'Provide image as base64 string or file path',
172
+ },
173
+ {
174
+ name: 'URL',
175
+ value: 'url',
176
+ description: 'Download image from URL',
177
+ },
178
+ {
179
+ name: 'Binary Data',
180
+ value: 'binary',
181
+ description: 'Use binary data from previous node',
182
+ },
373
183
  ],
374
184
  default: 'manual',
375
- description: 'Choose how to provide the image file',
376
- displayOptions: {
377
- show: {
378
- operation: ['imageAnalysis'],
379
- },
380
- },
185
+ description: 'Source of the image data',
381
186
  },
382
187
  {
383
188
  displayName: 'Image File',
384
189
  name: 'imageFile',
385
190
  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
191
  displayOptions: {
390
192
  show: {
391
- operation: ['imageAnalysis'],
193
+ includeImage: [true],
392
194
  imageSource: ['manual'],
393
195
  },
394
196
  },
197
+ default: '',
198
+ placeholder: 'Paste base64 string or file path',
199
+ description: 'Image as base64 string or file path',
395
200
  },
396
201
  {
397
202
  displayName: 'Image URL',
398
203
  name: 'imageUrl',
399
204
  type: 'string',
400
- default: '',
401
- placeholder: 'https://example.com/image.jpg',
402
- description: 'URL to download image file from',
403
205
  displayOptions: {
404
206
  show: {
405
- operation: ['imageAnalysis'],
207
+ includeImage: [true],
406
208
  imageSource: ['url'],
407
209
  },
408
210
  },
211
+ default: '',
212
+ placeholder: 'https://example.com/image.jpg',
213
+ description: 'URL of the image to download and include',
409
214
  },
410
215
  {
411
- displayName: 'Binary Property Name',
216
+ displayName: 'Image Binary Property',
412
217
  name: 'imageBinaryProperty',
413
218
  type: 'string',
219
+ displayOptions: {
220
+ show: {
221
+ includeImage: [true],
222
+ imageSource: ['binary'],
223
+ },
224
+ },
414
225
  default: 'data',
415
226
  placeholder: 'data',
416
- description: 'Name of the binary property containing the image file',
227
+ description: 'Name of the binary property containing the image',
228
+ },
229
+ {
230
+ displayName: 'Include Audio',
231
+ name: 'includeAudio',
232
+ type: 'boolean',
233
+ default: false,
234
+ description: 'Whether to include an audio file in the message',
235
+ },
236
+ {
237
+ displayName: 'Audio Source',
238
+ name: 'audioSource',
239
+ type: 'options',
417
240
  displayOptions: {
418
241
  show: {
419
- operation: ['imageAnalysis'],
420
- imageSource: ['binary'],
242
+ includeAudio: [true],
421
243
  },
422
244
  },
245
+ options: [
246
+ {
247
+ name: 'Manual Input',
248
+ value: 'manual',
249
+ description: 'Provide audio as base64 string or file path',
250
+ },
251
+ {
252
+ name: 'URL',
253
+ value: 'url',
254
+ description: 'Download audio from URL',
255
+ },
256
+ {
257
+ name: 'Binary Data',
258
+ value: 'binary',
259
+ description: 'Use binary data from previous node',
260
+ },
261
+ ],
262
+ default: 'manual',
263
+ description: 'Source of the audio data',
423
264
  },
424
265
  {
425
- displayName: 'System Prompt',
426
- name: 'systemPrompt',
266
+ displayName: 'Audio File',
267
+ name: 'audioFile',
427
268
  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
269
  displayOptions: {
435
270
  show: {
436
- operation: ['chatCompletion', 'imageAnalysis'],
271
+ includeAudio: [true],
272
+ audioSource: ['manual'],
437
273
  },
438
274
  },
275
+ default: '',
276
+ placeholder: 'Paste base64 string or file path',
277
+ description: 'Audio as base64 string or file path',
439
278
  },
440
279
  {
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',
280
+ displayName: 'Audio URL',
281
+ name: 'audioUrl',
282
+ type: 'string',
451
283
  displayOptions: {
452
284
  show: {
453
- operation: ['chatCompletion', 'imageAnalysis'],
285
+ includeAudio: [true],
286
+ audioSource: ['url'],
454
287
  },
455
288
  },
289
+ default: '',
290
+ placeholder: 'https://example.com/audio.mp3',
291
+ description: 'URL of the audio file to download and include',
456
292
  },
457
293
  {
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',
294
+ displayName: 'Audio Binary Property',
295
+ name: 'audioBinaryProperty',
296
+ type: 'string',
467
297
  displayOptions: {
468
298
  show: {
469
- operation: ['chatCompletion', 'imageAnalysis'],
299
+ includeAudio: [true],
300
+ audioSource: ['binary'],
470
301
  },
471
302
  },
303
+ default: 'data',
304
+ placeholder: 'data',
305
+ description: 'Name of the binary property containing the audio file',
306
+ },
307
+ {
308
+ displayName: 'Advanced Options',
309
+ name: 'advancedOptions',
310
+ type: 'collection',
311
+ placeholder: 'Add Field',
312
+ default: {},
313
+ options: [
314
+ {
315
+ displayName: 'Temperature',
316
+ name: 'temperature',
317
+ type: 'number',
318
+ typeOptions: {
319
+ minValue: 0,
320
+ maxValue: 2,
321
+ numberPrecision: 2,
322
+ },
323
+ default: 1,
324
+ description: 'Controls randomness of the response. Higher values make output more random.',
325
+ },
326
+ {
327
+ displayName: 'Max Tokens',
328
+ name: 'max_tokens',
329
+ type: 'number',
330
+ typeOptions: {
331
+ minValue: 1,
332
+ maxValue: 128000,
333
+ },
334
+ default: 4096,
335
+ description: 'Maximum number of tokens to generate in the response',
336
+ },
337
+ {
338
+ displayName: 'Top P',
339
+ name: 'top_p',
340
+ type: 'number',
341
+ typeOptions: {
342
+ minValue: 0,
343
+ maxValue: 1,
344
+ numberPrecision: 2,
345
+ },
346
+ default: 1,
347
+ description: 'Alternative to temperature, controls diversity via nucleus sampling',
348
+ },
349
+ ],
472
350
  },
473
351
  ],
474
352
  };
475
353
  }
476
354
  async execute() {
355
+ var _a, _b, _c;
477
356
  const items = this.getInputData();
478
357
  const returnData = [];
479
358
  for (let i = 0; i < items.length; i++) {
480
359
  try {
481
360
  const operation = this.getNodeParameter('operation', i);
482
361
  const model = this.getNodeParameter('model', i);
483
- let result;
484
- if (operation === 'chatCompletion') {
485
- const message = this.getNodeParameter('message', i);
486
- const systemPrompt = this.getNodeParameter('systemPrompt', i);
487
- const temperature = this.getNodeParameter('temperature', i);
488
- const maxTokens = this.getNodeParameter('maxTokens', i);
362
+ if (operation === 'chat') {
363
+ const userMessage = this.getNodeParameter('message', i);
364
+ const systemMessage = this.getNodeParameter('systemMessage', i, '');
365
+ const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
366
+ const includeImage = this.getNodeParameter('includeImage', i, false);
367
+ const includeAudio = this.getNodeParameter('includeAudio', i, false);
489
368
  const messages = [];
490
- if (systemPrompt) {
491
- messages.push({ role: 'system', content: systemPrompt });
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
- {
369
+ if (systemMessage) {
370
+ messages.push({
518
371
  role: 'system',
519
- content: 'You are an expert at audio transcription. When given an audio file, provide an accurate transcription of the spoken content.'
520
- },
521
- {
522
- role: 'user',
523
- content: `${transcriptionPrompt}\n\nAudio file: ${audioDataUrl}`
372
+ content: systemMessage,
373
+ });
374
+ }
375
+ let userContent = userMessage;
376
+ if (includeImage || includeAudio) {
377
+ const contentArray = [];
378
+ if (userMessage.trim()) {
379
+ contentArray.push({
380
+ type: 'text',
381
+ text: userMessage,
382
+ });
524
383
  }
525
- ];
526
- const requestBody = {
527
- model: model,
528
- messages: messages,
529
- temperature: 0.1,
530
- max_tokens: 4000,
531
- stream: false,
532
- };
533
- const response = await makeApiRequest(this, '/chat/completions', requestBody);
534
- result = {
535
- transcription: response.choices[0].message.content,
536
- language: language,
537
- model: model,
538
- usage: response.usage,
539
- timestamp: new Date().toISOString(),
540
- };
541
- }
542
- else if (operation === 'imageAnalysis') {
543
- const message = this.getNodeParameter('message', i);
544
- const systemPrompt = this.getNodeParameter('systemPrompt', i);
545
- const temperature = this.getNodeParameter('temperature', i);
546
- const maxTokens = this.getNodeParameter('maxTokens', i);
547
- const imageBase64 = await processImageFile(this, i);
548
- const messages = [];
549
- if (systemPrompt) {
550
- messages.push({ role: 'system', content: systemPrompt });
384
+ if (includeImage) {
385
+ const imageDataUrl = await processImageFileLegacy(this, i);
386
+ contentArray.push({
387
+ type: 'image_url',
388
+ image_url: {
389
+ url: imageDataUrl,
390
+ },
391
+ });
392
+ }
393
+ if (includeAudio) {
394
+ const audioResult = await processAudioFileLegacy(this, i);
395
+ if (audioResult.dataUrl) {
396
+ contentArray.push({
397
+ type: 'text',
398
+ text: `[Audio included: ${audioResult.description}]`,
399
+ });
400
+ }
401
+ else {
402
+ contentArray.push({
403
+ type: 'text',
404
+ text: `[Audio processing failed: ${audioResult.description}]`,
405
+ });
406
+ }
407
+ }
408
+ userContent = contentArray;
551
409
  }
552
410
  messages.push({
553
411
  role: 'user',
554
- content: [
555
- { type: 'text', text: message },
556
- { type: 'image_url', image_url: { url: imageBase64 } }
557
- ]
412
+ content: userContent,
558
413
  });
559
414
  const requestBody = {
560
- model: model,
561
- messages: messages,
562
- temperature: temperature,
563
- max_tokens: maxTokens,
415
+ model,
416
+ messages,
564
417
  stream: false,
418
+ ...advancedOptions,
565
419
  };
566
- const response = await makeApiRequest(this, '/chat/completions', requestBody);
567
- result = {
568
- response: response.choices[0].message.content,
569
- model: model,
570
- usage: response.usage,
571
- finish_reason: response.choices[0].finish_reason,
572
- timestamp: new Date().toISOString(),
420
+ const response = await (0, utils_1.makeApiRequest)(this, '/chat/completions', requestBody);
421
+ const result = {
422
+ message: ((_b = (_a = response.choices[0]) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.content) || '',
423
+ model,
424
+ operation,
425
+ usage: response.usage || null,
426
+ finish_reason: ((_c = response.choices[0]) === null || _c === void 0 ? void 0 : _c.finish_reason) || 'unknown',
573
427
  };
428
+ returnData.push({
429
+ json: result,
430
+ pairedItem: { item: i },
431
+ });
574
432
  }
575
- else {
576
- throw new Error(`Unknown operation: ${operation}`);
577
- }
578
- returnData.push({
579
- json: result,
580
- pairedItem: { item: i },
581
- });
582
433
  }
583
434
  catch (error) {
584
435
  if (this.continueOnFail()) {