diff --git a/src/addon/aikefu/api/controller/WebSocket.php b/src/addon/aikefu/api/controller/WebSocket.php
index 32b08bfa1..8bf1e47d9 100644
--- a/src/addon/aikefu/api/controller/WebSocket.php
+++ b/src/addon/aikefu/api/controller/WebSocket.php
@@ -112,8 +112,15 @@ class WebSocket extends WebSocketBase
return;
}
+ // 处理文件预览
+ if (isset($data['action']) && $data['action'] === 'file_preview') {
+ $this->handleFilePreview($conn, $data);
+ return;
+ }
+
$conn->send(json_encode(['type' => 'error', 'message' => 'Unknown action']));
+
} catch (\Exception $e) {
$conn->send(json_encode(['type' => 'error', 'message' => $e->getMessage(), 'line' => $e->getLine(), 'file' => $e->getFile(), 'trace' => $e->getTraceAsString()]));
}
@@ -268,7 +275,7 @@ class WebSocket extends WebSocketBase
$enable_stream = $stream || $response_mode == 'streaming';
// 构建请求数据和请求头
- $requestData = $this->buildRequestData($query, $user_id, $conversation_id, $enable_stream);
+ $requestData = $this->buildRequestData($query, $user_id, $conversation_id, $enable_stream, $data);
$headers = $this->buildRequestHeaders($config['api_key']);
// 发送请求到Dify API
@@ -299,7 +306,7 @@ class WebSocket extends WebSocketBase
try {
// 获取客户端信息
$clientInfo = $this->clientData[$conn->resourceId];
-
+
// 获取分片上传相关参数
$file_id = $data['file_id'] ?? '';
$file_name = $data['file_name'] ?? '';
@@ -358,7 +365,7 @@ class WebSocket extends WebSocketBase
try {
// 获取客户端信息
$clientInfo = $this->clientData[$conn->resourceId];
-
+
// 获取合并相关参数
$file_id = $data['file_id'] ?? '';
$file_name = $data['file_name'] ?? '';
@@ -485,17 +492,17 @@ class WebSocket extends WebSocketBase
$this->cleanupTempFiles($temp_dir);
}
}
-
+
// 解析错误信息
$errorMessage = $e->getMessage();
$errorCode = 500;
$errorType = 'upload_failed';
-
+
// 提取HTTP错误码和Dify错误信息
if (preg_match('/HTTP请求失败,状态码:(\d+),响应:(.*)/', $errorMessage, $matches)) {
- $errorCode = (int)$matches[1];
+ $errorCode = (int) $matches[1];
$errorResponse = $matches[2];
-
+
try {
$errorData = json_decode($errorResponse, true);
if (isset($errorData['code'])) {
@@ -508,7 +515,7 @@ class WebSocket extends WebSocketBase
// 解析失败,使用原始错误信息
}
}
-
+
$conn->send(json_encode([
'type' => 'error',
'code' => $errorCode,
@@ -555,7 +562,7 @@ class WebSocket extends WebSocketBase
try {
// 获取客户端信息
$clientInfo = $this->clientData[$conn->resourceId];
-
+
// 获取检查相关参数
$file_id = $data['file_id'] ?? '';
$total_chunks = $data['total_chunks'] ?? 0;
@@ -606,6 +613,144 @@ class WebSocket extends WebSocketBase
}
}
+ /**
+ * 处理文件预览
+ * @param ConnectionInterface $conn
+ * @param array $data
+ */
+ private function handleFilePreview(ConnectionInterface $conn, $data)
+ {
+ try {
+ // 获取客户端信息
+ $clientInfo = $this->clientData[$conn->resourceId];
+
+ // 获取预览相关参数
+ $file_id = $data['file_id'] ?? '';
+ $as_attachment = $data['as_attachment'] ?? false;
+ $user_id = $data['user_id'] ?? $clientInfo['user_id'];
+ $site_id = $data['uniacid'] ?? $clientInfo['site_id'];
+ $token = $data['token'] ?? $clientInfo['token'];
+
+ // 验证参数
+ if (empty($file_id)) {
+ throw new \Exception('文件ID不能为空');
+ }
+
+ // 验证参数并获取配置,与 Kefu.php 保持一致
+ $config = $this->validateAndGetConfig([
+ 'file_id' => ['required' => true, 'message' => '文件ID不能为空', 'description' => '文件ID'],
+ 'user_id' => ['required' => true, 'message' => '请求参数 `user_id` 不能为空', 'description' => '用户ID']
+ ], [
+ 'file_id' => $file_id,
+ 'user_id' => $user_id,
+ 'uniacid' => $site_id,
+ 'token' => $token
+ ]);
+
+ // 构建请求URL
+ $url = $config['base_url'] . '/files/' . $file_id . '/preview';
+ if ($as_attachment) {
+ $url .= '?as_attachment=true';
+ }
+
+ // 构建请求头
+ $headers = [
+ 'Authorization: Bearer ' . $config['api_key'],
+ 'Accept: */*'
+ ];
+
+ // 发送请求到Dify API
+ $response = $this->curlGetFile($url, $headers);
+
+ // 发送预览成功响应
+ $conn->send(json_encode([
+ 'type' => 'file_preview_success',
+ 'file_id' => $file_id,
+ 'file_url' => $url,
+ 'message' => '文件预览请求成功'
+ ]));
+
+ $this->log('文件预览请求成功,文件ID:' . $file_id, 'info');
+
+ } catch (\Exception $e) {
+ // 解析错误信息
+ $errorMessage = $e->getMessage();
+ $errorCode = 500;
+ $errorType = 'preview_failed';
+
+ // 提取HTTP错误码和Dify错误信息
+ if (preg_match('/HTTP请求失败,状态码:(\d+),响应:(.*)/', $errorMessage, $matches)) {
+ $errorCode = (int) $matches[1];
+ $errorResponse = $matches[2];
+
+ try {
+ $errorData = json_decode($errorResponse, true);
+ if (isset($errorData['code'])) {
+ $errorType = $errorData['code'];
+ }
+ if (isset($errorData['message'])) {
+ $errorMessage = $errorData['message'];
+ }
+ } catch (\Exception $decodeEx) {
+ // 解析失败,使用原始错误信息
+ }
+ }
+
+ $conn->send(json_encode([
+ 'type' => 'error',
+ 'code' => $errorCode,
+ 'error_type' => $errorType,
+ 'message' => '文件预览失败:' . $errorMessage
+ ]));
+ }
+ }
+
+ /**
+ * 封装文件预览的curl请求方法
+ * @param string $url 请求URL
+ * @param array $headers 请求头
+ * @return string 响应内容
+ */
+ private function curlGetFile($url, $headers = [])
+ {
+ $ch = curl_init();
+
+ // 设置URL
+ curl_setopt($ch, CURLOPT_URL, $url);
+
+ // 设置请求方法
+ curl_setopt($ch, CURLOPT_HTTPGET, true);
+
+ // 设置请求头
+ if (!empty($headers)) {
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ }
+
+ // 设置返回值
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 60);
+
+ // 执行请求
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+
+ // 关闭连接
+ curl_close($ch);
+
+ if ($response === false) {
+ throw new \Exception('Curl请求失败');
+ }
+
+ if ($httpCode >= 400) {
+ throw new \Exception('HTTP请求失败,状态码:' . $httpCode . ',响应:' . $response);
+ }
+
+ return $response;
+ }
+
+
/**
* 封装文件上传的curl请求方法(适用于 Dify 1.9.0 版本)
* @param string $url 请求URL
@@ -696,7 +841,7 @@ class WebSocket extends WebSocketBase
{
try {
// 记录开始处理流式请求
- $this->log('AI客服WebSocket流式请求开始处理,用户ID:' . $user_id . ',请求消息:' . $query, 'info');
+ $this->log('AI客服WebSocket流式请求开始处理,用户ID:' . $user_id . ',请求内容:' . json_encode($requestData), 'info');
// 初始化模型
$kefu_conversation_model = new KefuConversationModel();
@@ -1316,9 +1461,10 @@ class WebSocket extends WebSocketBase
* @param string $user_id 用户ID
* @param string $conversation_id 会话ID
* @param bool $stream 是否使用流式响应
+ * @param array $origin_data 原始数据
* @return array
*/
- private function buildRequestData($message, $user_id, $conversation_id, $stream)
+ private function buildRequestData($message, $user_id, $conversation_id, $stream, $origin_data)
{
$requestData = [
'inputs' => [],
@@ -1330,6 +1476,12 @@ class WebSocket extends WebSocketBase
// 如果有会话ID,添加到请求中
if (!empty($conversation_id)) {
$requestData['conversation_id'] = $conversation_id;
+
+ // ----- 只有会话ID的情况下,下列情况才添加相关的数据
+ // 如果有files字段,添加到请求中
+ if (!empty($origin_data['files']) && count($origin_data['files']) > 0) {
+ $requestData['files'] = $origin_data['files'];
+ }
}
return $requestData;
diff --git a/src/addon/aikefu/docs/ws_multi_addon_test.html b/src/addon/aikefu/docs/ws_multi_addon_test.html
index 70c50b3ff..549850c7b 100644
--- a/src/addon/aikefu/docs/ws_multi_addon_test.html
+++ b/src/addon/aikefu/docs/ws_multi_addon_test.html
@@ -10,7 +10,7 @@
-
+