@quidgest/chatbot 0.5.3 → 0.5.4
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/ChatBot/ChatBot.vue.d.ts +2 -0
- package/dist/components/ChatBot/__tests__/ChatBot.spec.d.ts +1 -0
- package/dist/components/ChatBot/types.d.ts +2 -1
- package/dist/components/ChatBotMessage/ChatBotMessage.vue.d.ts +3 -1
- package/dist/components/FieldPreview/FieldPreview.vue.d.ts +2 -0
- package/dist/composables/useChatApi.d.ts +1 -1
- package/dist/composables/useChatMessages.d.ts +1 -0
- package/dist/composables/useTexts.d.ts +4 -0
- package/dist/index.js +15 -15
- package/dist/index.mjs +1597 -2209
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/components/ChatBot/ChatBot.vue +57 -60
- package/src/components/ChatBot/__tests__/ChatBot.spec.ts +52 -0
- package/src/components/ChatBot/__tests__/__snapshots__/ChatBot.spec.ts.snap +39 -0
- package/src/components/ChatBot/types.ts +2 -1
- package/src/components/ChatBotMessage/ChatBotMessage.vue +5 -3
- package/src/components/ChatBotMessage/ChatBotMessageButtons.vue +1 -0
- package/src/components/ChatBotMessage/__tests__/ChatBotMessage.spec.ts +7 -3
- package/src/components/ChatBotMessage/__tests__/ChatBotMessageButtons.spec.ts +4 -4
- package/src/components/ChatToolBar/ChatToolBar.vue +2 -1
- package/src/components/ChatToolBar/__tests__/ChatToolBar.spec.ts +38 -18
- package/src/components/FieldPreview/FieldPreview.vue +31 -9
- package/src/components/FieldPreview/__tests__/__snapshots__/FieldPreview.spec.ts.snap +4 -10
- package/src/components/FieldPreview/field-preview.scss +4 -0
- package/src/components/MarkdownRender/MarkdownRender.vue +1 -0
- package/src/composables/__tests__/useChatMessages.spec.ts +14 -1
- package/src/composables/useChatApi.ts +57 -53
- package/src/composables/useChatMessages.ts +6 -1
- package/src/composables/useTexts.ts +4 -0
- package/src/test/setup.ts +5 -0
|
@@ -5,23 +5,24 @@
|
|
|
5
5
|
{{ texts.suggestionsForField }} <b>{{ props.name }}</b>
|
|
6
6
|
</span>
|
|
7
7
|
</div>
|
|
8
|
-
<div class="
|
|
8
|
+
<div :class="classes">
|
|
9
9
|
<component
|
|
10
10
|
:is="previewComponent"
|
|
11
11
|
v-bind="previewComponentProps" />
|
|
12
12
|
</div>
|
|
13
13
|
<div class="q-field-preview__footer">
|
|
14
14
|
<q-button-group borderless>
|
|
15
|
-
<!-- <q-button
|
|
16
|
-
:title="texts.regenerateResponse"
|
|
17
|
-
:disabled="props.disabled"
|
|
18
|
-
borderless
|
|
19
|
-
@click="console.log('Regenerate response')">
|
|
20
|
-
<q-icon icon="reset" />
|
|
21
|
-
</q-button> -->
|
|
22
15
|
<q-button
|
|
23
|
-
|
|
16
|
+
:title="texts.regenerateResponse"
|
|
17
|
+
:disabled="blockRegenerateButton"
|
|
18
|
+
:readonly="blockRegenerateButton"
|
|
19
|
+
borderless
|
|
20
|
+
@click="regenerate">
|
|
21
|
+
<q-icon icon="reset" />
|
|
22
|
+
</q-button>
|
|
23
|
+
<q-button
|
|
24
24
|
:label="texts.apply"
|
|
25
|
+
data-testid="apply-button"
|
|
25
26
|
:disabled="blockApplyButton"
|
|
26
27
|
:readonly="blockApplyButton"
|
|
27
28
|
@click="emitApply">
|
|
@@ -43,13 +44,19 @@
|
|
|
43
44
|
const props = defineProps<FieldPreviewProps>()
|
|
44
45
|
const emit = defineEmits<{
|
|
45
46
|
(e: 'apply', text: unknown): void
|
|
47
|
+
(e: 'regenerate', name: string): void
|
|
46
48
|
}>()
|
|
47
49
|
const texts = useTexts()
|
|
48
50
|
const blockApply = ref(props.applied)
|
|
51
|
+
const blockRegenerate = ref(false)
|
|
49
52
|
const blockApplyButton = computed(() => {
|
|
50
53
|
return props.disabled || blockApply.value
|
|
51
54
|
})
|
|
52
55
|
|
|
56
|
+
const blockRegenerateButton = computed(() => {
|
|
57
|
+
return props.disabled || blockRegenerate.value
|
|
58
|
+
})
|
|
59
|
+
|
|
53
60
|
const previewComponent = computed(() => {
|
|
54
61
|
if (props.type === 'text' || props.type === 'multiline_text') return MarkdownRender
|
|
55
62
|
|
|
@@ -65,6 +72,14 @@
|
|
|
65
72
|
return componentProps
|
|
66
73
|
})
|
|
67
74
|
|
|
75
|
+
const classes = computed(() => {
|
|
76
|
+
const classes = ['q-field-preview__content']
|
|
77
|
+
|
|
78
|
+
if (previewComponent.value !== MarkdownRender) classes.push('preserve-whitespace')
|
|
79
|
+
|
|
80
|
+
return classes
|
|
81
|
+
})
|
|
82
|
+
|
|
68
83
|
function emitApply() {
|
|
69
84
|
if (blockApply.value) return
|
|
70
85
|
blockApply.value = true
|
|
@@ -73,4 +88,11 @@
|
|
|
73
88
|
|
|
74
89
|
emit('apply', text)
|
|
75
90
|
}
|
|
91
|
+
|
|
92
|
+
function regenerate() {
|
|
93
|
+
if (blockRegenerate.value) return
|
|
94
|
+
blockRegenerate.value = true
|
|
95
|
+
|
|
96
|
+
emit('regenerate', props.name)
|
|
97
|
+
}
|
|
76
98
|
</script>
|
|
@@ -9,17 +9,11 @@ exports[`FieldPreview > renders correctly with default props 1`] = `
|
|
|
9
9
|
</div>
|
|
10
10
|
</div>
|
|
11
11
|
<div class="q-field-preview__footer">
|
|
12
|
-
<div class="q-button-group" role="group">
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
:disabled="props.disabled"
|
|
16
|
-
borderless
|
|
17
|
-
@click="console.log('Regenerate response')">
|
|
18
|
-
<q-icon icon="reset" />
|
|
19
|
-
</q-button> --><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless" data-testid="apply-button">
|
|
12
|
+
<div class="q-button-group" role="group"><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless" title="Regenerate response">
|
|
13
|
+
<!--v-if--><span class="q-button__content"><span data-test="reset"></span> </span>
|
|
14
|
+
</button><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless" data-testid="apply-button">
|
|
20
15
|
<!--v-if--><span class="q-button__content"><span data-test="apply"></span> Apply</span>
|
|
21
|
-
</button>
|
|
22
|
-
</div>
|
|
16
|
+
</button></div>
|
|
23
17
|
</div>
|
|
24
18
|
</div>"
|
|
25
19
|
`;
|
|
@@ -4,7 +4,8 @@ import { useChatMessages } from '../useChatMessages'
|
|
|
4
4
|
// Utils
|
|
5
5
|
import { describe, it, expect, beforeEach } from 'vitest'
|
|
6
6
|
|
|
7
|
-
const { addChatMessage, clearMessages, getMessages, getLastMessage } =
|
|
7
|
+
const { addChatMessage, clearMessages, getMessages, getLastMessage, deleteMessageById } =
|
|
8
|
+
useChatMessages()
|
|
8
9
|
|
|
9
10
|
beforeEach(() => {
|
|
10
11
|
// Reset chat messages before each test
|
|
@@ -48,4 +49,16 @@ describe('useChatMessages', () => {
|
|
|
48
49
|
expect(messages).toEqual([])
|
|
49
50
|
expect(messages.length).toBe(0)
|
|
50
51
|
})
|
|
52
|
+
|
|
53
|
+
it('should delete a message by ID', () => {
|
|
54
|
+
const msg1 = addChatMessage('First message', 'bot')
|
|
55
|
+
const msg2 = addChatMessage('Second message', 'user')
|
|
56
|
+
|
|
57
|
+
expect(getMessages().length).toBe(2)
|
|
58
|
+
deleteMessageById(msg1.id)
|
|
59
|
+
|
|
60
|
+
const messages = getMessages()
|
|
61
|
+
expect(messages.length).toBe(1)
|
|
62
|
+
expect(messages[0].id).toBe(msg2.id)
|
|
63
|
+
})
|
|
51
64
|
})
|
|
@@ -56,6 +56,62 @@ export function useChatApi(apiEndpoint: string) {
|
|
|
56
56
|
})
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
async function sendPrompt(
|
|
60
|
+
formData: FormData,
|
|
61
|
+
onChunk: (chunk: string) => void,
|
|
62
|
+
onError?: (error: Error) => void
|
|
63
|
+
) {
|
|
64
|
+
isLoading.value = true
|
|
65
|
+
try {
|
|
66
|
+
return await useSSE(
|
|
67
|
+
{
|
|
68
|
+
method: 'POST',
|
|
69
|
+
url: `${apiEndpoint}/prompt/submit`,
|
|
70
|
+
data: formData
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
onMessage: (data) => {
|
|
74
|
+
onChunk(data)
|
|
75
|
+
},
|
|
76
|
+
onDone: () => (isLoading.value = false)
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
} catch (error) {
|
|
80
|
+
isLoading.value = false
|
|
81
|
+
onError?.(error as Error)
|
|
82
|
+
console.error('Error in sendPrompt:', error)
|
|
83
|
+
throw error
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function getJobResultData(
|
|
88
|
+
jobId: string,
|
|
89
|
+
onChunk: (chunk: string) => void,
|
|
90
|
+
onMetaData: (metadata: Record<string, unknown>) => void,
|
|
91
|
+
onRequestError?: (error: Error) => void
|
|
92
|
+
) {
|
|
93
|
+
isLoading.value = true
|
|
94
|
+
try {
|
|
95
|
+
return await useSSE(
|
|
96
|
+
{
|
|
97
|
+
method: 'POST',
|
|
98
|
+
url: `${apiEndpoint}/get-job-result`,
|
|
99
|
+
data: {
|
|
100
|
+
jobId
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
onMessage: (data) => onChunk(data),
|
|
105
|
+
onFieldMetadata: (metadata) => onMetaData(metadata),
|
|
106
|
+
onDone: () => (isLoading.value = false)
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
} catch (error) {
|
|
110
|
+
lastError.value = error as Error
|
|
111
|
+
onRequestError?.(error as Error)
|
|
112
|
+
isLoading.value = false
|
|
113
|
+
}
|
|
114
|
+
}
|
|
59
115
|
async function clearChatData(
|
|
60
116
|
username: string,
|
|
61
117
|
project: string,
|
|
@@ -74,58 +130,6 @@ export function useChatApi(apiEndpoint: string) {
|
|
|
74
130
|
})
|
|
75
131
|
}
|
|
76
132
|
|
|
77
|
-
async function sendPrompt(
|
|
78
|
-
formData: FormData,
|
|
79
|
-
onChunk: (chunk: string) => void,
|
|
80
|
-
onError?: (error: Error) => void
|
|
81
|
-
) {
|
|
82
|
-
isLoading.value = true
|
|
83
|
-
return await useSSE(
|
|
84
|
-
{
|
|
85
|
-
method: 'POST',
|
|
86
|
-
url: `${apiEndpoint}/prompt/submit`,
|
|
87
|
-
data: formData
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
onMessage: (data) => {
|
|
91
|
-
onChunk(data)
|
|
92
|
-
},
|
|
93
|
-
onError: (error) => {
|
|
94
|
-
lastError.value = error
|
|
95
|
-
onError?.(error)
|
|
96
|
-
console.error('Error in sendPrompt:', error)
|
|
97
|
-
},
|
|
98
|
-
onDone: () => (isLoading.value = false)
|
|
99
|
-
}
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async function getFieldSuggestionData(
|
|
104
|
-
jobId: string,
|
|
105
|
-
onChunk: (chunk: string) => void,
|
|
106
|
-
onMetaData: (metadata: Record<string, unknown>) => void
|
|
107
|
-
) {
|
|
108
|
-
isLoading.value = true
|
|
109
|
-
return await useSSE(
|
|
110
|
-
{
|
|
111
|
-
method: 'POST',
|
|
112
|
-
url: `${apiEndpoint}/get-job-result`,
|
|
113
|
-
data: {
|
|
114
|
-
jobId
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
onMessage: (data) => onChunk(data),
|
|
119
|
-
onFieldMetadata: (metadata) => onMetaData(metadata),
|
|
120
|
-
onError: (error) => {
|
|
121
|
-
lastError.value = error
|
|
122
|
-
console.error('Error in getFieldSuggestionData:', error)
|
|
123
|
-
},
|
|
124
|
-
onDone: () => (isLoading.value = false)
|
|
125
|
-
}
|
|
126
|
-
)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
133
|
async function handleFeedback(feedback: number, comment: string, sessionID: string) {
|
|
130
134
|
return await baseRequest<{ success: boolean }>({
|
|
131
135
|
method: 'POST',
|
|
@@ -143,7 +147,7 @@ export function useChatApi(apiEndpoint: string) {
|
|
|
143
147
|
lastError,
|
|
144
148
|
getChatData,
|
|
145
149
|
clearChatData,
|
|
146
|
-
|
|
150
|
+
getJobResultData,
|
|
147
151
|
sendPrompt,
|
|
148
152
|
handleFeedback
|
|
149
153
|
}
|
|
@@ -41,6 +41,10 @@ export function useChatMessages() {
|
|
|
41
41
|
nextMessageId.value = 1
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function deleteMessageById(messageId: number) {
|
|
45
|
+
messages.value = messages.value.filter((m) => m.id !== messageId)
|
|
46
|
+
}
|
|
47
|
+
|
|
44
48
|
function getMessages() {
|
|
45
49
|
return messages.value
|
|
46
50
|
}
|
|
@@ -51,6 +55,7 @@ export function useChatMessages() {
|
|
|
51
55
|
addChatMessage,
|
|
52
56
|
getLastMessage,
|
|
53
57
|
clearMessages,
|
|
54
|
-
getMessages
|
|
58
|
+
getMessages,
|
|
59
|
+
deleteMessageById
|
|
55
60
|
}
|
|
56
61
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TODO: Implement localization
|
|
3
|
+
*/
|
|
1
4
|
export function useTexts() {
|
|
2
5
|
return {
|
|
3
6
|
copy: 'Copy',
|
|
@@ -24,6 +27,7 @@ export function useTexts() {
|
|
|
24
27
|
cancelButton: 'Cancel',
|
|
25
28
|
senderImage: 'Sender Image',
|
|
26
29
|
imagePreview: 'Image preview',
|
|
30
|
+
regenerateResponsePrompt: 'Regenerate a new response for field {0}',
|
|
27
31
|
regenerateResponse: 'Regenerate response',
|
|
28
32
|
generatingResponse: 'Generating',
|
|
29
33
|
suggestionsForField: 'Suggestions for field:',
|
package/src/test/setup.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { vi } from 'vitest'
|
|
|
2
2
|
import { config } from '@vue/test-utils'
|
|
3
3
|
|
|
4
4
|
import { createFramework } from '@quidgest/ui/framework'
|
|
5
|
+
import { QSelect } from '@quidgest/ui/components'
|
|
5
6
|
|
|
6
7
|
vi.mock('@quidgest/ui/components', async (importOriginal) => {
|
|
7
8
|
const original = await importOriginal<typeof import('@quidgest/ui/components')>()
|
|
@@ -34,3 +35,7 @@ config.global.plugins = [
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
]
|
|
38
|
+
|
|
39
|
+
config.global.components = {
|
|
40
|
+
QSelect
|
|
41
|
+
}
|