@quidgest/chatbot 0.0.6 → 0.0.8

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.
@@ -1,5 +1,12 @@
1
1
  <script setup lang="ts">
2
- import { onMounted, nextTick, computed, ref, watch, defineOptions } from 'vue'
2
+ import {
3
+ onMounted,
4
+ useTemplateRef,
5
+ nextTick,
6
+ ref,
7
+ watch,
8
+ defineOptions
9
+ } from 'vue'
3
10
  import type { Ref } from 'vue'
4
11
  import Axios from 'axios'
5
12
  import type { AxiosResponse } from 'axios'
@@ -7,31 +14,31 @@
7
14
 
8
15
  import {
9
16
  QButton,
10
- QTextField,
11
- QInputGroup,
12
- QIcon
17
+ QTextArea,
18
+ QIcon,
19
+ QLabel
13
20
  } from '@quidgest/ui/components'
14
21
 
15
22
  import type { ResourceStrings } from '@/types/texts.type'
16
- import type { ChatBotMessage, ChatBotMessageContent } from '@/types/message.type'
17
-
23
+ import type {
24
+ ChatBotMessage,
25
+ ChatBotMessageContent
26
+ } from '@/types/message.type'
18
27
 
19
28
  let messages: Ref<ChatBotMessage[]> = ref([])
20
- let msgHistoryStack: string[] = []
21
29
  let nextMessageId: number = 1
22
30
  let userPrompt: Ref<string> = ref('')
23
31
  let isLoading: Ref<boolean> = ref(false)
24
32
  let isChatDisabled: boolean = false
25
-
33
+
26
34
  // refs
27
- const scrollElement = ref<HTMLElement | null>(null)
28
- const promptInput = ref<HTMLInputElement | null>(null)
35
+ const scrollElement = useTemplateRef('scrollElement')
29
36
 
