feat(agent): 添加流式对话API实现
实现基于SSE的流式对话接口,支持消息发送和回调处理 添加@microsoft/fetch-event-source依赖
This commit is contained in:
parent
e60dac31fd
commit
935c662203
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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':
|
||||||
|
|
|
||||||
|
|
@ -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('请求已被取消');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue