@5minds/node-red-dashboard-2-processcube-chat 0.1.1-develop-bd0cb7-mcvkuzxr → 0.1.1-develop-cb2322-mf120t2z
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/nodes/ui-deepchat.html +87 -102
- package/nodes/ui-deepchat.js +13 -126
- package/package.json +2 -1
- package/resources/ui-deepchat.umd.js +273 -2
- package/resources/ui-deepchat.umd.js.map +1 -0
- package/ui/components/UIDeepChat.vue +322 -297
|
@@ -1,349 +1,374 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div class="deep-chat-container">
|
|
3
3
|
<deep-chat
|
|
4
|
-
|
|
5
|
-
:
|
|
6
|
-
:
|
|
7
|
-
:text-input="config.textInput"
|
|
8
|
-
:speech-to-text="speechToTextConfig"
|
|
9
|
-
:camera="cameraConfig"
|
|
10
|
-
:microphone="microphoneConfig"
|
|
11
|
-
:mixedFiles="attachmentsConfig"
|
|
12
|
-
:avatars="config.avatars"
|
|
13
|
-
:names="config.names"
|
|
14
|
-
:timestamps="config.timestamps"
|
|
15
|
-
:stream="config.stream"
|
|
4
|
+
:style="deepChatStyle"
|
|
5
|
+
:textInput="textInputConfig"
|
|
6
|
+
:introMessage="introMessageConfig"
|
|
16
7
|
:connect="connectConfig"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
:speechToText="props.speechToText"
|
|
9
|
+
:camera="props.camera"
|
|
10
|
+
:mixedFiles="props.attachments"
|
|
11
|
+
:avatars="props.avatars"
|
|
12
|
+
:names="props.names"
|
|
13
|
+
:timestamps="props.timestamps"
|
|
14
|
+
:stream="props.stream"
|
|
22
15
|
></deep-chat>
|
|
23
16
|
</div>
|
|
24
17
|
</template>
|
|
25
18
|
|
|
26
19
|
<script>
|
|
20
|
+
import 'deep-chat';
|
|
21
|
+
|
|
27
22
|
export default {
|
|
28
23
|
name: 'UIDeepChat',
|
|
29
24
|
props: ['id', 'props', 'state'],
|
|
30
|
-
|
|
25
|
+
inject: ['$socket'],
|
|
31
26
|
data() {
|
|
32
27
|
return {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
placeholder: 'Type a message...',
|
|
36
|
-
apiUrl: '',
|
|
37
|
-
apiKey: '',
|
|
38
|
-
model: 'gpt-3.5-turbo',
|
|
39
|
-
textInput: true,
|
|
40
|
-
speechToText: false,
|
|
41
|
-
camera: false,
|
|
42
|
-
microphone: false,
|
|
43
|
-
attachments: false,
|
|
44
|
-
avatars: true,
|
|
45
|
-
names: true,
|
|
46
|
-
timestamps: false,
|
|
47
|
-
stream: false
|
|
48
|
-
},
|
|
49
|
-
isDeepChatLoaded: false,
|
|
50
|
-
messages: []
|
|
51
|
-
}
|
|
28
|
+
conversation: [],
|
|
29
|
+
};
|
|
52
30
|
},
|
|
53
|
-
|
|
31
|
+
|
|
54
32
|
computed: {
|
|
55
|
-
|
|
33
|
+
deepChatStyle() {
|
|
56
34
|
return {
|
|
57
35
|
width: '100%',
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
speechToTextConfig() {
|
|
64
|
-
return this.config.speechToText ? {
|
|
65
|
-
button: true,
|
|
66
|
-
displayInterimResults: true
|
|
67
|
-
} : false
|
|
36
|
+
maxWidth: '600px',
|
|
37
|
+
height: '80vh',
|
|
38
|
+
borderRadius: '8px',
|
|
39
|
+
};
|
|
68
40
|
},
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
microphoneConfig() {
|
|
77
|
-
return this.config.microphone ? {
|
|
78
|
-
button: true,
|
|
79
|
-
audio: true
|
|
80
|
-
} : false
|
|
41
|
+
|
|
42
|
+
textInputConfig() {
|
|
43
|
+
return {
|
|
44
|
+
placeholder: {
|
|
45
|
+
text: this.props.placeholder || 'Type a message...',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
81
48
|
},
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
} : false
|
|
49
|
+
|
|
50
|
+
introMessageConfig() {
|
|
51
|
+
return {
|
|
52
|
+
text: this.props.introMessage || 'Hello! How can I help you today?',
|
|
53
|
+
};
|
|
88
54
|
},
|
|
89
|
-
|
|
55
|
+
|
|
90
56
|
connectConfig() {
|
|
91
|
-
if (this.config.apiUrl && this.config.apiKey) {
|
|
92
|
-
return {
|
|
93
|
-
url: this.config.apiUrl,
|
|
94
|
-
method: 'POST',
|
|
95
|
-
headers: {
|
|
96
|
-
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
97
|
-
'Content-Type': 'application/json'
|
|
98
|
-
},
|
|
99
|
-
body: {
|
|
100
|
-
model: this.config.model,
|
|
101
|
-
max_tokens: 2000,
|
|
102
|
-
temperature: 0.7
|
|
103
|
-
},
|
|
104
|
-
stream: this.config.stream
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Custom Handler für Node-RED Integration
|
|
109
57
|
return {
|
|
110
|
-
handler: this.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
mounted() {
|
|
117
|
-
this.loadDeepChat()
|
|
118
|
-
this.setupSocketListeners()
|
|
119
|
-
this.applyConfiguration()
|
|
58
|
+
handler: this.handleConnection,
|
|
59
|
+
};
|
|
60
|
+
},
|
|
120
61
|
},
|
|
121
|
-
|
|
122
62
|
beforeUnmount() {
|
|
123
|
-
this.
|
|
63
|
+
this.$socket.off('msg-input:' + this.id);
|
|
124
64
|
},
|
|
125
|
-
|
|
65
|
+
|
|
126
66
|
methods: {
|
|
127
|
-
async
|
|
67
|
+
async handleConnection(body, signals) {
|
|
128
68
|
try {
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
69
|
+
// Extract messages and files from FormData
|
|
70
|
+
let newMessages = [];
|
|
71
|
+
let files = [];
|
|
72
|
+
|
|
73
|
+
if (body instanceof FormData) {
|
|
74
|
+
for (let [key, value] of body.entries()) {
|
|
75
|
+
if (key.startsWith('message')) {
|
|
76
|
+
try {
|
|
77
|
+
const messageContent = JSON.parse(value);
|
|
78
|
+
newMessages.push(messageContent);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.error('Error parsing message:', e);
|
|
81
|
+
}
|
|
82
|
+
} else if (key === 'files') {
|
|
83
|
+
files.push(value);
|
|
84
|
+
}
|
|
138
85
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.
|
|
144
|
-
}
|
|
86
|
+
|
|
87
|
+
// Process files if present
|
|
88
|
+
if (files.length > 0 && newMessages.length > 0) {
|
|
89
|
+
const lastMessage = newMessages[newMessages.length - 1];
|
|
90
|
+
lastMessage.files = await this.processFiles(files);
|
|
91
|
+
}
|
|
92
|
+
} else if (body.messages) {
|
|
93
|
+
newMessages = body.messages;
|
|
145
94
|
}
|
|
95
|
+
|
|
96
|
+
// Add to conversation history
|
|
97
|
+
this.conversation.push(...newMessages);
|
|
98
|
+
|
|
99
|
+
// Send to Node-RED
|
|
100
|
+
const payload = this.formatForChatGPT(this.conversation);
|
|
101
|
+
this.sendToNodeRED(payload, signals);
|
|
146
102
|
} catch (error) {
|
|
147
|
-
console.error('Error
|
|
103
|
+
console.error('Error in handleConnection:', error);
|
|
104
|
+
this.sendErrorResponse(signals, 'Sorry, there was an error processing your message.');
|
|
148
105
|
}
|
|
149
106
|
},
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
107
|
+
|
|
108
|
+
async processFiles(files) {
|
|
109
|
+
try {
|
|
110
|
+
return await Promise.all(
|
|
111
|
+
files.map(async (file) => {
|
|
112
|
+
if (!(file instanceof File)) return file;
|
|
113
|
+
|
|
114
|
+
if (file.type.startsWith('image/')) {
|
|
115
|
+
return await this.processImageFile(file);
|
|
116
|
+
} else if (file.type.startsWith('audio/')) {
|
|
117
|
+
return await this.processAudioFile(file);
|
|
118
|
+
} else {
|
|
119
|
+
// Handle other file types (PDFs, documents, etc.)
|
|
120
|
+
return await this.processDocumentFile(file);
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('Error processing files:', error);
|
|
126
|
+
return [];
|
|
160
127
|
}
|
|
161
128
|
},
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
this.$socket.on('deepchat-clearMessages:' + this.id, () => {
|
|
177
|
-
this.clearMessages()
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
// Standard Dashboard Message Input
|
|
181
|
-
this.$socket.on('msg-input:' + this.id, (msg) => {
|
|
182
|
-
if (msg.payload) {
|
|
183
|
-
this.addMessage(msg.payload, msg.role || 'ai', msg.html, msg.files)
|
|
184
|
-
}
|
|
185
|
-
if (msg.config) {
|
|
186
|
-
this.config = { ...this.config, ...msg.config }
|
|
187
|
-
}
|
|
188
|
-
if (msg.clear) {
|
|
189
|
-
this.clearMessages()
|
|
190
|
-
}
|
|
191
|
-
})
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
removeSocketListeners() {
|
|
195
|
-
this.$socket.off('deepchat-newMessage:' + this.id)
|
|
196
|
-
this.$socket.off('deepchat-updateConfig:' + this.id)
|
|
197
|
-
this.$socket.off('deepchat-clearMessages:' + this.id)
|
|
198
|
-
this.$socket.off('msg-input:' + this.id)
|
|
129
|
+
|
|
130
|
+
processImageFile(file) {
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
const reader = new FileReader();
|
|
133
|
+
reader.onload = (e) =>
|
|
134
|
+
resolve({
|
|
135
|
+
name: file.name,
|
|
136
|
+
type: file.type,
|
|
137
|
+
size: file.size,
|
|
138
|
+
src: e.target.result,
|
|
139
|
+
});
|
|
140
|
+
reader.onerror = () => reject(new Error('Failed to read image'));
|
|
141
|
+
reader.readAsDataURL(file);
|
|
142
|
+
});
|
|
199
143
|
},
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
144
|
+
|
|
145
|
+
processAudioFile(file) {
|
|
146
|
+
return new Promise((resolve, reject) => {
|
|
147
|
+
const reader = new FileReader();
|
|
148
|
+
reader.onload = (e) => {
|
|
149
|
+
try {
|
|
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
|
|
156
|
+
|
|
157
|
+
resolve({
|
|
158
|
+
name: file.name,
|
|
159
|
+
type: file.type,
|
|
160
|
+
size: file.size,
|
|
161
|
+
base64Data: base64Data,
|
|
162
|
+
});
|
|
163
|
+
} catch (error) {
|
|
164
|
+
reject(error);
|
|
207
165
|
}
|
|
208
|
-
}
|
|
209
|
-
|
|
166
|
+
};
|
|
167
|
+
reader.onerror = () => reject(new Error('Failed to read audio'));
|
|
168
|
+
reader.readAsDataURL(file);
|
|
169
|
+
});
|
|
210
170
|
},
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
171
|
+
|
|
172
|
+
processDocumentFile(file) {
|
|
173
|
+
return new Promise((resolve, reject) => {
|
|
174
|
+
const reader = new FileReader();
|
|
175
|
+
reader.onload = (e) => {
|
|
176
|
+
try {
|
|
177
|
+
const base64Data = e.target.result.split(',')[1]; // Remove data URL prefix
|
|
178
|
+
|
|
179
|
+
resolve({
|
|
180
|
+
name: file.name,
|
|
181
|
+
type: file.type,
|
|
182
|
+
size: file.size,
|
|
183
|
+
fileData: base64Data, // Use fileData for documents
|
|
184
|
+
});
|
|
185
|
+
} catch (error) {
|
|
186
|
+
reject(error);
|
|
227
187
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
} catch (error) {
|
|
234
|
-
console.error('Error adding message to Deep Chat:', error)
|
|
235
|
-
}
|
|
188
|
+
};
|
|
189
|
+
reader.onerror = () => reject(new Error('Failed to read document'));
|
|
190
|
+
reader.readAsDataURL(file);
|
|
191
|
+
});
|
|
236
192
|
},
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
193
|
+
|
|
194
|
+
formatForChatGPT(conversation, textOnly = false) {
|
|
195
|
+
const payload = {
|
|
196
|
+
messages: conversation.map((msg) => this.formatMessage(msg, textOnly)),
|
|
197
|
+
model: this.props.model,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Add ChatGPT API extensions
|
|
201
|
+
if (this.props.tools) {
|
|
202
|
+
payload.tools = this.props.tools;
|
|
246
203
|
}
|
|
204
|
+
|
|
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;
|
|
247
234
|
},
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
235
|
+
|
|
236
|
+
formatMessage(msg, textOnly = false) {
|
|
237
|
+
const message = {
|
|
238
|
+
role: msg.role === 'ai' ? 'assistant' : 'user',
|
|
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;
|
|
271
265
|
},
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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;
|
|
278
297
|
},
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
298
|
+
|
|
299
|
+
getAudioFormat(mimeType) {
|
|
300
|
+
if (mimeType.includes('mp3')) return 'mp3';
|
|
301
|
+
if (mimeType.includes('wav')) return 'wav';
|
|
302
|
+
if (mimeType.includes('webm')) return 'webm';
|
|
303
|
+
if (mimeType.includes('m4a')) return 'm4a';
|
|
304
|
+
return 'wav';
|
|
286
305
|
},
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
306
|
+
|
|
307
|
+
sendToNodeRED(payload, signals, fallbackMessage = null) {
|
|
308
|
+
this.$socket.emit('widget-action', this.id, { payload });
|
|
309
|
+
|
|
310
|
+
this.$socket.once('msg-input:' + this.id, (msg) => {
|
|
311
|
+
this.handleNodeREDResponse(msg, signals);
|
|
312
|
+
});
|
|
290
313
|
},
|
|
291
|
-
|
|
292
|
-
handleError(error) {
|
|
293
|
-
console.error('Deep Chat Error:', error)
|
|
294
|
-
|
|
295
|
-
// Fehler an Node-RED melden
|
|
296
|
-
this.$socket.emit('chat-message', this.id, {
|
|
297
|
-
error: error.message || error,
|
|
298
|
-
timestamp: new Date().toISOString()
|
|
299
|
-
})
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
</script>
|
|
304
314
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
overflow: hidden;
|
|
310
|
-
background: var(--v-theme-surface);
|
|
311
|
-
}
|
|
315
|
+
handleNodeREDResponse(msg, signals) {
|
|
316
|
+
try {
|
|
317
|
+
// Store the complete ChatGPT response in conversation
|
|
318
|
+
const fullResponse = msg.payload;
|
|
312
319
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
320
|
+
// Create AI message with complete response data
|
|
321
|
+
const aiMessage = {
|
|
322
|
+
role: 'ai',
|
|
323
|
+
content: fullResponse.message?.content || fullResponse.content,
|
|
324
|
+
text: fullResponse.message?.content || fullResponse.content,
|
|
325
|
+
fullResponse: fullResponse,
|
|
326
|
+
};
|
|
321
327
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
--border-color: var(--v-theme-outline);
|
|
328
|
-
--text-color: var(--v-theme-on-surface);
|
|
329
|
-
--placeholder-color: var(--v-theme-on-surface-variant);
|
|
330
|
-
}
|
|
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
|
+
}
|
|
331
333
|
|
|
332
|
-
|
|
333
|
-
.ui-deepchat-container :deep(.text-input-container) {
|
|
334
|
-
border-top: 1px solid var(--v-theme-outline) !important;
|
|
335
|
-
background: var(--v-theme-surface) !important;
|
|
336
|
-
}
|
|
334
|
+
this.conversation.push(aiMessage);
|
|
337
335
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
|
345
|
+
signals.onResponse({
|
|
346
|
+
text: fullResponse.message?.content || fullResponse.content,
|
|
347
|
+
role: 'ai',
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.error('Error handling response:', error);
|
|
352
|
+
this.sendErrorResponse(signals, 'Error processing response');
|
|
353
|
+
}
|
|
354
|
+
},
|
|
342
355
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
356
|
+
sendErrorResponse(signals, message) {
|
|
357
|
+
if (signals && signals.onResponse) {
|
|
358
|
+
signals.onResponse({
|
|
359
|
+
text: message,
|
|
360
|
+
role: 'ai',
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
</script>
|
|
367
|
+
|
|
368
|
+
<style scoped>
|
|
369
|
+
.deep-chat-container {
|
|
370
|
+
display: flex;
|
|
371
|
+
justify-content: center;
|
|
372
|
+
width: 100%;
|
|
348
373
|
}
|
|
349
|
-
</style>
|
|
374
|
+
</style>
|