优化响应逻辑以及中间状态显示

This commit is contained in:
Wenjie Zhang 2024-10-15 00:38:24 +08:00
parent 7658599035
commit bf8580d649
2 changed files with 106 additions and 50 deletions

View File

@ -28,14 +28,30 @@ def chat_post(
cur_res_id: str = Body(...)): cur_res_id: str = Body(...)):
history_manager = HistoryManager(history) history_manager = HistoryManager(history)
new_query, refs = startup.retriever(query, history_manager.messages, meta)
refs_pool[cur_res_id] = refs
messages = history_manager.get_history_with_msg(new_query, max_rounds=meta.get('history_round')) def make_chunk(content, status, history):
history_manager.add_user(query) return json.dumps({
logger.debug(f"Web history: {history_manager.messages}") "response": content,
"history": history,
"model_name": startup.config.model_name,
"status": status,
}, ensure_ascii=False).encode('utf-8') + b"\n"
def generate_response(): def generate_response():
if meta.get("enable_retrieval"):
chunk = make_chunk("", "searching", history=None)
yield chunk
new_query, refs = startup.retriever(query, history_manager.messages, meta)
refs_pool[cur_res_id] = refs
else:
new_query = query
messages = history_manager.get_history_with_msg(new_query, max_rounds=meta.get('history_round'))
history_manager.add_user(query)
logger.debug(f"Web history: {history_manager.messages}")
content = "" content = ""
for delta in startup.model.predict(messages, stream=True): for delta in startup.model.predict(messages, stream=True):
if not delta.content: if not delta.content:
@ -47,12 +63,8 @@ def chat_post(
content += delta.content content += delta.content
logger.debug(f"Response: {content}") logger.debug(f"Response: {content}")
chunk = make_chunk(content, "loading", history=history_manager.update_ai(content))
_chunk = json.dumps({ yield chunk
"response": content,
"history": history_manager.update_ai(content),
}, ensure_ascii=False).encode('utf-8') + b"\n"
yield _chunk
return StreamingResponse(generate_response(), media_type='application/json') return StreamingResponse(generate_response(), media_type='application/json')

View File

@ -16,10 +16,10 @@
</a-tooltip> </a-tooltip>
</div> </div>
<div class="header__right"> <div class="header__right">
<div class="nav-btn text metas" v-if="meta.use_graph"> <div class="nav-btn text metas" v-if="meta.use_graph && meta.enable_retrieval">
<GoldOutlined /> 图数据库 <GoldOutlined /> 图数据库
</div> </div>
<a-dropdown v-if="meta.selectedKB !== null"> <a-dropdown v-if="meta.selectedKB !== null && meta.enable_retrieval">
<a class="ant-dropdown-link nav-btn" @click.prevent> <a class="ant-dropdown-link nav-btn" @click.prevent>
<!-- <component :is="meta.selectedKB === null ? BookOutlined : BookFilled" /> --> <!-- <component :is="meta.selectedKB === null ? BookOutlined : BookFilled" /> -->
<BookOutlined /> <BookOutlined />
@ -40,7 +40,20 @@
<component :is="opts.showPanel ? FolderOpenOutlined : FolderOutlined" /> <span class="text">选项</span> <component :is="opts.showPanel ? FolderOpenOutlined : FolderOutlined" /> <span class="text">选项</span>
</div> </div>
<div v-if="opts.showPanel" class="my-panal r0 top100 swing-in-top-fwd" ref="panel"> <div v-if="opts.showPanel" class="my-panal r0 top100 swing-in-top-fwd" ref="panel">
<div class="flex-center" v-if="configStore.config.enable_knowledge_base"> <div class="flex-center" @click="meta.stream = !meta.stream">
流式输出 <div @click.stop><a-switch v-model:checked="meta.stream" /></div>
</div>
<div class="flex-center" @click="meta.summary_title = !meta.summary_title">
总结对话标题 <div @click.stop><a-switch v-model:checked="meta.summary_title" /></div>
</div>
<div class="flex-center" @click="meta.enable_retrieval = !meta.enable_retrieval">
启用检索 <div @click.stop><a-switch v-model:checked="meta.enable_retrieval" /></div>
</div>
<div class="flex-center">
最大历史轮数 <a-input-number id="inputNumber" v-model:value="meta.history_round" :min="1" :max="50" />
</div>
<a-divider v-if="meta.enable_retrieval"></a-divider>
<div class="flex-center" v-if="configStore.config.enable_knowledge_base && meta.enable_retrieval">
知识库 知识库
<div @click.stop> <div @click.stop>
<a-dropdown> <a-dropdown>
@ -62,24 +75,15 @@
</a-dropdown> </a-dropdown>
</div> </div>
</div> </div>
<div class="flex-center" @click="meta.use_graph = !meta.use_graph" v-if="configStore.config.enable_knowledge_base"> <div class="flex-center" @click="meta.use_graph = !meta.use_graph" v-if="configStore.config.enable_knowledge_base && meta.enable_retrieval">
图数据库 <div @click.stop><a-switch v-model:checked="meta.use_graph" /></div> 图数据库 <div @click.stop><a-switch v-model:checked="meta.use_graph" /></div>
</div> </div>
<div class="flex-center" @click="meta.use_web = !meta.use_web" v-if="configStore.config.enable_search_engine"> <div class="flex-center" @click="meta.use_web = !meta.use_web" v-if="configStore.config.enable_search_engine && meta.enable_retrieval">
搜索引擎Bing <div @click.stop><a-switch v-model:checked="meta.use_web" /></div> 搜索引擎Bing <div @click.stop><a-switch v-model:checked="meta.use_web" /></div>
</div> </div>
<div class="flex-center" @click="meta.stream = !meta.stream"> <div class="flex-center" v-if="configStore.config.enable_knowledge_base && meta.enable_retrieval">
流式输出 <div @click.stop><a-switch v-model:checked="meta.stream" /></div>
</div>
<div class="flex-center" @click="meta.summary_title = !meta.summary_title">
总结对话标题 <div @click.stop><a-switch v-model:checked="meta.summary_title" /></div>
</div>
<div class="flex-center" v-if="configStore.config.enable_knowledge_base">
重写查询 <a-segmented v-model:value="meta.rewriteQuery" :options="['off', 'on', 'hyde']"/> 重写查询 <a-segmented v-model:value="meta.rewriteQuery" :options="['off', 'on', 'hyde']"/>
</div> </div>
<div class="flex-center">
最大历史轮数 <a-input-number id="inputNumber" v-model:value="meta.history_round" :min="1" :max="50" />
</div>
</div> </div>
</div> </div>
</div> </div>
@ -104,12 +108,19 @@
:class="message.role" :class="message.role"
> >
<p v-if="message.role=='sent'" style="white-space: pre-line" class="message-text">{{ message.text }}</p> <p v-if="message.role=='sent'" style="white-space: pre-line" class="message-text">{{ message.text }}</p>
<div v-else-if="message.text.length == 0 && message.status=='querying'" class="loading-dots"> <div v-else-if="message.text.length == 0 && message.status=='init'" class="loading-dots">
<div></div> <div></div>
<div></div> <div></div>
<div></div> <div></div>
</div> </div>
<div v-else-if="message.text.length == 0 || message.status == 'error'" class="err-msg">请求错误请重试</div> <div v-else-if="message.status == 'searching' && isStreaming" class="searching-msg"><i>正在检索</i></div>
<div
v-else-if="message.text.length == 0 || message.status == 'error' || (message.status != 'finished' && !isStreaming)"
class="err-msg"
@click="retryMessage(message.id)"
>
请求错误请重试
</div>
<div v-else <div v-else
v-html="renderMarkdown(message)" v-html="renderMarkdown(message)"
class="message-md" class="message-md"
@ -195,6 +206,7 @@ const opts = reactive({
}) })
const meta = reactive(JSON.parse(localStorage.getItem('meta')) || { const meta = reactive(JSON.parse(localStorage.getItem('meta')) || {
enable_retrieval: false,
use_graph: false, use_graph: false,
use_web: false, use_web: false,
graph_name: "neo4j", graph_name: "neo4j",
@ -306,33 +318,32 @@ const appendAiMessage = (message, refs=null) => {
role: 'received', role: 'received',
text: message, text: message,
refs, refs,
status: "querying", status: "init",
}) })
scrollToBottom() scrollToBottom()
} }
const updateMessage = (text, id, refs, status) => { const updateMessage = (info) => {
const message = conv.value.messages.find((message) => message.id === id); const message = conv.value.messages.find((message) => message.id === info.id);
if (message) { if (message) {
// text // text
if (text !== null && text !== undefined && text !== '') { if (info.text !== null && info.text !== undefined && info.text !== '') {
message.text = text; message.text = info.text;
} }
// refs // refs
if (refs !== null && refs !== undefined) { if (info.refs !== null && info.refs !== undefined) {
message.refs = refs; message.refs = info.refs;
}
// refs model_name if (info.model_name !== null && info.model_name !== undefined && info.model_name !== '') {
if (refs.model_name !== null && refs.model_name !== undefined && refs.model_name !== '') { message.model_name = info.model_name;
message.model_name = refs.model_name;
}
} }
// status // status
if (status !== null && status !== undefined && status !== '') { if (info.status !== null && info.status !== undefined && info.status !== '') {
message.status = status; message.status = info.status;
} }
} else { } else {
console.error('Message not found'); console.error('Message not found');
@ -412,11 +423,21 @@ const fetchChatResponse = (user_input, cur_res_id) => {
const readChunk = () => { const readChunk = () => {
return reader.read().then(({ done, value }) => { return reader.read().then(({ done, value }) => {
if (done) { if (done) {
fetchRefs(cur_res_id).then((data) => { const message = conv.value.messages.find((message) => message.id === cur_res_id)
console.log(data) if (message.refs && message.refs.meta.enable_retrieval) {
updateMessage(null, cur_res_id, data, "finished"); console.log("fetching refs")
fetchRefs(cur_res_id).then((data) => {
console.log(data)
updateMessage({
id: cur_res_id,
refs: data,
status: "finished",
});
updateStatus(cur_res_id, "finished");
})
} else {
updateStatus(cur_res_id, "finished"); updateStatus(cur_res_id, "finished");
}) }
isStreaming.value = false; isStreaming.value = false;
if (conv.value.messages.length === 2) { renameTitle(); } if (conv.value.messages.length === 2) { renameTitle(); }
return; return;
@ -426,9 +447,16 @@ const fetchChatResponse = (user_input, cur_res_id) => {
buffer += chunk; buffer += chunk;
try { try {
const data = JSON.parse(chunk); const data = JSON.parse(chunk);
updateMessage(data.response, cur_res_id, data.refs, "loading"); updateMessage({
id: cur_res_id,
text: data.response,
model_name: data.model_name,
status: data.status,
});
console.debug(data.response) console.debug(data.response)
conv.value.history = data.history; if (data.history) {
conv.value.history = data.history;
}
} catch (e) { } catch (e) {
// console.debug('JSON :', e, chunk); // console.debug('JSON :', e, chunk);
} }
@ -444,9 +472,6 @@ const fetchChatResponse = (user_input, cur_res_id) => {
updateStatus(cur_res_id, "error"); updateStatus(cur_res_id, "error");
isStreaming.value = false; isStreaming.value = false;
}) })
.finally(() => {
isStreaming.value = false;
});
} }
const fetchRefs = (cur_res_id) => { const fetchRefs = (cur_res_id) => {
@ -484,6 +509,19 @@ const sendMessage = () => {
} }
} }
const retryMessage = (id) => {
// id message message message
console.log("retryMessage", id)
const index = conv.value.messages.findIndex(message => message.id === id);
const pastMessage = conv.value.messages[index-1]
conv.value.inputText = pastMessage.text
if (index !== -1) {
conv.value.messages = conv.value.messages.slice(0, index-1);
}
console.log(conv.value.messages)
sendMessage();
}
const autoSend = (message) => { const autoSend = (message) => {
conv.value.inputText = message conv.value.inputText = message
sendMessage() sendMessage()
@ -677,6 +715,12 @@ watch(
border-radius: 8px; border-radius: 8px;
text-align: center; text-align: center;
background: #FFF0F0; background: #FFF0F0;
margin-bottom: 10px;
cursor: pointer;
}
.searching-msg {
color: var(--gray-500);
} }
} }