feat: 新增停止大模型回答功能(关联 Issue #104)
This commit is contained in:
parent
3b65dee0e8
commit
3e0b18d455
@ -100,6 +100,10 @@
|
||||
>
|
||||
请求错误,请重试。{{ message.message }}
|
||||
</div>
|
||||
<div v-if="message.isStoppedByUser" class="retry-hint">
|
||||
你停止生成了本次回答
|
||||
<span class="retry-link" @click="retryStoppedMessage(message)">重新编辑问题</span>
|
||||
</div>
|
||||
<RefsComponent v-if="message.role=='received' && message.status=='finished'" :message="message" />
|
||||
</div>
|
||||
</div>
|
||||
@ -153,9 +157,19 @@
|
||||
</a-dropdown>
|
||||
</div>
|
||||
<div class="options__right">
|
||||
<a-button size="large" @click="sendMessage" :disabled="(!conv.inputText && !isStreaming)" type="link">
|
||||
<template #icon> <ArrowUpOutlined v-if="!isStreaming" /> <LoadingOutlined v-else/> </template>
|
||||
</a-button>
|
||||
<a-tooltip :title="isStreaming ? '停止回答' : ''">
|
||||
<a-button
|
||||
size="large"
|
||||
@click="handleSendOrStop"
|
||||
:disabled="(!conv.inputText && !isStreaming)"
|
||||
type="link"
|
||||
>
|
||||
<template #icon>
|
||||
<StopOutlined v-if="isStreaming" />
|
||||
<ArrowUpOutlined v-else />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -188,6 +202,7 @@ import {
|
||||
RobotOutlined,
|
||||
CaretRightOutlined,
|
||||
DeploymentUnitOutlined,
|
||||
StopOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
import { onClickOutside } from '@vueuse/core'
|
||||
import { Marked } from 'marked';
|
||||
@ -456,6 +471,9 @@ const loadDatabases = () => {
|
||||
|
||||
// 新函数用于处理 fetch 请求
|
||||
const fetchChatResponse = (user_input, cur_res_id) => {
|
||||
const controller = new AbortController();
|
||||
const signal = controller.signal;
|
||||
|
||||
fetch('/api/chat/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
@ -466,7 +484,8 @@ const fetchChatResponse = (user_input, cur_res_id) => {
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
},
|
||||
signal // 添加 signal 用于中断请求
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.body) throw new Error("ReadableStream not supported.");
|
||||
@ -524,13 +543,24 @@ const fetchChatResponse = (user_input, cur_res_id) => {
|
||||
readChunk();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
updateMessage({
|
||||
id: cur_res_id,
|
||||
status: "error",
|
||||
});
|
||||
if (error.name === 'AbortError') {
|
||||
console.log('Fetch aborted');
|
||||
} else {
|
||||
console.error(error);
|
||||
updateMessage({
|
||||
id: cur_res_id,
|
||||
status: "error",
|
||||
});
|
||||
}
|
||||
isStreaming.value = false;
|
||||
});
|
||||
|
||||
// 监听 isStreaming 变化,当为 false 时中断请求
|
||||
watch(isStreaming, (newValue) => {
|
||||
if (!newValue) {
|
||||
controller.abort();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -607,6 +637,36 @@ watch(
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 处理发送或停止
|
||||
const handleSendOrStop = () => {
|
||||
if (isStreaming.value) {
|
||||
// 停止生成
|
||||
isStreaming.value = false;
|
||||
const lastMessage = conv.value.messages[conv.value.messages.length - 1];
|
||||
if (lastMessage) {
|
||||
lastMessage.isStoppedByUser = true;
|
||||
lastMessage.status = 'stopped';
|
||||
}
|
||||
} else {
|
||||
// 发送消息
|
||||
sendMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// 重试被停止的消息
|
||||
const retryStoppedMessage = (message) => {
|
||||
// 找到用户的原始问题
|
||||
const messageIndex = conv.value.messages.findIndex(msg => msg.id === message.id);
|
||||
if (messageIndex > 0) {
|
||||
const userMessage = conv.value.messages[messageIndex - 1];
|
||||
if (userMessage && userMessage.role === 'sent') {
|
||||
conv.value.inputText = userMessage.text;
|
||||
// 删除被停止的消息
|
||||
conv.value.messages = conv.value.messages.slice(0, messageIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@ -1109,6 +1169,34 @@ watch(
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.retry-hint {
|
||||
margin-top: 8px;
|
||||
padding: 8px 16px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.retry-link {
|
||||
color: #1890ff;
|
||||
cursor: pointer;
|
||||
margin-left: 4px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-btn-icon-only {
|
||||
&:has(.anticon-stop) {
|
||||
background-color: #ff4d4f !important;
|
||||
|
||||
&:hover {
|
||||
background-color: #ff7875 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user