@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.
- package/dist/components/CBMessage.vue.d.ts +34 -0
- package/dist/components/ChatBot.vue.d.ts +4 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/index.js +155 -90
- package/dist/index.mjs +155 -90
- package/dist/style.css +34 -40
- package/dist/types/message.type.d.ts +6 -2
- package/package.json +1 -1
- package/src/assets/styles/styles.scss +40 -46
- package/src/components/CBMessage.vue +81 -0
- package/src/components/ChatBot.vue +115 -91
- package/src/components/index.ts +7 -0
- package/src/types/message.type.ts +7 -2
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
94
|
+
loadChatData()
|
|
91
95
|
})
|
|
92
96
|
.catch((error: Error) => {
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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:
|
|
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.
|
|
254
|
+
if (msg) msg.message = chunk
|
|
226
255
|
}
|
|
227
256
|
})
|
|
228
257
|
.then(({ data }) => {
|
|
229
|
-
if (msg) msg.
|
|
258
|
+
if (msg) msg.message = data
|
|
230
259
|
})
|
|
231
260
|
.catch((error) => {
|
|
232
261
|
addChatMessage(props.texts.botIsSick)
|
|
233
262
|
|
|
234
|
-
|
|
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
|
|
243
|
-
|
|
271
|
+
function setCursorPosition(elem: HTMLInputElement, pos: number) {
|
|
272
|
+
elem.focus()
|
|
273
|
+
elem.setSelectionRange(pos, pos)
|
|
244
274
|
}
|
|
245
275
|
|
|
246
|
-
function
|
|
247
|
-
|
|
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
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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>
|