'error', 'message' => '消息内容不能为空' ] ]; } // 获取智能客服配置 $kefu_config_model = new KefuConfigModel(); $config_info = $kefu_config_model->getConfig($site_id)['data']['value'] ?? []; if (empty($config_info) || $config_info['status'] != 1) { return [ [ 'type' => 'error', 'message' => '智能客服暂未启用' ] ]; } $config = $config_info; $apiKey = $config['api_key']; $baseUrl = $config['base_url']; $chatEndpoint = $config['chat_endpoint']; // 构建请求数据 $requestData = [ 'inputs' => [], 'query' => $message, 'response_mode' => 'streaming', 'user' => $user_id, ]; if (!empty($conversation_id)) { $requestData['conversation_id'] = $conversation_id; } // 构建请求头 $headers = [ 'Authorization: Bearer ' . $apiKey, 'Content-Type: application/json', 'Accept: text/event-stream', ]; // 发送流式请求到Dify API $url = $baseUrl . $chatEndpoint; $result = $this->executeStreamRequest($url, $requestData, $headers); return $result; } catch (\Exception $e) { return [ [ 'type' => 'error', 'message' => '请求失败:' . $e->getMessage() ] ]; } } /** * 执行流式请求 */ private function executeStreamRequest($url, $requestData, $headers) { $ch = curl_init(); // 设置curl选项 curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData)); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_WRITEFUNCTION, [$this, 'streamCallback']); curl_setopt($ch, CURLOPT_TIMEOUT, 120); // 设置较长的超时时间 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 执行请求 $result = []; $this->stream_buffer = ''; $this->conversation_id = ''; $this->current_message_id = ''; $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($response === false || !empty($error)) { return [ [ 'type' => 'error', 'message' => '请求失败:' . $error ] ]; } if ($http_code >= 400) { return [ [ 'type' => 'error', 'message' => '服务端错误,HTTP状态码:' . $http_code ] ]; } return $this->parseStreamResponse($this->stream_buffer); } /** * 流式回调函数 */ private function streamCallback($ch, $data) { $this->stream_buffer .= $data; return strlen($data); } /** * 解析流式响应 */ private function parseStreamResponse($response) { $result = []; $lines = explode("\n", $response); $conversation_id = ''; $message_id = ''; $buffer = ''; foreach ($lines as $line) { $line = trim($line); if (empty($line)) { continue; } if (strpos($line, 'data: ') === 0) { $data_str = substr($line, 6); if ($data_str === '[DONE]') { // 流结束,发送完成事件 $result[] = [ 'type' => 'complete', 'conversation_id' => $conversation_id, 'message_id' => $message_id, 'content' => $buffer, 'finished' => true ]; break; } $data = json_decode($data_str, true); if (json_last_error() === JSON_ERROR_NONE && isset($data)) { // 提取会话ID和消息ID if (isset($data['conversation_id'])) { $conversation_id = $data['conversation_id']; } if (isset($data['message_id'])) { $message_id = $data['message_id']; } // 处理内容块 if (isset($data['answer'])) { $buffer .= $data['answer']; $result[] = [ 'type' => 'chunk', 'content' => $data['answer'], 'conversation_id' => $conversation_id, 'message_id' => $message_id, 'finished' => false ]; } // 检查是否结束 if (isset($data['finish_reason']) && $data['finish_reason'] !== 'null') { $result[] = [ 'type' => 'complete', 'conversation_id' => $conversation_id, 'message_id' => $message_id, 'content' => $buffer, 'finish_reason' => $data['finish_reason'], 'usage' => $data['usage'] ?? [], 'finished' => true ]; break; } } } } // 如果没有收到[DONE]信号,确保发送完成事件 if (empty($result) || end($result)['type'] !== 'complete') { $result[] = [ 'type' => 'complete', 'conversation_id' => $conversation_id, 'message_id' => $message_id, 'content' => $buffer, 'finished' => true ]; } return $result; } }