From 4d2467ae36b26c34665ce1ff14c592a35046c296 Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Sat, 6 Dec 2025 16:24:55 +0800 Subject: [PATCH] =?UTF-8?q?chore(addon/aikefu):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E8=AF=B4=E6=98=8E=E5=8F=8A=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/api_kefu.md | 545 +++++++++++++++++++++---- src/addon/aikefu/config/event.php | 3 + src/addon/aikefu/event/KefuGetInfo.php | 127 ++++++ src/app/api/controller/AI.php | 76 ++++ src/app/api/controller/Kefu.php | 187 --------- 5 files changed, 678 insertions(+), 260 deletions(-) create mode 100644 src/addon/aikefu/event/KefuGetInfo.php delete mode 100644 src/app/api/controller/Kefu.php diff --git a/docs/api_kefu.md b/docs/api_kefu.md index e22f537f9..d41f56214 100644 --- a/docs/api_kefu.md +++ b/docs/api_kefu.md @@ -2,7 +2,7 @@ ## 一、接口说明 -本接口用于连接微信小程序与Dify聊天机器人,实现智能客服功能。 +本接口用于连接微信小程序与Dify聊天机器人,实现智能客服功能。所有接口都采用事件驱动架构,支持高并发和模块化扩展。 ## 二、配置说明 @@ -28,9 +28,160 @@ ## 三、接口列表 -### 1. 智能客服聊天接口 +### 1. 系统健康检查 -**接口地址**:`/api/kefu/chat` +**接口地址**:`/api/health` + +**请求方式**:GET + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| uniacid | int | 是 | 站点ID | +| check_type | string | 否 | 检查类型:full(完整)、basic(基础)、ai_service(AI服务),默认full | + +**响应示例**: + +```json +{ + "code": 0, + "message": "healthy", + "data": { + "status": "healthy", + "check_id": "health_63a8f9c1234abcd", + "timestamp": "2023-12-25 10:30:45", + "total_checks": 4, + "passed_checks": 4, + "failed_checks": 0, + "response_time_ms": 156.78, + "components": { + "database": { + "status": "healthy", + "message": "数据库连接正常", + "response_time_ms": 12.34, + "details": { + "connection": "success", + "query_test": "passed" + } + }, + "ai_service_config": { + "status": "healthy", + "message": "AI服务配置正常", + "response_time_ms": 8.56, + "details": { + "configured": true, + "complete": true, + "enabled": true, + "base_url": "https://api.example.com" + } + }, + "ai_service_connection": { + "status": "healthy", + "message": "AI服务连接正常", + "response_time_ms": 45.67, + "details": { + "http_status": 200, + "url": "https://api.example.com" + } + }, + "system_resources": { + "status": "healthy", + "message": "系统资源正常", + "response_time_ms": 2.34, + "details": { + "php_version": "8.1.0", + "memory_usage": "45.67 MB", + "memory_limit": "512.00 MB", + "memory_usage_percent": "8.92%", + "max_execution_time": "30s" + } + } + }, + "warnings": [], + "errors": [] + } +} +``` + +### 2. 获取服务配置信息 + +**接口地址**:`/api/info` + +**请求方式**:GET + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| uniacid | int | 否 | 站点ID | +| member_id | int | 否 | 会员ID | +| token | string | 否 | 访问令牌 | + +**响应示例**: + +```json +{ + "code": 0, + "message": "success", + "data": { + "service_info": { + "name": "智能客服", + "version": "1.0.0", + "enabled": true, + "status": "enabled" + }, + "features": { + "chat": true, + "chat_stream": true, + "conversation_management": true, + "history_management": true + }, + "limits": { + "max_message_length": 4000, + "max_conversation_history": 100, + "rate_limit": { + "requests_per_minute": 60, + "requests_per_hour": 1000 + } + }, + "endpoints": { + "chat": "/api/chat", + "chat_stream": "/api/chatStream", + "create_conversation": "/api/createConversation", + "get_history": "/api/getHistory", + "clear_conversation": "/api/clearConversation", + "health": "/api/health", + "info": "/api/info" + }, + "api_config": { + "base_url": "https://api.dify.ai/v1", + "chat_endpoint": "/chat-messages", + "supports_streaming": true, + "authentication": "bearer_token" + }, + "client_info": { + "user_agent": "Mozilla/5.0...", + "ip": "192.168.1.100", + "timestamp": 1703505845 + }, + "server_info": { + "php_version": "8.1.0", + "server_time": "2023-12-25 10:30:45", + "timezone": "Asia/Shanghai" + }, + "user_stats": { + "can_use_service": true, + "member_id": 123, + "site_id": 1 + } + } +} +``` + +### 3. 智能客服聊天接口 + +**接口地址**:`/api/chat` **请求方式**:POST @@ -38,10 +189,13 @@ | 参数名 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | +| uniacid | int | 是 | 站点ID | | message | string | 是 | 用户输入的消息内容 | | user_id | string | 否 | 用户ID,默认使用当前登录会员ID | | conversation_id | string | 否 | 会话ID,第一次聊天可不传,系统会自动创建 | | stream | bool | 否 | 是否使用流式响应,默认false | +| member_id | int | 否 | 会员ID | +| token | string | 否 | 访问令牌 | **响应示例**: @@ -59,58 +213,78 @@ "completion_tokens": 20, "total_tokens": 30 } - }, - "timestamp": 1640995200 + } } ``` -### 2. 获取会话历史 +### 4. 智能客服流式聊天接口 -**接口地址**:`/api/kefu/getHistory` +**接口地址**:`/api/chatStream` **请求方式**:POST -**请求参数**: +**请求参数**:同 `/api/chat` 接口 -| 参数名 | 类型 | 必填 | 说明 | -| --- | --- | --- | --- | -| conversation_id | string | 是 | 会话ID | -| user_id | string | 否 | 用户ID,默认使用当前登录会员ID | -| limit | int | 否 | 每页条数,默认20 | -| offset | int | 否 | 偏移量,默认0 | +**响应格式**:Server-Sent Events (SSE) **响应示例**: -```json -{ - "code": 0, - "message": "success", +```javascript +// 开始事件 +event: start +data: { + "id": "unique_id", + "event": "start", + "timestamp": 1703505845, "data": { - "messages": [ - { - "id": "msg_123456789", - "role": "user", - "content": "你好", - "created_at": "2023-01-01T00:00:00Z" - }, - { - "id": "msg_987654321", - "role": "assistant", - "content": "您好,我是智能客服,有什么可以帮助您的?", - "created_at": "2023-01-01T00:00:01Z" - } - ], - "total": 2, - "limit": 20, - "offset": 0 - }, - "timestamp": 1640995200 + "request_id": "stream_123", + "message": "开始处理请求" + } +} + +// 内容块事件 +event: message +data: { + "id": "unique_id", + "event": "message", + "timestamp": 1703505845, + "data": { + "content": "您", + "conversation_id": "conv_123", + "finished": false + } +} + +// 完成事件 +event: complete +data: { + "id": "unique_id", + "event": "complete", + "timestamp": 1703505845, + "data": { + "conversation_id": "conv_123", + "message_id": "msg_456", + "usage": {}, + "finish_reason": "stop" + } +} + +// 结束事件 +event: end +data: { + "id": "unique_id", + "event": "end", + "timestamp": 1703505845, + "data": { + "request_id": "stream_123", + "status": "completed" + } } ``` -### 3. 创建新会话 +### 5. 创建新会话 -**接口地址**:`/api/kefu/createConversation` +**接口地址**:`/api/createConversation` **请求方式**:POST @@ -118,7 +292,10 @@ | 参数名 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | +| uniacid | int | 是 | 站点ID | | user_id | string | 否 | 用户ID,默认使用当前登录会员ID | +| member_id | int | 否 | 会员ID | +| token | string | 否 | 访问令牌 | **响应示例**: @@ -129,9 +306,83 @@ "data": { "conversation_id": "conv_123456789", "name": "智能客服会话", - "created_at": "2023-01-01T00:00:00Z" - }, - "timestamp": 1640995200 + "created_at": "2023-12-25 10:30:45" + } +} +``` + +### 6. 获取会话历史 + +**接口地址**:`/api/getHistory` + +**请求方式**:POST + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| uniacid | int | 是 | 站点ID | +| conversation_id | string | 是 | 会话ID | +| user_id | string | 否 | 用户ID,默认使用当前登录会员ID | +| limit | int | 否 | 每页条数,默认20 | +| offset | int | 否 | 偏移量,默认0 | +| member_id | int | 否 | 会员ID | +| token | string | 否 | 访问令牌 | + +**响应示例**: + +```json +{ + "code": 0, + "message": "success", + "data": { + "messages": [ + { + "id": 1, + "role": "user", + "content": "你好", + "create_time": "2023-12-25 10:30:45" + }, + { + "id": 2, + "role": "assistant", + "content": "您好,我是智能客服,有什么可以帮助您的?", + "create_time": "2023-12-25 10:30:46" + } + ], + "total": 2, + "limit": 20, + "offset": 0 + } +} +``` + +### 7. 清除会话历史 + +**接口地址**:`/api/clearConversation` + +**请求方式**:POST + +**请求参数**: + +| 参数名 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| uniacid | int | 是 | 站点ID | +| conversation_id | string | 否 | 会话ID(与user_id二选一) | +| user_id | string | 否 | 用户ID,用于清除该用户所有会话(与conversation_id二选一) | +| member_id | int | 否 | 会员ID | +| token | string | 否 | 访问令牌 | + +**响应示例**: + +```json +{ + "code": 0, + "message": "success", + "data": { + "deleted_messages": 15, + "deleted_conversations": 3 + } } ``` @@ -143,15 +394,41 @@ // 引入请求封装(根据项目实际情况调整) import { request } from '@/utils/request'; -// 智能客服聊天 +// 1. 获取服务配置信息 +async function getAIInfo() { + try { + const res = await request({ + url: '/api/info', + method: 'GET', + data: { + uniacid: 1 + } + }); + + if (res.code === 0) { + console.log('AI服务状态:', res.data.service_info); + console.log('可用功能:', res.data.features); + return res.data; + } else { + console.error('获取配置失败:', res.message); + return null; + } + } catch (error) { + console.error('获取配置请求失败:', error); + return null; + } +} + +// 2. 智能客服聊天(普通模式) async function chatWithAI(message, conversationId = '') { try { const res = await request({ - url: '/api/kefu/chat', + url: '/api/chat', method: 'POST', data: { + uniacid: 1, message: message, - conversation_id: conversationId, + conversation_id: conversationId // user_id: 'your-user-id', // 可选 // stream: false // 可选 } @@ -169,13 +446,78 @@ async function chatWithAI(message, conversationId = '') { } } -// 获取会话历史 +// 3. 智能客服聊天(流式模式) +async function chatWithAIStream(message, conversationId = '', onMessage, onComplete, onError) { + try { + const response = await uni.request({ + url: '/api/chatStream', + method: 'POST', + data: { + uniacid: 1, + message: message, + conversation_id: conversationId + }, + responseType: 'text' + }); + + // 处理流式响应 + if (response.statusCode === 200) { + const lines = response.data.split('\n'); + for (const line of lines) { + if (line.startsWith('data: ')) { + try { + const data = JSON.parse(line.substring(6)); + if (data.event === 'message' && onMessage) { + onMessage(data.data); + } else if (data.event === 'complete' && onComplete) { + onComplete(data.data); + } else if (data.event === 'error' && onError) { + onError(data.data); + } + } catch (e) { + console.warn('解析流式数据失败:', e); + } + } + } + } + } catch (error) { + console.error('流式聊天请求失败:', error); + if (onError) onError({ error: error.message }); + } +} + +// 4. 创建新会话 +async function createNewConversation() { + try { + const res = await request({ + url: '/api/createConversation', + method: 'POST', + data: { + uniacid: 1 + // user_id: 'your-user-id', // 可选 + } + }); + + if (res.code === 0) { + return res.data.conversation_id; + } else { + console.error('创建会话失败:', res.message); + return null; + } + } catch (error) { + console.error('创建会话请求失败:', error); + return null; + } +} + +// 5. 获取会话历史 async function getChatHistory(conversationId, limit = 20, offset = 0) { try { const res = await request({ - url: '/api/kefu/getHistory', + url: '/api/getHistory', method: 'POST', data: { + uniacid: 1, conversation_id: conversationId, limit: limit, offset: offset @@ -195,25 +537,51 @@ async function getChatHistory(conversationId, limit = 20, offset = 0) { } } -// 创建新会话 -async function createNewConversation() { +// 6. 清除会话历史 +async function clearConversation(conversationId = '', userId = '') { try { const res = await request({ - url: '/api/kefu/createConversation', + url: '/api/clearConversation', method: 'POST', data: { - // user_id: 'your-user-id', // 可选 + uniacid: 1, + conversation_id: conversationId, + user_id: userId } }); if (res.code === 0) { - return res.data.conversation_id; + return res.data; } else { - console.error('创建会话失败:', res.message); + console.error('清除会话失败:', res.message); return null; } } catch (error) { - console.error('创建会话请求失败:', error); + console.error('清除会话请求失败:', error); + return null; + } +} + +// 7. 健康检查 +async function checkHealth(checkType = 'full') { + try { + const res = await request({ + url: '/api/health', + method: 'GET', + data: { + uniacid: 1, + check_type: checkType + } + }); + + if (res.code === 0) { + return res.data; + } else { + console.error('健康检查失败:', res.message); + return null; + } + } catch (error) { + console.error('健康检查请求失败:', error); return null; } } @@ -221,46 +589,77 @@ async function createNewConversation() { ## 五、使用流程 -1. **初始化会话**:小程序端进入客服页面时,调用`createConversation`接口创建新会话,或使用本地存储的会话ID -2. **发送消息**:用户输入消息后,调用`chat`接口发送消息,获取机器人回复 -3. **显示消息**:将用户消息和机器人回复显示在聊天界面 -4. **加载历史记录**:需要时调用`getHistory`接口加载历史消息 -5. **维护会话**:保持会话ID,用于后续消息交流 +1. **初始化检查**:小程序端启动时,调用`health`和`info`接口检查服务状态 +2. **创建会话**:进入客服页面时,调用`createConversation`接口创建新会话,或使用本地存储的会话ID +3. **发送消息**:用户输入消息后,调用`chat`或`chatStream`接口发送消息,获取机器人回复 +4. **显示消息**:将用户消息和机器人回复显示在聊天界面 +5. **加载历史记录**:需要时调用`getHistory`接口加载历史消息 +6. **维护会话**:保持会话ID,用于后续消息交流 +7. **清理数据**:根据用户需求调用`clearConversation`接口清理历史数据 ## 六、注意事项 -1. 请确保Dify API密钥的安全性,不要泄露给前端 -2. 建议对用户ID进行加密处理,避免直接使用敏感信息 -3. 对于大量用户的场景,建议实现会话管理机制,定期清理过期会话 -4. 建议添加请求频率限制,防止恶意请求 -5. 在生产环境中,建议关闭DEBUG模式 +1. **必填参数**:所有接口都需要`uniacid`(站点ID)参数 +2. **事件驱动**:后端采用事件驱动架构,所有业务逻辑通过事件处理器执行 +3. **安全性**:请确保Dify API密钥的安全性,不要泄露给前端 +4. **用户标识**:建议对用户ID进行加密处理,避免直接使用敏感信息 +5. **流式支持**:推荐使用`chatStream`接口获得更好的用户体验 +6. **会话管理**:建议实现会话管理机制,定期清理过期会话 +7. **频率限制**:建议添加请求频率限制,防止恶意请求 +8. **生产环境**:在生产环境中,建议关闭DEBUG模式 ## 七、测试建议 -1. 首先在Dify平台测试聊天机器人功能是否正常 -2. 在后端配置正确的API密钥 -3. 使用Postman或类似工具测试后端API接口 -4. 在小程序端集成并测试完整流程 -5. 模拟不同场景下的用户输入,测试机器人回复效果 +1. **基础检查**:首先调用`health`接口检查系统状态 +2. **配置验证**:调用`info`接口验证配置信息 +3. **接口测试**:使用Postman或类似工具测试各个API接口 +4. **流式测试**:测试`chatStream`接口的流式响应 +5. **完整流程**:在小程序端集成并测试完整流程 +6. **边界测试**:模拟不同场景下的用户输入,测试机器人回复效果 +7. **压力测试**:测试接口在高并发情况下的表现 ## 八、常见问题 -### 1. 接口返回401错误 +### 1. 接口返回400错误 + +**原因**:缺少必填参数`uniacid`或参数格式错误 +**解决方法**:确保请求中包含有效的站点ID + +### 2. 健康检查返回503错误 + +**原因**:AI服务配置不完整或服务异常 +**解决方法**:检查插件配置和Dify API服务状态 + +### 3. 接口返回401错误 **原因**:Dify API密钥无效或过期 **解决方法**:重新获取有效的API密钥并更新插件配置 -### 2. 接口返回500错误 +### 4. 接口返回500错误 **原因**:后端服务器错误或Dify API服务异常 **解决方法**:查看服务器日志,检查Dify API服务状态 -### 3. 机器人回复为空 +### 5. 机器人回复为空 **原因**:Dify聊天机器人配置问题或请求参数错误 **解决方法**:检查Dify机器人配置,验证请求参数是否正确 -### 4. 会话ID无效 +### 6. 流式响应无法解析 + +**原因**:客户端不支持SSE或解析方式错误 +**解决方法**:使用正确的方式解析Server-Sent Events格式 + +### 7. 会话ID无效 **原因**:会话已过期或不存在 **解决方法**:创建新会话,获取新的会话ID + +## 九、性能优化建议 + +1. **缓存配置**:可对`info`接口返回的配置信息进行客户端缓存 +2. **连接复用**:HTTP请求使用连接池,减少建立连接的开销 +3. **压缩传输**:启用gzip压缩减少传输数据量 +4. **分页加载**:历史记录使用分页加载,避免一次性加载大量数据 +5. **CDN加速**:静态资源使用CDN加速访问 +6. **监控告警**:建立接口性能监控和告警机制 \ No newline at end of file diff --git a/src/addon/aikefu/config/event.php b/src/addon/aikefu/config/event.php index 9893130f5..4d94eb669 100644 --- a/src/addon/aikefu/config/event.php +++ b/src/addon/aikefu/config/event.php @@ -26,6 +26,9 @@ return [ 'KefuChatStream' => [ 'addon\aikefu\event\KefuChatStream' ], + 'KefuGetInfo' => [ + 'addon\aikefu\event\KefuGetInfo' + ], ], 'subscribe' => [ diff --git a/src/addon/aikefu/event/KefuGetInfo.php b/src/addon/aikefu/event/KefuGetInfo.php new file mode 100644 index 000000000..138f5cda8 --- /dev/null +++ b/src/addon/aikefu/event/KefuGetInfo.php @@ -0,0 +1,127 @@ +getConfig($site_id); + + $response_data = [ + 'service_info' => [ + 'name' => '智能客服', + 'version' => '1.0.0', + 'enabled' => false, + 'status' => 'disabled' + ], + 'features' => [], + 'limits' => [ + 'max_message_length' => 4000, + 'max_conversation_history' => 100, + 'rate_limit' => [ + 'requests_per_minute' => 60, + 'requests_per_hour' => 1000 + ] + ], + 'endpoints' => [ + 'chat' => '/api/chat', + 'chat_stream' => '/api/chatStream', + 'create_conversation' => '/api/createConversation', + 'get_history' => '/api/getHistory', + 'clear_conversation' => '/api/clearConversation', + 'health' => '/api/health', + 'info' => '/api/info' + ], + 'client_info' => $client_info, + 'server_info' => [ + 'php_version' => PHP_VERSION, + 'server_time' => date('Y-m-d H:i:s'), + 'timezone' => date_default_timezone_get() + ] + ]; + + // 处理配置信息 + if (!empty($config_info['data']['value'])) { + $config = $config_info['data']['value']; + + // 服务状态 + $response_data['service_info']['enabled'] = $config['status'] == 1; + $response_data['service_info']['status'] = $config['status'] == 1 ? 'enabled' : 'disabled'; + + // 可用功能 + if ($config['status'] == 1) { + $response_data['features'] = [ + 'chat' => true, + 'chat_stream' => true, + 'conversation_management' => true, + 'history_management' => true + ]; + } + + // API端点信息(仅在启用时显示详细配置) + if ($config['status'] == 1) { + $response_data['api_config'] = [ + 'base_url' => $config['base_url'] ?? '', + 'chat_endpoint' => $config['chat_endpoint'] ?? '', + 'supports_streaming' => true, + 'authentication' => 'bearer_token' + ]; + } + + // 限制配置(如果有的话) + if (isset($config['max_message_length'])) { + $response_data['limits']['max_message_length'] = intval($config['max_message_length']); + } + if (isset($config['rate_limit_per_minute'])) { + $response_data['limits']['rate_limit']['requests_per_minute'] = intval($config['rate_limit_per_minute']); + } + } + + // 添加使用统计信息(如果需要的话) + if ($member_id > 0) { + $response_data['user_stats'] = [ + 'can_use_service' => $response_data['service_info']['enabled'], + 'member_id' => $member_id, + 'site_id' => $site_id + ]; + } + + return [ + 'code' => 0, + 'message' => '获取配置信息成功', + 'data' => $response_data + ]; + + } catch (\Exception $e) { + return [ + 'code' => -1, + 'message' => '获取配置信息失败:' . $e->getMessage(), + 'data' => [ + 'service_info' => [ + 'name' => '智能客服', + 'status' => 'error' + ], + 'error' => $e->getMessage() + ] + ]; + } + } +} \ No newline at end of file diff --git a/src/app/api/controller/AI.php b/src/app/api/controller/AI.php index 47cb97db2..5acc69c50 100644 --- a/src/app/api/controller/AI.php +++ b/src/app/api/controller/AI.php @@ -125,6 +125,82 @@ class AI extends BaseApi } } + /** + * 获得AI服务的配置信息发送给客户端 + * @return \think\response\Json + */ + public function info() + { + // (可选)获取站点ID和会员ID,可以通过事件数据传递 + $site_id = $this->params['uniacid'] ?? $this->site_id; + $member_id = $this->params['member_id'] ?? $this->member_id; + $token = $this->params['token'] ?? $this->token; + + try { + // 准备事件数据 + $event_data = [ + 'site_id' => $site_id, + 'member_id' => $member_id, + 'token' => $token, + 'client_info' => [ + 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', + 'ip' => $this->getClientIp(), + 'timestamp' => time() + ] + ]; + + // 触发获取配置信息事件 + $result = Event::trigger('KefuGetInfo', $event_data); + + // 处理事件结果 + $response = [ + 'code' => 0, + 'message' => 'success', + 'data' => [] + ]; + + if (is_array($result) && !empty($result)) { + foreach ($result as $res) { + if (isset($res['code']) && $res['code'] < 0) { + $response = $res; + break; + } + if (isset($res['data'])) { + $response['data'] = array_merge($response['data'], $res['data']); + } + } + } + + return $this->response($response); + } catch (\Exception $e) { + return $this->response($this->error('请求失败:' . $e->getMessage())); + } + } + + /** + * 获取客户端IP地址 + */ + private function getClientIp() + { + $ip = ''; + + if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; + } elseif (isset($_SERVER['HTTP_X_REAL_IP']) && !empty($_SERVER['HTTP_X_REAL_IP'])) { + $ip = $_SERVER['HTTP_X_REAL_IP']; + } elseif (isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR'])) { + $ip = $_SERVER['REMOTE_ADDR']; + } + + // 处理多个IP的情况(X-Forwarded-For可能包含多个IP) + if (strpos($ip, ',') !== false) { + $ips = explode(',', $ip); + $ip = trim($ips[0]); + } + + return $ip; + } + /** * 清除会话历史 */ diff --git a/src/app/api/controller/Kefu.php b/src/app/api/controller/Kefu.php deleted file mode 100644 index 3b6d17bf3..000000000 --- a/src/app/api/controller/Kefu.php +++ /dev/null @@ -1,187 +0,0 @@ -params['message'] ?? ''; - $user_id = $this->params['user_id'] ?? $this->member_id; - $conversation_id = $this->params['conversation_id'] ?? ''; - $stream = $this->params['stream'] ?? false; - - // (可选)获取站点ID和会员ID,可以通过事件数据传递 - $site_id = $this->params['uniacid'] ?? $this->site_id; // 使用 uniacid, 方便以后迁移,而且uniacid 是唯一的, site_id 不是,同时被params给过滤了 - $member_id = $this->params['member_id'] ?? $this->member_id; - $token = $this->params['token'] ?? $this->token; - - // 验证参数 - if (empty($message)) { - return $this->response($this->error('请输入消息内容')); - } - - try { - // 准备事件数据 - $event_data = [ - 'message' => $message, - 'user_id' => $user_id, - 'conversation_id' => $conversation_id, - 'stream' => $stream, - 'site_id' =>$site_id, - 'member_id' => $member_id, - 'token' => $token, - ]; - - // 触发智能客服聊天事件 - $result = Event::trigger('KefuChat', $event_data); - - // 处理事件结果 - $response = [ - 'code' => 0, - 'message' => 'success', - 'data' => [] - ]; - - if (is_array($result) && !empty($result)) { - foreach ($result as $res) { - if (isset($res['code']) && $res['code'] < 0) { - $response = $res; - break; - } - if (isset($res['data'])) { - $response['data'] = array_merge($response['data'], $res['data']); - } - } - } - - return $this->response($response); - } catch (\Exception $e) { - return $this->response($this->error('请求失败:' . $e->getMessage())); - } - } - - /** - * 创建新会话 - * @return \think\response\Json - */ - public function createConversation() - { - // 获取请求参数 - $user_id = $this->params['user_id'] ?? $this->member_id; - - // (可选)获取站点ID和会员ID,可以通过事件数据传递 - $site_id = $this->params['uniacid'] ?? $this->site_id; // 使用 uniacid, 方便以后迁移,而且uniacid 是唯一的, site_id 不是,同时被params给过滤了 - $member_id = $this->params['member_id'] ?? $this->member_id; - $token = $this->params['token'] ?? $this->token; - - try { - // 准备事件数据 - $event_data = [ - 'user_id' => $user_id, - 'site_id' =>$site_id, - 'member_id' => $member_id, - 'token' => $token, - ]; - - // 触发创建会话事件 - $result = Event::trigger('KefuCreateConversation', $event_data); - - // 处理事件结果 - $response = [ - 'code' => 0, - 'message' => 'success', - 'data' => [] - ]; - - if (is_array($result) && !empty($result)) { - foreach ($result as $res) { - if (isset($res['code']) && $res['code'] < 0) { - $response = $res; - break; - } - if (isset($res['data'])) { - $response['data'] = array_merge($response['data'], $res['data']); - } - } - } - - return $this->response($response); - } catch (\Exception $e) { - return $this->response($this->error('请求失败:' . $e->getMessage())); - } - } - - /** - * 获取会话历史 - * @return \think\response\Json - */ - public function getHistory() - { - // 获取请求参数 - $conversation_id = $this->params['conversation_id'] ?? ''; - $user_id = $this->params['user_id'] ?? $this->member_id; - $limit = $this->params['limit'] ?? 20; - $offset = $this->params['offset'] ?? 0; - - // (可选)获取站点ID和会员ID,可以通过事件数据传递 - $site_id = $this->params['uniacid'] ?? $this->site_id; // 使用 uniacid, 方便以后迁移,而且uniacid 是唯一的, site_id 不是,同时被params给过滤了 - $member_id = $this->params['member_id'] ?? $this->member_id; - $token = $this->params['token'] ?? $this->token; - - // 验证参数 - if (empty($conversation_id)) { - return $this->response($this->error('会话ID不能为空')); - } - - try { - // 准备事件数据 - $event_data = [ - 'conversation_id' => $conversation_id, - 'user_id' => $user_id, - 'limit' => $limit, - 'offset' => $offset, - 'site_id' =>$site_id, - 'member_id' => $member_id, - 'token' => $token, - ]; - - // 触发获取历史消息事件 - $result = Event::trigger('KefuGetHistory', $event_data); - - // 处理事件结果 - $response = [ - 'code' => 0, - 'message' => 'success', - 'data' => [] - ]; - - if (is_array($result) && !empty($result)) { - foreach ($result as $res) { - if (isset($res['code']) && $res['code'] < 0) { - $response = $res; - break; - } - if (isset($res['data'])) { - $response['data'] = array_merge($response['data'], $res['data']); - } - } - } - - return $this->response($response); - } catch (\Exception $e) { - return $this->response($this->error('请求失败:' . $e->getMessage())); - } - } -}