import { request } from '../base' import type { ResultDomain } from '../../types' import type { TbChat, TbChatMessage, CreateChatParam, PrepareChatParam, StopChatParam, CommentMessageParam, ChatListParam, ChatMessageListParam, SSECallbacks, SSETask, SSEMessageData } from '../../types/ai/aiChat' /* eslint-disable @typescript-eslint/no-explicit-any */ declare const uni: { getStorageSync: (key: string) => any request: (options: any) => any } // API 基础配置 const BASE_URL = 'http://localhost:8180' /** * @description AI对话相关接口(直接调用ai模块) * @filename aiChat.ts * @author cascade * @copyright xyzh * @since 2025-12-23 */ export const aiChatAPI = { baseUrl: '/urban-lifeline/ai/chat', // ====================== AI对话管理 ====================== /** * 创建对话 * @param param agentId、userId、title 必传 */ createChat(param: CreateChatParam): Promise> { return request({ url: `${this.baseUrl}/conversation`, method: 'POST', data: param }) }, /** * 更新对话 * @param chat agentId、userId、title、userType 必传 */ updateChat(chat: TbChat): Promise> { return request({ url: `${this.baseUrl}/conversation`, method: 'PUT', data: chat }) }, /** * 查询对话列表 * @param param agentId 必传 */ getChatList(param: ChatListParam): Promise> { return request({ url: `${this.baseUrl}/conversations`, method: 'GET', data: param }) }, /** * 获取对话消息列表 * @param param agentId、chatId、userId 必传 */ getChatMessageList(param: ChatMessageListParam): Promise> { return request({ url: `${this.baseUrl}/messages`, method: 'POST', data: param }) }, /** * 准备流式对话会话 * @param param agentId、chatId、query、userId 必传 */ prepareChatMessageSession(param: PrepareChatParam): Promise> { return request({ url: `${this.baseUrl}/stream/prepare`, method: 'POST', data: param }) }, /** * 流式对话(SSE)- 返回EventSource URL */ getStreamUrl(sessionId: string): string { return `${this.baseUrl}/stream?sessionId=${sessionId}` }, /** * 建立SSE流式对话连接 * @param sessionId 会话ID(必传) * @param callbacks 回调函数 * @returns SSETask 可用于中止请求 */ streamChat(sessionId: string, callbacks: SSECallbacks): SSETask { const url = `${BASE_URL}${this.baseUrl}/stream?sessionId=${sessionId}` const token = uni.getStorageSync('token') || '' const requestTask = uni.request({ url: url, method: 'GET', header: { 'Accept': 'text/event-stream', 'Authorization': token ? `Bearer ${token}` : '' }, enableChunked: true, success: (res: any) => { console.log('SSE请求完成:', res) // 处理非200状态码 if (res.statusCode !== 200) { console.error('SSE请求状态码异常:', res.statusCode) let errorMsg = '抱歉,服务暂时不可用,请稍后重试。' if (res.statusCode === 401) { errorMsg = '登录已过期,请重新登录。' } else if (res.statusCode === 403) { errorMsg = '无权限访问,请联系管理员。' } else if (res.statusCode === 404) { errorMsg = '会话不存在或已过期,请重新发起对话。' } else if (res.statusCode >= 500) { errorMsg = '服务器异常,请稍后重试。' } callbacks.onError?.(errorMsg) } callbacks.onComplete?.() }, fail: (err: any) => { console.error('SSE请求失败:', err) callbacks.onError?.('网络连接失败,请稍后重试。') callbacks.onComplete?.() } }) // 监听分块数据 requestTask.onChunkReceived((res: any) => { try { const decoder = new TextDecoder('utf-8') const text = decoder.decode(new Uint8Array(res.data)) const lines = text.split('\n') for (const line of lines) { if (line.startsWith('data:')) { const dataStr = line.substring(5).trim() if (dataStr && dataStr !== '[DONE]') { try { const data: SSEMessageData = JSON.parse(dataStr) const event = data.event if (event === 'message' || event === 'agent_message') { callbacks.onMessage?.(data) } else if (event === 'message_end') { callbacks.onEnd?.(data.task_id || '') } else if (event === 'error' || data.message) { // 解析错误消息,提取友好提示 let errorMsg = data.message || '发生错误,请稍后重试。' // 处理嵌套的 JSON 错误信息 if (errorMsg.includes('invalid_param')) { errorMsg = '请求参数错误,请稍后重试。' } else if (errorMsg.includes('rate_limit')) { errorMsg = '请求过于频繁,请稍后再试。' } else if (errorMsg.includes('quota_exceeded')) { errorMsg = 'AI 服务额度已用完,请联系管理员。' } callbacks.onError?.(errorMsg) } } catch (e) { console.log('解析SSE数据失败:', dataStr) } } } } } catch (e) { console.error('处理分块数据失败:', e) } }) return { abort: () => { requestTask.abort() } } }, /** * 停止对话 * @param param taskId、agentId、userId 必传 */ stopChat(param: StopChatParam): Promise> { return request({ url: `${this.baseUrl}/stop`, method: 'POST', data: param }) }, /** * 评价对话消息 * @param param agentId、chatId、messageId、comment、userId 必传 */ commentChatMessage(param: CommentMessageParam): Promise> { return request({ url: `${this.baseUrl}/comment`, method: 'POST', data: param }) } }