@quidgest/chatbot 0.0.3 → 0.0.5

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.
@@ -0,0 +1,81 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import ChatBotIcon from '@/assets/chatbot.png'
4
+ import { QLineLoader } from '@quidgest/ui'
5
+
6
+ export interface CBMessageProps {
7
+ /*
8
+ * Sender of the message
9
+ */
10
+ sender?: 'bot' | 'user'
11
+
12
+ /*
13
+ * Message to be displayed
14
+ */
15
+ message?: string
16
+
17
+ /*
18
+ * Date of when the message was sent
19
+ */
20
+ date?: Date
21
+
22
+ /*
23
+ * If the message is loading
24
+ */
25
+ loading?: boolean
26
+ }
27
+
28
+ const props = withDefaults(defineProps<CBMessageProps>(), {
29
+ sender: 'user',
30
+ date: () => new Date()
31
+ })
32
+
33
+ const senderName = computed(() => {
34
+ return props.sender === 'bot' ? 'GenioBot' : 'You'
35
+ })
36
+
37
+ const getLocaleDate = computed(() => {
38
+ return props.date.toLocaleString()
39
+ })
40
+
41
+ const messageHeader = computed(() => {
42
+ return `${senderName.value} ${getLocaleDate.value}`
43
+ })
44
+ </script>
45
+
46
+ <template>
47
+ <div class="q-chatbot__message-container">
48
+
49
+ <!-- Chatbot Image -->
50
+ <img
51
+ v-if="props.sender === 'bot'"
52
+ :src="ChatBotIcon"
53
+ alt="Chatbot"
54
+ class="q-chatbot__profile" />
55
+
56
+ <div class="q-chatbot__message-wrapper">
57
+ <!-- Message header -->
58
+ <div
59
+ v-if="!loading"
60
+ class="q-chatbot__sender">
61
+ {{ messageHeader }}
62
+ </div>
63
+
64
+ <!-- Message body -->
65
+ <div class="q-chatbot__message">
66
+ <QLineLoader v-if="loading" />
67
+ <template v-else>
68
+ <div
69
+ class="q-chatbot__text"
70
+ v-if="props.sender == 'bot'"
71
+ v-html="props.message"></div>
72
+ <div
73
+ class="q-chatbot__text"
74
+ v-else>
75
+ {{ props.message }}
76
+ </div>
77
+ </template>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </template>
@@ -3,6 +3,8 @@
3
3
  import type { Ref } from 'vue'
4
4
  import Axios from 'axios'
5
5
  import type { AxiosResponse } from 'axios'
6
+ import { CBMessage } from '@/components'
7
+
6
8
  import {
7
9
  QButton,
8
10
  QTextField,
@@ -11,13 +13,13 @@
11
13
  } from '@quidgest/ui'
12
14
 
13
15
  import type { ResourceStrings } from '@/types/texts.type'
14
- import type { ChatBotMessage } from '@/types/message.type'
15
- import ChatBotIcon from '@/assets/chatbot.png'
16
+ import type { ChatBotMessage, ChatBotMessageContent } from '@/types/message.type'
17
+
16
18
 
17
19
  let messages: Ref<ChatBotMessage[]> = ref([])
18
20
  let msgHistoryStack: string[] = []
19
21
  let nextMessageId: number = 1
20
- let userPrompt: Ref<string> = ref('');
22
+ let userPrompt: Ref<string> = ref('')
21
23
  let isChatDisabled: boolean = false
22
24
  let isLoading: boolean = false
23
25
 
@@ -40,6 +42,11 @@
40
42
  * Genio username
41
43
  */
42
44
  username: string
45
+
46
+ /**
47
+ * Project aplication path
48
+ */
49
+ projectPath: string
43
50
  }
44
51
 
45
52
  const props = withDefaults(defineProps<ChatBotProps>(), {
@@ -62,16 +69,13 @@
62
69
  nextTick(scrollChatToBottom)
63
70
  })
64
71
 
65
- const sortedMessages = computed(() => {
66
- return messages.value.toSorted((a: ChatBotMessage, b: ChatBotMessage) => {
67
- const diff = new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
68
- return diff !== 0 ? diff : a.sender === 'user' ? -1 : 1
69
- })
70
- })
71
-
72
72
  const userMessages = computed(() => {
73
73
  return messages.value.filter((m: ChatBotMessage) => m.sender === 'user')
74
74
  })
75
+
76
+ function setDisabledState(state: boolean) {
77
+ isChatDisabled = state
78
+ }
75
79
 
