feat(agent): 添加流式对话API实现

实现基于SSE的流式对话接口,支持消息发送和回调处理
添加@microsoft/fetch-event-source依赖
This commit is contained in:
dzq 2025-12-19 17:19:11 +08:00
parent e60dac31fd
commit 935c662203
3 changed files with 107 additions and 0 deletions

View File

@ -20,6 +20,7 @@
"prepare": "" "prepare": ""
}, },
"dependencies": { "dependencies": {
"@microsoft/fetch-event-source": "^2.0.1",
"@unhead/vue": "2.0.19", "@unhead/vue": "2.0.19",
"@vant/touch-emulator": "^1.4.0", "@vant/touch-emulator": "^1.4.0",
"@vant/use": "^1.6.0", "@vant/use": "^1.6.0",

View File

@ -11,6 +11,9 @@ importers:
.: .:
dependencies: dependencies:
'@microsoft/fetch-event-source':
specifier: ^2.0.1
version: 2.0.1
'@unhead/vue': '@unhead/vue':
specifier: 2.0.19 specifier: 2.0.19
version: 2.0.19(vue@3.5.25(typescript@5.9.3)) version: 2.0.19(vue@3.5.25(typescript@5.9.3))
@ -1017,6 +1020,9 @@ packages:
'@jridgewell/trace-mapping@0.3.31': '@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@microsoft/fetch-event-source@2.0.1':
resolution: {integrity: sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==}
'@noble/hashes@1.8.0': '@noble/hashes@1.8.0':
resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
engines: {node: ^14.21.3 || >=16} engines: {node: ^14.21.3 || >=16}
@ -5053,6 +5059,8 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2 '@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
'@microsoft/fetch-event-source@2.0.1': {}
'@noble/hashes@1.8.0': {} '@noble/hashes@1.8.0': {}
'@paralleldrive/cuid2@2.3.1': '@paralleldrive/cuid2@2.3.1':

98
src/api/agent/index.ts Normal file
View File

@ -0,0 +1,98 @@
const AGENT_BASE_URL = '';
import { fetchEventSource } from '@microsoft/fetch-event-source';
export const baseInfoApi = () => {
return fetch(`${AGENT_BASE_URL}`, {
method: 'GET',
});
}
/**
* JSON {"text":"我来"}
* @param message
* @param callbacks
* @param options abort signal
* @example
* // 使用示例:
* streamApi('你好', {
* onopen(response) {
* console.log('连接已建立', response);
* },
* onmessage(data) {
* // data 是服务器发送的原始字符串,如 '{"text":"我来"}'
* console.log('收到消息:', data);
* },
* onclose() {
* console.log('连接已关闭');
* },
* onerror(error) {
* console.error('连接错误:', error);
* }
* }, { signal: abortController.signal });
*/
export const streamApi = (
message: string,
callbacks: {
onopen?: (response: Response) => void;
onmessage?: (data: string) => void;
onclose?: () => void;
onerror?: (error: Error) => void;
},
options?: { signal?: AbortSignal }
) => {
// 启动 fetchEventSource
fetchEventSource(`${AGENT_BASE_URL}/stream`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message }),
signal: options?.signal,
async onopen(response) {
// 检查响应是否正常
if (response.ok && response.headers.get('content-type')?.includes('text/event-stream')) {
// 连接成功,调用 onopen 回调
callbacks.onopen?.(response);
} else {
// 如果响应不正常,抛出错误
throw new Error(`SSE 连接失败: ${response.status} ${response.statusText}`);
}
},
onmessage(msg) {
// 处理服务器发送的消息
// msg.data 应该是 JSON 字符串,如 {"text":"..."}
try {
const data = msg.data;
console.log('Received message:', data);
if (data && data !== '[DONE]') {
callbacks.onmessage?.(data);
}
} catch (error) {
console.warn('处理 SSE 消息时出错:', error);
}
},
onclose() {
// 连接关闭
console.log('SSE 连接已关闭');
callbacks.onclose?.();
},
onerror(err) {
// 发生错误
console.error('SSE 连接错误:', err);
callbacks.onerror?.(err instanceof Error ? err : new Error(String(err)));
// 重新抛出错误以停止重试
throw err;
},
}).catch(error => {
// 捕获 fetchEventSource 的 Promise 拒绝
if (error.name !== 'AbortError') {
console.error('fetchEventSource 错误:', error);
callbacks.onerror?.(error instanceof Error ? error : new Error(String(error)));
} else {
// AbortError 是正常的取消操作,不需要调用 onerror
console.log('请求已被取消');
}
});
}