@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.
@@ -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="isDisabled"
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(message: string, sender: 'bot' | 'user' = 'bot') {
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
- const params = {
263
- message: prompt,
264
- project: props.projectPath,
265
- user: props.username
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
- <span
4
- v-for="(_, index) in dots"
5
- :key="index"
6
- class="dot"
7
- :style="{ animationDelay: (index * 0.2) + 's' }">
8
- &bull;
9
- </span>
3
+ <span
4
+ v-for="(_, index) in dots"
5
+ :key="index"
6
+ class="dot"
7
+ :style="{ animationDelay: index * 0.2 + 's' }">
8
+ &bull;
9
+ </span>
10
10
  </div>
11
- </template>
12
-
13
- <script setup lang="ts">
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
14
  const dots = [1, 2, 3]
15
- </script>
16
-
15
+ </script>
@@ -1,7 +1,8 @@
1
- import { ResourceStrings } from "./texts.type"
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'