diff --git a/src/addon/aikefu/data/install.sql b/src/addon/aikefu/data/install.sql index d57b46cbc..aed564972 100644 --- a/src/addon/aikefu/data/install.sql +++ b/src/addon/aikefu/data/install.sql @@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS `lucky_aikefu_conversation` ( KEY `site_id` (`site_id`), KEY `user_id` (`user_id`), KEY `conversation_id` (`conversation_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='智能客服会话表'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4_unicode_ci COMMENT='智能客服会话表'; -- 创建智能客服消息表 CREATE TABLE IF NOT EXISTS `lucky_aikefu_message` ( @@ -33,4 +33,10 @@ CREATE TABLE IF NOT EXISTS `lucky_aikefu_message` ( KEY `user_id` (`user_id`), KEY `conversation_id` (`conversation_id`), KEY `message_id` (`message_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='智能客服消息表'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4_unicode_ci COMMENT='智能客服消息表'; + +-- 修改表字符集,utf8mb4_unicode_ci, 兼容emoji表情 + +ALTER TABLE lucky_aikefu_message MODIFY content TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +ALTER TABLE lucky_aikefu_conversation CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +ALTER TABLE lucky_aikefu_message CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; \ No newline at end of file diff --git a/src/app/api/controller/AI.php b/src/app/api/controller/AI.php index b229d80e2..11d881718 100644 --- a/src/app/api/controller/AI.php +++ b/src/app/api/controller/AI.php @@ -328,176 +328,6 @@ class AI extends BaseApi } } - /** - * 智能客服聊天流式接口 - */ - public function chatStream() - { - // 获取请求参数 - $message = $this->params['message'] ?? ''; - $user_id = $this->params['user_id'] ?? $this->member_id; - $conversation_id = $this->params['conversation_id'] ?? ''; - $stream = true; - - // (可选)获取站点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)) { - $this->sendStreamError('请输入消息内容'); - exit; - } - - // 准备事件数据 - $event_data = [ - 'message' => $message, - 'user_id' => $user_id, - 'conversation_id' => $conversation_id, - 'stream' => $stream, - 'site_id' =>$site_id, - 'member_id' => $member_id, - 'token' => $token, - 'request_id' => uniqid('stream_', true), - 'timestamp' => time(), - ]; - - try { - // 设置流式响应头 - $this->setStreamHeaders(); - - // 发送开始事件 - $this->sendStreamEvent('start', [ - 'request_id' => $event_data['request_id'], - 'timestamp' => $event_data['timestamp'], - 'message' => '开始处理请求' - ]); - - // 触发流式聊天事件 - $result = Event::trigger('KefuChatStream', $event_data); - - // 处理事件结果并流式输出 - $this->processStreamResults($result, $event_data); - - } catch (\Exception $e) { - $this->sendStreamError('请求失败:' . $e->getMessage()); - } - } - - /** - * 设置流式响应头 - */ - private function setStreamHeaders() - { - header('Content-Type: text/event-stream'); - header('Cache-Control: no-cache'); - header('Connection: keep-alive'); - header('Access-Control-Allow-Origin: *'); - header('Access-Control-Allow-Headers: Cache-Control, Content-Type'); - header('X-Accel-Buffering: no'); // 禁用nginx缓冲 - if (function_exists('apache_setenv')) { - apache_setenv('no-gzip', '1'); - } - } - - /** - * 发送流式事件 - */ - private function sendStreamEvent($event_type, $data) - { - $payload = [ - 'id' => uniqid(), - 'event' => $event_type, - 'timestamp' => time(), - 'data' => $data - ]; - - echo "event: {$event_type}\n"; - echo "data: " . json_encode($payload, JSON_UNESCAPED_UNICODE) . "\n\n"; - - if (ob_get_level()) { - ob_flush(); - } - flush(); - } - - /** - * 发送流式错误 - */ - private function sendStreamError($message) - { - if (!headers_sent()) { - $this->setStreamHeaders(); - } - - $this->sendStreamEvent('error', [ - 'error' => $message, - 'finished' => true - ]); - - exit; - } - - /** - * 处理流式结果 - */ - private function processStreamResults($results, $event_data) - { - try { - if (is_array($results) && !empty($results)) { - foreach ($results as $result) { - if (isset($result['type'])) { - switch ($result['type']) { - case 'chunk': - // 发送内容块 - $this->sendStreamEvent('message', [ - 'content' => $result['content'] ?? '', - 'conversation_id' => $result['conversation_id'] ?? $event_data['conversation_id'], - 'message_id' => $result['message_id'] ?? '', - 'finished' => $result['finished'] ?? false - ]); - break; - - case 'error': - // 发送错误 - $this->sendStreamEvent('error', [ - 'error' => $result['message'] ?? '未知错误', - 'conversation_id' => $result['conversation_id'] ?? $event_data['conversation_id'] - ]); - break; - - case 'complete': - // 发送完成事件 - $this->sendStreamEvent('complete', [ - 'conversation_id' => $result['conversation_id'] ?? $event_data['conversation_id'], - 'message_id' => $result['message_id'] ?? '', - 'usage' => $result['usage'] ?? [], - 'finish_reason' => $result['finish_reason'] ?? '' - ]); - break; - } - } - } - } else { - // 如果没有事件处理器或结果为空,发送完成事件 - $this->sendStreamEvent('complete', [ - 'conversation_id' => $event_data['conversation_id'], - 'message' => '暂无可用响应' - ]); - } - - // 发送结束事件 - $this->sendStreamEvent('end', [ - 'request_id' => $event_data['request_id'], - 'status' => 'completed' - ]); - - } catch (\Exception $e) { - $this->sendStreamError('处理流式结果失败:' . $e->getMessage()); - } - } - /**