@5minds/node-red-dashboard-2-processcube-chat 0.1.1-add-functionality-483501-mdqg8xpt → 0.1.1-add-functionality-94845a-me8hect9

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.
@@ -147,7 +147,12 @@ export default {
147
147
  const reader = new FileReader();
148
148
  reader.onload = (e) => {
149
149
  try {
150
- const base64Data = e.target.result.split(',')[1]; // Remove data URL prefix
150
+ const result = e.target.result;
151
+ const commaIndex = result.indexOf(',');
152
+ if (commaIndex === -1) {
153
+ throw new Error('Invalid data URL format: missing comma separator');
154
+ }
155
+ const base64Data = result.split(',')[1]; // Remove data URL prefix
151
156
 
152
157
  resolve({
153
158
  name: file.name,
@@ -187,55 +192,108 @@ export default {
187
192
  },
188
193
 
189
194
  formatForChatGPT(conversation, textOnly = false) {
190
- return {
191
- messages: conversation.map((msg) => {
192
- if (msg.text && (!msg.files || msg.files.length === 0)) {
193
- return {
194
- role: msg.role === 'ai' ? 'assistant' : 'user',
195
- content: msg.text,
196
- };
197
- } else if (msg.files && msg.files.length > 0) {
198
- const content = [{ type: 'text', text: msg.text || '' }];
199
-
200
- msg.files.forEach((file) => {
201
- if (file.type && file.type.startsWith('image/') && file.src) {
202
- content.push({
203
- type: 'image_url',
204
- image_url: { url: file.src },
205
- });
206
- } else if (!textOnly && file.type && file.type.startsWith('audio/') && file.base64Data) {
207
- const format = this.getAudioFormat(file.type);
208
- content.push({
209
- type: 'input_audio',
210
- input_audio: {
211
- data: file.base64Data,
212
- format: format,
213
- },
214
- });
215
- } else if (!textOnly && file.fileData) {
216
- content.push({
217
- type: 'file',
218
- file: {
219
- filename: file.name,
220
- file_data: file.fileData,
221
- },
222
- });
223
- }
224
- });
195
+ const payload = {
196
+ messages: conversation.map((msg) => this.formatMessage(msg, textOnly)),
197
+ model: this.props.model,
198
+ };
225
199
 
226
- return {
227
- role: msg.role === 'ai' ? 'assistant' : 'user',
228
- content: content,
229
- };
230
- }
200
+ // Add ChatGPT API extensions
201
+ if (this.props.tools) {
202
+ payload.tools = this.props.tools;
203
+ }
231
204
 
232
- return {
233
- role: msg.role === 'ai' ? 'assistant' : 'user',
234
- content: msg.text || '',
235
- };
236
- }),
237
- model: this.props.model,
205
+ if (this.props.tool_choice) {
206
+ payload.tool_choice = this.props.tool_choice;
207
+ }
208
+
209
+ if (this.props.temperature !== undefined) {
210
+ payload.temperature = this.props.temperature;
211
+ }
212
+
213
+ if (this.props.max_tokens) {
214
+ payload.max_tokens = this.props.max_tokens;
215
+ }
216
+
217
+ if (this.props.top_p !== undefined) {
218
+ payload.top_p = this.props.top_p;
219
+ }
220
+
221
+ if (this.props.frequency_penalty !== undefined) {
222
+ payload.frequency_penalty = this.props.frequency_penalty;
223
+ }
224
+
225
+ if (this.props.presence_penalty !== undefined) {
226
+ payload.presence_penalty = this.props.presence_penalty;
227
+ }
228
+
229
+ if (this.props.response_format) {
230
+ payload.response_format = this.props.response_format;
231
+ }
232
+
233
+ return payload;
234
+ },
235
+
236
+ formatMessage(msg, textOnly = false) {
237
+ const message = {
238
+ role: msg.role === 'ai' ? 'assistant' : 'user',
238
239
  };
240
+
241
+ // Handle tool calls (for assistant messages)
242
+ if (msg.tool_calls) {
243
+ message.tool_calls = msg.tool_calls;
244
+ message.content = msg.content || null;
245
+ return message;
246
+ }
247
+
248
+ // Handle tool responses (for tool messages)
249
+ if (msg.role === 'tool') {
250
+ message.role = 'tool';
251
+ message.content = msg.content;
252
+ message.tool_call_id = msg.tool_call_id;
253
+ return message;
254
+ }
255
+
256
+ // Handle messages with files
257
+ if (msg.files && msg.files.length > 0) {
258
+ message.content = this.buildContentArray(msg, textOnly);
259
+ return message;
260
+ }
261
+
262
+ // Handle text-only messages
263
+ message.content = msg.text || msg.content || '';
264
+ return message;
265
+ },
266
+
267
+ buildContentArray(msg, textOnly) {
268
+ const content = [{ type: 'text', text: msg.text || '' }];
269
+
270
+ msg.files.forEach((file) => {
271
+ if (file.type && file.type.startsWith('image/') && file.src) {
272
+ content.push({
273
+ type: 'image_url',
274
+ image_url: { url: file.src },
275
+ });
276
+ } else if (!textOnly && file.type && file.type.startsWith('audio/') && file.base64Data) {
277
+ const format = this.getAudioFormat(file.type);
278
+ content.push({
279
+ type: 'input_audio',
280
+ input_audio: {
281
+ data: file.base64Data,
282
+ format: format,
283
+ },
284
+ });
285
+ } else if (!textOnly && file.fileData) {
286
+ content.push({
287
+ type: 'file',
288
+ file: {
289
+ filename: file.name,
290
+ file_data: file.fileData,
291
+ },
292
+ });
293
+ }
294
+ });
295
+
296
+ return content;
239
297
  },
240
298
 
241
299
  getAudioFormat(mimeType) {
@@ -256,16 +314,36 @@ export default {
256
314
 
257
315
  handleNodeREDResponse(msg, signals) {
258
316
  try {
317
+ // Store the complete ChatGPT response in conversation
318
+ const fullResponse = msg.payload;
319
+
320
+ // Create AI message with complete response data
259
321
  const aiMessage = {
260
- text: msg.payload.text || msg.payload.content,
261
322
  role: 'ai',
323
+ content: fullResponse.message?.content || fullResponse.content,
324
+ text: fullResponse.message?.content || fullResponse.content,
325
+ fullResponse: fullResponse,
262
326
  };
263
327
 
328
+ // Handle tool calls if present
329
+ if (fullResponse.message?.tool_calls) {
330
+ aiMessage.tool_calls = fullResponse.message.tool_calls;
331
+ aiMessage.content = fullResponse.message.content || null;
332
+ }
333
+
264
334
  this.conversation.push(aiMessage);
265
335
 
266
- if (msg.payload) {
336
+ // For the chat display, show appropriate response
337
+ if (fullResponse.message?.tool_calls) {
338
+ // If ChatGPT wants to call tools, show a message
339
+ signals.onResponse({
340
+ text: 'Function call requested...',
341
+ role: 'ai',
342
+ });
343
+ } else if (fullResponse.message?.content || fullResponse.content) {
344
+ // Normal text response
267
345
  signals.onResponse({
268
- text: msg.payload.text || msg.payload.content,
346
+ text: fullResponse.message?.content || fullResponse.content,
269
347
  role: 'ai',
270
348
  });
271
349
  }