@quidgest/chatbot 0.0.9 → 0.1.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/CBMessage.vue.d.ts +44 -0
- package/dist/components/ChatBot.vue.d.ts +10 -2
- package/dist/index.js +68 -6
- package/dist/index.mjs +2376 -1197
- package/dist/style.css +1 -1
- package/dist/types/chatbot.type.d.ts +1 -0
- package/dist/types/message.type.d.ts +5 -0
- package/package.json +12 -11
- package/src/assets/copy.svg +7 -0
- package/src/assets/styles/styles.scss +74 -20
- package/src/assets/thumbDown.svg +9 -0
- package/src/assets/thumbUp.svg +9 -0
- package/src/components/CBMessage.vue +200 -14
- package/src/components/ChatBot.vue +121 -13
- package/src/components/PulseDots.vue +11 -12
- package/src/types/chatbot.type.ts +3 -2
- package/src/types/message.type.ts +5 -0
|
@@ -28,9 +28,29 @@
|
|
|
28
28
|
:date-format="props.dateFormat"
|
|
29
29
|
:user-image="props.userImage"
|
|
30
30
|
:chatbot-image="props.chatbotImage"
|
|
31
|
-
:loading="isLoading && !message.message"
|
|
31
|
+
:loading="isLoading && !message.message"
|
|
32
|
+
:imagePreviewUrl="message.imagePreviewUrl"
|
|
33
|
+
:apiEndpoint="props.apiEndpoint"
|
|
34
|
+
:sessionID="message.sessionID"/>
|
|
32
35
|
</div>
|
|
33
36
|
</div>
|
|
37
|
+
<!--show image preview if exists-->
|
|
38
|
+
<div
|
|
39
|
+
v-if="imagePreviewUrl"
|
|
40
|
+
class="q-chatbot__image-preview">
|
|
41
|
+
<img
|
|
42
|
+
:src="imagePreviewUrl"
|
|
43
|
+
alt="Image preview" />
|
|
44
|
+
<q-button
|
|
45
|
+
class="q-chatbot__remove-image"
|
|
46
|
+
b-style="secondary"
|
|
47
|
+
flat
|
|
48
|
+
round
|
|
49
|
+
@click="removeImage">
|
|
50
|
+
<q-icon icon="bin" />
|
|
51
|
+
</q-button>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
34
54
|
|
|
35
55
|
<div class="q-chatbot__footer-container">
|
|
36
56
|
<q-label :label="props.texts.inputLabel"/>
|
|
@@ -48,11 +68,32 @@
|
|
|
48
68
|
@keyup.enter="sendMessage" />
|
|
49
69
|
</div>
|
|
50
70
|
<div class="q-chatbot__send-container">
|
|
71
|
+
<!-- Upload button moved to the same container as send, but positioned to the left -->
|
|
72
|
+
<q-button
|
|
73
|
+
:title="props.texts.imageUpload"
|
|
74
|
+
b-style="primary"
|
|
75
|
+
class="q-chatbot__upload"
|
|
76
|
+
:disabled="isChatDisabled || isLoading || hasSelectedImage"
|
|
77
|
+
@click="triggerImageUpload">
|
|
78
|
+
<q-icon icon="upload" />
|
|
79
|
+
</q-button>
|
|
80
|
+
|
|
81
|
+
<!-- Hidden file input -->
|
|
82
|
+
<input
|
|
83
|
+
id="image-upload"
|
|
84
|
+
type="file"
|
|
85
|
+
ref="imageInput"
|
|
86
|
+
@change="handleImageUpload"
|
|
87
|
+
:accept="acceptedImageTypes"
|
|
88
|
+
class="hidden-input" style="display: none;" />
|
|
89
|
+
|
|
90
|
+
<div class="spacer"></div>
|
|
91
|
+
|
|
51
92
|
<q-button
|
|
52
93
|
:title="props.texts.sendMessage"
|
|
53
94
|
b-style="primary"
|
|
54
95
|
class="q-chatbot__send"
|
|
55
|
-
:disabled="
|
|
96
|
+
:disabled="isSendButtonDisabled"
|
|
56
97
|
:readonly="isDisabled"
|
|
57
98
|
:loading="isLoading"
|
|
58
99
|
@click="sendMessage">
|
|
@@ -62,7 +103,6 @@
|
|
|
62
103
|
</div>
|
|
63
104
|
</div>
|
|
64
105
|
</div>
|
|
65
|
-
</div>
|
|
66
106
|
</template>
|
|
67
107
|
|
|
68
108
|
|
|
@@ -75,6 +115,7 @@
|
|
|
75
115
|
|
|
76
116
|
import { QButton, QTextArea, QIcon, QLabel } from '@quidgest/ui/components'
|
|
77
117
|
import type { ChatBotMessage, ChatBotMessageContent, ChatBotMessageSender } from '@/types/message.type'
|
|
118
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
78
119
|
|
|
79
120
|
import ChatBotIcon from '@/assets/chatbot.png'
|
|
80
121
|
import UserIcon from '@/assets/user_avatar.png'
|
|
@@ -90,6 +131,16 @@
|
|
|
90
131
|
const messagesContainer = ref<HTMLElement | null>(null)
|
|
91
132
|
// Flag to control auto-scrolling
|
|
92
133
|
const autoScrollEnabled = ref(true)
|
|
134
|
+
|
|
135
|
+
const imageInput = ref<HTMLInputElement | null>(null)
|
|
136
|
+
const imagePreviewUrl = ref<string | null>(null)
|
|
137
|
+
const acceptedImageTypes = computed(() => '.png, .jpeg, .jpg, .svg, .webp')
|
|
138
|
+
const hasSelectedImage = ref<boolean>(false)
|
|
139
|
+
|
|
140
|
+
// Computed property to check if the send button should be enabled
|
|
141
|
+
const isSendButtonDisabled = computed(() => {
|
|
142
|
+
return userPrompt.value.trim().length === 0 || isLoading.value || isChatDisabled.value
|
|
143
|
+
})
|
|
93
144
|
|
|
94
145
|
const props = withDefaults(defineProps<ChatBotProps>(), {
|
|
95
146
|
apiEndpoint: 'http://localhost:3000',
|
|
@@ -101,6 +152,10 @@
|
|
|
101
152
|
sendMessage: 'Send message',
|
|
102
153
|
clearChat: 'Clear chat',
|
|
103
154
|
inputLabel: 'What can I help with?',
|
|
155
|
+
imageUpload: 'Upload Image',
|
|
156
|
+
imageUploadQButton: 'Upload Image',
|
|
157
|
+
goodResponse: 'Good response',
|
|
158
|
+
badResponse: 'Bad response',
|
|
104
159
|
initialMessage:
|
|
105
160
|
"Howdy! I am GenioBot 👋, Quidgest's personal AI assistant! How can I help you?",
|
|
106
161
|
initialAgentMessage: 'Just a temporary message while we are working on the agent mode',
|
|
@@ -167,9 +222,12 @@
|
|
|
167
222
|
}
|
|
168
223
|
sendInitialMessage()
|
|
169
224
|
response.data.history.forEach((message: ChatBotMessageContent) => {
|
|
225
|
+
const imgUrl = message.imageUrl ? props.controllerEndpoint + message.imageUrl : undefined
|
|
170
226
|
addChatMessage(
|
|
171
227
|
message.content,
|
|
172
|
-
message.type === 'ai' ? 'bot' : 'user'
|
|
228
|
+
message.type === 'ai' ? 'bot' : 'user',
|
|
229
|
+
imgUrl,
|
|
230
|
+
message.sessionID
|
|
173
231
|
)
|
|
174
232
|
})
|
|
175
233
|
})
|
|
@@ -181,12 +239,21 @@
|
|
|
181
239
|
}
|
|
182
240
|
|
|
183
241
|
// Modified addChatMessage to add isStreaming flag for empty bot messages
|
|
184
|
-
function addChatMessage(
|
|
242
|
+
function addChatMessage(
|
|
243
|
+
message: string,
|
|
244
|
+
sender: 'bot' | 'user' = 'bot',
|
|
245
|
+
imagePreviewUrl: string | null = null,
|
|
246
|
+
sessionID?: string,
|
|
247
|
+
isWelcomeMessage?: boolean
|
|
248
|
+
) {
|
|
185
249
|
messages.value.push({
|
|
186
250
|
id: nextMessageId.value++,
|
|
187
251
|
message,
|
|
188
252
|
date: new Date(),
|
|
189
253
|
sender: sender,
|
|
254
|
+
imagePreviewUrl: imagePreviewUrl ?? undefined,
|
|
255
|
+
sessionID: sessionID || uuidv4(),
|
|
256
|
+
isWelcomeMessage: isWelcomeMessage ?? false
|
|
190
257
|
})
|
|
191
258
|
nextTick(() => {
|
|
192
259
|
if (autoScrollEnabled.value) scrollToBottom()
|
|
@@ -203,7 +270,7 @@
|
|
|
203
270
|
const message = props.mode === 'chat'
|
|
204
271
|
? props.texts.initialMessage
|
|
205
272
|
: props.texts.initialAgentMessage
|
|
206
|
-
addChatMessage(message)
|
|
273
|
+
addChatMessage(message, 'bot', null, undefined, true)
|
|
207
274
|
}
|
|
208
275
|
|
|
209
276
|
function resetChat() {
|
|
@@ -237,6 +304,29 @@
|
|
|
237
304
|
}
|
|
238
305
|
}
|
|
239
306
|
|
|
307
|
+
function removeImage() {
|
|
308
|
+
imagePreviewUrl.value = ''
|
|
309
|
+
if (imageInput.value) {
|
|
310
|
+
imageInput.value.value = ''
|
|
311
|
+
}
|
|
312
|
+
hasSelectedImage.value = false
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function triggerImageUpload() {
|
|
316
|
+
imageInput.value?.click()
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function handleImageUpload(event: Event) {
|
|
320
|
+
// Store the selected image in imageInput
|
|
321
|
+
const target = event.target as HTMLInputElement
|
|
322
|
+
imageInput.value = target
|
|
323
|
+
|
|
324
|
+
if (target.files && target.files[0]) {
|
|
325
|
+
imagePreviewUrl.value = URL.createObjectURL(target.files[0])
|
|
326
|
+
hasSelectedImage.value = true
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
240
330
|
function sendMessage() {
|
|
241
331
|
if (
|
|
242
332
|
userPrompt.value.trim().length === 0 ||
|
|
@@ -246,23 +336,41 @@
|
|
|
246
336
|
return
|
|
247
337
|
|
|
248
338
|
// Add user's message and force scroll to bottom
|
|
249
|
-
addChatMessage(userPrompt.value, 'user')
|
|
339
|
+
addChatMessage(userPrompt.value, 'user', imagePreviewUrl.value)
|
|
250
340
|
scrollToBottom()
|
|
251
341
|
|
|
252
342
|
// Send prompt to bot
|
|
253
|
-
setChatPrompt(userPrompt.value)
|
|
343
|
+
setChatPrompt(userPrompt.value, imageInput.value?.files?.[0])
|
|
344
|
+
removeImage()
|
|
254
345
|
userPrompt.value = '' // Clear user input
|
|
255
346
|
}
|
|
256
347
|
|
|
257
|
-
function setChatPrompt(prompt: string) {
|
|
348
|
+
function setChatPrompt(prompt: string, image?: File) {
|
|
258
349
|
// Add an empty bot message marked as streaming to trigger bouncing dots animation
|
|
259
350
|
addChatMessage('', 'bot')
|
|
260
351
|
let msg = getLastMessage()
|
|
261
352
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
353
|
+
|
|
354
|
+
const currentSessionID: string = msg?.sessionID || ''
|
|
355
|
+
|
|
356
|
+
let params = null
|
|
357
|
+
|
|
358
|
+
if (image) {
|
|
359
|
+
params = new FormData()
|
|
360
|
+
// Create the FormData
|
|
361
|
+
params.append('message', prompt)
|
|
362
|
+
params.append('project', props.projectPath)
|
|
363
|
+
params.append('user', props.username)
|
|
364
|
+
params.append('image', image)
|
|
365
|
+
params.append('sessionID', currentSessionID)
|
|
366
|
+
} else {
|
|
367
|
+
//Send message request
|
|
368
|
+
params = {
|
|
369
|
+
message: prompt,
|
|
370
|
+
project: props.projectPath,
|
|
371
|
+
user: props.username,
|
|
372
|
+
sessionID: currentSessionID
|
|
373
|
+
}
|
|
266
374
|
}
|
|
267
375
|
|
|
268
376
|
isLoading.value = true
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="pulsing-dots">
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
10
|
</div>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
14
|
const dots = [1, 2, 3]
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
</script>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { ResourceStrings } from
|
|
1
|
+
import { ResourceStrings } from './texts.type'
|
|
2
2
|
|
|
3
3
|
export type ChatBotProps = {
|
|
4
4
|
apiEndpoint?: string
|
|
5
|
+
controllerEndpoint?: string
|
|
5
6
|
texts?: ResourceStrings
|
|
6
7
|
username: string
|
|
7
8
|
projectPath: string
|
|
@@ -11,4 +12,4 @@ export type ChatBotProps = {
|
|
|
11
12
|
mode?: ChatBotMode
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export type ChatBotMode = 'chat' | 'agent'
|
|
15
|
+
export type ChatBotMode = 'chat' | 'agent'
|
|
@@ -3,11 +3,16 @@ export type ChatBotMessage = {
|
|
|
3
3
|
message: string
|
|
4
4
|
date: Date
|
|
5
5
|
sender: ChatBotMessageSender
|
|
6
|
+
sessionID: string
|
|
7
|
+
imagePreviewUrl?: string
|
|
8
|
+
isWelcomeMessage?: boolean
|
|
6
9
|
}
|
|
7
10
|
|
|
8
11
|
export type ChatBotMessageContent = {
|
|
9
12
|
content: string
|
|
10
13
|
type: string
|
|
14
|
+
sessionID: string
|
|
15
|
+
imageUrl?: string
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
export type ChatBotMessageSender = 'bot' | 'user'
|