ai-chat-bot-interface 1.0.1 → 1.0.3
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 +1 -1
- package/src/ChatUi.less +7 -0
- package/src/ChatUi.vue +92 -44
- package/src/components/DishesList.vue +2 -2
- package/src/components/PlanCard.vue +40 -0
package/package.json
CHANGED
package/src/ChatUi.less
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
}
|
|
28
28
|
&_sug {
|
|
29
29
|
cursor: pointer;
|
|
30
|
+
font-size: 14px;
|
|
30
31
|
margin-bottom: 8px;
|
|
31
32
|
padding: 6px 16px;
|
|
32
33
|
border-radius: 8px;
|
|
@@ -40,7 +41,11 @@
|
|
|
40
41
|
&_box {
|
|
41
42
|
width: 100%;
|
|
42
43
|
height: 100%;
|
|
44
|
+
font-size: 14px;
|
|
43
45
|
background-color: @bg-color;
|
|
46
|
+
.btn {
|
|
47
|
+
border: none;
|
|
48
|
+
}
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
&_wrap {
|
|
@@ -127,6 +132,7 @@
|
|
|
127
132
|
border-radius: @border-radius;
|
|
128
133
|
|
|
129
134
|
/deep/ .text {
|
|
135
|
+
word-break: break-all;
|
|
130
136
|
white-space: pre-wrap;
|
|
131
137
|
|
|
132
138
|
a {
|
|
@@ -213,5 +219,6 @@
|
|
|
213
219
|
color: #1d1c2359;
|
|
214
220
|
background-color: #2e2e380a;
|
|
215
221
|
font-size: 12px;
|
|
222
|
+
text-align: center;
|
|
216
223
|
}
|
|
217
224
|
}
|
package/src/ChatUi.vue
CHANGED
|
@@ -4,15 +4,17 @@
|
|
|
4
4
|
<div class="cui_header">
|
|
5
5
|
<div class="title" @click.stop="queryHistoryList">
|
|
6
6
|
<img class="logo" :src="logo" alt="logo" style="width: 24px; height: 24px;"/>
|
|
7
|
-
{{ name }}
|
|
7
|
+
{{ name }}
|
|
8
8
|
</div>
|
|
9
9
|
<div class="btn_group">
|
|
10
|
-
<
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
|
|
10
|
+
<template v-show="false">
|
|
11
|
+
<button class="btn">
|
|
12
|
+
<clear-icon/>
|
|
13
|
+
</button>
|
|
14
|
+
<button class="btn">
|
|
15
|
+
<close-icon/>
|
|
16
|
+
</button>
|
|
17
|
+
</template>
|
|
16
18
|
</div>
|
|
17
19
|
</div>
|
|
18
20
|
<div class="cui_content">
|
|
@@ -42,7 +44,8 @@
|
|
|
42
44
|
<p class="text" v-html="conv.content"></p>
|
|
43
45
|
<div v-if="conv.extra.length && !isAnswering">
|
|
44
46
|
<template v-for="(comp, idx) in conv.extra" :key="idx">
|
|
45
|
-
<dishes-list :sku-list="comp.
|
|
47
|
+
<dishes-list v-if="comp.showType === 'card'" :sku-list="comp.skuList" @select="handleCardTap"/>
|
|
48
|
+
<plan-card v-if="comp.showType === 'plan'" @select="handleCardTap({ type: 'match'})" />
|
|
46
49
|
</template>
|
|
47
50
|
</div>
|
|
48
51
|
</div>
|
|
@@ -50,23 +53,15 @@
|
|
|
50
53
|
</div>
|
|
51
54
|
<div v-else class="replay role_user">
|
|
52
55
|
<div class="replay_content">
|
|
53
|
-
|
|
54
56
|
<div class="name">User_{{ uid }} <!--<span class="time">12:30</span>--></div>
|
|
55
57
|
<div class="box">
|
|
56
58
|
<p class="text" v-html="conv.content"></p>
|
|
57
|
-
<div v-if="conv.extra.length && !isAnswering">
|
|
58
|
-
<template v-for="(comp, idx) in conv.extra" :key="idx">
|
|
59
|
-
<dishes-list :sku-list="comp.content.skuList"
|
|
60
|
-
@select="handleCardTap"
|
|
61
|
-
/>
|
|
62
|
-
</template>
|
|
63
|
-
</div>
|
|
64
59
|
</div>
|
|
65
60
|
</div>
|
|
66
61
|
<img class="avatar" :src="avatar" alt="avatar">
|
|
67
62
|
</div>
|
|
68
63
|
</template>
|
|
69
|
-
<div ref="endTarget" style="height: 100px;"
|
|
64
|
+
<div ref="endTarget" style="height: 100px;"/>
|
|
70
65
|
</div>
|
|
71
66
|
<div class="cui_operate">
|
|
72
67
|
<button class="btn" @click.stop="createConv">
|
|
@@ -79,7 +74,7 @@
|
|
|
79
74
|
</div>
|
|
80
75
|
</div>
|
|
81
76
|
</div>
|
|
82
|
-
<div class="cui_footer">Powered by
|
|
77
|
+
<div class="cui_footer">Powered by DeepSeek</div>
|
|
83
78
|
</div>
|
|
84
79
|
</div>
|
|
85
80
|
|
|
@@ -95,6 +90,7 @@ import mock from './mock';
|
|
|
95
90
|
import {get, post} from './utils/request';
|
|
96
91
|
import DishesCard from './components/DishesCard.vue';
|
|
97
92
|
import DishesList from './components/DishesList.vue';
|
|
93
|
+
import PlanCard from './components/PlanCard.vue';
|
|
98
94
|
|
|
99
95
|
const chatOptions = computed(() => {
|
|
100
96
|
return {
|
|
@@ -102,7 +98,7 @@ const chatOptions = computed(() => {
|
|
|
102
98
|
Authorization: `Bearer ${props.token}`,
|
|
103
99
|
'Content-Type': 'application/json',
|
|
104
100
|
},
|
|
105
|
-
}
|
|
101
|
+
};
|
|
106
102
|
});
|
|
107
103
|
const conversationId = ref('');
|
|
108
104
|
const isAnswering = ref(false);
|
|
@@ -132,10 +128,13 @@ const props = defineProps({
|
|
|
132
128
|
},
|
|
133
129
|
token: {
|
|
134
130
|
type: String,
|
|
135
|
-
required: true
|
|
136
|
-
}
|
|
131
|
+
required: true,
|
|
132
|
+
},
|
|
137
133
|
|
|
138
134
|
});
|
|
135
|
+
|
|
136
|
+
const Emits = defineEmits(['call']);
|
|
137
|
+
|
|
139
138
|
const endTarget = ref(null);
|
|
140
139
|
const inputText = ref('');
|
|
141
140
|
const botInfo = ref({});
|
|
@@ -200,16 +199,18 @@ const messageCreate = async () => {
|
|
|
200
199
|
);
|
|
201
200
|
};
|
|
202
201
|
const chatConv = async (data) => {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (!(!isAnswering.value && (inputText || data.code))) {
|
|
202
|
+
let isInCode = data.hasOwnProperty('text') && data.hasOwnProperty('code');
|
|
203
|
+
if (!(!isAnswering.value && (inputText.value || isInCode))) {
|
|
206
204
|
return;
|
|
207
205
|
}
|
|
206
|
+
const inText = inputText.value;
|
|
207
|
+
console.log('== user send ==', isInCode, data, inText);
|
|
208
|
+
isAnswering.value = true;
|
|
208
209
|
historyList.value.push({
|
|
209
210
|
conversation_id: conversationId.value,
|
|
210
211
|
bot_id: props.botId,
|
|
211
212
|
role: 'user',
|
|
212
|
-
content:
|
|
213
|
+
content: isInCode ? data.text : inText,
|
|
213
214
|
status: 'ended',
|
|
214
215
|
extra: [],
|
|
215
216
|
});
|
|
@@ -230,7 +231,7 @@ const chatConv = async (data) => {
|
|
|
230
231
|
{
|
|
231
232
|
'role': 'user',
|
|
232
233
|
'content_type': 'text',
|
|
233
|
-
'content':
|
|
234
|
+
'content': isInCode ? data.code : inText, // '配餐1600kcal,身高173,体重60kg,生成一天的套餐',
|
|
234
235
|
}],
|
|
235
236
|
}),
|
|
236
237
|
credentials: 'same-origin', // 默认同源策略
|
|
@@ -288,22 +289,25 @@ const chatConv = async (data) => {
|
|
|
288
289
|
&& strObj.hasOwnProperty('content_type')
|
|
289
290
|
&& strObj.content_type === 'text'
|
|
290
291
|
&& strObj.hasOwnProperty('type')
|
|
291
|
-
&& strObj.type === 'answer'
|
|
292
|
-
|
|
293
|
-
historyList.value[idx].content = handleText(historyList.value[idx].content +
|
|
292
|
+
&& strObj.type === 'answer'
|
|
293
|
+
&& !strObj.hasOwnProperty('created_at')) {
|
|
294
|
+
historyList.value[idx].content = handleText(historyList.value[idx].content + strObj.content);
|
|
294
295
|
} else if (strObj.hasOwnProperty('type')
|
|
295
296
|
&& strObj.type === 'tool_response') {
|
|
296
297
|
const extraObj = JSON.parse(strObj.content);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
298
|
+
if(extraObj.hasOwnProperty('showType')) {
|
|
299
|
+
historyList.value[idx].extra.push({...extraObj});
|
|
300
|
+
}else if(extraObj.hasOwnProperty('response_for_model')){
|
|
301
|
+
const modelObj = JSON.parse(extraObj.response_for_model);
|
|
302
|
+
if(modelObj.hasOwnProperty('showType')) {
|
|
303
|
+
historyList.value[idx].extra.push({...modelObj});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
301
306
|
}
|
|
302
307
|
}
|
|
303
308
|
});
|
|
304
309
|
}
|
|
305
310
|
console.log('====', historyList.value);
|
|
306
|
-
console.log('== txt ==', txt);
|
|
307
311
|
};
|
|
308
312
|
|
|
309
313
|
const queryHistoryList = async () => {
|
|
@@ -314,16 +318,55 @@ const queryHistoryList = async () => {
|
|
|
314
318
|
);
|
|
315
319
|
if (res.code === 0 && res.data && res.data.length) {
|
|
316
320
|
historyList.value = [];
|
|
321
|
+
const cardList = [];
|
|
317
322
|
res.data.forEach(row => {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
323
|
+
if(row.hasOwnProperty('content_type')) {
|
|
324
|
+
if(row.content_type === 'text') {
|
|
325
|
+
historyList.value.push({
|
|
326
|
+
chat_id: row.chat_id,
|
|
327
|
+
conversation_id: row.conversation_id,
|
|
328
|
+
bot_id: row.bot_id,
|
|
329
|
+
role: row.role,
|
|
330
|
+
content: handleText(row.content),
|
|
331
|
+
status: 'ended',
|
|
332
|
+
extra: [],
|
|
333
|
+
});
|
|
334
|
+
}else if(row.content_type === 'card' && row.role === 'assistant') {
|
|
335
|
+
try {
|
|
336
|
+
const cardObj = JSON.parse(row.content);
|
|
337
|
+
if(cardObj.hasOwnProperty('showType')) {
|
|
338
|
+
cardList.push({
|
|
339
|
+
chat_id: row.chat_id,
|
|
340
|
+
conversation_id: row.conversation_id,
|
|
341
|
+
bot_id: row.bot_id,
|
|
342
|
+
role: row.role,
|
|
343
|
+
extra:[{...cardObj}]
|
|
344
|
+
})
|
|
345
|
+
}else if(cardObj.hasOwnProperty('response_for_model')){
|
|
346
|
+
const modelObj = JSON.parse(cardObj.response_for_model);
|
|
347
|
+
if(modelObj.hasOwnProperty('showType')) {
|
|
348
|
+
cardList.push({
|
|
349
|
+
chat_id: row.chat_id,
|
|
350
|
+
conversation_id: row.conversation_id,
|
|
351
|
+
bot_id: row.bot_id,
|
|
352
|
+
role: row.role,
|
|
353
|
+
extra:[{...modelObj}]
|
|
354
|
+
})
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}catch (e) {
|
|
358
|
+
console.log('== 解析错误 ==');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
326
362
|
});
|
|
363
|
+
cardList.forEach(card => {
|
|
364
|
+
const idx = historyList.value.findIndex(c => c.chat_id === card.chat_id && c.role === 'assistant');
|
|
365
|
+
if(idx > -1) {
|
|
366
|
+
historyList.value[idx].extra = [...card.extra];
|
|
367
|
+
}
|
|
368
|
+
})
|
|
369
|
+
console.log(historyList.value, cardList);
|
|
327
370
|
}
|
|
328
371
|
};
|
|
329
372
|
|
|
@@ -348,14 +391,19 @@ const handleCardTap = ({type}) => {
|
|
|
348
391
|
case 'change':
|
|
349
392
|
chatConv({code: '換一套菜品', text: '換一套菜品'});
|
|
350
393
|
break;
|
|
394
|
+
case 'match':
|
|
395
|
+
chatConv({code: '請用以上方案為我配餐', text: '請用以上方案為我配餐'});
|
|
396
|
+
break;
|
|
397
|
+
default:
|
|
398
|
+
Emits('call', { type });
|
|
351
399
|
}
|
|
352
400
|
};
|
|
353
401
|
|
|
354
402
|
const scrollToEnd = () => {
|
|
355
403
|
nextTick(() => {
|
|
356
404
|
endTarget.value.scrollIntoView();
|
|
357
|
-
})
|
|
358
|
-
}
|
|
405
|
+
});
|
|
406
|
+
};
|
|
359
407
|
</script>
|
|
360
408
|
|
|
361
409
|
<style scoped lang="less">
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
</div>
|
|
12
12
|
</template>
|
|
13
13
|
<div class="btn_group">
|
|
14
|
-
<div class="btn btn_1" @click.stop="handleBtn('change')">換一套菜品</div
|
|
14
|
+
<!-- <div class="btn btn_1" @click.stop="handleBtn('change')">換一套菜品</div>-->
|
|
15
15
|
<div class="btn btn_2" @click.stop="handleBtn('order')">去下單</div>
|
|
16
16
|
</div>
|
|
17
17
|
</div>
|
|
@@ -69,7 +69,7 @@ const handleBtn = (type) => {
|
|
|
69
69
|
|
|
70
70
|
&_group {
|
|
71
71
|
display: grid;
|
|
72
|
-
grid-template-columns: 1fr
|
|
72
|
+
grid-template-columns: 1fr;
|
|
73
73
|
grid-column-gap: 10px;
|
|
74
74
|
margin-top: 20px;
|
|
75
75
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="btn_group">
|
|
3
|
+
<div class="btn btn_2" @click.stop="handleSel">用該方案配餐</div>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup>
|
|
8
|
+
|
|
9
|
+
const Emits = defineEmits(['select']);
|
|
10
|
+
const handleSel = () => {
|
|
11
|
+
Emits('select', {})
|
|
12
|
+
}
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<style scoped lang="less">
|
|
16
|
+
.btn {
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
width: 100%;
|
|
19
|
+
height: 38px;
|
|
20
|
+
line-height: 38px;
|
|
21
|
+
background-color: #E6F5EB;
|
|
22
|
+
border-radius: 19px;
|
|
23
|
+
text-align: center;
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
font-size: 13px;
|
|
26
|
+
color: #039938;
|
|
27
|
+
|
|
28
|
+
&_2 {
|
|
29
|
+
color: #fff;
|
|
30
|
+
background-color: #039938;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&_group {
|
|
34
|
+
display: grid;
|
|
35
|
+
grid-template-columns: 1fr;
|
|
36
|
+
grid-column-gap: 10px;
|
|
37
|
+
margin-top: 20px;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
</style>
|