refactor: 使用 Manticore Search 替换 SeekDB

This commit is contained in:
kuaifan 2026-01-01 03:16:03 +00:00
parent 10c6177a9f
commit 48ef4cfdef
24 changed files with 1017 additions and 1102 deletions

View File

@ -4,12 +4,12 @@ namespace App\Console\Commands;
use App\Models\File; use App\Models\File;
use App\Module\Apps; use App\Module\Apps;
use App\Module\SeekDB\SeekDBFile; use App\Module\Manticore\ManticoreFile;
use App\Module\SeekDB\SeekDBKeyValue; use App\Module\Manticore\ManticoreKeyValue;
use Cache; use Cache;
use Illuminate\Console\Command; use Illuminate\Console\Command;
class SyncFileToSeekDB extends Command class SyncFileToManticore extends Command
{ {
/** /**
* 更新数据 * 更新数据
@ -21,16 +21,16 @@ class SyncFileToSeekDB extends Command
* --c: 清除索引 * --c: 清除索引
*/ */
protected $signature = 'seekdb:sync-files {--f} {--i} {--c} {--u} {--batch=100}'; protected $signature = 'manticore:sync-files {--f} {--i} {--c} {--u} {--batch=100}';
protected $description = '同步文件内容到 SeekDB'; protected $description = '同步文件内容到 Manticore Search';
/** /**
* @return int * @return int
*/ */
public function handle(): int public function handle(): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
$this->error("应用「SeekDB」未安装"); $this->error("应用「Manticore Search」未安装");
return 1; return 1;
} }
@ -54,8 +54,8 @@ class SyncFileToSeekDB extends Command
// 清除索引 // 清除索引
if ($this->option('c')) { if ($this->option('c')) {
$this->info('清除索引...'); $this->info('清除索引...');
SeekDBKeyValue::clear(); ManticoreKeyValue::clear();
SeekDBFile::clear(); ManticoreFile::clear();
$this->info("索引删除成功"); $this->info("索引删除成功");
$this->releaseLock(); $this->releaseLock();
return 0; return 0;
@ -64,7 +64,7 @@ class SyncFileToSeekDB extends Command
// 仅同步文件用户关系 // 仅同步文件用户关系
if ($this->option('u')) { if ($this->option('u')) {
$this->info('开始同步文件用户关系...'); $this->info('开始同步文件用户关系...');
$count = SeekDBFile::syncAllFileUsers(function ($count) { $count = ManticoreFile::syncAllFileUsers(function ($count) {
if ($count % 1000 === 0) { if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系..."); $this->info(" 已同步 {$count} 条关系...");
} }
@ -83,7 +83,7 @@ class SyncFileToSeekDB extends Command
if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) { if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) {
// 全量同步:清空后重建 // 全量同步:清空后重建
$this->info("\n全量同步文件用户关系..."); $this->info("\n全量同步文件用户关系...");
$count = SeekDBFile::syncAllFileUsers(function ($count) { $count = ManticoreFile::syncAllFileUsers(function ($count) {
if ($count % 1000 === 0) { if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系..."); $this->info(" 已同步 {$count} 条关系...");
} }
@ -92,7 +92,7 @@ class SyncFileToSeekDB extends Command
} elseif ($this->option('i')) { } elseif ($this->option('i')) {
// 增量同步:只同步新增的 // 增量同步:只同步新增的
$this->info("\n增量同步文件用户关系..."); $this->info("\n增量同步文件用户关系...");
$count = SeekDBFile::syncFileUsersIncremental(function ($count) { $count = ManticoreFile::syncFileUsersIncremental(function ($count) {
if ($count % 1000 === 0) { if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系..."); $this->info(" 已同步 {$count} 条关系...");
} }
@ -161,8 +161,8 @@ class SyncFileToSeekDB extends Command
private function syncFiles(): void private function syncFiles(): void
{ {
// 获取上次同步的最后ID // 获取上次同步的最后ID
$lastKey = "sync:seekdbFileLastId"; $lastKey = "sync:manticoreFileLastId";
$lastId = $this->option('i') ? intval(SeekDBKeyValue::get($lastKey, 0)) : 0; $lastId = $this->option('i') ? intval(ManticoreKeyValue::get($lastKey, 0)) : 0;
if ($lastId > 0) { if ($lastId > 0) {
$this->info("\n同步文件数据({$lastId}..."); $this->info("\n同步文件数据({$lastId}...");
@ -171,8 +171,8 @@ class SyncFileToSeekDB extends Command
} }
// 查询条件:排除文件夹,使用最大文件限制 // 查询条件:排除文件夹,使用最大文件限制
// 具体的文件类型大小检查在 SeekDBFile::sync 中进行 // 具体的文件类型大小检查在 ManticoreFile::sync 中进行
$maxFileSize = SeekDBFile::getMaxFileSize(); $maxFileSize = ManticoreFile::getMaxFileSize();
$query = File::where('id', '>', $lastId) $query = File::where('id', '>', $lastId)
->where('type', '!=', 'folder') ->where('type', '!=', 'folder')
->where('size', '<=', $maxFileSize); ->where('size', '<=', $maxFileSize);
@ -208,16 +208,16 @@ class SyncFileToSeekDB extends Command
$this->setLock(); $this->setLock();
// 同步数据 // 同步数据
$lastNum = SeekDBFile::batchSync($files); $lastNum = ManticoreFile::batchSync($files);
$total += $lastNum; $total += $lastNum;
// 更新最后ID // 更新最后ID
$lastId = $files->last()->id; $lastId = $files->last()->id;
SeekDBKeyValue::set($lastKey, $lastId); ManticoreKeyValue::set($lastKey, $lastId);
} while (count($files) == $batchSize); } while (count($files) == $batchSize);
$this->info("同步文件结束 - 最后ID {$lastId}"); $this->info("同步文件结束 - 最后ID {$lastId}");
$this->info("已索引文件数量: " . SeekDBFile::getIndexedCount()); $this->info("已索引文件数量: " . ManticoreFile::getIndexedCount());
} }
} }

View File

@ -4,12 +4,12 @@ namespace App\Console\Commands;
use App\Models\Project; use App\Models\Project;
use App\Module\Apps; use App\Module\Apps;
use App\Module\SeekDB\SeekDBProject; use App\Module\Manticore\ManticoreProject;
use App\Module\SeekDB\SeekDBKeyValue; use App\Module\Manticore\ManticoreKeyValue;
use Cache; use Cache;
use Illuminate\Console\Command; use Illuminate\Console\Command;
class SyncProjectToSeekDB extends Command class SyncProjectToManticore extends Command
{ {
/** /**
* 更新数据 * 更新数据
@ -21,16 +21,16 @@ class SyncProjectToSeekDB extends Command
* --c: 清除索引 * --c: 清除索引
*/ */
protected $signature = 'seekdb:sync-projects {--f} {--i} {--c} {--u} {--batch=100}'; protected $signature = 'manticore:sync-projects {--f} {--i} {--c} {--u} {--batch=100}';
protected $description = '同步项目数据到 SeekDB'; protected $description = '同步项目数据到 Manticore Search';
/** /**
* @return int * @return int
*/ */
public function handle(): int public function handle(): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
$this->error("应用「SeekDB」未安装"); $this->error("应用「Manticore Search」未安装");
return 1; return 1;
} }
@ -53,8 +53,7 @@ class SyncProjectToSeekDB extends Command
// 清除索引 // 清除索引
if ($this->option('c')) { if ($this->option('c')) {
$this->info('清除索引...'); $this->info('清除索引...');
SeekDBProject::clear(); ManticoreProject::clear();
SeekDBKeyValue::set('sync:seekdbProjectLastId', 0);
$this->info("索引删除成功"); $this->info("索引删除成功");
$this->releaseLock(); $this->releaseLock();
return 0; return 0;
@ -63,7 +62,7 @@ class SyncProjectToSeekDB extends Command
// 仅同步项目成员关系 // 仅同步项目成员关系
if ($this->option('u')) { if ($this->option('u')) {
$this->info('开始同步项目成员关系...'); $this->info('开始同步项目成员关系...');
$count = SeekDBProject::syncAllProjectUsers(function ($count) { $count = ManticoreProject::syncAllProjectUsers(function ($count) {
if ($count % 1000 === 0) { if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系..."); $this->info(" 已同步 {$count} 条关系...");
} }
@ -78,18 +77,16 @@ class SyncProjectToSeekDB extends Command
// 同步项目成员关系 // 同步项目成员关系
if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) { if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) {
// 全量同步:清空后重建
$this->info("\n全量同步项目成员关系..."); $this->info("\n全量同步项目成员关系...");
$count = SeekDBProject::syncAllProjectUsers(function ($count) { $count = ManticoreProject::syncAllProjectUsers(function ($count) {
if ($count % 1000 === 0) { if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系..."); $this->info(" 已同步 {$count} 条关系...");
} }
}); });
$this->info("项目成员关系同步完成,共 {$count}"); $this->info("项目成员关系同步完成,共 {$count}");
} elseif ($this->option('i')) { } elseif ($this->option('i')) {
// 增量同步:只同步新增的
$this->info("\n增量同步项目成员关系..."); $this->info("\n增量同步项目成员关系...");
$count = SeekDBProject::syncProjectUsersIncremental(function ($count) { $count = ManticoreProject::syncProjectUsersIncremental(function ($count) {
if ($count % 1000 === 0) { if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系..."); $this->info(" 已同步 {$count} 条关系...");
} }
@ -113,12 +110,13 @@ class SyncProjectToSeekDB extends Command
private function setLock(): void private function setLock(): void
{ {
$lockKey = md5($this->signature); $lockKey = md5($this->signature);
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 300); Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 600);
} }
private function releaseLock(): void private function releaseLock(): void
{ {
Cache::forget(md5($this->signature)); $lockKey = md5($this->signature);
Cache::forget($lockKey);
} }
public function handleSignal(int $signal): void public function handleSignal(int $signal): void
@ -129,23 +127,25 @@ class SyncProjectToSeekDB extends Command
private function syncProjects(): void private function syncProjects(): void
{ {
$lastKey = "sync:seekdbProjectLastId"; $lastKey = "sync:manticoreProjectLastId";
$lastId = $this->option('i') ? intval(SeekDBKeyValue::get($lastKey, 0)) : 0; $lastId = $this->option('i') ? intval(ManticoreKeyValue::get($lastKey, 0)) : 0;
if ($lastId > 0) { if ($lastId > 0) {
$this->info("\n增量同步项目数据(从ID: {$lastId}..."); $this->info("\n同步项目数据({$lastId}...");
} else { } else {
$this->info("\n全量同步项目数据..."); $this->info("\n同步项目数据...");
} }
// 只同步未归档的项目 // 排除已归档项目
$query = Project::where('id', '>', $lastId) $query = Project::where('id', '>', $lastId)
->whereNull('archived_at'); ->whereNull('archived_at');
$num = 0; $num = 0;
$count = $query->count(); $count = $query->count();
$batchSize = $this->option('batch'); $batchSize = $this->option('batch');
$total = 0; $total = 0;
$lastNum = 0;
do { do {
$projects = Project::where('id', '>', $lastId) $projects = Project::where('id', '>', $lastId)
@ -160,19 +160,22 @@ class SyncProjectToSeekDB extends Command
$num += count($projects); $num += count($projects);
$progress = $count > 0 ? round($num / $count * 100, 2) : 100; $progress = $count > 0 ? round($num / $count * 100, 2) : 100;
$this->info("{$num}/{$count} ({$progress}%) 正在同步项目ID {$projects->first()->id} ~ {$projects->last()->id}"); if ($progress < 100) {
$progress = number_format($progress, 2);
}
$this->info("{$num}/{$count} ({$progress}%) 正在同步项目ID {$projects->first()->id} ~ {$projects->last()->id} ({$total}|{$lastNum})");
$this->setLock(); $this->setLock();
$synced = SeekDBProject::batchSync($projects); $lastNum = ManticoreProject::batchSync($projects);
$total += $synced; $total += $lastNum;
$lastId = $projects->last()->id; $lastId = $projects->last()->id;
SeekDBKeyValue::set($lastKey, $lastId); ManticoreKeyValue::set($lastKey, $lastId);
} while (count($projects) == $batchSize); } while (count($projects) == $batchSize);
$this->info("同步项目结束 - 最后ID {$lastId},共同步 {$total} 个项目"); $this->info("同步项目结束 - 最后ID {$lastId}");
$this->info("已索引项目数量: " . SeekDBProject::getIndexedCount()); $this->info("已索引项目数量: " . ManticoreProject::getIndexedCount());
} }
} }

View File

@ -4,12 +4,12 @@ namespace App\Console\Commands;
use App\Models\ProjectTask; use App\Models\ProjectTask;
use App\Module\Apps; use App\Module\Apps;
use App\Module\SeekDB\SeekDBTask; use App\Module\Manticore\ManticoreTask;
use App\Module\SeekDB\SeekDBKeyValue; use App\Module\Manticore\ManticoreKeyValue;
use Cache; use Cache;
use Illuminate\Console\Command; use Illuminate\Console\Command;
class SyncTaskToSeekDB extends Command class SyncTaskToManticore extends Command
{ {
/** /**
* 更新数据 * 更新数据
@ -21,16 +21,16 @@ class SyncTaskToSeekDB extends Command
* --c: 清除索引 * --c: 清除索引
*/ */
protected $signature = 'seekdb:sync-tasks {--f} {--i} {--c} {--u} {--batch=100}'; protected $signature = 'manticore:sync-tasks {--f} {--i} {--c} {--u} {--batch=100}';
protected $description = '同步任务数据到 SeekDB'; protected $description = '同步任务数据到 Manticore Search';
/** /**
* @return int * @return int
*/ */
public function handle(): int public function handle(): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
$this->error("应用「SeekDB」未安装"); $this->error("应用「Manticore Search」未安装");
return 1; return 1;
} }
@ -53,8 +53,7 @@ class SyncTaskToSeekDB extends Command
// 清除索引 // 清除索引
if ($this->option('c')) { if ($this->option('c')) {
$this->info('清除索引...'); $this->info('清除索引...');
SeekDBTask::clear(); ManticoreTask::clear();
SeekDBKeyValue::set('sync:seekdbTaskLastId', 0);
$this->info("索引删除成功"); $this->info("索引删除成功");
$this->releaseLock(); $this->releaseLock();
return 0; return 0;
@ -63,7 +62,7 @@ class SyncTaskToSeekDB extends Command
// 仅同步任务成员关系 // 仅同步任务成员关系
if ($this->option('u')) { if ($this->option('u')) {
$this->info('开始同步任务成员关系...'); $this->info('开始同步任务成员关系...');
$count = SeekDBTask::syncAllTaskUsers(function ($count) { $count = ManticoreTask::syncAllTaskUsers(function ($count) {
if ($count % 1000 === 0) { if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系..."); $this->info(" 已同步 {$count} 条关系...");
} }
@ -78,18 +77,16 @@ class SyncTaskToSeekDB extends Command
// 同步任务成员关系 // 同步任务成员关系
if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) { if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) {
// 全量同步:清空后重建
$this->info("\n全量同步任务成员关系..."); $this->info("\n全量同步任务成员关系...");
$count = SeekDBTask::syncAllTaskUsers(function ($count) { $count = ManticoreTask::syncAllTaskUsers(function ($count) {
if ($count % 1000 === 0) { if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系..."); $this->info(" 已同步 {$count} 条关系...");
} }
}); });
$this->info("任务成员关系同步完成,共 {$count}"); $this->info("任务成员关系同步完成,共 {$count}");
} elseif ($this->option('i')) { } elseif ($this->option('i')) {
// 增量同步:只同步新增的
$this->info("\n增量同步任务成员关系..."); $this->info("\n增量同步任务成员关系...");
$count = SeekDBTask::syncTaskUsersIncremental(function ($count) { $count = ManticoreTask::syncTaskUsersIncremental(function ($count) {
if ($count % 1000 === 0) { if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系..."); $this->info(" 已同步 {$count} 条关系...");
} }
@ -113,12 +110,13 @@ class SyncTaskToSeekDB extends Command
private function setLock(): void private function setLock(): void
{ {
$lockKey = md5($this->signature); $lockKey = md5($this->signature);
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 600); // 任务可能较多10分钟 Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 600);
} }
private function releaseLock(): void private function releaseLock(): void
{ {
Cache::forget(md5($this->signature)); $lockKey = md5($this->signature);
Cache::forget($lockKey);
} }
public function handleSignal(int $signal): void public function handleSignal(int $signal): void
@ -129,27 +127,31 @@ class SyncTaskToSeekDB extends Command
private function syncTasks(): void private function syncTasks(): void
{ {
$lastKey = "sync:seekdbTaskLastId"; $lastKey = "sync:manticoreTaskLastId";
$lastId = $this->option('i') ? intval(SeekDBKeyValue::get($lastKey, 0)) : 0; $lastId = $this->option('i') ? intval(ManticoreKeyValue::get($lastKey, 0)) : 0;
if ($lastId > 0) { if ($lastId > 0) {
$this->info("\n增量同步任务数据(从ID: {$lastId}..."); $this->info("\n同步任务数据({$lastId}...");
} else { } else {
$this->info("\n全量同步任务数据..."); $this->info("\n同步任务数据...");
} }
// 只同步未归档的任务(包括软删除恢复的情况) // 排除已归档和已删除的任务
$query = ProjectTask::where('id', '>', $lastId) $query = ProjectTask::where('id', '>', $lastId)
->whereNull('archived_at'); ->whereNull('archived_at')
->whereNull('deleted_at');
$num = 0; $num = 0;
$count = $query->count(); $count = $query->count();
$batchSize = $this->option('batch'); $batchSize = $this->option('batch');
$total = 0; $total = 0;
$lastNum = 0;
do { do {
$tasks = ProjectTask::where('id', '>', $lastId) $tasks = ProjectTask::where('id', '>', $lastId)
->whereNull('archived_at') ->whereNull('archived_at')
->whereNull('deleted_at')
->orderBy('id') ->orderBy('id')
->limit($batchSize) ->limit($batchSize)
->get(); ->get();
@ -160,19 +162,22 @@ class SyncTaskToSeekDB extends Command
$num += count($tasks); $num += count($tasks);
$progress = $count > 0 ? round($num / $count * 100, 2) : 100; $progress = $count > 0 ? round($num / $count * 100, 2) : 100;
$this->info("{$num}/{$count} ({$progress}%) 正在同步任务ID {$tasks->first()->id} ~ {$tasks->last()->id}"); if ($progress < 100) {
$progress = number_format($progress, 2);
}
$this->info("{$num}/{$count} ({$progress}%) 正在同步任务ID {$tasks->first()->id} ~ {$tasks->last()->id} ({$total}|{$lastNum})");
$this->setLock(); $this->setLock();
$synced = SeekDBTask::batchSync($tasks); $lastNum = ManticoreTask::batchSync($tasks);
$total += $synced; $total += $lastNum;
$lastId = $tasks->last()->id; $lastId = $tasks->last()->id;
SeekDBKeyValue::set($lastKey, $lastId); ManticoreKeyValue::set($lastKey, $lastId);
} while (count($tasks) == $batchSize); } while (count($tasks) == $batchSize);
$this->info("同步任务结束 - 最后ID {$lastId},共同步 {$total} 个任务"); $this->info("同步任务结束 - 最后ID {$lastId}");
$this->info("已索引任务数量: " . SeekDBTask::getIndexedCount()); $this->info("已索引任务数量: " . ManticoreTask::getIndexedCount());
} }
} }

View File

@ -4,12 +4,12 @@ namespace App\Console\Commands;
use App\Models\User; use App\Models\User;
use App\Module\Apps; use App\Module\Apps;
use App\Module\SeekDB\SeekDBUser; use App\Module\Manticore\ManticoreUser;
use App\Module\SeekDB\SeekDBKeyValue; use App\Module\Manticore\ManticoreKeyValue;
use Cache; use Cache;
use Illuminate\Console\Command; use Illuminate\Console\Command;
class SyncUserToSeekDB extends Command class SyncUserToManticore extends Command
{ {
/** /**
* 更新数据 * 更新数据
@ -20,16 +20,16 @@ class SyncUserToSeekDB extends Command
* --c: 清除索引 * --c: 清除索引
*/ */
protected $signature = 'seekdb:sync-users {--f} {--i} {--c} {--batch=100}'; protected $signature = 'manticore:sync-users {--f} {--i} {--c} {--batch=100}';
protected $description = '同步用户数据到 SeekDB联系人搜索'; protected $description = '同步用户数据到 Manticore Search';
/** /**
* @return int * @return int
*/ */
public function handle(): int public function handle(): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
$this->error("应用「SeekDB」未安装"); $this->error("应用「Manticore Search」未安装");
return 1; return 1;
} }
@ -52,8 +52,7 @@ class SyncUserToSeekDB extends Command
// 清除索引 // 清除索引
if ($this->option('c')) { if ($this->option('c')) {
$this->info('清除索引...'); $this->info('清除索引...');
SeekDBUser::clear(); ManticoreUser::clear();
SeekDBKeyValue::set('sync:seekdbUserLastId', 0);
$this->info("索引删除成功"); $this->info("索引删除成功");
$this->releaseLock(); $this->releaseLock();
return 0; return 0;
@ -76,12 +75,13 @@ class SyncUserToSeekDB extends Command
private function setLock(): void private function setLock(): void
{ {
$lockKey = md5($this->signature); $lockKey = md5($this->signature);
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 300); Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 600);
} }
private function releaseLock(): void private function releaseLock(): void
{ {
Cache::forget(md5($this->signature)); $lockKey = md5($this->signature);
Cache::forget($lockKey);
} }
public function handleSignal(int $signal): void public function handleSignal(int $signal): void
@ -92,16 +92,16 @@ class SyncUserToSeekDB extends Command
private function syncUsers(): void private function syncUsers(): void
{ {
$lastKey = "sync:seekdbUserLastId"; $lastKey = "sync:manticoreUserLastId";
$lastId = $this->option('i') ? intval(SeekDBKeyValue::get($lastKey, 0)) : 0; $lastId = $this->option('i') ? intval(ManticoreKeyValue::get($lastKey, 0)) : 0;
if ($lastId > 0) { if ($lastId > 0) {
$this->info("\n增量同步用户数据(从ID: {$lastId}..."); $this->info("\n同步用户数据({$lastId}...");
} else { } else {
$this->info("\n全量同步用户数据..."); $this->info("\n同步用户数据...");
} }
// 只同步非机器人且未禁用的用户 // 排除机器人和已禁用账号
$query = User::where('userid', '>', $lastId) $query = User::where('userid', '>', $lastId)
->where('bot', 0) ->where('bot', 0)
->whereNull('disable_at'); ->whereNull('disable_at');
@ -109,7 +109,9 @@ class SyncUserToSeekDB extends Command
$num = 0; $num = 0;
$count = $query->count(); $count = $query->count();
$batchSize = $this->option('batch'); $batchSize = $this->option('batch');
$total = 0; $total = 0;
$lastNum = 0;
do { do {
$users = User::where('userid', '>', $lastId) $users = User::where('userid', '>', $lastId)
@ -125,19 +127,22 @@ class SyncUserToSeekDB extends Command
$num += count($users); $num += count($users);
$progress = $count > 0 ? round($num / $count * 100, 2) : 100; $progress = $count > 0 ? round($num / $count * 100, 2) : 100;
$this->info("{$num}/{$count} ({$progress}%) 正在同步用户ID {$users->first()->userid} ~ {$users->last()->userid}"); if ($progress < 100) {
$progress = number_format($progress, 2);
}
$this->info("{$num}/{$count} ({$progress}%) 正在同步用户ID {$users->first()->userid} ~ {$users->last()->userid} ({$total}|{$lastNum})");
$this->setLock(); $this->setLock();
$synced = SeekDBUser::batchSync($users); $lastNum = ManticoreUser::batchSync($users);
$total += $synced; $total += $lastNum;
$lastId = $users->last()->userid; $lastId = $users->last()->userid;
SeekDBKeyValue::set($lastKey, $lastId); ManticoreKeyValue::set($lastKey, $lastId);
} while (count($users) == $batchSize); } while (count($users) == $batchSize);
$this->info("同步用户结束 - 最后ID {$lastId},共同步 {$total} 个用户"); $this->info("同步用户结束 - 最后ID {$lastId}");
$this->info("已索引用户数量: " . SeekDBUser::getIndexedCount()); $this->info("已索引用户数量: " . ManticoreUser::getIndexedCount());
} }
} }

View File

@ -7,10 +7,10 @@ use App\Models\File;
use App\Models\User; use App\Models\User;
use App\Module\Base; use App\Module\Base;
use App\Module\Apps; use App\Module\Apps;
use App\Module\SeekDB\SeekDBFile; use App\Module\Manticore\ManticoreFile;
use App\Module\SeekDB\SeekDBUser; use App\Module\Manticore\ManticoreUser;
use App\Module\SeekDB\SeekDBProject; use App\Module\Manticore\ManticoreProject;
use App\Module\SeekDB\SeekDBTask; use App\Module\Manticore\ManticoreTask;
/** /**
* @apiDefine search * @apiDefine search
@ -22,7 +22,7 @@ class SearchController extends AbstractController
/** /**
* @api {get} api/search/contact AI 搜索联系人 * @api {get} api/search/contact AI 搜索联系人
* *
* @apiDescription 需要token身份需要安装 SeekDB 应用 * @apiDescription 需要token身份需要安装 Manticore Search 应用
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup search * @apiGroup search
* @apiName contact * @apiName contact
@ -39,8 +39,8 @@ class SearchController extends AbstractController
{ {
User::auth(); User::auth();
if (!Apps::isInstalled('seekdb')) { if (!Apps::isInstalled('manticore')) {
return Base::retError('SeekDB 应用未安装'); return Base::retError('Manticore Search 应用未安装');
} }
$key = trim(Request::input('key')); $key = trim(Request::input('key'));
@ -51,7 +51,7 @@ class SearchController extends AbstractController
return Base::retSuccess('success', []); return Base::retSuccess('success', []);
} }
$results = SeekDBUser::search($key, $searchType, $take); $results = ManticoreUser::search($key, $searchType, $take);
// 补充用户完整信息 // 补充用户完整信息
$userids = array_column($results, 'userid'); $userids = array_column($results, 'userid');
@ -78,7 +78,7 @@ class SearchController extends AbstractController
/** /**
* @api {get} api/search/project AI 搜索项目 * @api {get} api/search/project AI 搜索项目
* *
* @apiDescription 需要token身份需要安装 SeekDB 应用 * @apiDescription 需要token身份需要安装 Manticore Search 应用
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup search * @apiGroup search
* @apiName project * @apiName project
@ -95,8 +95,8 @@ class SearchController extends AbstractController
{ {
$user = User::auth(); $user = User::auth();
if (!Apps::isInstalled('seekdb')) { if (!Apps::isInstalled('manticore')) {
return Base::retError('SeekDB 应用未安装'); return Base::retError('Manticore Search 应用未安装');
} }
$key = trim(Request::input('key')); $key = trim(Request::input('key'));
@ -107,7 +107,7 @@ class SearchController extends AbstractController
return Base::retSuccess('success', []); return Base::retSuccess('success', []);
} }
$results = SeekDBProject::search($user->userid, $key, $searchType, $take); $results = ManticoreProject::search($user->userid, $key, $searchType, $take);
// 补充项目完整信息 // 补充项目完整信息
$projectIds = array_column($results, 'project_id'); $projectIds = array_column($results, 'project_id');
@ -133,7 +133,7 @@ class SearchController extends AbstractController
/** /**
* @api {get} api/search/task AI 搜索任务 * @api {get} api/search/task AI 搜索任务
* *
* @apiDescription 需要token身份需要安装 SeekDB 应用 * @apiDescription 需要token身份需要安装 Manticore Search 应用
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup search * @apiGroup search
* @apiName task * @apiName task
@ -150,8 +150,8 @@ class SearchController extends AbstractController
{ {
$user = User::auth(); $user = User::auth();
if (!Apps::isInstalled('seekdb')) { if (!Apps::isInstalled('manticore')) {
return Base::retError('SeekDB 应用未安装'); return Base::retError('Manticore Search 应用未安装');
} }
$key = trim(Request::input('key')); $key = trim(Request::input('key'));
@ -162,7 +162,7 @@ class SearchController extends AbstractController
return Base::retSuccess('success', []); return Base::retSuccess('success', []);
} }
$results = SeekDBTask::search($user->userid, $key, $searchType, $take); $results = ManticoreTask::search($user->userid, $key, $searchType, $take);
// 补充任务完整信息 // 补充任务完整信息
$taskIds = array_column($results, 'task_id'); $taskIds = array_column($results, 'task_id');
@ -189,7 +189,7 @@ class SearchController extends AbstractController
/** /**
* @api {get} api/search/file AI 搜索文件 * @api {get} api/search/file AI 搜索文件
* *
* @apiDescription 需要token身份需要安装 SeekDB 应用 * @apiDescription 需要token身份需要安装 Manticore Search 应用
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup search * @apiGroup search
* @apiName file * @apiName file
@ -206,8 +206,8 @@ class SearchController extends AbstractController
{ {
$user = User::auth(); $user = User::auth();
if (!Apps::isInstalled('seekdb')) { if (!Apps::isInstalled('manticore')) {
return Base::retError('SeekDB 应用未安装'); return Base::retError('Manticore Search 应用未安装');
} }
$key = trim(Request::input('key')); $key = trim(Request::input('key'));
@ -218,7 +218,7 @@ class SearchController extends AbstractController
return Base::retSuccess('success', []); return Base::retSuccess('success', []);
} }
$results = SeekDBFile::search($user->userid, $key, $searchType, 0, $take); $results = ManticoreFile::search($user->userid, $key, $searchType, 0, $take);
// 补充文件完整信息 // 补充文件完整信息
$fileIds = array_column($results, 'file_id'); $fileIds = array_column($results, 'file_id');

View File

@ -22,7 +22,7 @@ use App\Tasks\DeleteBotMsgTask;
use App\Tasks\CheckinRemindTask; use App\Tasks\CheckinRemindTask;
use App\Tasks\CloseMeetingRoomTask; use App\Tasks\CloseMeetingRoomTask;
use App\Tasks\ZincSearchSyncTask; use App\Tasks\ZincSearchSyncTask;
use App\Tasks\SeekDBSyncTask; use App\Tasks\ManticoreSyncTask;
use App\Tasks\UnclaimedTaskRemindTask; use App\Tasks\UnclaimedTaskRemindTask;
use Hhxsv5\LaravelS\Swoole\Task\Task; use Hhxsv5\LaravelS\Swoole\Task\Task;
use Laravolt\Avatar\Avatar; use Laravolt\Avatar\Avatar;
@ -274,8 +274,8 @@ class IndexController extends InvokeController
Task::deliver(new CloseMeetingRoomTask()); Task::deliver(new CloseMeetingRoomTask());
// ZincSearch 同步 // ZincSearch 同步
Task::deliver(new ZincSearchSyncTask()); Task::deliver(new ZincSearchSyncTask());
// SeekDB 同步 // Manticore Search 同步
Task::deliver(new SeekDBSyncTask()); Task::deliver(new ManticoreSyncTask());
return "success"; return "success";
} }

View File

@ -55,7 +55,7 @@ class Apps
'drawio' => 'Drawio', 'drawio' => 'Drawio',
'minder' => 'Minder', 'minder' => 'Minder',
'search' => 'ZincSearch', 'search' => 'ZincSearch',
'seekdb' => 'SeekDB', 'manticore' => 'Manticore Search',
default => $appId, default => $appId,
}; };
throw new ApiException("应用「{$name}」未安装", [], 0, false); throw new ApiException("应用「{$name}」未安装", [], 0, false);

View File

@ -1,6 +1,6 @@
<?php <?php
namespace App\Module\SeekDB; namespace App\Module\Manticore;
use App\Models\File; use App\Models\File;
use App\Models\FileContent; use App\Models\FileContent;
@ -13,7 +13,7 @@ use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
/** /**
* SeekDB 文件搜索类 * Manticore Search 文件搜索类
* *
* 使用方法: * 使用方法:
* *
@ -28,7 +28,7 @@ use Illuminate\Support\Facades\DB;
* 3. 工具方法 * 3. 工具方法
* - 清空索引: clear(); * - 清空索引: clear();
*/ */
class SeekDBFile class ManticoreFile
{ {
/** /**
* 可搜索的文件类型 * 可搜索的文件类型
@ -83,18 +83,17 @@ class SeekDBFile
return []; return [];
} }
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
// 未安装 SeekDB,降级到 MySQL LIKE 搜索 // 未安装 Manticore,降级到 MySQL LIKE 搜索
return self::searchByMysql($userid, $keyword, $from, $size); return self::searchByMysql($userid, $keyword, $from, $size);
} }
try { try {
// 权限过滤已在 SeekDBBase 中通过 JOIN file_users 表实现
switch ($searchType) { switch ($searchType) {
case 'text': case 'text':
// 纯全文搜索 // 纯全文搜索
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::fullTextSearch($keyword, $userid, $size, $from) ManticoreBase::fullTextSearch($keyword, $userid, $size, $from)
); );
case 'vector': case 'vector':
@ -103,11 +102,11 @@ class SeekDBFile
if (empty($embedding)) { if (empty($embedding)) {
// embedding 获取失败,降级到全文搜索 // embedding 获取失败,降级到全文搜索
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::fullTextSearch($keyword, $userid, $size, $from) ManticoreBase::fullTextSearch($keyword, $userid, $size, $from)
); );
} }
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::vectorSearch($embedding, $userid, $size) ManticoreBase::vectorSearch($embedding, $userid, $size)
); );
case 'hybrid': case 'hybrid':
@ -115,11 +114,11 @@ class SeekDBFile
// 混合搜索 // 混合搜索
$embedding = self::getEmbedding($keyword); $embedding = self::getEmbedding($keyword);
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::hybridSearch($keyword, $embedding, $userid, $size) ManticoreBase::hybridSearch($keyword, $embedding, $userid, $size)
); );
} }
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB search error: ' . $e->getMessage()); Log::error('Manticore search error: ' . $e->getMessage());
return self::searchByMysql($userid, $keyword, $from, $size); return self::searchByMysql($userid, $keyword, $from, $size);
} }
} }
@ -152,7 +151,7 @@ class SeekDBFile
/** /**
* 格式化搜索结果 * 格式化搜索结果
* *
* @param array $results SeekDB 返回的结果 * @param array $results Manticore 返回的结果
* @return array 格式化后的结果 * @return array 格式化后的结果
*/ */
private static function formatSearchResults(array $results): array private static function formatSearchResults(array $results): array
@ -210,14 +209,14 @@ class SeekDBFile
// ============================== // ==============================
/** /**
* 同步单个文件到 SeekDB * 同步单个文件到 Manticore
* *
* @param File $file 文件模型 * @param File $file 文件模型
* @return bool 是否成功 * @return bool 是否成功
*/ */
public static function sync(File $file): bool public static function sync(File $file): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
@ -229,7 +228,7 @@ class SeekDBFile
// 根据文件类型检查大小限制 // 根据文件类型检查大小限制
$maxSize = self::getMaxFileSizeByExt($file->ext); $maxSize = self::getMaxFileSizeByExt($file->ext);
if ($file->size > $maxSize) { if ($file->size > $maxSize) {
Log::info("SeekDB: Skip large file {$file->id} ({$file->size} bytes, max: {$maxSize})"); Log::info("Manticore: Skip large file {$file->id} ({$file->size} bytes, max: {$maxSize})");
return true; return true;
} }
@ -249,9 +248,8 @@ class SeekDBFile
} }
} }
// 写入 SeekDB // 写入 Manticore
// pshare 指向共享根文件夹的 ID用于权限过滤 $result = ManticoreBase::upsertFileVector([
$result = SeekDBBase::upsertFileVector([
'file_id' => $file->id, 'file_id' => $file->id,
'userid' => $file->userid, 'userid' => $file->userid,
'pshare' => $file->pshare ?? 0, 'pshare' => $file->pshare ?? 0,
@ -262,12 +260,9 @@ class SeekDBFile
'content_vector' => $embedding, 'content_vector' => $embedding,
]); ]);
// 注意file_users 只需要同步共享文件夹的关系,不需要同步每个文件
// 因为搜索时是通过 pshare 关联 file_users 表
return $result; return $result;
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB sync error: ' . $e->getMessage(), [ Log::error('Manticore sync error: ' . $e->getMessage(), [
'file_id' => $file->id, 'file_id' => $file->id,
'file_name' => $file->name, 'file_name' => $file->name,
]); ]);
@ -314,7 +309,7 @@ class SeekDBFile
*/ */
public static function batchSync(iterable $files): int public static function batchSync(iterable $files): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
@ -335,11 +330,11 @@ class SeekDBFile
*/ */
public static function delete(int $fileId): bool public static function delete(int $fileId): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
return SeekDBBase::deleteFileVector($fileId); return ManticoreBase::deleteFileVector($fileId);
} }
/** /**
@ -397,11 +392,11 @@ class SeekDBFile
*/ */
public static function clear(): bool public static function clear(): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
return SeekDBBase::clearAllFileVectors(); return ManticoreBase::clearAllFileVectors();
} }
/** /**
@ -411,11 +406,11 @@ class SeekDBFile
*/ */
public static function getIndexedCount(): int public static function getIndexedCount(): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
return SeekDBBase::getIndexedFileCount(); return ManticoreBase::getIndexedFileCount();
} }
// ============================== // ==============================
@ -423,14 +418,14 @@ class SeekDBFile
// ============================== // ==============================
/** /**
* 同步单个文件的用户关系到 SeekDB * 同步单个文件的用户关系到 Manticore
* *
* @param int $fileId 文件ID * @param int $fileId 文件ID
* @return bool 是否成功 * @return bool 是否成功
*/ */
public static function syncFileUsers(int $fileId): bool public static function syncFileUsers(int $fileId): bool
{ {
if (!Apps::isInstalled("seekdb") || $fileId <= 0) { if (!Apps::isInstalled("manticore") || $fileId <= 0) {
return false; return false;
} }
@ -447,16 +442,16 @@ class SeekDBFile
}) })
->toArray(); ->toArray();
// 同步到 SeekDB // 同步到 Manticore
return SeekDBBase::syncFileUsers($fileId, $users); return ManticoreBase::syncFileUsers($fileId, $users);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB syncFileUsers error: ' . $e->getMessage(), ['file_id' => $fileId]); Log::error('Manticore syncFileUsers error: ' . $e->getMessage(), ['file_id' => $fileId]);
return false; return false;
} }
} }
/** /**
* 添加文件用户关系到 SeekDB * 添加文件用户关系到 Manticore
* *
* @param int $fileId 文件ID * @param int $fileId 文件ID
* @param int $userid 用户ID * @param int $userid 用户ID
@ -465,11 +460,11 @@ class SeekDBFile
*/ */
public static function addFileUser(int $fileId, int $userid, int $permission = 0): bool public static function addFileUser(int $fileId, int $userid, int $permission = 0): bool
{ {
if (!Apps::isInstalled("seekdb") || $fileId <= 0) { if (!Apps::isInstalled("manticore") || $fileId <= 0) {
return false; return false;
} }
return SeekDBBase::upsertFileUser($fileId, $userid, $permission); return ManticoreBase::upsertFileUser($fileId, $userid, $permission);
} }
/** /**
@ -481,15 +476,15 @@ class SeekDBFile
*/ */
public static function removeFileUser(int $fileId, ?int $userid = null): bool public static function removeFileUser(int $fileId, ?int $userid = null): bool
{ {
if (!Apps::isInstalled("seekdb") || $fileId <= 0) { if (!Apps::isInstalled("manticore") || $fileId <= 0) {
return false; return false;
} }
if ($userid === null) { if ($userid === null) {
return SeekDBBase::deleteFileUsers($fileId); return ManticoreBase::deleteFileUsers($fileId);
} }
return SeekDBBase::deleteFileUser($fileId, $userid); return ManticoreBase::deleteFileUser($fileId, $userid);
} }
/** /**
@ -500,7 +495,7 @@ class SeekDBFile
*/ */
public static function syncAllFileUsers(?callable $progressCallback = null): int public static function syncAllFileUsers(?callable $progressCallback = null): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
@ -508,8 +503,8 @@ class SeekDBFile
$lastId = 0; $lastId = 0;
$batchSize = 1000; $batchSize = 1000;
// 先清空 SeekDB 中的 file_users 表 // 先清空 Manticore 中的 file_users 表
SeekDBBase::clearAllFileUsers(); ManticoreBase::clearAllFileUsers();
// 分批同步 // 分批同步
while (true) { while (true) {
@ -523,7 +518,7 @@ class SeekDBFile
} }
foreach ($records as $record) { foreach ($records as $record) {
SeekDBBase::upsertFileUser($record->file_id, $record->userid, $record->permission); ManticoreBase::upsertFileUser($record->file_id, $record->userid, $record->permission);
$count++; $count++;
$lastId = $record->id; $lastId = $record->id;
} }
@ -544,14 +539,14 @@ class SeekDBFile
*/ */
public static function syncFileUsersIncremental(?callable $progressCallback = null): int public static function syncFileUsersIncremental(?callable $progressCallback = null): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
$count = 0; $count = 0;
$batchSize = 1000; $batchSize = 1000;
$lastKey = "sync:seekdbFileUserLastId"; $lastKey = "sync:manticoreFileUserLastId";
$lastId = intval(SeekDBKeyValue::get($lastKey, 0)); $lastId = intval(ManticoreKeyValue::get($lastKey, 0));
// 分批同步新增的记录 // 分批同步新增的记录
while (true) { while (true) {
@ -565,13 +560,13 @@ class SeekDBFile
} }
foreach ($records as $record) { foreach ($records as $record) {
SeekDBBase::upsertFileUser($record->file_id, $record->userid, $record->permission); ManticoreBase::upsertFileUser($record->file_id, $record->userid, $record->permission);
$count++; $count++;
$lastId = $record->id; $lastId = $record->id;
} }
// 保存进度 // 保存进度
SeekDBKeyValue::set($lastKey, $lastId); ManticoreKeyValue::set($lastKey, $lastId);
if ($progressCallback) { if ($progressCallback) {
$progressCallback($count); $progressCallback($count);

View File

@ -0,0 +1,139 @@
<?php
namespace App\Module\Manticore;
use App\Module\Apps;
use Illuminate\Support\Facades\Log;
/**
* Manticore Search 键值存储类
*
* 用于存储同步进度等配置信息
*/
class ManticoreKeyValue
{
/**
* 获取值
*
* @param string $key
* @param mixed $default 默认值
* @return mixed
*/
public static function get(string $key, $default = null)
{
if (!Apps::isInstalled("manticore")) {
return $default;
}
$instance = new ManticoreBase();
$result = $instance->queryOne(
"SELECT v FROM key_values WHERE k = ?",
[$key]
);
return $result ? $result['v'] : $default;
}
/**
* 设置值
*
* @param string $key
* @param mixed $value
* @return bool 是否成功
*/
public static function set(string $key, $value): bool
{
if (!Apps::isInstalled("manticore")) {
return false;
}
$instance = new ManticoreBase();
// 先删除已存在的记录
$instance->execute("DELETE FROM key_values WHERE k = ?", [$key]);
// 生成唯一 ID基于 key 的 hash
$id = abs(crc32($key));
// 插入新记录
return $instance->execute(
"INSERT INTO key_values (id, k, v) VALUES (?, ?, ?)",
[$id, $key, (string)$value]
);
}
/**
* 删除值
*
* @param string $key
* @return bool 是否成功
*/
public static function delete(string $key): bool
{
if (!Apps::isInstalled("manticore")) {
return false;
}
$instance = new ManticoreBase();
return $instance->execute("DELETE FROM key_values WHERE k = ?", [$key]);
}
/**
* 清空所有键值
*
* @return bool 是否成功
*/
public static function clear(): bool
{
if (!Apps::isInstalled("manticore")) {
return false;
}
$instance = new ManticoreBase();
return $instance->execute("TRUNCATE TABLE key_values");
}
/**
* 检查键是否存在
*
* @param string $key
* @return bool 是否存在
*/
public static function exists(string $key): bool
{
if (!Apps::isInstalled("manticore")) {
return false;
}
$instance = new ManticoreBase();
$result = $instance->queryOne(
"SELECT id FROM key_values WHERE k = ?",
[$key]
);
return $result !== null;
}
/**
* 获取所有键值对
*
* @return array 键值对数组
*/
public static function all(): array
{
if (!Apps::isInstalled("manticore")) {
return [];
}
$instance = new ManticoreBase();
$results = $instance->query("SELECT k, v FROM key_values");
$data = [];
foreach ($results as $row) {
$data[$row['k']] = $row['v'];
}
return $data;
}
}

View File

@ -1,17 +1,16 @@
<?php <?php
namespace App\Module\SeekDB; namespace App\Module\Manticore;
use App\Models\Project; use App\Models\Project;
use App\Models\ProjectUser; use App\Models\ProjectUser;
use App\Module\Apps; use App\Module\Apps;
use App\Module\Base; use App\Module\Base;
use App\Module\AI; use App\Module\AI;
use App\Module\SeekDB\SeekDBKeyValue;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/** /**
* SeekDB 项目搜索类 * Manticore Search 项目搜索类
* *
* 使用方法: * 使用方法:
* *
@ -31,7 +30,7 @@ use Illuminate\Support\Facades\Log;
* 4. 工具方法 * 4. 工具方法
* - 清空索引: clear(); * - 清空索引: clear();
*/ */
class SeekDBProject class ManticoreProject
{ {
/** /**
* 搜索项目(支持全文、向量、混合搜索) * 搜索项目(支持全文、向量、混合搜索)
@ -48,7 +47,7 @@ class SeekDBProject
return []; return [];
} }
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return []; return [];
} }
@ -56,29 +55,29 @@ class SeekDBProject
switch ($searchType) { switch ($searchType) {
case 'text': case 'text':
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::projectFullTextSearch($keyword, $userid, $limit, 0) ManticoreBase::projectFullTextSearch($keyword, $userid, $limit, 0)
); );
case 'vector': case 'vector':
$embedding = self::getEmbedding($keyword); $embedding = self::getEmbedding($keyword);
if (empty($embedding)) { if (empty($embedding)) {
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::projectFullTextSearch($keyword, $userid, $limit, 0) ManticoreBase::projectFullTextSearch($keyword, $userid, $limit, 0)
); );
} }
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::projectVectorSearch($embedding, $userid, $limit) ManticoreBase::projectVectorSearch($embedding, $userid, $limit)
); );
case 'hybrid': case 'hybrid':
default: default:
$embedding = self::getEmbedding($keyword); $embedding = self::getEmbedding($keyword);
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::projectHybridSearch($keyword, $embedding, $userid, $limit) ManticoreBase::projectHybridSearch($keyword, $embedding, $userid, $limit)
); );
} }
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB project search error: ' . $e->getMessage()); Log::error('Manticore project search error: ' . $e->getMessage());
return []; return [];
} }
} }
@ -110,7 +109,7 @@ class SeekDBProject
/** /**
* 格式化搜索结果 * 格式化搜索结果
* *
* @param array $results SeekDB 返回的结果 * @param array $results Manticore 返回的结果
* @return array 格式化后的结果 * @return array 格式化后的结果
*/ */
private static function formatSearchResults(array $results): array private static function formatSearchResults(array $results): array
@ -135,14 +134,14 @@ class SeekDBProject
// ============================== // ==============================
/** /**
* 同步单个项目到 SeekDB * 同步单个项目到 Manticore
* *
* @param Project $project 项目模型 * @param Project $project 项目模型
* @return bool 是否成功 * @return bool 是否成功
*/ */
public static function sync(Project $project): bool public static function sync(Project $project): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
@ -164,8 +163,8 @@ class SeekDBProject
} }
} }
// 写入 SeekDB // 写入 Manticore
$result = SeekDBBase::upsertProjectVector([ $result = ManticoreBase::upsertProjectVector([
'project_id' => $project->id, 'project_id' => $project->id,
'userid' => $project->userid ?? 0, 'userid' => $project->userid ?? 0,
'personal' => $project->personal ?? 0, 'personal' => $project->personal ?? 0,
@ -176,7 +175,7 @@ class SeekDBProject
return $result; return $result;
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB project sync error: ' . $e->getMessage(), [ Log::error('Manticore project sync error: ' . $e->getMessage(), [
'project_id' => $project->id, 'project_id' => $project->id,
'project_name' => $project->name, 'project_name' => $project->name,
]); ]);
@ -212,7 +211,7 @@ class SeekDBProject
*/ */
public static function batchSync(iterable $projects): int public static function batchSync(iterable $projects): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
@ -233,14 +232,14 @@ class SeekDBProject
*/ */
public static function delete(int $projectId): bool public static function delete(int $projectId): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
// 删除项目索引 // 删除项目索引
SeekDBBase::deleteProjectVector($projectId); ManticoreBase::deleteProjectVector($projectId);
// 删除项目成员关系 // 删除项目成员关系
SeekDBBase::deleteAllProjectUsers($projectId); ManticoreBase::deleteAllProjectUsers($projectId);
return true; return true;
} }
@ -252,12 +251,12 @@ class SeekDBProject
*/ */
public static function clear(): bool public static function clear(): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
SeekDBBase::clearAllProjectVectors(); ManticoreBase::clearAllProjectVectors();
SeekDBBase::clearAllProjectUsers(); ManticoreBase::clearAllProjectUsers();
return true; return true;
} }
@ -269,11 +268,11 @@ class SeekDBProject
*/ */
public static function getIndexedCount(): int public static function getIndexedCount(): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
return SeekDBBase::getIndexedProjectCount(); return ManticoreBase::getIndexedProjectCount();
} }
// ============================== // ==============================
@ -281,7 +280,7 @@ class SeekDBProject
// ============================== // ==============================
/** /**
* 添加项目成员到 SeekDB * 添加项目成员到 Manticore
* *
* @param int $projectId 项目ID * @param int $projectId 项目ID
* @param int $userid 用户ID * @param int $userid 用户ID
@ -289,11 +288,11 @@ class SeekDBProject
*/ */
public static function addProjectUser(int $projectId, int $userid): bool public static function addProjectUser(int $projectId, int $userid): bool
{ {
if (!Apps::isInstalled("seekdb") || $projectId <= 0 || $userid <= 0) { if (!Apps::isInstalled("manticore") || $projectId <= 0 || $userid <= 0) {
return false; return false;
} }
return SeekDBBase::upsertProjectUser($projectId, $userid); return ManticoreBase::upsertProjectUser($projectId, $userid);
} }
/** /**
@ -305,22 +304,22 @@ class SeekDBProject
*/ */
public static function removeProjectUser(int $projectId, int $userid): bool public static function removeProjectUser(int $projectId, int $userid): bool
{ {
if (!Apps::isInstalled("seekdb") || $projectId <= 0 || $userid <= 0) { if (!Apps::isInstalled("manticore") || $projectId <= 0 || $userid <= 0) {
return false; return false;
} }
return SeekDBBase::deleteProjectUser($projectId, $userid); return ManticoreBase::deleteProjectUser($projectId, $userid);
} }
/** /**
* 同步项目的所有成员到 SeekDB * 同步项目的所有成员到 Manticore
* *
* @param int $projectId 项目ID * @param int $projectId 项目ID
* @return bool 是否成功 * @return bool 是否成功
*/ */
public static function syncProjectUsers(int $projectId): bool public static function syncProjectUsers(int $projectId): bool
{ {
if (!Apps::isInstalled("seekdb") || $projectId <= 0) { if (!Apps::isInstalled("manticore") || $projectId <= 0) {
return false; return false;
} }
@ -330,10 +329,10 @@ class SeekDBProject
->pluck('userid') ->pluck('userid')
->toArray(); ->toArray();
// 同步到 SeekDB // 同步到 Manticore
return SeekDBBase::syncProjectUsers($projectId, $userids); return ManticoreBase::syncProjectUsers($projectId, $userids);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB syncProjectUsers error: ' . $e->getMessage(), ['project_id' => $projectId]); Log::error('Manticore syncProjectUsers error: ' . $e->getMessage(), ['project_id' => $projectId]);
return false; return false;
} }
} }
@ -346,7 +345,7 @@ class SeekDBProject
*/ */
public static function syncAllProjectUsers(?callable $progressCallback = null): int public static function syncAllProjectUsers(?callable $progressCallback = null): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
@ -354,8 +353,8 @@ class SeekDBProject
$lastId = 0; $lastId = 0;
$batchSize = 1000; $batchSize = 1000;
// 先清空 SeekDB 中的 project_users 表 // 先清空 Manticore 中的 project_users 表
SeekDBBase::clearAllProjectUsers(); ManticoreBase::clearAllProjectUsers();
// 分批同步 // 分批同步
while (true) { while (true) {
@ -369,7 +368,7 @@ class SeekDBProject
} }
foreach ($records as $record) { foreach ($records as $record) {
SeekDBBase::upsertProjectUser($record->project_id, $record->userid); ManticoreBase::upsertProjectUser($record->project_id, $record->userid);
$count++; $count++;
$lastId = $record->id; $lastId = $record->id;
} }
@ -390,14 +389,14 @@ class SeekDBProject
*/ */
public static function syncProjectUsersIncremental(?callable $progressCallback = null): int public static function syncProjectUsersIncremental(?callable $progressCallback = null): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
$count = 0; $count = 0;
$batchSize = 1000; $batchSize = 1000;
$lastKey = "sync:seekdbProjectUserLastId"; $lastKey = "sync:manticoreProjectUserLastId";
$lastId = intval(SeekDBKeyValue::get($lastKey, 0)); $lastId = intval(ManticoreKeyValue::get($lastKey, 0));
// 分批同步新增的记录 // 分批同步新增的记录
while (true) { while (true) {
@ -411,13 +410,13 @@ class SeekDBProject
} }
foreach ($records as $record) { foreach ($records as $record) {
SeekDBBase::upsertProjectUser($record->project_id, $record->userid); ManticoreBase::upsertProjectUser($record->project_id, $record->userid);
$count++; $count++;
$lastId = $record->id; $lastId = $record->id;
} }
// 保存进度 // 保存进度
SeekDBKeyValue::set($lastKey, $lastId); ManticoreKeyValue::set($lastKey, $lastId);
if ($progressCallback) { if ($progressCallback) {
$progressCallback($count); $progressCallback($count);

View File

@ -1,6 +1,6 @@
<?php <?php
namespace App\Module\SeekDB; namespace App\Module\Manticore;
use App\Models\ProjectTask; use App\Models\ProjectTask;
use App\Models\ProjectTaskContent; use App\Models\ProjectTaskContent;
@ -9,11 +9,10 @@ use App\Models\ProjectTaskVisibilityUser;
use App\Module\Apps; use App\Module\Apps;
use App\Module\Base; use App\Module\Base;
use App\Module\AI; use App\Module\AI;
use App\Module\SeekDB\SeekDBKeyValue;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/** /**
* SeekDB 任务搜索类 * Manticore Search 任务搜索类
* *
* 权限逻辑说明: * 权限逻辑说明:
* - visibility = 1: 项目人员可见,通过 project_users 表过滤 * - visibility = 1: 项目人员可见,通过 project_users 表过滤
@ -38,7 +37,7 @@ use Illuminate\Support\Facades\Log;
* 4. 工具方法 * 4. 工具方法
* - 清空索引: clear(); * - 清空索引: clear();
*/ */
class SeekDBTask class ManticoreTask
{ {
/** /**
* 最大内容长度(字符) * 最大内容长度(字符)
@ -60,7 +59,7 @@ class SeekDBTask
return []; return [];
} }
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return []; return [];
} }
@ -68,29 +67,29 @@ class SeekDBTask
switch ($searchType) { switch ($searchType) {
case 'text': case 'text':
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::taskFullTextSearch($keyword, $userid, $limit, 0) ManticoreBase::taskFullTextSearch($keyword, $userid, $limit, 0)
); );
case 'vector': case 'vector':
$embedding = self::getEmbedding($keyword); $embedding = self::getEmbedding($keyword);
if (empty($embedding)) { if (empty($embedding)) {
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::taskFullTextSearch($keyword, $userid, $limit, 0) ManticoreBase::taskFullTextSearch($keyword, $userid, $limit, 0)
); );
} }
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::taskVectorSearch($embedding, $userid, $limit) ManticoreBase::taskVectorSearch($embedding, $userid, $limit)
); );
case 'hybrid': case 'hybrid':
default: default:
$embedding = self::getEmbedding($keyword); $embedding = self::getEmbedding($keyword);
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::taskHybridSearch($keyword, $embedding, $userid, $limit) ManticoreBase::taskHybridSearch($keyword, $embedding, $userid, $limit)
); );
} }
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB task search error: ' . $e->getMessage()); Log::error('Manticore task search error: ' . $e->getMessage());
return []; return [];
} }
} }
@ -122,7 +121,7 @@ class SeekDBTask
/** /**
* 格式化搜索结果 * 格式化搜索结果
* *
* @param array $results SeekDB 返回的结果 * @param array $results Manticore 返回的结果
* @return array 格式化后的结果 * @return array 格式化后的结果
*/ */
private static function formatSearchResults(array $results): array private static function formatSearchResults(array $results): array
@ -149,14 +148,14 @@ class SeekDBTask
// ============================== // ==============================
/** /**
* 同步单个任务到 SeekDB * 同步单个任务到 Manticore
* *
* @param ProjectTask $task 任务模型 * @param ProjectTask $task 任务模型
* @return bool 是否成功 * @return bool 是否成功
*/ */
public static function sync(ProjectTask $task): bool public static function sync(ProjectTask $task): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
@ -181,8 +180,8 @@ class SeekDBTask
} }
} }
// 写入 SeekDB // 写入 Manticore
$result = SeekDBBase::upsertTaskVector([ $result = ManticoreBase::upsertTaskVector([
'task_id' => $task->id, 'task_id' => $task->id,
'project_id' => $task->project_id ?? 0, 'project_id' => $task->project_id ?? 0,
'userid' => $task->userid ?? 0, 'userid' => $task->userid ?? 0,
@ -195,7 +194,7 @@ class SeekDBTask
return $result; return $result;
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB task sync error: ' . $e->getMessage(), [ Log::error('Manticore task sync error: ' . $e->getMessage(), [
'task_id' => $task->id, 'task_id' => $task->id,
'task_name' => $task->name, 'task_name' => $task->name,
]); ]);
@ -298,7 +297,7 @@ class SeekDBTask
*/ */
public static function batchSync(iterable $tasks): int public static function batchSync(iterable $tasks): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
@ -319,14 +318,14 @@ class SeekDBTask
*/ */
public static function delete(int $taskId): bool public static function delete(int $taskId): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
// 删除任务索引 // 删除任务索引
SeekDBBase::deleteTaskVector($taskId); ManticoreBase::deleteTaskVector($taskId);
// 删除任务成员关系 // 删除任务成员关系
SeekDBBase::deleteAllTaskUsers($taskId); ManticoreBase::deleteAllTaskUsers($taskId);
return true; return true;
} }
@ -340,11 +339,11 @@ class SeekDBTask
*/ */
public static function updateVisibility(int $taskId, int $visibility): bool public static function updateVisibility(int $taskId, int $visibility): bool
{ {
if (!Apps::isInstalled("seekdb") || $taskId <= 0) { if (!Apps::isInstalled("manticore") || $taskId <= 0) {
return false; return false;
} }
return SeekDBBase::updateTaskVisibility($taskId, $visibility); return ManticoreBase::updateTaskVisibility($taskId, $visibility);
} }
/** /**
@ -354,12 +353,12 @@ class SeekDBTask
*/ */
public static function clear(): bool public static function clear(): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
SeekDBBase::clearAllTaskVectors(); ManticoreBase::clearAllTaskVectors();
SeekDBBase::clearAllTaskUsers(); ManticoreBase::clearAllTaskUsers();
return true; return true;
} }
@ -371,11 +370,11 @@ class SeekDBTask
*/ */
public static function getIndexedCount(): int public static function getIndexedCount(): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
return SeekDBBase::getIndexedTaskCount(); return ManticoreBase::getIndexedTaskCount();
} }
// ============================== // ==============================
@ -383,7 +382,7 @@ class SeekDBTask
// ============================== // ==============================
/** /**
* 添加任务成员到 SeekDB * 添加任务成员到 Manticore
* *
* @param int $taskId 任务ID * @param int $taskId 任务ID
* @param int $userid 用户ID * @param int $userid 用户ID
@ -391,11 +390,11 @@ class SeekDBTask
*/ */
public static function addTaskUser(int $taskId, int $userid): bool public static function addTaskUser(int $taskId, int $userid): bool
{ {
if (!Apps::isInstalled("seekdb") || $taskId <= 0 || $userid <= 0) { if (!Apps::isInstalled("manticore") || $taskId <= 0 || $userid <= 0) {
return false; return false;
} }
return SeekDBBase::upsertTaskUser($taskId, $userid); return ManticoreBase::upsertTaskUser($taskId, $userid);
} }
/** /**
@ -407,11 +406,11 @@ class SeekDBTask
*/ */
public static function removeTaskUser(int $taskId, int $userid): bool public static function removeTaskUser(int $taskId, int $userid): bool
{ {
if (!Apps::isInstalled("seekdb") || $taskId <= 0 || $userid <= 0) { if (!Apps::isInstalled("manticore") || $taskId <= 0 || $userid <= 0) {
return false; return false;
} }
return SeekDBBase::deleteTaskUser($taskId, $userid); return ManticoreBase::deleteTaskUser($taskId, $userid);
} }
/** /**
@ -426,7 +425,7 @@ class SeekDBTask
*/ */
public static function removeVisibilityUser(int $taskId, int $userid): bool public static function removeVisibilityUser(int $taskId, int $userid): bool
{ {
if (!Apps::isInstalled("seekdb") || $taskId <= 0 || $userid <= 0) { if (!Apps::isInstalled("manticore") || $taskId <= 0 || $userid <= 0) {
return false; return false;
} }
@ -450,10 +449,10 @@ class SeekDBTask
return true; return true;
} }
// 从 SeekDB 删除 // 从 Manticore 删除
return SeekDBBase::deleteTaskUser($taskId, $userid); return ManticoreBase::deleteTaskUser($taskId, $userid);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB removeVisibilityUser error: ' . $e->getMessage(), [ Log::error('Manticore removeVisibilityUser error: ' . $e->getMessage(), [
'task_id' => $taskId, 'task_id' => $taskId,
'userid' => $userid, 'userid' => $userid,
]); ]);
@ -462,7 +461,7 @@ class SeekDBTask
} }
/** /**
* 同步任务的所有成员到 SeekDB * 同步任务的所有成员到 Manticore
* *
* 包括ProjectTaskUser ProjectTaskVisibilityUser * 包括ProjectTaskUser ProjectTaskVisibilityUser
* *
@ -471,7 +470,7 @@ class SeekDBTask
*/ */
public static function syncTaskUsers(int $taskId): bool public static function syncTaskUsers(int $taskId): bool
{ {
if (!Apps::isInstalled("seekdb") || $taskId <= 0) { if (!Apps::isInstalled("manticore") || $taskId <= 0) {
return false; return false;
} }
@ -490,10 +489,10 @@ class SeekDBTask
// 合并去重 // 合并去重
$allUserIds = array_unique(array_merge($taskUserIds, $visibilityUserIds)); $allUserIds = array_unique(array_merge($taskUserIds, $visibilityUserIds));
// 同步到 SeekDB // 同步到 Manticore
return SeekDBBase::syncTaskUsers($taskId, $allUserIds); return ManticoreBase::syncTaskUsers($taskId, $allUserIds);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB syncTaskUsers error: ' . $e->getMessage(), ['task_id' => $taskId]); Log::error('Manticore syncTaskUsers error: ' . $e->getMessage(), ['task_id' => $taskId]);
return false; return false;
} }
} }
@ -506,7 +505,7 @@ class SeekDBTask
*/ */
public static function syncAllTaskUsers(?callable $progressCallback = null): int public static function syncAllTaskUsers(?callable $progressCallback = null): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
@ -514,8 +513,8 @@ class SeekDBTask
$lastId = 0; $lastId = 0;
$batchSize = 1000; $batchSize = 1000;
// 先清空 SeekDB 中的 task_users 表 // 先清空 Manticore 中的 task_users 表
SeekDBBase::clearAllTaskUsers(); ManticoreBase::clearAllTaskUsers();
// 同步 ProjectTaskUser // 同步 ProjectTaskUser
while (true) { while (true) {
@ -529,10 +528,10 @@ class SeekDBTask
} }
foreach ($records as $record) { foreach ($records as $record) {
SeekDBBase::upsertTaskUser($record->task_id, $record->userid); ManticoreBase::upsertTaskUser($record->task_id, $record->userid);
// 如果有父任务,也添加到父任务 // 如果有父任务,也添加到父任务
if ($record->task_pid) { if ($record->task_pid) {
SeekDBBase::upsertTaskUser($record->task_pid, $record->userid); ManticoreBase::upsertTaskUser($record->task_pid, $record->userid);
} }
$count++; $count++;
$lastId = $record->id; $lastId = $record->id;
@ -556,7 +555,7 @@ class SeekDBTask
} }
foreach ($records as $record) { foreach ($records as $record) {
SeekDBBase::upsertTaskUser($record->task_id, $record->userid); ManticoreBase::upsertTaskUser($record->task_id, $record->userid);
$count++; $count++;
$lastId = $record->id; $lastId = $record->id;
} }
@ -577,7 +576,7 @@ class SeekDBTask
*/ */
public static function syncTaskUsersIncremental(?callable $progressCallback = null): int public static function syncTaskUsersIncremental(?callable $progressCallback = null): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
@ -585,8 +584,8 @@ class SeekDBTask
$batchSize = 1000; $batchSize = 1000;
// 同步 ProjectTaskUser 新增 // 同步 ProjectTaskUser 新增
$lastKey1 = "sync:seekdbTaskUserLastId"; $lastKey1 = "sync:manticoreTaskUserLastId";
$lastId1 = intval(SeekDBKeyValue::get($lastKey1, 0)); $lastId1 = intval(ManticoreKeyValue::get($lastKey1, 0));
while (true) { while (true) {
$records = ProjectTaskUser::where('id', '>', $lastId1) $records = ProjectTaskUser::where('id', '>', $lastId1)
@ -599,15 +598,15 @@ class SeekDBTask
} }
foreach ($records as $record) { foreach ($records as $record) {
SeekDBBase::upsertTaskUser($record->task_id, $record->userid); ManticoreBase::upsertTaskUser($record->task_id, $record->userid);
if ($record->task_pid) { if ($record->task_pid) {
SeekDBBase::upsertTaskUser($record->task_pid, $record->userid); ManticoreBase::upsertTaskUser($record->task_pid, $record->userid);
} }
$count++; $count++;
$lastId1 = $record->id; $lastId1 = $record->id;
} }
SeekDBKeyValue::set($lastKey1, $lastId1); ManticoreKeyValue::set($lastKey1, $lastId1);
if ($progressCallback) { if ($progressCallback) {
$progressCallback($count); $progressCallback($count);
@ -615,8 +614,8 @@ class SeekDBTask
} }
// 同步 ProjectTaskVisibilityUser 新增 // 同步 ProjectTaskVisibilityUser 新增
$lastKey2 = "sync:seekdbTaskVisibilityUserLastId"; $lastKey2 = "sync:manticoreTaskVisibilityUserLastId";
$lastId2 = intval(SeekDBKeyValue::get($lastKey2, 0)); $lastId2 = intval(ManticoreKeyValue::get($lastKey2, 0));
while (true) { while (true) {
$records = ProjectTaskVisibilityUser::where('id', '>', $lastId2) $records = ProjectTaskVisibilityUser::where('id', '>', $lastId2)
@ -629,12 +628,12 @@ class SeekDBTask
} }
foreach ($records as $record) { foreach ($records as $record) {
SeekDBBase::upsertTaskUser($record->task_id, $record->userid); ManticoreBase::upsertTaskUser($record->task_id, $record->userid);
$count++; $count++;
$lastId2 = $record->id; $lastId2 = $record->id;
} }
SeekDBKeyValue::set($lastKey2, $lastId2); ManticoreKeyValue::set($lastKey2, $lastId2);
if ($progressCallback) { if ($progressCallback) {
$progressCallback($count); $progressCallback($count);

View File

@ -1,6 +1,6 @@
<?php <?php
namespace App\Module\SeekDB; namespace App\Module\Manticore;
use App\Models\User; use App\Models\User;
use App\Module\Apps; use App\Module\Apps;
@ -9,7 +9,7 @@ use App\Module\AI;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/** /**
* SeekDB 用户搜索类(联系人搜索) * Manticore Search 用户搜索类(联系人搜索)
* *
* 使用方法: * 使用方法:
* *
@ -24,7 +24,7 @@ use Illuminate\Support\Facades\Log;
* 3. 工具方法 * 3. 工具方法
* - 清空索引: clear(); * - 清空索引: clear();
*/ */
class SeekDBUser class ManticoreUser
{ {
/** /**
* 搜索用户(支持全文、向量、混合搜索) * 搜索用户(支持全文、向量、混合搜索)
@ -40,7 +40,7 @@ class SeekDBUser
return []; return [];
} }
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return []; return [];
} }
@ -48,29 +48,29 @@ class SeekDBUser
switch ($searchType) { switch ($searchType) {
case 'text': case 'text':
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::userFullTextSearch($keyword, $limit, 0) ManticoreBase::userFullTextSearch($keyword, $limit, 0)
); );
case 'vector': case 'vector':
$embedding = self::getEmbedding($keyword); $embedding = self::getEmbedding($keyword);
if (empty($embedding)) { if (empty($embedding)) {
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::userFullTextSearch($keyword, $limit, 0) ManticoreBase::userFullTextSearch($keyword, $limit, 0)
); );
} }
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::userVectorSearch($embedding, $limit) ManticoreBase::userVectorSearch($embedding, $limit)
); );
case 'hybrid': case 'hybrid':
default: default:
$embedding = self::getEmbedding($keyword); $embedding = self::getEmbedding($keyword);
return self::formatSearchResults( return self::formatSearchResults(
SeekDBBase::userHybridSearch($keyword, $embedding, $limit) ManticoreBase::userHybridSearch($keyword, $embedding, $limit)
); );
} }
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB user search error: ' . $e->getMessage()); Log::error('Manticore user search error: ' . $e->getMessage());
return []; return [];
} }
} }
@ -102,7 +102,7 @@ class SeekDBUser
/** /**
* 格式化搜索结果 * 格式化搜索结果
* *
* @param array $results SeekDB 返回的结果 * @param array $results Manticore 返回的结果
* @return array 格式化后的结果 * @return array 格式化后的结果
*/ */
private static function formatSearchResults(array $results): array private static function formatSearchResults(array $results): array
@ -127,14 +127,14 @@ class SeekDBUser
// ============================== // ==============================
/** /**
* 同步单个用户到 SeekDB * 同步单个用户到 Manticore
* *
* @param User $user 用户模型 * @param User $user 用户模型
* @return bool 是否成功 * @return bool 是否成功
*/ */
public static function sync(User $user): bool public static function sync(User $user): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
@ -161,8 +161,8 @@ class SeekDBUser
} }
} }
// 写入 SeekDB // 写入 Manticore
$result = SeekDBBase::upsertUserVector([ $result = ManticoreBase::upsertUserVector([
'userid' => $user->userid, 'userid' => $user->userid,
'nickname' => $user->nickname ?? '', 'nickname' => $user->nickname ?? '',
'email' => $user->email ?? '', 'email' => $user->email ?? '',
@ -174,7 +174,7 @@ class SeekDBUser
return $result; return $result;
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SeekDB user sync error: ' . $e->getMessage(), [ Log::error('Manticore user sync error: ' . $e->getMessage(), [
'userid' => $user->userid, 'userid' => $user->userid,
'nickname' => $user->nickname, 'nickname' => $user->nickname,
]); ]);
@ -216,7 +216,7 @@ class SeekDBUser
*/ */
public static function batchSync(iterable $users): int public static function batchSync(iterable $users): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
@ -237,11 +237,11 @@ class SeekDBUser
*/ */
public static function delete(int $userid): bool public static function delete(int $userid): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
return SeekDBBase::deleteUserVector($userid); return ManticoreBase::deleteUserVector($userid);
} }
/** /**
@ -251,11 +251,11 @@ class SeekDBUser
*/ */
public static function clear(): bool public static function clear(): bool
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return false; return false;
} }
return SeekDBBase::clearAllUserVectors(); return ManticoreBase::clearAllUserVectors();
} }
/** /**
@ -265,11 +265,11 @@ class SeekDBUser
*/ */
public static function getIndexedCount(): int public static function getIndexedCount(): int
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return 0; return 0;
} }
return SeekDBBase::getIndexedUserCount(); return ManticoreBase::getIndexedUserCount();
} }
} }

