Skip to content

Commit 4f28713

Browse files
committed
feat: recommend question block add loading
1 parent de5ffe4 commit 4f28713

File tree

5 files changed

+131
-75
lines changed

5 files changed

+131
-75
lines changed

frontend/src/views/chat/RecommendQuestion.vue

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,37 @@
11
<script setup lang="ts">
2-
import { computed } from 'vue'
2+
import { computed, nextTick, ref } from 'vue'
33
import { endsWith, startsWith } from 'lodash-es'
44
import { useI18n } from 'vue-i18n'
5+
import { chatApi, ChatInfo } from '@/api/chat.ts'
56
67
const props = withDefaults(
78
defineProps<{
9+
recordId?: number
10+
currentChat?: ChatInfo
811
questions?: string
912
firstChat?: boolean
1013
}>(),
1114
{
15+
recordId: undefined,
16+
currentChat: () => new ChatInfo(),
1217
questions: '[]',
1318
firstChat: false,
1419
}
1520
)
21+
22+
const emits = defineEmits(['clickQuestion', 'update:currentChat'])
23+
24+
const loading = ref(false)
25+
26+
const _currentChat = computed({
27+
get() {
28+
return props.currentChat
29+
},
30+
set(v) {
31+
emits('update:currentChat', v)
32+
},
33+
})
34+
1635
const computedQuestions = computed<string>(() => {
1736
if (
1837
props.questions &&
@@ -25,20 +44,98 @@ const computedQuestions = computed<string>(() => {
2544
return []
2645
})
2746
28-
const emits = defineEmits(['clickQuestion'])
29-
3047
const { t } = useI18n()
3148
3249
function clickQuestion(question: string): void {
3350
emits('clickQuestion', question)
3451
}
52+
53+
async function getRecommendQuestions() {
54+
loading.value = true
55+
try {
56+
const response = await chatApi.recommendQuestions(props.recordId)
57+
const reader = response.body.getReader()
58+
const decoder = new TextDecoder()
59+
60+
while (true) {
61+
const { done, value } = await reader.read()
62+
if (done) {
63+
break
64+
}
65+
66+
const chunk = decoder.decode(value)
67+
68+
let _list = [chunk]
69+
70+
const lines = chunk.trim().split('}\n\n{')
71+
if (lines.length > 1) {
72+
_list = []
73+
for (let line of lines) {
74+
if (!line.trim().startsWith('{')) {
75+
line = '{' + line.trim()
76+
}
77+
if (!line.trim().endsWith('}')) {
78+
line = line.trim() + '}'
79+
}
80+
_list.push(line)
81+
}
82+
}
83+
84+
for (const str of _list) {
85+
let data
86+
try {
87+
data = JSON.parse(str)
88+
} catch (err) {
89+
console.error('JSON string:', str)
90+
throw err
91+
}
92+
93+
if (data.code && data.code !== 200) {
94+
ElMessage({
95+
message: data.msg,
96+
type: 'error',
97+
showClose: true,
98+
})
99+
return
100+
}
101+
102+
switch (data.type) {
103+
case 'recommended_question':
104+
if (
105+
data.content &&
106+
data.content.length > 0 &&
107+
startsWith(data.content.trim(), '[') &&
108+
endsWith(data.content.trim(), ']')
109+
) {
110+
if (_currentChat.value?.records) {
111+
for (let record of _currentChat.value.records) {
112+
if (record.id === props.recordId) {
113+
record.recommended_question = data.content
114+
115+
await nextTick()
116+
}
117+
}
118+
}
119+
}
120+
}
121+
}
122+
}
123+
} finally {
124+
loading.value = false
125+
}
126+
}
127+
128+
defineExpose({ getRecommendQuestions, id: () => props.recordId })
35129
</script>
36130

37131
<template>
38-
<div v-if="computedQuestions.length > 0" class="recommend-questions">
132+
<div v-if="computedQuestions.length > 0 || loading" class="recommend-questions">
39133
<div v-if="firstChat">{{ t('qa.guess_u_ask') }}</div>
40134
<div v-else class="continue-ask">{{ t('qa.continue_to_ask') }}</div>
41-
<div class="question-grid">
135+
<div v-if="loading">
136+
<el-button style="min-width: unset" type="primary" link loading />
137+
</div>
138+
<div v-else class="question-grid">
42139
<div
43140
v-for="(question, index) in computedQuestions"
44141
:key="index"

frontend/src/views/chat/answer/AnalysisAnswer.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { computed, nextTick } from 'vue'
55
import MdComponent from '@/views/chat/component/MdComponent.vue'
66
const props = withDefaults(
77
defineProps<{
8-
chatList: Array<ChatInfo>
8+
chatList?: Array<ChatInfo>
99
currentChatId?: number
10-
currentChat: ChatInfo
10+
currentChat?: ChatInfo
1111
message?: ChatMessage
1212
loading?: boolean
1313
}>(),

frontend/src/views/chat/answer/ChartAnswer.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { Chat, chatApi, ChatInfo, type ChatMessage, ChatRecord, questionApi } fr
44
import { computed, nextTick } from 'vue'
55
const props = withDefaults(
66
defineProps<{
7-
chatList: Array<ChatInfo>
7+
chatList?: Array<ChatInfo>
88
currentChatId?: number
9-
currentChat: ChatInfo
9+
currentChat?: ChatInfo
1010
message?: ChatMessage
1111
loading?: boolean
1212
reasoningName: 'sql_answer' | 'chart_answer' | Array<'sql_answer' | 'chart_answer'>

frontend/src/views/chat/answer/PredictAnswer.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { computed, nextTick } from 'vue'
55
import MdComponent from '@/views/chat/component/MdComponent.vue'
66
const props = withDefaults(
77
defineProps<{
8-
chatList: Array<ChatInfo>
8+
chatList?: Array<ChatInfo>
99
currentChatId?: number
10-
currentChat: ChatInfo
10+
currentChat?: ChatInfo
1111
message?: ChatMessage
1212
loading?: boolean
1313
}>(),

frontend/src/views/chat/index.vue

Lines changed: 23 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@
9393
<ChatRow :current-chat="currentChat" :msg="message" :hide-avatar="message.first_chat">
9494
<RecommendQuestion
9595
v-if="message.role === 'assistant' && message.first_chat"
96+
ref="recommendQuestionRef"
97+
:current-chat="currentChat"
98+
:record-id="message.record?.id"
9699
:questions="message.recommended_question"
97100
:first-chat="message.first_chat"
98101
@click-question="quickAsk"
@@ -181,6 +184,9 @@
181184
</template>
182185
<template #footer>
183186
<RecommendQuestion
187+
ref="recommendQuestionRef"
188+
:current-chat="currentChat"
189+
:record-id="message.record?.id"
184190
:questions="message.recommended_question"
185191
:first-chat="message.first_chat"
186192
@click-question="quickAsk"
@@ -303,7 +309,7 @@ import ChatListContainer from './ChatListContainer.vue'
303309
import ChatCreator from '@/views/chat/ChatCreator.vue'
304310
import ChatToolBar from './ChatToolBar.vue'
305311
import { useI18n } from 'vue-i18n'
306-
import { endsWith, find, startsWith } from 'lodash-es'
312+
import { find } from 'lodash-es'
307313
import icon_new_chat_outlined from '@/assets/svg/icon_new_chat_outlined.svg'
308314
import icon_sidebar_outlined from '@/assets/svg/icon_sidebar_outlined.svg'
309315
import icon_replace_outlined from '@/assets/svg/icon_replace_outlined.svg'
@@ -373,6 +379,7 @@ const computedMessages = computed<Array<ChatMessage>>(() => {
373379
})
374380
}
375381
382+
console.log(messages)
376383
return messages
377384
})
378385
@@ -465,72 +472,24 @@ function onChatCreated(chat: ChatInfo) {
465472
}
466473
}
467474
468-
async function getRecommendQuestions(record_id?: number) {
469-
const response = await chatApi.recommendQuestions(record_id)
470-
const reader = response.body.getReader()
471-
const decoder = new TextDecoder()
475+
const recommendQuestionRef = ref()
472476
473-
while (true) {
474-
const { done, value } = await reader.read()
475-
if (done) {
476-
break
477-
}
478-
479-
const chunk = decoder.decode(value)
480-
481-
let _list = [chunk]
482-
483-
const lines = chunk.trim().split('}\n\n{')
484-
if (lines.length > 1) {
485-
_list = []
486-
for (let line of lines) {
487-
if (!line.trim().startsWith('{')) {
488-
line = '{' + line.trim()
489-
}
490-
if (!line.trim().endsWith('}')) {
491-
line = line.trim() + '}'
492-
}
493-
_list.push(line)
494-
}
495-
}
496-
497-
for (const str of _list) {
498-
let data
499-
try {
500-
data = JSON.parse(str)
501-
} catch (err) {
502-
console.error('JSON string:', str)
503-
throw err
504-
}
505-
506-
if (data.code && data.code !== 200) {
507-
ElMessage({
508-
message: data.msg,
509-
type: 'error',
510-
showClose: true,
511-
})
512-
return
513-
}
514-
515-
switch (data.type) {
516-
case 'recommended_question':
517-
if (
518-
data.content &&
519-
data.content.length > 0 &&
520-
startsWith(data.content.trim(), '[') &&
521-
endsWith(data.content.trim(), ']')
522-
) {
523-
if (currentChat.value?.records) {
524-
for (let record of currentChat.value.records) {
525-
if (record.id === record_id) {
526-
record.recommended_question = data.content
527-
}
528-
}
529-
}
477+
function getRecommendQuestions(id?: number) {
478+
nextTick(() => {
479+
if (recommendQuestionRef.value) {
480+
if (recommendQuestionRef.value instanceof Array) {
481+
for (let i = 0; i < recommendQuestionRef.value.length; i++) {
482+
const _id = recommendQuestionRef.value[i].id()
483+
if (_id === id) {
484+
recommendQuestionRef.value[i].getRecommendQuestions()
485+
break
530486
}
487+
}
488+
} else {
489+
recommendQuestionRef.value.getRecommendQuestions()
531490
}
532491
}
533-
}
492+
})
534493
}
535494
536495
onMounted(() => {
@@ -549,7 +508,7 @@ const chartAnswerRef = ref()
549508
async function onChartAnswerFinish(id: number) {
550509
loading.value = false
551510
isTyping.value = false
552-
await getRecommendQuestions(id)
511+
getRecommendQuestions(id)
553512
}
554513
555514
function onChartAnswerError() {

0 commit comments

Comments
 (0)