76
80
  function initChat() {
77
81
  Axios.post(props.apiEndpoint + '/auth/login', {
@@ -80,32 +84,59 @@
80
84
  })
81
85
  .then((response: AxiosResponse) => {
82
86
  if (response.status != 200 || !response.data.success) {
83
- isChatDisabled = true
87
+ setDisabledState(true)
84
88
  addChatMessage(props.texts.loginError)
85
89
  return console.log(
86
90
  `Unsuccessful login, endpoint gave status ${response.status}`
87
91
  )
88
92
  }
89
93
 
90
- sendInitialMessage()
94
+ loadChatData()
91
95
  })
92
96
  .catch((error: Error) => {
93
- if (error) {
94
- isChatDisabled = true
97
+ setDisabledState(true)
98
+ addChatMessage(props.texts.loginError)
99
+ console.log(
100
+ 'The following error ocurred while trying to login: \n' +
101
+ error
102
+ )
103
+ })
104
+ }
105
+
106
+ function loadChatData() {
107
+ Axios.post(props.apiEndpoint + '/prompt/load', {
108
+ username: props.username,
109
+ project: props.projectPath
110
+ })
111
+ .then((response: AxiosResponse) => {
112
+ if (response.status != 200 || !response.data.success) {
113
+ setDisabledState(true)
95
114
  addChatMessage(props.texts.loginError)
96
- console.log(
97
- 'The following error ocurred while trying to login: \n' +
98
- error
115
+ return console.log(
116
+ `Unsuccessful load, endpoint gave status ${response.status}`
99
117
  )
100
118
  }
119
+
120
+ sendInitialMessage()
121
+ response.data.history.forEach((message: ChatBotMessageContent) => {
122
+ addChatMessage(message.content, message.type === "ai" ? "bot" : "user")
123
+ })
124
+ })
125
+ .catch((error: Error) => {
126
+ setDisabledState(true)
127
+ addChatMessage(props.texts.loginError)
128
+ console.log(
129
+ 'The following error ocurred while trying to login: \n' +
130
+ error
131
+ )
101
132
  })
102
133
  }
103
134
 
104
135
  function addChatMessage(message: string, sender: 'bot' | 'user' = 'bot') {
105
136
  messages.value.push({
106
137
  id: nextMessageId++,
107
- text: message,
108
- timestamp: new Date(),
138
+ message,
139
+ date: new Date(),
109
140
  sender: sender
110
141
  })
111
142
  }
@@ -125,9 +156,7 @@
125
156
  msgHistoryStack = []
126
157
  userPrompt.value = ''
127
158
  isLoading = false
128
- isChatDisabled = false
129
-
130
- sendInitialMessage()
159
+ setDisabledState(false)
131
160
  }
132
161
 
133
162
  function scrollChatToBottom() {
@@ -161,13 +190,13 @@
161
190
 
162
191
  //Save current prompt (even if modified) & update input
163
192
  msgHistoryStack.push(userPrompt.value)
164
- userPrompt.value = lastMsgObj.text
193
+ userPrompt.value = lastMsgObj.message
165
194
 
166
195
  //Set the cursor to the end of text
167
196
  nextTick(() =>
168
197
  setCursorPosition(
169
198
  promptInput.value as HTMLInputElement,
170
- lastMsgObj.text.length
199
+ lastMsgObj.message.length
171
200
  )
172
201
  )
173
202
  } else if (event.key == 'ArrowDown') {
@@ -206,7 +235,7 @@
206
235
  //Send message request
207
236
  let params = {
208
237
  message: prompt,
209
- project: 'GenIO',
238
+ project: props.projectPath,
210
239
  user: props.username
211
240
  }
212
241
 
@@ -222,16 +251,16 @@
222
251
 
223
252
  if (status != 200) return
224
253
 
225
- if (msg) msg.text = chunk
254
+ if (msg) msg.message = chunk
226
255
  }
227
256
  })
228
257
  .then(({ data }) => {
229
- if (msg) msg.text = data
258
+ if (msg) msg.message = data
230
259
  })
231
260
  .catch((error) => {
232
261
  addChatMessage(props.texts.botIsSick)
233
262
 
234
- isChatDisabled = true
263
+ setDisabledState(true)
235
264
  console.log(error)
236
265
  })
237
266
  .finally(() => {
@@ -239,21 +268,50 @@
239
268
  })
240
269
  }
241
270
 