View File

@ -1,181 +0,0 @@
<?php
namespace App\Module\SeekDB;
use App\Module\Apps;
use Illuminate\Support\Facades\Log;
/**
* SeekDB 键值存储类
*
* 用于存储同步进度、配置等键值数据
*
* 使用方法:
*
* 1. 基本操作
* - 设置键值: set('sync_last_id', 12345);
* - 获取键值: $lastId = get('sync_last_id', 0);
* - 删除键值: delete('sync_last_id');
*
* 2. 批量操作
* - 批量设置: batchSet(['key1' => 'value1', 'key2' => 'value2']);
* - 批量获取: $values = batchGet(['key1', 'key2']);
*/
class SeekDBKeyValue
{
/**
* 设置键值
*
* @param string $key 键名
* @param mixed $value 值(会被 JSON 编码)
* @return bool 是否成功
*/
public static function set(string $key, mixed $value): bool
{
if (!Apps::isInstalled("seekdb") || empty($key)) {
return false;
}
$instance = new SeekDBBase();
$jsonValue = is_string($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE);
// 使用 REPLACE INTO 实现 upsert
$sql = "REPLACE INTO key_values (k, v, updated_at) VALUES (?, ?, NOW())";
return $instance->execute($sql, [$key, $jsonValue]);
}
/**
* 获取键值
*
* @param string $key 键名
* @param mixed $default 默认值
* @return mixed 值或默认值
*/
public static function get(string $key, mixed $default = null): mixed
{
if (!Apps::isInstalled("seekdb") || empty($key)) {
return $default;
}
$instance = new SeekDBBase();
$result = $instance->queryOne(
"SELECT v FROM key_values WHERE k = ?",
[$key]
);
if (!$result || !isset($result['v'])) {
return $default;
}
$value = $result['v'];
// 尝试 JSON 解码
$decoded = json_decode($value, true);
if (json_last_error() === JSON_ERROR_NONE) {
return $decoded;
}
return $value;
}
/**
* 删除键值
*
* @param string $key 键名
* @return bool 是否成功
*/
public static function delete(string $key): bool
{
if (!Apps::isInstalled("seekdb") || empty($key)) {
return false;
}
$instance = new SeekDBBase();
return $instance->execute(
"DELETE FROM key_values WHERE k = ?",
[$key]
);
}
/**
* 批量设置键值
*
* @param array $keyValues 键值对数组
* @return bool 是否全部成功
*/
public static function batchSet(array $keyValues): bool
{
if (!Apps::isInstalled("seekdb") || empty($keyValues)) {
return false;
}
$instance = new SeekDBBase();
$success = true;
foreach ($keyValues as $key => $value) {
$jsonValue = is_string($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE);
$result = $instance->execute(
"REPLACE INTO key_values (k, v, updated_at) VALUES (?, ?, NOW())",
[$key, $jsonValue]
);
if (!$result) {
$success = false;
}
}
return $success;
}
/**
* 批量获取键值
*
* @param array $keys 键名数组
* @return array 键值对数组
*/
public static function batchGet(array $keys): array
{
if (!Apps::isInstalled("seekdb") || empty($keys)) {
return [];
}
$instance = new SeekDBBase();
$placeholders = implode(',', array_fill(0, count($keys), '?'));
$results = $instance->query(
"SELECT k, v FROM key_values WHERE k IN ({$placeholders})",
$keys
);
$values = [];
foreach ($results as $row) {
$value = $row['v'];
$decoded = json_decode($value, true);
$values[$row['k']] = (json_last_error() === JSON_ERROR_NONE) ? $decoded : $value;
}
// 填充未找到的键为 null
foreach ($keys as $key) {
if (!isset($values[$key])) {
$values[$key] = null;
}
}
return $values;
}
/**
* 清空所有键值
*
* @return bool 是否成功
*/
public static function clear(): bool
{
if (!Apps::isInstalled("seekdb")) {
return false;
}
$instance = new SeekDBBase();
return $instance->execute("TRUNCATE TABLE key_values");
}
}