30
37
  export type ChatBotProps = {
31
38
  /**
32
39
  * API Enpoint URL
33
40
  */
34
- apiEndpoint?: string,
41
+ apiEndpoint?: string
35
42
 
36
43
  /**
37
44
  * Static resource texts used by ChatBot
@@ -59,7 +66,7 @@
59
66
  texts: () => ({
60
67
  chatbotTitle: 'ChatBot',
61
68
  qButtonTitle: 'Send message',
62
- placeholderMessage: 'Type your message here...',
69
+ inputLabel: 'What can I help with?',
63
70
  initialMessage:
64
71
  "Howdy! I am GenioBot 👋, Quidgest's personal AI assistant! How can I help you?",
65
72
  loginError:
@@ -73,38 +80,34 @@
73
80
  initChat()
74
81
  })
75
82
 
76
- const userMessages = computed(() => {
77
- return messages.value.filter((m: ChatBotMessage) => m.sender === 'user')
78
- })
79
-
80
83
  function setDisabledState(state: boolean) {
81
84
  isChatDisabled = state
82
85
  }
83
-
86
+
84
87
  function initChat() {
85
88
  Axios.post(props.apiEndpoint + '/auth/login', {
86
89
  username: props.username,
87
90
  password: 'test'
88
91
  })
89
- .then((response: AxiosResponse) => {
90
- if (response.status != 200 || !response.data.success) {
92
+ .then((response: AxiosResponse) => {
93
+ if (response.status != 200 || !response.data.success) {
94
+ setDisabledState(true)
95
+ addChatMessage(props.texts.loginError)
96
+ return console.log(
97
+ `Unsuccessful login, endpoint gave status ${response.status}`
98
+ )
99
+ }
100
+
101
+ loadChatData()
102
+ })
103
+ .catch((error: Error) => {
91
104
  setDisabledState(true)
92
105
  addChatMessage(props.texts.loginError)
93
- return console.log(
94
- `Unsuccessful login, endpoint gave status ${response.status}`
106
+ console.log(
107
+ 'The following error ocurred while trying to login: \n' +
108
+ error
95
109
  )
96
- }
97
-
98
- loadChatData()
99
- })
100
- .catch((error: Error) => {
101
- setDisabledState(true)
102
- addChatMessage(props.texts.loginError)
103
- console.log(
104
- 'The following error ocurred while trying to login: \n' +
105
- error
106
- )
107
- })
110
+ })
108
111
  }
109
112
 
110
113
  function loadChatData() {
@@ -112,28 +115,33 @@
112
115
  username: props.username,
113
116
  project: props.projectPath
114
117
  })
115
- .then((response: AxiosResponse) => {
116
- if (response.status != 200 || !response.data.success) {
118
+ .then((response: AxiosResponse) => {
119
+ if (response.status != 200 || !response.data.success) {
120
+ setDisabledState(true)
121
+ addChatMessage(props.texts.loginError)
122
+ return console.log(
123
+ `Unsuccessful load, endpoint gave status ${response.status}`
124
+ )
125
+ }
126
+
127
+ sendInitialMessage()
128
+ response.data.history.forEach(
129
+ (message: ChatBotMessageContent) => {
130
+ addChatMessage(
131
+ message.content,
132
+ message.type === 'ai' ? 'bot' : 'user'
133
+ )
134
+ }
135
+ )
136
+ })
137
+ .catch((error: Error) => {
117
138
  setDisabledState(true)
118
139
  addChatMessage(props.texts.loginError)
119
- return console.log(
120
- `Unsuccessful load, endpoint gave status ${response.status}`
140
+ console.log(
141
+ 'The following error ocurred while trying to login: \n' +
142
+ error
121
143
  )
122
- }
123
-
124
- sendInitialMessage()
125
- response.data.history.forEach((message: ChatBotMessageContent) => {
126
- addChatMessage(message.content, message.type === "ai" ? "bot" : "user")
127
144
  })
128
- })
129
- .catch((error: Error) => {
130
- setDisabledState(true)
131
- addChatMessage(props.texts.loginError)
132
- console.log(
133
- 'The following error ocurred while trying to login: \n' +
134
- error
135
- )
136
- })
137
145
  }
138
146
 
139
147
  function addChatMessage(message: string, sender: 'bot' | 'user' = 'bot') {
@@ -159,58 +167,15 @@
159
167
 
160
168
  function resetChat() {
161
169
  messages.value = []
162
- msgHistoryStack = []
163
170
  userPrompt.value = ''
164
171
  isLoading.value = false
165
172
  setDisabledState(false)
166
173
  }
167
174
 
168
175
  function scrollToBottom() {
169
- scrollElement.value?.scrollIntoView({ behavior: 'smooth' })
176
+ scrollElement.value?.scrollIntoView({ behavior: 'smooth' })
170
177
  }
171
178
 
172
- function handleKey(event: KeyboardEvent) {
173
- if(promptInput.value == null) return;
174
-
175
- if (event.key == 'ArrowUp') {
176
- //No user messages, no need to continue
177
- if (userMessages.value.length == 0) return
178
-
179
- //Get next message to read
180
- let lastMsgObj =
181
- userMessages.value[
182
- userMessages.value.length -
183
- 1 -
184
- msgHistoryStack.length
185
- ]
186
-
187
- //No more messages to go through
188
- if (!lastMsgObj) return
189
-
190
- //Save current prompt (even if modified) & update input
191
- msgHistoryStack.push(userPrompt.value)
192
- userPrompt.value = lastMsgObj.message
193
-
194
- //Set the cursor to the end of text
195
- nextTick(() =>
196
- setCursorPosition(
197
- promptInput.value as HTMLInputElement,
198
- lastMsgObj.message.length
199
- )
200
- )
201
- } else if (event.key == 'ArrowDown') {
202
- let previousHistoryText = msgHistoryStack.pop()
203
-
204
- if (!previousHistoryText) {
205
- //No more prompts in the stack
206
- userPrompt.value = ''
207
- return
208
- }
209
-
210
- userPrompt.value = previousHistoryText
211
- }
212
- }
213
-
214
179
  function sendMessage() {
215
180
  if (
216
181
  userPrompt.value.trim().length == 0 ||
@@ -243,8 +208,7 @@
243
208
  method: 'POST',
244
209
  data: params,
245
210
  onDownloadProgress: (progressEvent) => {
246
- const chunk =
247
- progressEvent.event?.currentTarget.response
211
+ const chunk = progressEvent.event?.currentTarget.response
248
212
  const status = progressEvent.event?.currentTarget.status
249
213
 
250
214
  if (status != 200) return
@@ -253,74 +217,69 @@
253
217
  scrollToBottom()
254
218
  }
255
219
  })
256
- .then(({ data }) => {
257
- if (msg) msg.message = data
258
- })
259
- .catch((error) => {
260
- addChatMessage(props.texts.botIsSick)
261
-
262
- setDisabledState(true)
263
- console.log(error)
264
- })
265
- .finally(() => {
266
- isLoading.value = false
267
- })
268
- }
220
+ .then(({ data }) => {
221
+ if (msg) msg.message = data
222
+ })
223
+ .catch((error) => {
224
+ addChatMessage(props.texts.botIsSick)
269
225
 
270
- function setCursorPosition(elem: HTMLInputElement, pos: number) {
271
- elem.focus()
272
- elem.setSelectionRange(pos, pos)
226
+ setDisabledState(true)
227
+ console.log(error)
228
+ })
229
+ .finally(() => {
230
+ isLoading.value = false
231
+ })
273
232
  }
274
233
 
275
- function clearChat() {
234
+ function clearChat() {
276
235
  Axios.post(props.apiEndpoint + '/prompt/clear', {
277
236
  username: props.username,
278
237
  project: props.projectPath
279
238
  })
280
- .then((response: AxiosResponse) => {
281
- if (response.status != 200 || !response.data.success) {
239
+ .then((response: AxiosResponse) => {
240
+ if (response.status != 200 || !response.data.success) {
241
+ setDisabledState(true)
242
+ addChatMessage(props.texts.loginError)
243
+ return console.log(
244
+ `Unsuccessful login, endpoint gave status ${response.status}`
245
+ )
246
+ }
247
+
248
+ resetChat()
249
+ sendInitialMessage()
250
+ })
251
+ .catch((error: Error) => {
282
252
  setDisabledState(true)
283
253
  addChatMessage(props.texts.loginError)
284
- return console.log(
285
- `Unsuccessful login, endpoint gave status ${response.status}`
254
+ console.log(
255
+ 'The following error ocurred while trying to communicate with the endpoint: \n' +
256
+ error
286
257
  )
287
- }
288
-
289
- resetChat()
290
- sendInitialMessage()
291
- })
292
- .catch((error: Error) => {
293
- setDisabledState(true)
294
- addChatMessage(props.texts.loginError)
295
- console.log(
296
- 'The following error ocurred while trying to communicate with the endpoint: \n' +
297
- error
298
- )
299
- })
258
+ })
300
259
  }
301
260
 
302
261
  function getMessageClasses(sender: 'user' | 'bot') {
303
262
  const classes: string[] = ['q-chatbot__messages-wrapper']
304
263
 
305
- if(sender == 'user')
306
- classes.push('q-chatbot__messages-wrapper_right')
264
+ if (sender == 'user') classes.push('q-chatbot__messages-wrapper_right')
307
265
 
308
266
  return classes
309
267
  }
310
268
 
311
- watch(() => props.apiEndpoint, () => {
312
- resetChat()
313
- initChat()
314
- })
269
+ watch(
270
+ () => props.apiEndpoint,
271
+ () => {
272
+ resetChat()
273
+ initChat()
274
+ }
275
+ )
315
276
 
316
277
  defineOptions({ name: 'ChatBot' })
317
278
  </script>
318
279
 
319
280
  <template>
320
281
  <div class="q-chatbot">
321
- <div
322
- class="q-chatbot__content">
323
-
282
+ <div class="q-chatbot__content">
324
283
  <!-- Chat tools -->
325
284
  <div class="q-chatbot__tools">
326
285
  <QButton
@@ -338,36 +297,42 @@
338
297
  v-for="message in messages"
339
298
  :key="message.id"
340
299
  :class="getMessageClasses(message.sender)">
341
- <CBMessage v-bind="message" :date-format="props.dateFormat" :loading="isLoading && !message.message" />
300
+ <CBMessage
301
+ v-bind="message"
302
+ :date-format="props.dateFormat"
303
+ :loading="isLoading && !message.message" />
342
304
  </div>
343
305
  </div>
344
306
 
345
307
  <div ref="scrollElement"></div>
308
+
309
+ <div class="q-chatbot__footer-container">
310
+ <label> {{ props.texts.inputLabel }} </label>
311
+ <div class="q-chatbot__footer">
312
+ <div class="q-chatbot__input">
313
+ <QTextArea
314
+ v-model="userPrompt"
315
+ size="block"
316
+ autosize
317
+ resize="none"
318
+ :rows="2"
319
+ :disabled="isChatDisabled"
320
+ @keyup.enter="sendMessage" />
321
+ </div>
322
+ <div class="q-chatbot__send-container">
323
+ <QButton
324
+ :title="props.texts.qButtonTitle"
325
+ b-style="primary"
326
+ class="q-chatbot__send"
327
+ :disabled="isChatDisabled || isLoading"
328
+ :loading="isLoading"
329
+ @click="sendMessage">
330
+ <QIcon icon="send" />
331
+ </QButton>
332
+ </div>
333
+ </div>
334
+ </div>
346
335
  </div>
347
336
 
348
- <QInputGroup
349
- size="block"
350
- :disabled="isChatDisabled">
351
- <QTextField
352
- ref="promptInput"
353
- v-model="userPrompt"
354
- class="q-chatbot__input"
355
- :placeholder="props.texts.placeholderMessage"
356
- :disabled="isChatDisabled"
357
- @keyup.enter="sendMessage"
358
- @keydown="handleKey" />
359
-
360
- <template #append>
361
- <QButton
362
- :title="props.texts.qButtonTitle"
363
- b-style="primary"
364
- class="q-chatbot__send"
365
- :disabled="isChatDisabled || isLoading"
366
- :loading="isLoading"
367
- @click="sendMessage">
368
- <QIcon icon="send" />
369
- </QButton>
370
- </template>
371
- </QInputGroup>
372
337
  </div>
373
338
  </template>
@@ -1,7 +1,4 @@
1
- import CBMessage from "./CBMessage.vue"
2
- import type { CBMessageProps } from "./CBMessage.vue"
1
+ import CBMessage from './CBMessage.vue'
2
+ import type { CBMessageProps } from './CBMessage.vue'
3
3
 
4
- export {
5
- CBMessage,
6
- CBMessageProps
7
- }
4
+ export { CBMessage, CBMessageProps }
@@ -1,11 +1,11 @@
1
1
  export type ChatBotMessage = {
2
- id: number,
3
- message: string,
4
- date: Date,
2
+ id: number
3
+ message: string
4
+ date: Date
5
5
  sender: 'bot' | 'user'
6
6
  }
7
7
 
8
8
  export type ChatBotMessageContent = {
9
- content: string,
9
+ content: string
10
10
  type: string
11
- }
11
+ }
@@ -1,3 +1,3 @@
1
1
  export type ResourceStrings = {
2
2
  [key: string]: string
3
- }
3
+ }