242
- function getSenderName(sender: 'bot' | 'user') {
243
- return sender === 'bot' ? 'GenioBot' : 'You'
271
+ function setCursorPosition(elem: HTMLInputElement, pos: number) {
272
+ elem.focus()
273
+ elem.setSelectionRange(pos, pos)
244
274
  }
245
275
 
246
- function getConvertedTime(date: Date) {
247
- return date.toLocaleString()
276
+ function clearChat() {
277
+ Axios.post(props.apiEndpoint + '/prompt/clear', {
278
+ username: props.username,
279
+ project: props.projectPath
280
+ })
281
+ .then((response: AxiosResponse) => {
282
+ if (response.status != 200 || !response.data.success) {
283
+ setDisabledState(true)
284
+ addChatMessage(props.texts.loginError)
285
+ return console.log(
286
+ `Unsuccessful login, endpoint gave status ${response.status}`
287
+ )
288
+ }
289
+
290
+ resetChat()
291
+ sendInitialMessage()
292
+ })
293
+ .catch((error: Error) => {
294
+ setDisabledState(true)
295
+ addChatMessage(props.texts.loginError)
296
+ console.log(
297
+ 'The following error ocurred while trying to communicate with the endpoint: \n' +
298
+ error
299
+ )
300
+ })
248
301
  }
249
302
 
250
- function setCursorPosition(elem: HTMLInputElement, pos: number) {
251
- elem.focus()
252
- elem.setSelectionRange(pos, pos)
303
+ function getMessageClasses(sender: 'user' | 'bot') {
304
+ const classes: string[] = ['q-chatbot__messages-wrapper']
305
+
306
+ if(sender == 'user')
307
+ classes.push('q-chatbot__messages-wrapper_right')
308
+
309
+ return classes
253
310
  }
254
311
 
255
312
  watch(() => props.apiEndpoint, () => {
256
313
  resetChat()
314
+ initChat()
257
315
  })
258
316
 
259
317
  defineOptions({ name: 'ChatBot' })
@@ -261,63 +319,29 @@
261
319
 
262
320
  <template>
263
321
  <div class="q-chatbot">
264
- <div class="c-sidebar__subtitle">
265
- <span>{{ props.texts.chatbotTitle }}</span>
266
- </div>
267
-
268
322
  <div
269
- class="q-chatbot__content"
270
- ref="messagesContainer">
271
- <div
272
- v-for="message in sortedMessages"
273
- :key="message.id"
274
- :class="[
275
- 'q-chatbot__message-wrapper',
276
- {
277
- 'q-chatbot__message-wrapper_right':
278
- message.sender == 'user'
279
- }
280
- ]">
281
- <img
282
- v-if="message.sender == 'bot'"
283
- :src="ChatBotIcon"
284
- alt=""
285
- class="q-chatbot__profile" />
286
-
287
- <div class="q-chatbot__message">
288
- <div
289
- v-if="isLoading && !message.text"
290
- class="q-chatbot__message-loading">
291
- <div></div>
292
- <div></div>
293
- <div></div>
294
- </div>
295
-
296
- <template v-else>
297
- <div
298
- class="q-chatbot__sender"
299
- v-if="message.text && message.sender == 'bot'">
300
- {{
301
- getSenderName(message.sender) +
302
- ' ' +
303
- getConvertedTime(message.timestamp)
304
- }}
305
- </div>
306
- <div
307
- class="q-chatbot__timestamp"
308
- v-if="message.text && message.sender == 'user'">
309
- {{ getConvertedTime(message.timestamp) }}
310
- </div>
311
- <div
312
- class="q-chatbot__text"
313
- v-if="message.sender == 'bot'"
314
- v-html="message.text"></div>
315
- <div
316
- class="q-chatbot__text"
317
- v-else>
318
- {{ message.text }}
319
- </div>
320
- </template>
323
+ ref="messagesContainer"
324
+ class="q-chatbot__content">
325
+
326
+ <!-- Chat tools -->
327
+ <div class="q-chatbot__tools">
328
+ <q-button
329
+ :title="props.texts.qButtonTitle"
330
+ b-style="plain"
331
+ class="clear-btn"
332
+ :disabled="isChatDisabled"
333
+ borderless
334
+ @click="clearChat">
335
+ <q-icon icon="bin" />
336
+ </q-button>
337
+ </div>
338
+
339
+ <div class="q-chatbot__messages-container">
340
+ <div
341
+ v-for="message in messages"
342
+ :key="message.id"
343
+ :class="getMessageClasses(message.sender)">
344
+ <CBMessage v-bind="message" :loading="isLoading && !message.message" />
321
345
  </div>
322
346
  </div>
323
347
  </div>
@@ -0,0 +1,7 @@
1
+ import CBMessage from "./CBMessage.vue"
2
+ import type { CBMessageProps } from "./CBMessage.vue"
3
+
4
+ export {
5
+ CBMessage,
6
+ CBMessageProps
7
+ }
@@ -1,6 +1,11 @@
1
1
  export type ChatBotMessage = {
2
2
  id: number,
3
- text: string,
4
- timestamp: Date,
3
+ message: string,
4
+ date: Date,
5
5
  sender: 'bot' | 'user'
6
+ }
7
+
8
+ export type ChatBotMessageContent = {
9
+ content: string,
10
+ type: string
6
11
  }