From bad3b2987dc6e734f412816c97b192e25a720c73 Mon Sep 17 00:00:00 2001 From: zoujing Date: Tue, 22 Jul 2025 22:33:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=B9=E7=BD=91=E7=BB=9C=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E7=9A=84=E8=B0=83=E6=95=B4=E4=BC=98=E5=8C=96=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manager/LoginManager.js | 5 ++- pages/chat/ChatMainList.vue | 3 +- pages/drawer/DrawerHome.vue | 23 +--------- request/api/AgentChatApi.js | 19 -------- request/api/AgentChatStream.js | 79 +++++++++++++++++++++++++++++++++ request/api/Index.js | 1 - request/api/LoginApi.js | 9 +++- request/base/request.js | 81 +++------------------------------- 8 files changed, 99 insertions(+), 121 deletions(-) delete mode 100644 request/api/AgentChatApi.js create mode 100644 request/api/AgentChatStream.js delete mode 100644 request/api/Index.js diff --git a/manager/LoginManager.js b/manager/LoginManager.js index 1fd4a5a..73ecd5b 100644 --- a/manager/LoginManager.js +++ b/manager/LoginManager.js @@ -1,4 +1,4 @@ -import { login } from "../request/api/Index"; +import { login } from "../request/api/LoginApi"; import { getWeChatAuthCode } from "./AuthManager"; @@ -12,7 +12,8 @@ export async function loginAuth() { scope: 'server', //clientId: '1', username: 'admin', - password: 'YehdBPev' + password: 'YehdBPev', + }); if (response.access_token) { uni.setStorageSync('token', response.access_token) diff --git a/pages/chat/ChatMainList.vue b/pages/chat/ChatMainList.vue index 5388cb9..b0555ac 100644 --- a/pages/chat/ChatMainList.vue +++ b/pages/chat/ChatMainList.vue @@ -74,6 +74,7 @@ import OneFeelMK001 from '../module/OneFeelMK001.vue'; import request from '../../request/base/request'; + import { agentChatStream } from '../../request/api/AgentChatStream'; // 导航栏相关 const statusBarHeight = ref(20); @@ -225,7 +226,7 @@ } // 2. 流式接收内容 - request.getAIChatStream(args, (chunk) => { + agentChatStream(args, (chunk) => { console.log('分段内容:', chunk) if (chunk && chunk.content) { // 收到内容,停止动画 diff --git a/pages/drawer/DrawerHome.vue b/pages/drawer/DrawerHome.vue index eb96131..12fc8ef 100644 --- a/pages/drawer/DrawerHome.vue +++ b/pages/drawer/DrawerHome.vue @@ -21,10 +21,9 @@ import { defineEmits } from 'vue' const emits = defineEmits(['closeDrawer']) import * as loginMnager from '@/manager/LoginManager' - - import { getAgentChatMessage } from '@/request/api/AgentChatApi.js' -import request from '../../request/base/request' + import request from '../../request/base/request' + const closeDrawer = () => { emits('closeDrawer') console.log('=============关闭抽屉') @@ -43,25 +42,7 @@ import request from '../../request/base/request' console.log('=============登录') // 这里可以处理登录逻辑,比如调用登录接口等 } - - const sendChat = () => { - console.log('=============会话测试') - - const args = { - "conversationId":"1931957498711957505", - "agentId":"1", - "messageType": 0, - "messageContent":"酒店一共有哪些温泉?" - } - - - request.getAIChatStream(args, (chunk) => { - // 每收到一段数据都会回调 - console.log('分段内容:', chunk) - // 你可以在这里追加到消息列表 - }) - } diff --git a/request/api/AgentChatApi.js b/request/api/AgentChatApi.js deleted file mode 100644 index d477c0a..0000000 --- a/request/api/AgentChatApi.js +++ /dev/null @@ -1,19 +0,0 @@ -import request from "../base/request"; - -function getAgentChatMessage() { - const args = { - "conversationId":"1931957498711957505", - "agentId":"1", - "messageType": 0, - "messageContent":"酒店一共有哪些温泉?" - } - const defaultConfig = { - header: { - Accept: 'text/event-stream', - 'Content-Type': 'application/json' - }, - }; - return request.post('/agent/assistant/chat', args, defaultConfig); -} - -export { getAgentChatMessage } \ No newline at end of file diff --git a/request/api/AgentChatStream.js b/request/api/AgentChatStream.js new file mode 100644 index 0000000..f8e4285 --- /dev/null +++ b/request/api/AgentChatStream.js @@ -0,0 +1,79 @@ +import { BASE_URL } from "../../constant/base"; + +/// 请求流式数据的API +const API = '/agent/assistant/chat'; + +/** + * 获取AI聊天流式信息(仅微信小程序支持) + * @param {Object} params 请求参数 + * @param {Function} onChunk 回调,每收到一段数据触发 + * @returns {Promise} + */ +function agentChatStream(params, onChunk) { + return new Promise((resolve, reject) => { + const token = uni.getStorageSync('token'); + + console.log("发送请求内容: ", params) + // #ifdef MP-WEIXIN + const requestTask = uni.request({ + url: BASE_URL + API, // 替换为你的接口地址 + method: 'POST', + data: params, + enableChunked: true, + header: { + Accept: 'text/event-stream', + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, // 如需token可加 + }, + responseType: 'arraybuffer', + success(res) { + resolve(res.data); + }, + fail(err) { + reject(err); + } + }); + + requestTask.onHeadersReceived(res => { + console.log('onHeadersReceived', res); + }); + + requestTask.onChunkReceived(res => { + const base64 = uni.arrayBufferToBase64(res.data); + let data = ''; + try { + data = decodeURIComponent(escape(atob(base64))); + } catch (e) { + // 某些平台可能不支持 atob,可以直接用 base64 + data = base64; + } + const messages = parseSSEChunk(data); + messages.forEach(msg => { + if (onChunk) onChunk(msg); + }); + }); + // #endif + }); +} + +// 解析SSE分段数据 +function parseSSEChunk(raw) { + // 拆分为多段 + const lines = raw.split('\n\n'); + const results = []; + lines.forEach(line => { + // 只处理包含 data: 的行 + const dataMatch = line.match(/data:(\{.*\})/); + if (dataMatch && dataMatch[1]) { + try { + const obj = JSON.parse(dataMatch[1]); + results.push(obj); + } catch (e) { + // 解析失败忽略 + } + } + }); + return results; +} + +export { agentChatStream } \ No newline at end of file diff --git a/request/api/Index.js b/request/api/Index.js deleted file mode 100644 index 5134db7..0000000 --- a/request/api/Index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './LoginApi.js' \ No newline at end of file diff --git a/request/api/LoginApi.js b/request/api/LoginApi.js index 2e3446c..e4990da 100644 --- a/request/api/LoginApi.js +++ b/request/api/LoginApi.js @@ -1,7 +1,14 @@ import request from "../base/request"; function login(args) { - return request.post('/auth/oauth2/token', args); + const config = { + header: { + Authorization: 'Basic Y3VzdG9tOmN1c3RvbQ==', // 可在此动态设置 token + 'Content-Type': 'application/x-www-form-urlencoded' + }, + }; + uni.setStorageSync('token', '') + return request.post('/auth/oauth2/token', args, config); } export { login } \ No newline at end of file diff --git a/request/base/request.js b/request/base/request.js index 5e2116d..f45f3a9 100644 --- a/request/base/request.js +++ b/request/base/request.js @@ -2,8 +2,8 @@ import { BASE_URL } from "../../constant/base"; const defaultConfig = { header: { - Authorization: 'Basic Y3VzdG9tOmN1c3RvbQ==', // 可在此动态设置 token - 'Content-Type': 'application/x-www-form-urlencoded' + Authorization: '', // 可在此动态设置 token + 'Content-Type': 'application/json' }, }; @@ -35,6 +35,7 @@ function request(url, args = {}, method = 'POST', customConfig = {}) { ...customConfig, header }; + console.log("请求接口:" + url) console.log("请求头:" + JSON.stringify(config)) console.log("请求参数:" + JSON.stringify(args)) @@ -63,81 +64,9 @@ request.post = function(url, args = {}, config = {}) { }; // 支持 GET -request.get = function(url, args = {}) { - return request(url, args, 'GET'); +request.get = function(url, args = {}, config = {}) { + return request(url, args, 'GET', config); }; -/** - * 获取AI聊天流式信息(仅微信小程序支持) - * @param {Object} params 请求参数 - * @param {Function} onChunk 回调,每收到一段数据触发 - * @returns {Promise} - */ -request.getAIChatStream = function(params, onChunk) { - return new Promise((resolve, reject) => { - const token = uni.getStorageSync('token'); - - console.log("发送请求内容: ", params) - // #ifdef MP-WEIXIN - const requestTask = uni.request({ - url: BASE_URL + '/agent/assistant/chat', // 替换为你的接口地址 - method: 'POST', - data: params, - enableChunked: true, - header: { - Accept: 'text/event-stream', - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, // 如需token可加 - }, - responseType: 'arraybuffer', - success(res) { - resolve(res.data); - }, - fail(err) { - reject(err); - } - }); - - requestTask.onHeadersReceived(res => { - console.log('onHeadersReceived', res); - }); - - requestTask.onChunkReceived(res => { - const base64 = uni.arrayBufferToBase64(res.data); - let data = ''; - try { - data = decodeURIComponent(escape(atob(base64))); - } catch (e) { - // 某些平台可能不支持 atob,可以直接用 base64 - data = base64; - } - const messages = parseSSEChunk(data); - messages.forEach(msg => { - if (onChunk) onChunk(msg); - }); - }); - // #endif - }); -} - -// 解析SSE分段数据 -function parseSSEChunk(raw) { - // 拆分为多段 - const lines = raw.split('\n\n'); - const results = []; - lines.forEach(line => { - // 只处理包含 data: 的行 - const dataMatch = line.match(/data:(\{.*\})/); - if (dataMatch && dataMatch[1]) { - try { - const obj = JSON.parse(dataMatch[1]); - results.push(obj); - } catch (e) { - // 解析失败忽略 - } - } - }); - return results; -} export default request; \ No newline at end of file