feat: 修改sse调用

This commit is contained in:
rd
2025-08-25 11:49:58 +08:00
parent db9b53821b
commit 13670acc9a
6 changed files with 189 additions and 117 deletions

View File

@ -12,8 +12,8 @@ import { useClipboard } from '@vueuse/core';
import { genRandomId } from '@/utils/tools';
import { useChatStore } from '@/stores/modules/chat';
import { getHeaders } from '@/api/all/chat';
import { EventSourcePolyfill } from 'event-source-polyfill'; // 导入 event-source-polyfill
import type { BubbleListProps } from '@/components/xt-chat/xt-bubble/types';
import querySSE from '@/utils/querySSE';
const QUESTION_ROLE = 'question';
const ANSWER_ROLE = 'text';
@ -28,7 +28,6 @@ export default {
const { copy } = useClipboard();
const senderRef = ref(null);
const eventSource = ref(null);
const rightViewRef = ref(null);
const bubbleListRef = ref<any>(null);
const searchValue = ref('');
@ -163,102 +162,109 @@ export default {
};
const initSse = () => {
// 先清理可能存在的旧连接
if (eventSource.value) {
eventSource.value.close();
eventSource.value = null;
}
const handleStart = () => {
conversationList.value.push({
role: ANSWER_ROLE,
content: (
<div class="flex items-center ">
<span class="font-family-medium color-#211F24 text-14px font-400 lh-22px mr-4px">智能思考</span>
<icon-caret-up size={16} class="color-#211F24" />
</div>
),
});
};
// 构建SSE连接URL
const url = new URL('http://localhost:3000/agent/input');
url.searchParams.append('content', searchValue.value || '测试');
url.searchParams.append('session_id', conversationId.value as string);
url.searchParams.append('agent_id', chatStore.agentInfo?.agent_id || '67890');
const handleNodeUpdate = (data) => {
switch (data.status) {
case 'running':
conversationList.value.push({
content: data.message,
role: ANSWER_ROLE,
});
break;
case 'success':
conversationList.value.push({
content: data.output,
role: ANSWER_ROLE,
messageRender: (content) => <div v-html={md.render(content)}></div>,
});
break;
}
};
const handleFinalResult = (data) => {
showRightView.value = true;
const _files = data.output?.files;
rightViewContent.value = _files[0]?.content || '';
conversationList.value.push({
id: currentAnswerId.value,
role: FILE_ROLE,
content: _files,
footer: ({ item }) => {
const nonQuestionElements = conversationList.value.filter((item) => item.role !== QUESTION_ROLE);
const isLastAnswer = nonQuestionElements[nonQuestionElements.length - 1]?.id === item.id;
return (
<div class="flex items-center">
<Tooltip title="下载" onClick={() => onDownload(rightViewContent.value)}>
<icon-download size={16} class="color-#737478 cursor-pointer" />
</Tooltip>
{isLastAnswer && (
<Tooltip
title="重新生成"
onClick={() => onRefresh(currentAnswerId.value, conversationList.value.length)}
>
<icon-refresh size={16} class="color-#737478 cursor-pointer" />
</Tooltip>
)}
</div>
);
},
});
};
const handleEnd = () => {
generateLoading.value = false;
};
const handleError = () => {
generateLoading.value = false;
message.error('连接服务器失败');
};
try {
eventSource.value = new EventSourcePolyfill(url.toString(), {
headers: { ...getHeaders(), Accept: 'text/event-stream' },
});
const url = `http://localhost:3000/agent/input?content=${searchValue.value}&session_id=${conversationId.value}&agent_id=${chatStore.agentInfo?.agent_id}`;
searchValue.value = '';
// 任务开始
eventSource.value.addEventListener('start', function () {
conversationList.value.push({
role: ANSWER_ROLE,
content: (
<div class="flex items-center ">
<span class="font-family-medium color-#211F24 text-14px font-400 lh-22px mr-4px">智能思考</span>
<icon-caret-up size={16} class="color-#211F24" />
</div>
),
});
});
eventSource.value.addEventListener('node_update', function (event) {
console.log('Node updated:', event.data);
const data = JSON.parse(event.data);
switch (data.status) {
case 'running':
conversationList.value.push({
content: data.message,
role: ANSWER_ROLE,
});
break;
case 'success':
conversationList.value.push({
content: data.output,
role: ANSWER_ROLE,
});
break;
}
});
eventSource.value.addEventListener('final_result', function (event) {
showRightView.value = true;
const data = JSON.parse(event.data);
const _files = data.output?.files;
rightViewContent.value = _files[0]?.content || '';
conversationList.value.push({
id: currentAnswerId.value,
role: FILE_ROLE,
content: _files,
footer: ({ item }) => {
const nonQuestionElements = conversationList.value.filter((item) => item.role !== QUESTION_ROLE);
const isLastAnswer = nonQuestionElements[nonQuestionElements.length - 1]?.id === item.id;
return (
<div class="flex items-center">
<Tooltip title="下载" onClick={() => onDownload(rightViewContent.value)}>
<icon-download size={16} class="color-#737478 cursor-pointer" />
</Tooltip>
{isLastAnswer && (
<Tooltip
title="重新生成"
onClick={() => onRefresh(currentAnswerId.value, conversationList.value.length)}
>
<icon-refresh size={16} class="color-#737478 cursor-pointer" />
</Tooltip>
)}
</div>
);
querySSE(
{
handleMessage(parsedData) {
const { event, data } = parsedData;
switch (event) {
case 'start':
handleStart();
break;
case 'node_update':
handleNodeUpdate(data);
break;
case 'final_result':
handleFinalResult(data);
break;
case 'end':
handleEnd();
break;
case 'error':
handleError();
break;
default:
break;
}
},
});
});
eventSource.value.addEventListener('end', function (event) {
generateLoading.value = false;
closeSse();
});
// 处理错误事件
eventSource.value.onerror = function (error) {
console.error('EventSource error:', error);
generateLoading.value = false;
message.error('连接服务器失败');
closeSse();
};
async handleOpen(response) {
console.log('onopen', response);
},
},
url,
);
} catch (error) {
console.error('Failed to initialize SSE:', error);
message.error('初始化连接失败');
@ -266,24 +272,12 @@ export default {
}
};
const closeSse = () => {
if (eventSource.value) {
eventSource.value.close();
eventSource.value = null;
}
// 确保加载状态被重置
generateLoading.value = false;
};
onMounted(() => {
searchValue.value = chatStore.searchValue;
chatStore.clearSearchValue();
searchValue.value && initSse();
});
onUnmounted(() => {
closeSse();
});
return () => (
<div class="conversation-detail-wrap w-full h-full flex">