View File

@ -3,7 +3,7 @@
namespace App\Observers; namespace App\Observers;
use App\Models\File; use App\Models\File;
use App\Tasks\SeekDBSyncTask; use App\Tasks\ManticoreSyncTask;
class FileObserver extends AbstractObserver class FileObserver extends AbstractObserver
{ {
@ -19,7 +19,7 @@ class FileObserver extends AbstractObserver
if ($file->type === 'folder') { if ($file->type === 'folder') {
return; return;
} }
self::taskDeliver(new SeekDBSyncTask('file_sync', $file->toArray())); self::taskDeliver(new ManticoreSyncTask('file_sync', $file->toArray()));
} }
/** /**
@ -41,7 +41,7 @@ class FileObserver extends AbstractObserver
->pluck('id') ->pluck('id')
->toArray(); ->toArray();
if (!empty($childFileIds)) { if (!empty($childFileIds)) {
self::taskDeliver(new SeekDBSyncTask('file_pshare_update', [ self::taskDeliver(new ManticoreSyncTask('file_pshare_update', [
'file_ids' => $childFileIds, 'file_ids' => $childFileIds,
'pshare' => $newPshare, 'pshare' => $newPshare,
])); ]));
@ -53,7 +53,7 @@ class FileObserver extends AbstractObserver
if ($file->type === 'folder') { if ($file->type === 'folder') {
return; return;
} }
self::taskDeliver(new SeekDBSyncTask('file_sync', $file->toArray())); self::taskDeliver(new ManticoreSyncTask('file_sync', $file->toArray()));
} }
/** /**
@ -64,7 +64,7 @@ class FileObserver extends AbstractObserver
*/ */
public function deleted(File $file) public function deleted(File $file)
{ {
self::taskDeliver(new SeekDBSyncTask('file_delete', $file->toArray())); self::taskDeliver(new ManticoreSyncTask('file_delete', $file->toArray()));
} }
/** /**
@ -79,7 +79,7 @@ class FileObserver extends AbstractObserver
if ($file->type === 'folder') { if ($file->type === 'folder') {
return; return;
} }
self::taskDeliver(new SeekDBSyncTask('file_sync', $file->toArray())); self::taskDeliver(new ManticoreSyncTask('file_sync', $file->toArray()));
} }
/** /**
@ -90,7 +90,7 @@ class FileObserver extends AbstractObserver
*/ */
public function forceDeleted(File $file) public function forceDeleted(File $file)
{ {
self::taskDeliver(new SeekDBSyncTask('file_delete', $file->toArray())); self::taskDeliver(new ManticoreSyncTask('file_delete', $file->toArray()));
} }
} }

