feat(WebSocket): 添加数据库连接检查和文件预览功能

- 在DefaultWebSocketController中添加数据库连接检查功能
- 实现文件预览和下载功能及相关API接口
- 更新测试页面支持文件预览和下载操作
- 移除旧的数据库维护子进程机制,改为函数检查
- 在构建请求数据时添加文件字段支持
This commit is contained in:
2026-01-26 08:40:07 +08:00
parent 0a7301f39d
commit ef708e6b40
3 changed files with 417 additions and 167 deletions

View File

@@ -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;