ai-chat-bot-interface 1.3.1 → 1.4.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.
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-chat-bot-interface",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"description": "A AI chat bot interface. (private)",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"bot"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
+
"v-viewer": "^3.0.21",
|
|
20
21
|
"vue": "^3.5.13"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
package/src/App.vue
CHANGED
|
@@ -5,9 +5,10 @@ import ChatUi from './ChatUi.vue';
|
|
|
5
5
|
<template>
|
|
6
6
|
<div style="width: 100vw; height: 100vh">
|
|
7
7
|
<chat-ui
|
|
8
|
-
bot-id="
|
|
9
|
-
token="
|
|
8
|
+
bot-id="555"
|
|
9
|
+
token="pat_88888"
|
|
10
10
|
uid="262598"
|
|
11
|
+
:def-msg="{ placeholder: '发消息...' }"
|
|
11
12
|
:show-header="true"
|
|
12
13
|
/>
|
|
13
14
|
</div>
|
package/src/ChatUi.vue
CHANGED
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
</p>
|
|
76
76
|
</template>
|
|
77
77
|
<template v-if="conv.content">
|
|
78
|
-
<
|
|
78
|
+
<assistant-replay :content="conv.content" />
|
|
79
79
|
<template v-if="!isAnswering">
|
|
80
80
|
<div v-if="conv.extra.length">
|
|
81
81
|
<template v-for="(comp, idx) in conv.extra" :key="idx">
|
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
<plan-card
|
|
96
96
|
v-if="comp.showType === 'plan'"
|
|
97
97
|
:info="comp"
|
|
98
|
+
:def-msg="finalDefMsg"
|
|
98
99
|
@select="handleCardTap({ type: 'match' }, comp)"
|
|
99
100
|
/>
|
|
100
101
|
</template>
|
|
@@ -136,6 +137,7 @@
|
|
|
136
137
|
:new-chat="!showHeader"
|
|
137
138
|
:token="token"
|
|
138
139
|
:tag-list="tagList"
|
|
140
|
+
:def-msg="finalDefMsg"
|
|
139
141
|
@send="chatConv"
|
|
140
142
|
@tag="handleTagSel"
|
|
141
143
|
@call="handleCall"
|
|
@@ -162,6 +164,7 @@ import LoadingIcon2 from './components/icons/loadingIcon2.vue';
|
|
|
162
164
|
import ImgeList from './components/imgeList.vue';
|
|
163
165
|
import ThinkingIcon from './components/icons/ThinkingIcon.vue';
|
|
164
166
|
import OkIcon from './components/icons/OkIcon.vue';
|
|
167
|
+
import AssistantReplay from './components/assistantReplay/assistantReplay.vue';
|
|
165
168
|
|
|
166
169
|
const chatOptions = computed(() => {
|
|
167
170
|
return {
|
|
@@ -175,6 +178,14 @@ const conversationId = ref('');
|
|
|
175
178
|
const isAnswering = ref(false);
|
|
176
179
|
const historyList = ref([]);
|
|
177
180
|
|
|
181
|
+
const msgObj = {
|
|
182
|
+
placeholder: '發消息⋯',
|
|
183
|
+
fileText: '請根據我上傳的體檢報告為我生成飲食方案',
|
|
184
|
+
uploadingTips: '文件正在上傳,請稍候...',
|
|
185
|
+
matchText: '請用以上方案為我配餐',
|
|
186
|
+
matchContent: '請用以上方案為我配餐',
|
|
187
|
+
};
|
|
188
|
+
|
|
178
189
|
const props = defineProps({
|
|
179
190
|
logo: {
|
|
180
191
|
type: String,
|
|
@@ -213,10 +224,21 @@ const props = defineProps({
|
|
|
213
224
|
{ name: '体检报告', value: 'exam', type: 'upload', msg: '体检报告' },
|
|
214
225
|
],
|
|
215
226
|
},
|
|
227
|
+
defMsg: {
|
|
228
|
+
type: Object,
|
|
229
|
+
default: () => ({}),
|
|
230
|
+
},
|
|
216
231
|
});
|
|
217
232
|
|
|
218
233
|
const Emits = defineEmits(['call']);
|
|
219
234
|
|
|
235
|
+
const finalDefMsg = computed(() => {
|
|
236
|
+
return {
|
|
237
|
+
...msgObj,
|
|
238
|
+
...props.defMsg,
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
|
|
220
242
|
const endTarget = ref(null);
|
|
221
243
|
const inputText = ref('');
|
|
222
244
|
const botInfo = ref({});
|
|
@@ -285,7 +307,7 @@ const createConv = async () => {
|
|
|
285
307
|
|
|
286
308
|
const chatConv = async (data) => {
|
|
287
309
|
let isInCode = Array.isArray(data); // data.hasOwnProperty('text') && data.hasOwnProperty('code');
|
|
288
|
-
|
|
310
|
+
const botId = props.botId;
|
|
289
311
|
if (!(!isAnswering.value && (inputText.value || isInCode))) {
|
|
290
312
|
return;
|
|
291
313
|
}
|
|
@@ -308,7 +330,7 @@ const chatConv = async (data) => {
|
|
|
308
330
|
if (item.hasOwnProperty('content') && item.content) {
|
|
309
331
|
if (item.hasOwnProperty('type') && item.type === 'object_string') {
|
|
310
332
|
console.log('=== item ====', item);
|
|
311
|
-
botId = '7474884145253023795';
|
|
333
|
+
// botId = '7474884145253023795';
|
|
312
334
|
additional_messages.push({
|
|
313
335
|
content: JSON.stringify(
|
|
314
336
|
item.content.map((con) => ({
|
|
@@ -565,11 +587,14 @@ const queryBotInfo = async () => {
|
|
|
565
587
|
};
|
|
566
588
|
|
|
567
589
|
const handleText = (str) => {
|
|
590
|
+
return str;
|
|
568
591
|
// console.log(str);
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
)
|
|
592
|
+
// let txt = '';
|
|
593
|
+
//
|
|
594
|
+
// return str.replaceAll(
|
|
595
|
+
// /\[([^\]]+)\]\((https?:\/\/[^)]+)\)/gi,
|
|
596
|
+
// '<a href="$2" target="_blank">[$1]</a>',
|
|
597
|
+
// );
|
|
573
598
|
};
|
|
574
599
|
const handleBack = () => {
|
|
575
600
|
Emits('call', { type: 'back' });
|
|
@@ -593,7 +618,10 @@ const handleCardTap = ({ type }, info) => {
|
|
|
593
618
|
break;
|
|
594
619
|
case 'match':
|
|
595
620
|
chatConv([
|
|
596
|
-
{
|
|
621
|
+
{
|
|
622
|
+
content: finalDefMsg.value.matchContent,
|
|
623
|
+
text: finalDefMsg.value.matchText,
|
|
624
|
+
},
|
|
597
625
|
]);
|
|
598
626
|
break;
|
|
599
627
|
default:
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
ref="txtEle"
|
|
53
53
|
class="input"
|
|
54
54
|
rows="1"
|
|
55
|
-
placeholder="
|
|
55
|
+
:placeholder="defMsg.placeholder"
|
|
56
56
|
@input="handleInput"
|
|
57
57
|
@keyup.enter="sendMsg"
|
|
58
58
|
/>
|
|
@@ -140,6 +140,10 @@ const props = defineProps({
|
|
|
140
140
|
type: Boolean,
|
|
141
141
|
default: false,
|
|
142
142
|
},
|
|
143
|
+
defMsg: {
|
|
144
|
+
type: Object,
|
|
145
|
+
required: true,
|
|
146
|
+
},
|
|
143
147
|
});
|
|
144
148
|
const Emits = defineEmits(['update:modelValue', 'send', 'tag', 'call']);
|
|
145
149
|
|
|
@@ -194,7 +198,7 @@ const sendMsg = () => {
|
|
|
194
198
|
uFileList.value.findIndex((f) => f.percent < 100) > -1
|
|
195
199
|
) {
|
|
196
200
|
Emits('call', {
|
|
197
|
-
message:
|
|
201
|
+
message: props.defMsg.uploadingTips,
|
|
198
202
|
reason: 'is_uploading',
|
|
199
203
|
value: 'toast',
|
|
200
204
|
type: 'call',
|
|
@@ -245,7 +249,7 @@ const handleUpload = async (idx) => {
|
|
|
245
249
|
const file = uFileList.value[idx].file;
|
|
246
250
|
console.log('========', file);
|
|
247
251
|
if (!textValue.value) {
|
|
248
|
-
textValue.value =
|
|
252
|
+
textValue.value = props.defMsg.fileText;
|
|
249
253
|
}
|
|
250
254
|
const formDate = new FormData();
|
|
251
255
|
formDate.append('file', file);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<p class="text">
|
|
3
|
+
<template v-for="(item, idx) in msgList" :key="idx">
|
|
4
|
+
<template v-if="item.type === 'text'">{{ item.content }}</template>
|
|
5
|
+
<template v-if="item.type === 'link'">
|
|
6
|
+
<a class="link" @click.stop="previewImg(item)">{{ item.content }}</a>
|
|
7
|
+
</template>
|
|
8
|
+
</template>
|
|
9
|
+
</p>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
import { computed, ref } from 'vue';
|
|
14
|
+
import { api as viewerApi } from 'v-viewer';
|
|
15
|
+
|
|
16
|
+
const props = defineProps({
|
|
17
|
+
content: {
|
|
18
|
+
type: String,
|
|
19
|
+
default: '',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const images = ref([]);
|
|
24
|
+
const msgList = computed(() => {
|
|
25
|
+
const regEx = /\[([^\]]+)]\((https?:\/\/[^)]+)\)/gi;
|
|
26
|
+
const matches = [...props.content.matchAll(regEx)];
|
|
27
|
+
let remaining = props.content;
|
|
28
|
+
let pointer = 0;
|
|
29
|
+
const result = [];
|
|
30
|
+
if (matches.length) {
|
|
31
|
+
matches.forEach((match, index) => {
|
|
32
|
+
result.push({
|
|
33
|
+
type: 'text',
|
|
34
|
+
content: match.input.slice(pointer, match.index).replace(regEx, ''),
|
|
35
|
+
});
|
|
36
|
+
result.push({
|
|
37
|
+
type: 'link',
|
|
38
|
+
string: match[0],
|
|
39
|
+
...JSON.parse(match[0].replace(regEx, '{"content":"[$1]","url":"$2"}')),
|
|
40
|
+
});
|
|
41
|
+
remaining = match.input.slice(match.index).replace(match[0], '');
|
|
42
|
+
pointer = match.index;
|
|
43
|
+
});
|
|
44
|
+
if (remaining.length) {
|
|
45
|
+
result.push({
|
|
46
|
+
type: 'text',
|
|
47
|
+
content: remaining,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
result.push({
|
|
52
|
+
type: 'text',
|
|
53
|
+
content: remaining,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const previewImg = ({ url }) => {
|
|
60
|
+
images.value = [url];
|
|
61
|
+
viewerApi({
|
|
62
|
+
images: images.value,
|
|
63
|
+
options: {
|
|
64
|
+
navbar: false,
|
|
65
|
+
toolbar: {
|
|
66
|
+
flipHorizontal: false,
|
|
67
|
+
flipVertical: false,
|
|
68
|
+
next: false,
|
|
69
|
+
prev: false,
|
|
70
|
+
play: false,
|
|
71
|
+
reset: true,
|
|
72
|
+
oneToOne: true,
|
|
73
|
+
rotateLeft: true,
|
|
74
|
+
rotateRight: true,
|
|
75
|
+
zoomIn: true,
|
|
76
|
+
zoomOut: true,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<style scoped lang="less">
|
|
84
|
+
.text {
|
|
85
|
+
word-break: break-all;
|
|
86
|
+
white-space: pre-wrap;
|
|
87
|
+
margin: 0;
|
|
88
|
+
}
|
|
89
|
+
.link {
|
|
90
|
+
color: #039938;
|
|
91
|
+
}
|
|
92
|
+
</style>
|