View File

@ -3,7 +3,7 @@
namespace App\Observers; namespace App\Observers;
use App\Models\FileUser; use App\Models\FileUser;
use App\Tasks\SeekDBSyncTask; use App\Tasks\ManticoreSyncTask;
class FileUserObserver extends AbstractObserver class FileUserObserver extends AbstractObserver
{ {
@ -15,7 +15,7 @@ class FileUserObserver extends AbstractObserver
*/ */
public function created(FileUser $fileUser) public function created(FileUser $fileUser)
{ {
self::taskDeliver(new SeekDBSyncTask('file_user_add', [ self::taskDeliver(new ManticoreSyncTask('file_user_add', [
'file_id' => $fileUser->file_id, 'file_id' => $fileUser->file_id,
'userid' => $fileUser->userid, 'userid' => $fileUser->userid,
'permission' => $fileUser->permission, 'permission' => $fileUser->permission,
@ -30,7 +30,7 @@ class FileUserObserver extends AbstractObserver
*/ */
public function updated(FileUser $fileUser) public function updated(FileUser $fileUser)
{ {
self::taskDeliver(new SeekDBSyncTask('file_user_add', [ self::taskDeliver(new ManticoreSyncTask('file_user_add', [
'file_id' => $fileUser->file_id, 'file_id' => $fileUser->file_id,
'userid' => $fileUser->userid, 'userid' => $fileUser->userid,
'permission' => $fileUser->permission, 'permission' => $fileUser->permission,
@ -45,7 +45,7 @@ class FileUserObserver extends AbstractObserver
*/ */
public function deleted(FileUser $fileUser) public function deleted(FileUser $fileUser)
{ {
self::taskDeliver(new SeekDBSyncTask('file_user_remove', [ self::taskDeliver(new ManticoreSyncTask('file_user_remove', [
'file_id' => $fileUser->file_id, 'file_id' => $fileUser->file_id,
'userid' => $fileUser->userid, 'userid' => $fileUser->userid,
])); ]));

View File

@ -5,7 +5,7 @@ namespace App\Observers;
use App\Models\Deleted; use App\Models\Deleted;
use App\Models\Project; use App\Models\Project;
use App\Models\ProjectUser; use App\Models\ProjectUser;
use App\Tasks\SeekDBSyncTask; use App\Tasks\ManticoreSyncTask;
class ProjectObserver extends AbstractObserver class ProjectObserver extends AbstractObserver
{ {
@ -17,7 +17,7 @@ class ProjectObserver extends AbstractObserver
*/ */
public function created(Project $project) public function created(Project $project)
{ {
self::taskDeliver(new SeekDBSyncTask('project_sync', $project->toArray())); self::taskDeliver(new ManticoreSyncTask('project_sync', $project->toArray()));
} }
/** /**
@ -49,9 +49,9 @@ class ProjectObserver extends AbstractObserver
if ($isDirty) { if ($isDirty) {
if ($project->archived_at) { if ($project->archived_at) {
self::taskDeliver(new SeekDBSyncTask('project_delete', ['project_id' => $project->id])); self::taskDeliver(new ManticoreSyncTask('project_delete', ['project_id' => $project->id]));
} else { } else {
self::taskDeliver(new SeekDBSyncTask('project_sync', $project->toArray())); self::taskDeliver(new ManticoreSyncTask('project_sync', $project->toArray()));
} }
} }
} }
@ -65,7 +65,7 @@ class ProjectObserver extends AbstractObserver
public function deleted(Project $project) public function deleted(Project $project)
{ {
Deleted::record('project', $project->id, $this->userids($project)); Deleted::record('project', $project->id, $this->userids($project));
self::taskDeliver(new SeekDBSyncTask('project_delete', ['project_id' => $project->id])); self::taskDeliver(new ManticoreSyncTask('project_delete', ['project_id' => $project->id]));
} }
/** /**
@ -77,7 +77,7 @@ class ProjectObserver extends AbstractObserver
public function restored(Project $project) public function restored(Project $project)
{ {
Deleted::forget('project', $project->id, $this->userids($project)); Deleted::forget('project', $project->id, $this->userids($project));
self::taskDeliver(new SeekDBSyncTask('project_sync', $project->toArray())); self::taskDeliver(new ManticoreSyncTask('project_sync', $project->toArray()));
} }
/** /**
@ -88,7 +88,7 @@ class ProjectObserver extends AbstractObserver
*/ */
public function forceDeleted(Project $project) public function forceDeleted(Project $project)
{ {
self::taskDeliver(new SeekDBSyncTask('project_delete', ['project_id' => $project->id])); self::taskDeliver(new ManticoreSyncTask('project_delete', ['project_id' => $project->id]));
} }
/** /**

View File

@ -7,7 +7,7 @@ use App\Models\ProjectTask;
use App\Models\ProjectTaskUser; use App\Models\ProjectTaskUser;
use App\Models\ProjectTaskVisibilityUser; use App\Models\ProjectTaskVisibilityUser;
use App\Models\ProjectUser; use App\Models\ProjectUser;
use App\Tasks\SeekDBSyncTask; use App\Tasks\ManticoreSyncTask;
class ProjectTaskObserver extends AbstractObserver class ProjectTaskObserver extends AbstractObserver
{ {
@ -19,7 +19,7 @@ class ProjectTaskObserver extends AbstractObserver
*/ */
public function created(ProjectTask $projectTask) public function created(ProjectTask $projectTask)
{ {
self::taskDeliver(new SeekDBSyncTask('task_sync', $projectTask->toArray())); self::taskDeliver(new ManticoreSyncTask('task_sync', $projectTask->toArray()));
} }
/** /**
@ -32,8 +32,8 @@ class ProjectTaskObserver extends AbstractObserver
{ {
if ($projectTask->isDirty('visibility')) { if ($projectTask->isDirty('visibility')) {
self::visibilityUpdate($projectTask); self::visibilityUpdate($projectTask);
// 同步 visibility 变化到 SeekDB // 同步 visibility 变化到 Manticore
self::taskDeliver(new SeekDBSyncTask('task_visibility_update', [ self::taskDeliver(new ManticoreSyncTask('task_visibility_update', [
'task_id' => $projectTask->id, 'task_id' => $projectTask->id,
'visibility' => $projectTask->visibility, 'visibility' => $projectTask->visibility,
])); ]));
@ -59,9 +59,9 @@ class ProjectTaskObserver extends AbstractObserver
if ($isDirty) { if ($isDirty) {
if ($projectTask->archived_at) { if ($projectTask->archived_at) {
self::taskDeliver(new SeekDBSyncTask('task_delete', ['task_id' => $projectTask->id])); self::taskDeliver(new ManticoreSyncTask('task_delete', ['task_id' => $projectTask->id]));
} else { } else {
self::taskDeliver(new SeekDBSyncTask('task_sync', $projectTask->toArray())); self::taskDeliver(new ManticoreSyncTask('task_sync', $projectTask->toArray()));
} }
} }
} }
@ -75,7 +75,7 @@ class ProjectTaskObserver extends AbstractObserver
public function deleted(ProjectTask $projectTask) public function deleted(ProjectTask $projectTask)
{ {
Deleted::record('projectTask', $projectTask->id, self::userids($projectTask)); Deleted::record('projectTask', $projectTask->id, self::userids($projectTask));
self::taskDeliver(new SeekDBSyncTask('task_delete', ['task_id' => $projectTask->id])); self::taskDeliver(new ManticoreSyncTask('task_delete', ['task_id' => $projectTask->id]));
} }
/** /**
@ -87,7 +87,7 @@ class ProjectTaskObserver extends AbstractObserver
public function restored(ProjectTask $projectTask) public function restored(ProjectTask $projectTask)
{ {
Deleted::forget('projectTask', $projectTask->id, self::userids($projectTask)); Deleted::forget('projectTask', $projectTask->id, self::userids($projectTask));
self::taskDeliver(new SeekDBSyncTask('task_sync', $projectTask->toArray())); self::taskDeliver(new ManticoreSyncTask('task_sync', $projectTask->toArray()));
} }
/** /**
@ -98,7 +98,7 @@ class ProjectTaskObserver extends AbstractObserver
*/ */
public function forceDeleted(ProjectTask $projectTask) public function forceDeleted(ProjectTask $projectTask)
{ {
self::taskDeliver(new SeekDBSyncTask('task_delete', ['task_id' => $projectTask->id])); self::taskDeliver(new ManticoreSyncTask('task_delete', ['task_id' => $projectTask->id]));
} }
/** /**

View File

@ -5,7 +5,7 @@ namespace App\Observers;
use App\Models\Deleted; use App\Models\Deleted;
use App\Models\ProjectTaskUser; use App\Models\ProjectTaskUser;
use App\Models\ProjectUser; use App\Models\ProjectUser;
use App\Tasks\SeekDBSyncTask; use App\Tasks\ManticoreSyncTask;
class ProjectTaskUserObserver extends AbstractObserver class ProjectTaskUserObserver extends AbstractObserver
{ {
@ -22,14 +22,14 @@ class ProjectTaskUserObserver extends AbstractObserver
Deleted::forget('projectTask', $projectTaskUser->task_pid, $projectTaskUser->userid); Deleted::forget('projectTask', $projectTaskUser->task_pid, $projectTaskUser->userid);
} }
// 同步任务成员到 SeekDB // 同步任务成员到 Manticore
self::taskDeliver(new SeekDBSyncTask('task_user_add', [ self::taskDeliver(new ManticoreSyncTask('task_user_add', [
'task_id' => $projectTaskUser->task_id, 'task_id' => $projectTaskUser->task_id,
'userid' => $projectTaskUser->userid, 'userid' => $projectTaskUser->userid,
])); ]));
// 如果是子任务,同时添加到父任务 // 如果是子任务,同时添加到父任务
if ($projectTaskUser->task_pid) { if ($projectTaskUser->task_pid) {
self::taskDeliver(new SeekDBSyncTask('task_user_add', [ self::taskDeliver(new ManticoreSyncTask('task_user_add', [
'task_id' => $projectTaskUser->task_pid, 'task_id' => $projectTaskUser->task_pid,
'userid' => $projectTaskUser->userid, 'userid' => $projectTaskUser->userid,
])); ]));
@ -59,8 +59,8 @@ class ProjectTaskUserObserver extends AbstractObserver
Deleted::record('projectTask', $projectTaskUser->task_id, $projectTaskUser->userid); Deleted::record('projectTask', $projectTaskUser->task_id, $projectTaskUser->userid);
} }
// 从 SeekDB 删除任务成员关系 // 从 Manticore 删除任务成员关系
self::taskDeliver(new SeekDBSyncTask('task_user_remove', [ self::taskDeliver(new ManticoreSyncTask('task_user_remove', [
'task_id' => $projectTaskUser->task_id, 'task_id' => $projectTaskUser->task_id,
'userid' => $projectTaskUser->userid, 'userid' => $projectTaskUser->userid,
])); ]));

View File

@ -3,7 +3,7 @@
namespace App\Observers; namespace App\Observers;
use App\Models\ProjectTaskVisibilityUser; use App\Models\ProjectTaskVisibilityUser;
use App\Tasks\SeekDBSyncTask; use App\Tasks\ManticoreSyncTask;
/** /**
* ProjectTaskVisibilityUser 观察者 * ProjectTaskVisibilityUser 观察者
@ -20,8 +20,8 @@ class ProjectTaskVisibilityUserObserver extends AbstractObserver
*/ */
public function created(ProjectTaskVisibilityUser $visibilityUser) public function created(ProjectTaskVisibilityUser $visibilityUser)
{ {
// 将指定成员添加到 SeekDB 的 task_users 表 // 将指定成员添加到 Manticore 的 task_users 表
self::taskDeliver(new SeekDBSyncTask('task_user_add', [ self::taskDeliver(new ManticoreSyncTask('task_user_add', [
'task_id' => $visibilityUser->task_id, 'task_id' => $visibilityUser->task_id,
'userid' => $visibilityUser->userid, 'userid' => $visibilityUser->userid,
])); ]));
@ -36,7 +36,7 @@ class ProjectTaskVisibilityUserObserver extends AbstractObserver
public function updated(ProjectTaskVisibilityUser $visibilityUser) public function updated(ProjectTaskVisibilityUser $visibilityUser)
{ {
// 通常不会更新,但如果更新了也同步 // 通常不会更新,但如果更新了也同步
self::taskDeliver(new SeekDBSyncTask('task_user_add', [ self::taskDeliver(new ManticoreSyncTask('task_user_add', [
'task_id' => $visibilityUser->task_id, 'task_id' => $visibilityUser->task_id,
'userid' => $visibilityUser->userid, 'userid' => $visibilityUser->userid,
])); ]));
@ -50,10 +50,10 @@ class ProjectTaskVisibilityUserObserver extends AbstractObserver
*/ */
public function deleted(ProjectTaskVisibilityUser $visibilityUser) public function deleted(ProjectTaskVisibilityUser $visibilityUser)
{ {
// 从 SeekDB 的 task_users 表删除该成员 // 从 Manticore 的 task_users 表删除该成员
// 注意:需要检查该用户是否仍是任务的负责人/协作人 // 注意:需要检查该用户是否仍是任务的负责人/协作人
// 如果是,则不应该删除(因为 ProjectTaskUser 仍存在) // 如果是,则不应该删除(因为 ProjectTaskUser 仍存在)
self::taskDeliver(new SeekDBSyncTask('task_visibility_user_remove', [ self::taskDeliver(new ManticoreSyncTask('task_visibility_user_remove', [
'task_id' => $visibilityUser->task_id, 'task_id' => $visibilityUser->task_id,
'userid' => $visibilityUser->userid, 'userid' => $visibilityUser->userid,
])); ]));

View File

@ -4,7 +4,7 @@ namespace App\Observers;
use App\Models\Deleted; use App\Models\Deleted;
use App\Models\ProjectUser; use App\Models\ProjectUser;
use App\Tasks\SeekDBSyncTask; use App\Tasks\ManticoreSyncTask;
class ProjectUserObserver extends AbstractObserver class ProjectUserObserver extends AbstractObserver
{ {
@ -17,7 +17,7 @@ class ProjectUserObserver extends AbstractObserver
public function created(ProjectUser $projectUser) public function created(ProjectUser $projectUser)
{ {
Deleted::forget('project', $projectUser->project_id, $projectUser->userid); Deleted::forget('project', $projectUser->project_id, $projectUser->userid);
self::taskDeliver(new SeekDBSyncTask('project_user_add', [ self::taskDeliver(new ManticoreSyncTask('project_user_add', [
'project_id' => $projectUser->project_id, 'project_id' => $projectUser->project_id,
'userid' => $projectUser->userid, 'userid' => $projectUser->userid,
])); ]));
@ -43,7 +43,7 @@ class ProjectUserObserver extends AbstractObserver
public function deleted(ProjectUser $projectUser) public function deleted(ProjectUser $projectUser)
{ {
Deleted::record('project', $projectUser->project_id, $projectUser->userid); Deleted::record('project', $projectUser->project_id, $projectUser->userid);
self::taskDeliver(new SeekDBSyncTask('project_user_remove', [ self::taskDeliver(new ManticoreSyncTask('project_user_remove', [
'project_id' => $projectUser->project_id, 'project_id' => $projectUser->project_id,
'userid' => $projectUser->userid, 'userid' => $projectUser->userid,
])); ]));

View File

@ -3,7 +3,7 @@
namespace App\Observers; namespace App\Observers;
use App\Models\User; use App\Models\User;
use App\Tasks\SeekDBSyncTask; use App\Tasks\ManticoreSyncTask;
class UserObserver extends AbstractObserver class UserObserver extends AbstractObserver
{ {
@ -19,7 +19,7 @@ class UserObserver extends AbstractObserver
if ($user->bot) { if ($user->bot) {
return; return;
} }
self::taskDeliver(new SeekDBSyncTask('user_sync', $user->toArray())); self::taskDeliver(new ManticoreSyncTask('user_sync', $user->toArray()));
} }
/** /**
@ -48,9 +48,9 @@ class UserObserver extends AbstractObserver
if ($isDirty) { if ($isDirty) {
// 如果用户被禁用,删除索引;否则更新索引 // 如果用户被禁用,删除索引;否则更新索引
if ($user->disable_at) { if ($user->disable_at) {
self::taskDeliver(new SeekDBSyncTask('user_delete', ['userid' => $user->userid])); self::taskDeliver(new ManticoreSyncTask('user_delete', ['userid' => $user->userid]));
} else { } else {
self::taskDeliver(new SeekDBSyncTask('user_sync', $user->toArray())); self::taskDeliver(new ManticoreSyncTask('user_sync', $user->toArray()));
} }
} }
} }
@ -63,7 +63,7 @@ class UserObserver extends AbstractObserver
*/ */
public function deleted(User $user) public function deleted(User $user)
{ {
self::taskDeliver(new SeekDBSyncTask('user_delete', ['userid' => $user->userid])); self::taskDeliver(new ManticoreSyncTask('user_delete', ['userid' => $user->userid]));
} }
} }

View File

@ -7,20 +7,20 @@ use App\Models\User;
use App\Models\Project; use App\Models\Project;
use App\Models\ProjectTask; use App\Models\ProjectTask;
use App\Module\Apps; use App\Module\Apps;
use App\Module\SeekDB\SeekDBBase; use App\Module\Manticore\ManticoreBase;
use App\Module\SeekDB\SeekDBFile; use App\Module\Manticore\ManticoreFile;
use App\Module\SeekDB\SeekDBUser; use App\Module\Manticore\ManticoreUser;
use App\Module\SeekDB\SeekDBProject; use App\Module\Manticore\ManticoreProject;
use App\Module\SeekDB\SeekDBTask; use App\Module\Manticore\ManticoreTask;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
/** /**
* 通用 SeekDB 同步任务 * 通用 Manticore Search 同步任务
* *
* 支持文件、用户、项目、任务的同步操作 * 支持文件、用户、项目、任务的同步操作
*/ */
class SeekDBSyncTask extends AbstractTask class ManticoreSyncTask extends AbstractTask
{ {
private $action; private $action;
@ -35,7 +35,7 @@ class SeekDBSyncTask extends AbstractTask
public function start() public function start()
{ {
if (!Apps::isInstalled("seekdb")) { if (!Apps::isInstalled("manticore")) {
return; return;
} }
@ -46,21 +46,21 @@ class SeekDBSyncTask extends AbstractTask
case 'file_sync': case 'file_sync':
$file = File::find($this->data['id'] ?? 0); $file = File::find($this->data['id'] ?? 0);
if ($file) { if ($file) {
SeekDBFile::sync($file); ManticoreFile::sync($file);
} }
break; break;
case 'file_delete': case 'file_delete':
$fileId = $this->data['id'] ?? 0; $fileId = $this->data['id'] ?? 0;
if ($fileId > 0) { if ($fileId > 0) {
SeekDBFile::delete($fileId); ManticoreFile::delete($fileId);
} }
break; break;
case 'file_user_sync': case 'file_user_sync':
$fileId = $this->data['file_id'] ?? 0; $fileId = $this->data['file_id'] ?? 0;
if ($fileId > 0) { if ($fileId > 0) {
SeekDBFile::syncFileUsers($fileId); ManticoreFile::syncFileUsers($fileId);
} }
break; break;
@ -69,7 +69,7 @@ class SeekDBSyncTask extends AbstractTask
$userid = $this->data['userid'] ?? 0; $userid = $this->data['userid'] ?? 0;
$permission = $this->data['permission'] ?? 0; $permission = $this->data['permission'] ?? 0;
if ($fileId > 0) { if ($fileId > 0) {
SeekDBFile::addFileUser($fileId, $userid, $permission); ManticoreFile::addFileUser($fileId, $userid, $permission);
} }
break; break;
@ -77,7 +77,7 @@ class SeekDBSyncTask extends AbstractTask
$fileId = $this->data['file_id'] ?? 0; $fileId = $this->data['file_id'] ?? 0;
$userid = $this->data['userid'] ?? null; $userid = $this->data['userid'] ?? null;
if ($fileId > 0) { if ($fileId > 0) {
SeekDBFile::removeFileUser($fileId, $userid); ManticoreFile::removeFileUser($fileId, $userid);
} }
break; break;
@ -85,7 +85,7 @@ class SeekDBSyncTask extends AbstractTask
$fileIds = $this->data['file_ids'] ?? []; $fileIds = $this->data['file_ids'] ?? [];
$pshare = $this->data['pshare'] ?? 0; $pshare = $this->data['pshare'] ?? 0;
if (!empty($fileIds)) { if (!empty($fileIds)) {
SeekDBBase::batchUpdatePshare($fileIds, $pshare); ManticoreBase::batchUpdatePshare($fileIds, $pshare);
} }
break; break;
@ -95,14 +95,14 @@ class SeekDBSyncTask extends AbstractTask
case 'user_sync': case 'user_sync':
$user = User::find($this->data['userid'] ?? 0); $user = User::find($this->data['userid'] ?? 0);
if ($user) { if ($user) {
SeekDBUser::sync($user); ManticoreUser::sync($user);
} }
break; break;
case 'user_delete': case 'user_delete':
$userid = $this->data['userid'] ?? 0; $userid = $this->data['userid'] ?? 0;
if ($userid > 0) { if ($userid > 0) {
SeekDBUser::delete($userid); ManticoreUser::delete($userid);
} }
break; break;
@ -112,14 +112,14 @@ class SeekDBSyncTask extends AbstractTask
case 'project_sync': case 'project_sync':
$project = Project::find($this->data['id'] ?? 0); $project = Project::find($this->data['id'] ?? 0);
if ($project) { if ($project) {
SeekDBProject::sync($project); ManticoreProject::sync($project);
} }
break; break;
case 'project_delete': case 'project_delete':
$projectId = $this->data['project_id'] ?? 0; $projectId = $this->data['project_id'] ?? 0;
if ($projectId > 0) { if ($projectId > 0) {
SeekDBProject::delete($projectId); ManticoreProject::delete($projectId);
} }
break; break;
@ -127,7 +127,7 @@ class SeekDBSyncTask extends AbstractTask
$projectId = $this->data['project_id'] ?? 0; $projectId = $this->data['project_id'] ?? 0;
$userid = $this->data['userid'] ?? 0; $userid = $this->data['userid'] ?? 0;
if ($projectId > 0 && $userid > 0) { if ($projectId > 0 && $userid > 0) {
SeekDBProject::addProjectUser($projectId, $userid); ManticoreProject::addProjectUser($projectId, $userid);
} }
break; break;
@ -135,14 +135,14 @@ class SeekDBSyncTask extends AbstractTask
$projectId = $this->data['project_id'] ?? 0; $projectId = $this->data['project_id'] ?? 0;
$userid = $this->data['userid'] ?? 0; $userid = $this->data['userid'] ?? 0;
if ($projectId > 0 && $userid > 0) { if ($projectId > 0 && $userid > 0) {
SeekDBProject::removeProjectUser($projectId, $userid); ManticoreProject::removeProjectUser($projectId, $userid);
} }
break; break;
case 'project_users_sync': case 'project_users_sync':
$projectId = $this->data['project_id'] ?? 0; $projectId = $this->data['project_id'] ?? 0;
if ($projectId > 0) { if ($projectId > 0) {
SeekDBProject::syncProjectUsers($projectId); ManticoreProject::syncProjectUsers($projectId);
} }
break; break;
@ -152,14 +152,14 @@ class SeekDBSyncTask extends AbstractTask
case 'task_sync': case 'task_sync':
$task = ProjectTask::find($this->data['id'] ?? 0); $task = ProjectTask::find($this->data['id'] ?? 0);
if ($task) { if ($task) {
SeekDBTask::sync($task); ManticoreTask::sync($task);
} }
break; break;
case 'task_delete': case 'task_delete':
$taskId = $this->data['task_id'] ?? 0; $taskId = $this->data['task_id'] ?? 0;
if ($taskId > 0) { if ($taskId > 0) {
SeekDBTask::delete($taskId); ManticoreTask::delete($taskId);
} }
break; break;
@ -167,7 +167,7 @@ class SeekDBSyncTask extends AbstractTask
$taskId = $this->data['task_id'] ?? 0; $taskId = $this->data['task_id'] ?? 0;
$visibility = $this->data['visibility'] ?? 1; $visibility = $this->data['visibility'] ?? 1;
if ($taskId > 0) { if ($taskId > 0) {
SeekDBTask::updateVisibility($taskId, $visibility); ManticoreTask::updateVisibility($taskId, $visibility);
} }
break; break;
@ -175,7 +175,7 @@ class SeekDBSyncTask extends AbstractTask
$taskId = $this->data['task_id'] ?? 0; $taskId = $this->data['task_id'] ?? 0;
$userid = $this->data['userid'] ?? 0; $userid = $this->data['userid'] ?? 0;
if ($taskId > 0 && $userid > 0) { if ($taskId > 0 && $userid > 0) {
SeekDBTask::addTaskUser($taskId, $userid); ManticoreTask::addTaskUser($taskId, $userid);
} }
break; break;
@ -183,7 +183,7 @@ class SeekDBSyncTask extends AbstractTask
$taskId = $this->data['task_id'] ?? 0; $taskId = $this->data['task_id'] ?? 0;
$userid = $this->data['userid'] ?? 0; $userid = $this->data['userid'] ?? 0;
if ($taskId > 0 && $userid > 0) { if ($taskId > 0 && $userid > 0) {
SeekDBTask::removeTaskUser($taskId, $userid); ManticoreTask::removeTaskUser($taskId, $userid);
} }
break; break;
@ -192,14 +192,14 @@ class SeekDBSyncTask extends AbstractTask
$taskId = $this->data['task_id'] ?? 0; $taskId = $this->data['task_id'] ?? 0;
$userid = $this->data['userid'] ?? 0; $userid = $this->data['userid'] ?? 0;
if ($taskId > 0 && $userid > 0) { if ($taskId > 0 && $userid > 0) {
SeekDBTask::removeVisibilityUser($taskId, $userid); ManticoreTask::removeVisibilityUser($taskId, $userid);
} }
break; break;
case 'task_users_sync': case 'task_users_sync':
$taskId = $this->data['task_id'] ?? 0; $taskId = $this->data['task_id'] ?? 0;
if ($taskId > 0) { if ($taskId > 0) {
SeekDBTask::syncTaskUsers($taskId); ManticoreTask::syncTaskUsers($taskId);
} }
break; break;
@ -219,22 +219,22 @@ class SeekDBSyncTask extends AbstractTask
private function incrementalUpdate() private function incrementalUpdate()
{ {
// 60分钟执行一次 // 60分钟执行一次
$time = intval(Cache::get("SeekDBSyncTask:Time")); $time = intval(Cache::get("ManticoreSyncTask:Time"));
if (time() - $time < 60 * 60) { if (time() - $time < 60 * 60) {
return; return;
} }
// 执行开始 // 执行开始
Cache::put("SeekDBSyncTask:Time", time(), Carbon::now()->addMinutes(60)); Cache::put("ManticoreSyncTask:Time", time(), Carbon::now()->addMinutes(60));
// 执行增量同步(同时同步向量表和用户关系表的新增数据) // 执行增量同步(同时同步向量表和用户关系表的新增数据)
@shell_exec("php /var/www/artisan seekdb:sync-files --i 2>&1 &"); @shell_exec("php /var/www/artisan manticore:sync-files --i 2>&1 &");
@shell_exec("php /var/www/artisan seekdb:sync-users --i 2>&1 &"); @shell_exec("php /var/www/artisan manticore:sync-users --i 2>&1 &");
@shell_exec("php /var/www/artisan seekdb:sync-projects --i 2>&1 &"); @shell_exec("php /var/www/artisan manticore:sync-projects --i 2>&1 &");
@shell_exec("php /var/www/artisan seekdb:sync-tasks --i 2>&1 &"); @shell_exec("php /var/www/artisan manticore:sync-tasks --i 2>&1 &");
// 执行完成 // 执行完成
Cache::put("SeekDBSyncTask:Time", time(), Carbon::now()->addMinutes(5)); Cache::put("ManticoreSyncTask:Time", time(), Carbon::now()->addMinutes(5));
} }
public function end() public function end()

View File

@ -156,7 +156,7 @@ export default {
aiSearchAvailable() { aiSearchAvailable() {
return this.microAppsIds return this.microAppsIds
&& this.microAppsIds.includes('seekdb') && this.microAppsIds.includes('manticore')
&& this.microAppsIds.includes('ai') && this.microAppsIds.includes('ai')
}, },