From 9a8304d5952a66aa3f186b456e302e56f3a0f96b Mon Sep 17 00:00:00 2001 From: kuaifan Date: Sat, 3 Jan 2026 21:59:44 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=20Manticore=20?= =?UTF-8?q?=E5=90=91=E9=87=8F=E6=9B=B4=E6=96=B0=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E6=9B=B4=E6=96=B0=E5=A4=B1=E8=B4=A5=E7=9A=84?= =?UTF-8?q?=20ID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Module/Manticore/ManticoreBase.php | 11 ++++++++-- app/Module/Manticore/ManticoreFile.php | 10 +++++++++ app/Module/Manticore/ManticoreMsg.php | 13 +++++++++++- app/Module/Manticore/ManticoreProject.php | 8 +++++++ app/Module/Manticore/ManticoreTask.php | 26 ++++++++++++++++++++--- app/Module/Manticore/ManticoreUser.php | 8 +++++++ 6 files changed, 70 insertions(+), 6 deletions(-) diff --git a/app/Module/Manticore/ManticoreBase.php b/app/Module/Manticore/ManticoreBase.php index 89a8d283f..db5df4452 100644 --- a/app/Module/Manticore/ManticoreBase.php +++ b/app/Module/Manticore/ManticoreBase.php @@ -330,8 +330,15 @@ class ManticoreBase */ public static function escapeMatch(string $keyword): string { - // Manticore 特殊字符转义 - $special = ['\\', '(', ')', '|', '-', '!', '@', '~', '"', '&', '/', '^', '$', '=', '<', '>', '*']; + // Manticore 特殊字符转义(完整列表) + // 参考: https://manual.manticoresearch.com/Searching/Full_text_matching/Escaping + $special = [ + '\\', // 反斜杠(必须最先处理) + '(', ')', '[', ']', // 括号 + '|', '-', '!', '@', '~', '^', '$', '*', '?', // 操作符 + '"', '\'', // 引号 + '&', '/', '=', '<', '>', ':', // 其他特殊字符 + ]; foreach ($special as $char) { $keyword = str_replace($char, '\\' . $char, $keyword); } diff --git a/app/Module/Manticore/ManticoreFile.php b/app/Module/Manticore/ManticoreFile.php index eb0ab8254..4ccf65bd1 100644 --- a/app/Module/Manticore/ManticoreFile.php +++ b/app/Module/Manticore/ManticoreFile.php @@ -260,6 +260,8 @@ class ManticoreFile $maxSize = self::getMaxFileSizeByExt($file->ext); if ($file->size > $maxSize) { Log::info("Manticore: Skip large file {$file->id} ({$file->size} bytes, max: {$maxSize})"); + // 删除可能存在的旧索引(文件更新后可能超限) + self::delete($file->id); return true; } @@ -545,6 +547,7 @@ class ManticoreFile } $embeddings = $result['data']; + $failedIds = []; // 5. 逐个更新向量到 Manticore foreach ($ids as $index => $fileId) { @@ -555,8 +558,15 @@ class ManticoreFile $vectorStr = '[' . implode(',', $embeddings[$index]) . ']'; if (ManticoreBase::updateFileVector($fileId, $vectorStr)) { $successCount++; + } else { + $failedIds[] = $fileId; } } + + // 记录更新失败的 ID + if (!empty($failedIds)) { + Log::warning('ManticoreFile: Vector update failed', ['file_ids' => $failedIds]); + } } return $successCount; diff --git a/app/Module/Manticore/ManticoreMsg.php b/app/Module/Manticore/ManticoreMsg.php index baf41f879..7e33c080d 100644 --- a/app/Module/Manticore/ManticoreMsg.php +++ b/app/Module/Manticore/ManticoreMsg.php @@ -484,11 +484,15 @@ class ManticoreMsg $result = AI::getBatchEmbeddings($texts); if (Base::isError($result)) { - Log::warning('ManticoreMsg batch embedding failed: ' . ($result['msg'] ?? 'Unknown error')); + Log::warning('ManticoreMsg: Batch embedding failed', [ + 'msg_ids' => $idsArray, + 'error' => $result['msg'] ?? 'Unknown error', + ]); continue; } $embeddings = $result['data'] ?? []; + $failedIds = []; // 更新向量 foreach ($embeddings as $index => $embedding) { @@ -504,8 +508,15 @@ class ManticoreMsg $vectorStr = '[' . implode(',', $embedding) . ']'; if (ManticoreBase::updateMsgVector($msgId, $vectorStr)) { $count++; + } else { + $failedIds[] = $msgId; } } + + // 记录更新失败的 ID + if (!empty($failedIds)) { + Log::warning('ManticoreMsg: Vector update failed', ['msg_ids' => $failedIds]); + } } return $count; diff --git a/app/Module/Manticore/ManticoreProject.php b/app/Module/Manticore/ManticoreProject.php index 98f488f40..f9966dd76 100644 --- a/app/Module/Manticore/ManticoreProject.php +++ b/app/Module/Manticore/ManticoreProject.php @@ -367,6 +367,7 @@ class ManticoreProject } $embeddings = $result['data']; + $failedIds = []; // 5. 逐个更新向量到 Manticore foreach ($ids as $index => $projectId) { @@ -377,8 +378,15 @@ class ManticoreProject $vectorStr = '[' . implode(',', $embeddings[$index]) . ']'; if (ManticoreBase::updateProjectVector($projectId, $vectorStr)) { $successCount++; + } else { + $failedIds[] = $projectId; } } + + // 记录更新失败的 ID + if (!empty($failedIds)) { + Log::warning('ManticoreProject: Vector update failed', ['project_ids' => $failedIds]); + } } return $successCount; diff --git a/app/Module/Manticore/ManticoreTask.php b/app/Module/Manticore/ManticoreTask.php index e5a5b4532..9bfadb530 100644 --- a/app/Module/Manticore/ManticoreTask.php +++ b/app/Module/Manticore/ManticoreTask.php @@ -151,7 +151,7 @@ class ManticoreTask /** * 获取任务的 allowed_users 列表 - * + * * 根据 visibility 计算有权限查看此任务的用户列表: * - visibility=1: 项目成员 * - visibility=2: 任务成员(负责人/协作人) @@ -159,10 +159,22 @@ class ManticoreTask * - 子任务: 还需要继承父任务的成员 * * @param ProjectTask $task 任务模型 + * @param int $depth 递归深度(防止无限递归) + * @param array $visited 已访问的任务ID(防止循环引用) * @return array 有权限的用户ID数组 */ - public static function getAllowedUsers(ProjectTask $task): array + public static function getAllowedUsers(ProjectTask $task, int $depth = 0, array $visited = []): array { + // 防止无限递归:深度超过10层或循环引用 + if ($depth > 10 || in_array($task->id, $visited)) { + Log::warning('ManticoreTask: getAllowedUsers recursion limit reached', [ + 'task_id' => $task->id, + 'depth' => $depth, + ]); + return []; + } + $visited[] = $task->id; + $userids = []; // 1. 根据 visibility 获取基础成员 @@ -191,7 +203,7 @@ class ManticoreTask if ($task->parent_id > 0) { $parentTask = ProjectTask::find($task->parent_id); if ($parentTask) { - $parentUsers = self::getAllowedUsers($parentTask); + $parentUsers = self::getAllowedUsers($parentTask, $depth + 1, $visited); $userids = array_merge($userids, $parentUsers); } } @@ -584,6 +596,7 @@ class ManticoreTask } $embeddings = $result['data']; + $failedIds = []; // 5. 逐个更新向量到 Manticore foreach ($ids as $index => $taskId) { @@ -594,8 +607,15 @@ class ManticoreTask $vectorStr = '[' . implode(',', $embeddings[$index]) . ']'; if (ManticoreBase::updateTaskVector($taskId, $vectorStr)) { $successCount++; + } else { + $failedIds[] = $taskId; } } + + // 记录更新失败的 ID + if (!empty($failedIds)) { + Log::warning('ManticoreTask: Vector update failed', ['task_ids' => $failedIds]); + } } return $successCount; diff --git a/app/Module/Manticore/ManticoreUser.php b/app/Module/Manticore/ManticoreUser.php index 1e3df5575..ac8f6e809 100644 --- a/app/Module/Manticore/ManticoreUser.php +++ b/app/Module/Manticore/ManticoreUser.php @@ -332,6 +332,7 @@ class ManticoreUser } $embeddings = $result['data']; + $failedIds = []; // 5. 逐个更新向量到 Manticore foreach ($ids as $index => $userid) { @@ -342,8 +343,15 @@ class ManticoreUser $vectorStr = '[' . implode(',', $embeddings[$index]) . ']'; if (ManticoreBase::updateUserVector($userid, $vectorStr)) { $successCount++; + } else { + $failedIds[] = $userid; } } + + // 记录更新失败的 ID + if (!empty($failedIds)) { + Log::warning('ManticoreUser: Vector update failed', ['user_ids' => $failedIds]); + } } return $successCount;