@quidgest/chatbot 0.4.0 → 0.5.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.
- package/dist/components/ChatBot/ChatBot.vue.d.ts +53 -0
- package/dist/components/ChatBot/types.d.ts +48 -0
- package/dist/components/ChatBotInput/ChatBotInput.vue.d.ts +17 -0
- package/dist/components/ChatBotInput/index.d.ts +5 -0
- package/dist/components/ChatBotInput/types.d.ts +28 -0
- package/dist/components/ChatBotMessage/ChatBotMessage.vue.d.ts +41 -0
- package/dist/components/ChatBotMessage/ChatBotMessageButtons.vue.d.ts +21 -0
- package/dist/components/ChatBotMessage/index.d.ts +6 -0
- package/dist/components/ChatBotMessage/types.d.ts +46 -0
- package/dist/components/ChatToolBar/ChatToolBar.vue.d.ts +39 -0
- package/dist/components/ChatToolBar/index.d.ts +5 -0
- package/dist/components/ChatToolBar/types.d.ts +16 -0
- package/dist/components/FieldPreview/FieldPreview.vue.d.ts +17 -0
- package/dist/components/FieldPreview/index.d.ts +5 -0
- package/dist/components/FieldPreview/types.d.ts +7 -0
- package/dist/components/MarkdownRender/MarkdownRender.vue.d.ts +13 -0
- package/dist/components/MarkdownRender/index.d.ts +5 -0
- package/dist/components/MarkdownRender/types.d.ts +7 -0
- package/dist/composables/useChatApi.d.ts +23 -0
- package/dist/composables/useChatMessages.d.ts +11 -0
- package/dist/composables/useSSE.d.ts +10 -0
- package/dist/composables/useTexts.d.ts +26 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +27 -47
- package/dist/index.mjs +2651 -8663
- package/dist/style.css +1 -1
- package/dist/utils/helper.d.ts +1 -0
- package/package.json +5 -5
- package/src/assets/chatbot_profile.svg +1 -0
- package/src/assets/styles/styles.scss +10 -42
- package/src/components/ChatBot/ChatBot.vue +375 -0
- package/src/components/ChatBot/types.ts +55 -0
- package/src/components/ChatBotInput/ChatBotInput.vue +195 -0
- package/src/components/ChatBotInput/index.ts +5 -0
- package/src/components/ChatBotInput/types.ts +33 -0
- package/src/components/ChatBotMessage/ChatBotMessage.vue +139 -0
- package/src/components/ChatBotMessage/ChatBotMessageButtons.vue +169 -0
- package/src/components/ChatBotMessage/index.ts +8 -0
- package/src/components/ChatBotMessage/types.ts +70 -0
- package/src/components/ChatToolBar/ChatToolBar.vue +82 -0
- package/src/components/ChatToolBar/index.ts +5 -0
- package/src/components/ChatToolBar/types.ts +18 -0
- package/src/components/FieldPreview/FieldPreview.vue +78 -0
- package/src/components/FieldPreview/field-preview.scss +34 -0
- package/src/components/FieldPreview/index.ts +5 -0
- package/src/components/FieldPreview/types.ts +7 -0
- package/src/components/MarkdownRender/MarkdownRender.vue +25 -0
- package/src/components/MarkdownRender/index.ts +5 -0
- package/src/components/MarkdownRender/markdown-render.scss +24 -0
- package/src/components/MarkdownRender/types.ts +7 -0
- package/src/components/PulseDots/PulseDots.vue +24 -0
- package/src/components/PulseDots/pulse-dots.scss +37 -0
- package/src/composables/useChatApi.ts +156 -0
- package/src/composables/useChatMessages.ts +58 -0
- package/src/composables/useSSE.ts +90 -0
- package/src/composables/useTexts.ts +32 -0
- package/src/index.ts +1 -1
- package/src/utils/helper.ts +12 -0
- package/dist/components/CBMessage.vue.d.ts +0 -95
- package/dist/components/ChatBot.vue.d.ts +0 -65
- package/dist/components/index.d.ts +0 -4
- package/dist/types/chatbot.type.d.ts +0 -14
- package/dist/types/message.type.d.ts +0 -34
- package/dist/types/texts.type.d.ts +0 -3
- package/src/assets/chatbot.png +0 -0
- package/src/components/CBMessage.vue +0 -276
- package/src/components/ChatBot.vue +0 -496
- package/src/components/PulseDots.vue +0 -15
- package/src/components/index.ts +0 -4
- package/src/types/chatbot.type.ts +0 -15
- package/src/types/message.type.ts +0 -55
- package/src/types/texts.type.ts +0 -3
- /package/dist/components/{PulseDots.vue.d.ts → PulseDots/PulseDots.vue.d.ts} +0 -0
|
@@ -1,496 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="q-chatbot">
|
|
3
|
-
<div class="q-chatbot__content">
|
|
4
|
-
<!-- Chat tools -->
|
|
5
|
-
<div class="q-chatbot__tools">
|
|
6
|
-
<q-button
|
|
7
|
-
:title="props.texts.clearChat"
|
|
8
|
-
:disabled="isChatDisabled"
|
|
9
|
-
borderless
|
|
10
|
-
@click="clearChat">
|
|
11
|
-
<QIcon icon="bin" />
|
|
12
|
-
</q-button>
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
<!-- Attach ref to messages container -->
|
|
16
|
-
<div
|
|
17
|
-
ref="messagesContainer"
|
|
18
|
-
class="q-chatbot__messages-container"
|
|
19
|
-
@scroll="handleScroll">
|
|
20
|
-
<div
|
|
21
|
-
v-for="message in messages"
|
|
22
|
-
:key="message.id"
|
|
23
|
-
:class="getMessageClasses(message.sender)">
|
|
24
|
-
<!-- Pass the streaming flag to CBMessage for animation -->
|
|
25
|
-
<c-b-message
|
|
26
|
-
v-bind="message"
|
|
27
|
-
:date-format="props.dateFormat"
|
|
28
|
-
:user-image="props.userImage"
|
|
29
|
-
:chatbot-image="props.chatbotImage"
|
|
30
|
-
:loading="isLoading && !message.message"
|
|
31
|
-
:imagePreviewUrl="message.imagePreviewUrl"
|
|
32
|
-
:apiEndpoint="props.apiEndpoint"
|
|
33
|
-
:sessionID="message.sessionID"/>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
<div class="q-chatbot__footer-container">
|
|
39
|
-
<q-label :label="props.texts.inputLabel"/>
|
|
40
|
-
<div
|
|
41
|
-
class="q-chatbot__footer"
|
|
42
|
-
@dragover.prevent="onDragOver"
|
|
43
|
-
@dragleave.prevent="onDragLeave"
|
|
44
|
-
@drop.prevent="onDrop"
|
|
45
|
-
:class="chatBotFooterClasses">
|
|
46
|
-
<div class="q-chatbot__input-wrapper">
|
|
47
|
-
<div
|
|
48
|
-
v-if="imagePreviewUrl"
|
|
49
|
-
class="q-chatbot__image-preview">
|
|
50
|
-
<img
|
|
51
|
-
:src="imagePreviewUrl"
|
|
52
|
-
tabindex="0"
|
|
53
|
-
alt="Image preview" />
|
|
54
|
-
<q-button
|
|
55
|
-
class="q-chatbot__remove-image"
|
|
56
|
-
tabindex="0"
|
|
57
|
-
flat
|
|
58
|
-
round
|
|
59
|
-
@click="removeImage">
|
|
60
|
-
<q-icon icon="bin" />
|
|
61
|
-
</q-button>
|
|
62
|
-
</div>
|
|
63
|
-
<div class="q-chatbot__input">
|
|
64
|
-
<q-text-area
|
|
65
|
-
v-model="userPrompt"
|
|
66
|
-
size="block"
|
|
67
|
-
autosize
|
|
68
|
-
resize="none"
|
|
69
|
-
:rows="2"
|
|
70
|
-
:disabled="isDisabled"
|
|
71
|
-
@keyup.enter="sendMessage" />
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
<div class="q-chatbot__send-container">
|
|
75
|
-
<!-- Upload button moved to the same container as send, but positioned to the left -->
|
|
76
|
-
<q-button
|
|
77
|
-
:title="props.texts.imageUpload"
|
|
78
|
-
class="q-chatbot__upload"
|
|
79
|
-
:disabled="isChatDisabled || isLoading || hasSelectedImage"
|
|
80
|
-
@click="triggerImageUpload">
|
|
81
|
-
<q-icon icon="upload" />
|
|
82
|
-
</q-button>
|
|
83
|
-
|
|
84
|
-
<!-- Hidden file input -->
|
|
85
|
-
<input
|
|
86
|
-
id="image-upload"
|
|
87
|
-
type="file"
|
|
88
|
-
ref="imageInput"
|
|
89
|
-
@change="handleImageUpload"
|
|
90
|
-
:accept="acceptedImageTypes"
|
|
91
|
-
class="hidden-input" style="display: none;" />
|
|
92
|
-
|
|
93
|
-
<q-button
|
|
94
|
-
:title="props.texts.sendMessage"
|
|
95
|
-
variant="bold"
|
|
96
|
-
class="q-chatbot__send"
|
|
97
|
-
:disabled="isSendButtonDisabled"
|
|
98
|
-
:readonly="isSendButtonDisabled"
|
|
99
|
-
:loading="isLoading"
|
|
100
|
-
@click="sendMessage">
|
|
101
|
-
<q-icon icon="send" />
|
|
102
|
-
</q-button>
|
|
103
|
-
</div>
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
</template>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<script setup lang="ts">
|
|
111
|
-
import { onMounted, nextTick, ref, watch, computed } from 'vue'
|
|
112
|
-
import type { Ref } from 'vue'
|
|
113
|
-
import axios from 'axios'
|
|
114
|
-
import type { AxiosResponse } from 'axios'
|
|
115
|
-
import { CBMessage } from '@/components'
|
|
116
|
-
|
|
117
|
-
import { QButton, QTextArea, QIcon, QLabel } from '@quidgest/ui/components'
|
|
118
|
-
import type { ChatBotMessage, ChatBotMessageContent, ChatBotMessageSender } from '@/types/message.type'
|
|
119
|
-
import { v4 as uuidv4 } from 'uuid'
|
|
120
|
-
|
|
121
|
-
import ChatBotIcon from '@/assets/chatbot.png'
|
|
122
|
-
import UserIcon from '@/assets/user_avatar.png'
|
|
123
|
-
import { ChatBotProps } from '@/types/chatbot.type'
|
|
124
|
-
|
|
125
|
-
const messages: Ref<ChatBotMessage[]> = ref([])
|
|
126
|
-
const nextMessageId = ref(1)
|
|
127
|
-
const userPrompt = ref('')
|
|
128
|
-
const isLoading = ref(false)
|
|
129
|
-
const isChatDisabled = ref(false)
|
|
130
|
-
|
|
131
|
-
// Ref for the messages container
|
|
132
|
-
const messagesContainer = ref<HTMLElement | null>(null)
|
|
133
|
-
// Flag to control auto-scrolling
|
|
134
|
-
const autoScrollEnabled = ref(true)
|
|
135
|
-
|
|
136
|
-
const imageInput = ref<HTMLInputElement | null>(null)
|
|
137
|
-
const imagePreviewUrl = ref<string | null>(null)
|
|
138
|
-
const acceptedImageTypes = computed(() => '.png, .jpeg, .jpg, .svg, .webp')
|
|
139
|
-
const hasSelectedImage = ref<boolean>(false)
|
|
140
|
-
const isDragging = ref(false)
|
|
141
|
-
|
|
142
|
-
// Computed property to check if the send button should be enabled
|
|
143
|
-
const isSendButtonDisabled = computed(() => {
|
|
144
|
-
return userPrompt.value.trim().length === 0 || isLoading.value || isChatDisabled.value
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
const props = withDefaults(defineProps<ChatBotProps>(), {
|
|
148
|
-
apiEndpoint: 'http://localhost:3000',
|
|
149
|
-
userImage: UserIcon,
|
|
150
|
-
chatbotImage: ChatBotIcon,
|
|
151
|
-
mode: 'chat',
|
|
152
|
-
texts: () => ({
|
|
153
|
-
chatbotTitle: 'ChatBot',
|
|
154
|
-
sendMessage: 'Send message',
|
|
155
|
-
clearChat: 'Clear chat',
|
|
156
|
-
inputLabel: 'What can I help with?',
|
|
157
|
-
imageUpload: 'Upload Image',
|
|
158
|
-
imageUploadQButton: 'Upload Image',
|
|
159
|
-
goodResponse: 'Good response',
|
|
160
|
-
badResponse: 'Bad response',
|
|
161
|
-
initialMessage:
|
|
162
|
-
"Howdy! I am GenioBot 👋, Quidgest's personal AI assistant! How can I help you?",
|
|
163
|
-
initialAgentMessage: 'Just a temporary message while we are working on the agent mode',
|
|
164
|
-
loginError:
|
|
165
|
-
'Uh oh, I could not authenticate with the Quidgest API endpoint 😓',
|
|
166
|
-
botIsSick:
|
|
167
|
-
'*cough cough* GenioBot is not feeling alright 🥴️🤒, looks like something failed!'
|
|
168
|
-
})
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
onMounted(() => {
|
|
172
|
-
initChat()
|
|
173
|
-
nextTick(() => {
|
|
174
|
-
messagesContainer.value?.addEventListener('scroll', handleScroll)
|
|
175
|
-
})
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
const isDisabled = computed(() => {
|
|
179
|
-
return isChatDisabled.value || isLoading.value
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
const chatBotFooterClasses = computed(() => {
|
|
183
|
-
return {
|
|
184
|
-
'q-chatbot__footer-disabled': isDisabled.value,
|
|
185
|
-
'drag-over' : isDragging.value && !hasSelectedImage.value,
|
|
186
|
-
}
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
function setDisabledState(state: boolean) {
|
|
190
|
-
isChatDisabled.value = state
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async function initChat() {
|
|
194
|
-
try {
|
|
195
|
-
await axios.post(props.apiEndpoint + '/auth/login', {
|
|
196
|
-
username: props.username,
|
|
197
|
-
password: 'test'
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
loadChatData()
|
|
201
|
-
} catch (error) {
|
|
202
|
-
setDisabledState(true)
|
|
203
|
-
addChatMessage(props.texts.loginError)
|
|
204
|
-
console.log('Error logging in: ' + error)
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
async function loadChatData() {
|
|
209
|
-
try {
|
|
210
|
-
const response = await axios.post(props.apiEndpoint + '/prompt/load', {
|
|
211
|
-
username: props.username,
|
|
212
|
-
project: props.projectPath
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
if(!response) return console.error('No response from server');
|
|
216
|
-
|
|
217
|
-
if (response.status !== 200 || !response.data.success) {
|
|
218
|
-
setDisabledState(true)
|
|
219
|
-
addChatMessage(props.texts.botIsSick)
|
|
220
|
-
console.log(`Unsuccessful load, endpoint gave status ${response.status}`)
|
|
221
|
-
return
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
sendInitialMessage()
|
|
225
|
-
response.data.history.forEach((message: ChatBotMessageContent) => {
|
|
226
|
-
const imgUrl = message.imageUrl ? props.controllerEndpoint + message.imageUrl : undefined
|
|
227
|
-
addChatMessage(
|
|
228
|
-
message.content,
|
|
229
|
-
message.type === 'ai' ? 'bot' : 'user',
|
|
230
|
-
imgUrl,
|
|
231
|
-
message.sessionID)
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
} catch(error) {
|
|
235
|
-
setDisabledState(true)
|
|
236
|
-
addChatMessage(props.texts.botIsSick)
|
|
237
|
-
console.log('Error loading: ' + error)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Modified addChatMessage to add isStreaming flag for empty bot messages
|
|
243
|
-
function addChatMessage(
|
|
244
|
-
message: string,
|
|
245
|
-
sender: 'bot' | 'user' = 'bot',
|
|
246
|
-
imagePreviewUrl: string | null = null,
|
|
247
|
-
sessionID?: string,
|
|
248
|
-
isWelcomeMessage?: boolean
|
|
249
|
-
) {
|
|
250
|
-
messages.value.push({
|
|
251
|
-
id: nextMessageId.value++,
|
|
252
|
-
message,
|
|
253
|
-
date: new Date(),
|
|
254
|
-
sender: sender,
|
|
255
|
-
imagePreviewUrl: imagePreviewUrl ?? undefined,
|
|
256
|
-
sessionID: sessionID || uuidv4(),
|
|
257
|
-
isWelcomeMessage: isWelcomeMessage ?? false
|
|
258
|
-
})
|
|
259
|
-
nextTick(() => {
|
|
260
|
-
if (autoScrollEnabled.value) scrollToBottom()
|
|
261
|
-
})
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function getLastMessage() {
|
|
265
|
-
return messages.value.find(
|
|
266
|
-
(m: ChatBotMessage) => m.id === nextMessageId.value - 1
|
|
267
|
-
)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function sendInitialMessage() {
|
|
271
|
-
const message = props.mode === 'chat'
|
|
272
|
-
? props.texts.initialMessage
|
|
273
|
-
: props.texts.initialAgentMessage
|
|
274
|
-
addChatMessage(message, 'bot', null, undefined, true)
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function resetChat() {
|
|
278
|
-
messages.value = []
|
|
279
|
-
userPrompt.value = ''
|
|
280
|
-
isLoading.value = false
|
|
281
|
-
setDisabledState(false)
|
|
282
|
-
autoScrollEnabled.value = true
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function scrollToBottom() {
|
|
286
|
-
nextTick(() => {
|
|
287
|
-
if (messagesContainer.value) {
|
|
288
|
-
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
|
|
289
|
-
}
|
|
290
|
-
})
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function handleScroll() {
|
|
294
|
-
if (messagesContainer.value) {
|
|
295
|
-
const threshold = 20 // px threshold from the bottom
|
|
296
|
-
const { scrollTop, clientHeight, scrollHeight } = messagesContainer.value
|
|
297
|
-
if (scrollTop + clientHeight >= scrollHeight - threshold) {
|
|
298
|
-
autoScrollEnabled.value = true
|
|
299
|
-
} else {
|
|
300
|
-
autoScrollEnabled.value = false
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
function removeImage() {
|
|
306
|
-
imagePreviewUrl.value = ''
|
|
307
|
-
if (imageInput.value) {
|
|
308
|
-
imageInput.value.value = ''
|
|
309
|
-
}
|
|
310
|
-
hasSelectedImage.value = false
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function triggerImageUpload() {
|
|
314
|
-
imageInput.value?.click()
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function handleImageUpload(event: Event) {
|
|
318
|
-
// Store the selected image in imageInput
|
|
319
|
-
const target = event.target as HTMLInputElement
|
|
320
|
-
imageInput.value = target
|
|
321
|
-
|
|
322
|
-
if (target.files && target.files[0]) {
|
|
323
|
-
imagePreviewUrl.value = URL.createObjectURL(target.files[0])
|
|
324
|
-
hasSelectedImage.value = true
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
function sendMessage() {
|
|
329
|
-
if (
|
|
330
|
-
userPrompt.value.trim().length === 0 ||
|
|
331
|
-
isLoading.value ||
|
|
332
|
-
isChatDisabled.value
|
|
333
|
-
)
|
|
334
|
-
return
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if(messagesContainer.value) {
|
|
338
|
-
messagesContainer.value.scrollTo({
|
|
339
|
-
top: messagesContainer.value.scrollHeight,
|
|
340
|
-
behavior: 'smooth'
|
|
341
|
-
})
|
|
342
|
-
}
|
|
343
|
-
addChatMessage(userPrompt.value, 'user', imagePreviewUrl.value)
|
|
344
|
-
|
|
345
|
-
// Send prompt to bot
|
|
346
|
-
setChatPrompt(userPrompt.value, imageInput.value?.files?.[0])
|
|
347
|
-
removeImage()
|
|
348
|
-
userPrompt.value = '' // Clear user input
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
async function setChatPrompt(prompt: string, image?: File) {
|
|
352
|
-
// Add an empty bot message marked as streaming to trigger bouncing dots animation
|
|
353
|
-
addChatMessage('', 'bot')
|
|
354
|
-
let msg = getLastMessage()
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const currentSessionID: string = msg?.sessionID || ''
|
|
358
|
-
|
|
359
|
-
const formData = new FormData()
|
|
360
|
-
if (image) {
|
|
361
|
-
formData.append('image', image)
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
formData.append('message', prompt)
|
|
365
|
-
formData.append('project', props.projectPath)
|
|
366
|
-
formData.append('user', props.username)
|
|
367
|
-
formData.append('sessionID', currentSessionID)
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
isLoading.value = true
|
|
371
|
-
|
|
372
|
-
try {
|
|
373
|
-
const response = await axios.post(props.apiEndpoint + '/prompt/submit', formData, {
|
|
374
|
-
headers: {
|
|
375
|
-
'Content-Type': 'text/event-stream',
|
|
376
|
-
'Accept': 'text/event-stream',
|
|
377
|
-
},
|
|
378
|
-
responseType: 'stream',
|
|
379
|
-
adapter: 'fetch',
|
|
380
|
-
})
|
|
381
|
-
|
|
382
|
-
if(!response) return console.error('No response from server')
|
|
383
|
-
|
|
384
|
-
const reader = response.data.getReader()
|
|
385
|
-
const decoder = new TextDecoder("utf-8")
|
|
386
|
-
|
|
387
|
-
while(true) {
|
|
388
|
-
const { done, value } = await reader.read()
|
|
389
|
-
if(done) break
|
|
390
|
-
|
|
391
|
-
const chunk = decoder.decode(value, { stream: true })
|
|
392
|
-
const eventList = chunk.match(/data:\s*({.*?})/g)
|
|
393
|
-
if(!eventList) continue
|
|
394
|
-
|
|
395
|
-
for(const event of eventList) {
|
|
396
|
-
try {
|
|
397
|
-
const rawData = event.split('data:')[1].trim()
|
|
398
|
-
const data = JSON.parse(rawData)
|
|
399
|
-
if(msg) {
|
|
400
|
-
msg.message += data.value
|
|
401
|
-
}
|
|
402
|
-
} catch (error) {
|
|
403
|
-
console.error('Error parsing match:', error)
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
if(autoScrollEnabled.value) scrollToBottom()
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
isLoading.value = false
|
|
410
|
-
} catch (error) {
|
|
411
|
-
setDisabledState(true)
|
|
412
|
-
addChatMessage(props.texts.botIsSick)
|
|
413
|
-
console.log('Error setting chat prompt: ' + error)
|
|
414
|
-
return
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
function clearChat() {
|
|
419
|
-
axios.post(props.apiEndpoint + '/prompt/clear', {
|
|
420
|
-
username: props.username,
|
|
421
|
-
project: props.projectPath
|
|
422
|
-
})
|
|
423
|
-
.then((response: AxiosResponse) => {
|
|
424
|
-
if (response.status !== 200 || !response.data.success) {
|
|
425
|
-
setDisabledState(true)
|
|
426
|
-
addChatMessage(props.texts.loginError)
|
|
427
|
-
console.log(`Unsuccessful clear, endpoint gave status ${response.status}`)
|
|
428
|
-
return
|
|
429
|
-
}
|
|
430
|
-
resetChat()
|
|
431
|
-
sendInitialMessage()
|
|
432
|
-
})
|
|
433
|
-
.catch((error: Error) => {
|
|
434
|
-
setDisabledState(true)
|
|
435
|
-
addChatMessage(props.texts.loginError)
|
|
436
|
-
console.log('Error clearing chat: ' + error)
|
|
437
|
-
})
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
function getMessageClasses(sender: ChatBotMessageSender) {
|
|
441
|
-
const classes: string[] = ['q-chatbot__messages-wrapper']
|
|
442
|
-
if (sender === 'user') classes.push('q-chatbot__messages-wrapper_right')
|
|
443
|
-
return classes
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
function onDragOver(event: DragEvent) {
|
|
448
|
-
event.preventDefault()
|
|
449
|
-
if (!isDisabled.value) {
|
|
450
|
-
isDragging.value = true
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
function onDragLeave(event: DragEvent) {
|
|
455
|
-
event.preventDefault()
|
|
456
|
-
isDragging.value = false
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
function onDrop(event: DragEvent) {
|
|
460
|
-
event.preventDefault()
|
|
461
|
-
isDragging.value = false
|
|
462
|
-
|
|
463
|
-
if (isDisabled.value || hasSelectedImage.value)
|
|
464
|
-
return
|
|
465
|
-
|
|
466
|
-
const files = event.dataTransfer?.files
|
|
467
|
-
if (files && files.length > 0) {
|
|
468
|
-
// Check if file is an image
|
|
469
|
-
const file = files[0]
|
|
470
|
-
if (file.type.startsWith('image/')) {
|
|
471
|
-
// Create a file input event
|
|
472
|
-
if (imageInput.value) {
|
|
473
|
-
// Create a new FileList-like object
|
|
474
|
-
const dataTransfer = new DataTransfer()
|
|
475
|
-
dataTransfer.items.add(file)
|
|
476
|
-
imageInput.value.files = dataTransfer.files
|
|
477
|
-
|
|
478
|
-
// Set the preview URL
|
|
479
|
-
imagePreviewUrl.value = URL.createObjectURL(file)
|
|
480
|
-
hasSelectedImage.value = true
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
watch(
|
|
488
|
-
() => props.apiEndpoint,
|
|
489
|
-
() => {
|
|
490
|
-
resetChat()
|
|
491
|
-
initChat()
|
|
492
|
-
}
|
|
493
|
-
)
|
|
494
|
-
|
|
495
|
-
defineOptions({ name: 'ChatBot' })
|
|
496
|
-
</script>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="pulsing-dots">
|
|
3
|
-
<span
|
|
4
|
-
v-for="(_, index) in dots"
|
|
5
|
-
:key="index"
|
|
6
|
-
class="dot"
|
|
7
|
-
:style="{ animationDelay: index * 0.2 + 's' }">
|
|
8
|
-
•
|
|
9
|
-
</span>
|
|
10
|
-
</div>
|
|
11
|
-
</template>
|
|
12
|
-
|
|
13
|
-
<script setup lang="ts">
|
|
14
|
-
const dots = [1, 2, 3]
|
|
15
|
-
</script>
|
package/src/components/index.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ResourceStrings } from './texts.type'
|
|
2
|
-
|
|
3
|
-
export type ChatBotProps = {
|
|
4
|
-
apiEndpoint?: string
|
|
5
|
-
controllerEndpoint?: string
|
|
6
|
-
texts?: ResourceStrings
|
|
7
|
-
username: string
|
|
8
|
-
projectPath: string
|
|
9
|
-
userImage?: string
|
|
10
|
-
chatbotImage?: string
|
|
11
|
-
dateFormat?: string
|
|
12
|
-
mode?: ChatBotMode
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type ChatBotMode = 'chat' | 'agent'
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
export type ChatBotMessage = {
|
|
2
|
-
id: number
|
|
3
|
-
message: string
|
|
4
|
-
date: Date
|
|
5
|
-
sender: ChatBotMessageSender
|
|
6
|
-
sessionID: string
|
|
7
|
-
imagePreviewUrl?: string
|
|
8
|
-
isWelcomeMessage?: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export type ChatBotMessageContent = {
|
|
12
|
-
content: string
|
|
13
|
-
type: string
|
|
14
|
-
sessionID: string
|
|
15
|
-
imageUrl?: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export type ChatBotMessageSender = 'bot' | 'user'
|
|
19
|
-
|
|
20
|
-
export interface CBMessageProps {
|
|
21
|
-
/*
|
|
22
|
-
* Sender of the message
|
|
23
|
-
*/
|
|
24
|
-
sender?: ChatBotMessageSender
|
|
25
|
-
|
|
26
|
-
/*
|
|
27
|
-
* Message to be displayed
|
|
28
|
-
*/
|
|
29
|
-
message?: string
|
|
30
|
-
|
|
31
|
-
/*
|
|
32
|
-
* Date of when the message was sent
|
|
33
|
-
*/
|
|
34
|
-
date?: Date
|
|
35
|
-
|
|
36
|
-
/*
|
|
37
|
-
* If the message is loading
|
|
38
|
-
*/
|
|
39
|
-
loading?: boolean
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Project locale
|
|
43
|
-
*/
|
|
44
|
-
dateFormat?: string
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* User image
|
|
48
|
-
*/
|
|
49
|
-
userImage: string
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Chatbot image
|
|
53
|
-
*/
|
|
54
|
-
chatbotImage: string
|
|
55
|
-
}
|
package/src/types/texts.type.ts
DELETED
|
File without changes
|