mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-17 03:03:41 +00:00
feat: 添加 Manticore 同步命令通用锁机制,优化信号处理与锁管理
This commit is contained in:
parent
610979f30b
commit
ea0d27fdea
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Console\Commands\Traits\ManticoreSyncLock;
|
||||||
use App\Models\File;
|
use App\Models\File;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\ProjectTask;
|
use App\Models\ProjectTask;
|
||||||
@ -14,7 +15,6 @@ use App\Module\Manticore\ManticoreMsg;
|
|||||||
use App\Module\Manticore\ManticoreProject;
|
use App\Module\Manticore\ManticoreProject;
|
||||||
use App\Module\Manticore\ManticoreTask;
|
use App\Module\Manticore\ManticoreTask;
|
||||||
use App\Module\Manticore\ManticoreUser;
|
use App\Module\Manticore\ManticoreUser;
|
||||||
use Cache;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,6 +30,8 @@ use Illuminate\Console\Command;
|
|||||||
*/
|
*/
|
||||||
class GenerateManticoreVectors extends Command
|
class GenerateManticoreVectors extends Command
|
||||||
{
|
{
|
||||||
|
use ManticoreSyncLock;
|
||||||
|
|
||||||
protected $signature = 'manticore:generate-vectors
|
protected $signature = 'manticore:generate-vectors
|
||||||
{--type=all : 类型 (msg/file/task/project/user/all)}
|
{--type=all : 类型 (msg/file/task/project/user/all)}
|
||||||
{--batch=50 : 每批 embedding 数量}
|
{--batch=50 : 每批 embedding 数量}
|
||||||
@ -79,8 +81,6 @@ class GenerateManticoreVectors extends Command
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
private bool $shouldStop = false;
|
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
if (!Apps::isInstalled("manticore")) {
|
if (!Apps::isInstalled("manticore")) {
|
||||||
@ -93,22 +93,12 @@ class GenerateManticoreVectors extends Command
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册信号处理器
|
$this->registerSignalHandlers();
|
||||||
if (extension_loaded('pcntl')) {
|
|
||||||
pcntl_async_signals(true);
|
|
||||||
pcntl_signal(SIGINT, [$this, 'handleSignal']);
|
|
||||||
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查锁
|
if (!$this->acquireLock()) {
|
||||||
$lockInfo = $this->getLock();
|
|
||||||
if ($lockInfo) {
|
|
||||||
$this->error("命令已在运行中,开始时间: {$lockInfo['started_at']}");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setLock();
|
|
||||||
|
|
||||||
$type = $this->option('type');
|
$type = $this->option('type');
|
||||||
$batchSize = intval($this->option('batch'));
|
$batchSize = intval($this->option('batch'));
|
||||||
$sleepSeconds = intval($this->option('sleep'));
|
$sleepSeconds = intval($this->option('sleep'));
|
||||||
@ -212,29 +202,4 @@ class GenerateManticoreVectors extends Command
|
|||||||
|
|
||||||
return max(0, $remaining);
|
return max(0, $remaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLock(): ?array
|
|
||||||
{
|
|
||||||
$lockKey = 'manticore:generate-vectors:lock';
|
|
||||||
return Cache::has($lockKey) ? Cache::get($lockKey) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = 'manticore:generate-vectors:lock';
|
|
||||||
// 锁有效期 30 分钟,持续处理时会不断刷新
|
|
||||||
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 1800);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function releaseLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = 'manticore:generate-vectors:lock';
|
|
||||||
Cache::forget($lockKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleSignal(int $signal): void
|
|
||||||
{
|
|
||||||
$this->info("\n收到信号,将在当前批次完成后退出...");
|
|
||||||
$this->shouldStop = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Console\Commands\Traits\ManticoreSyncLock;
|
||||||
use App\Models\File;
|
use App\Models\File;
|
||||||
use App\Module\Apps;
|
use App\Module\Apps;
|
||||||
use App\Module\Manticore\ManticoreFile;
|
use App\Module\Manticore\ManticoreFile;
|
||||||
use App\Module\Manticore\ManticoreKeyValue;
|
use App\Module\Manticore\ManticoreKeyValue;
|
||||||
use Cache;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class SyncFileToManticore extends Command
|
class SyncFileToManticore extends Command
|
||||||
{
|
{
|
||||||
|
use ManticoreSyncLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
||||||
* --f: 全量更新 (默认)
|
* --f: 全量更新 (默认)
|
||||||
@ -26,11 +28,6 @@ class SyncFileToManticore extends Command
|
|||||||
protected $signature = 'manticore:sync-files {--f} {--i} {--c} {--batch=100} {--sleep=3}';
|
protected $signature = 'manticore:sync-files {--f} {--i} {--c} {--batch=100} {--sleep=3}';
|
||||||
protected $description = '同步文件内容到 Manticore Search(MVA 权限方案)';
|
protected $description = '同步文件内容到 Manticore Search(MVA 权限方案)';
|
||||||
|
|
||||||
private bool $shouldStop = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
if (!Apps::isInstalled("manticore")) {
|
if (!Apps::isInstalled("manticore")) {
|
||||||
@ -38,22 +35,12 @@ class SyncFileToManticore extends Command
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册信号处理器(仅在支持pcntl扩展的环境下)
|
$this->registerSignalHandlers();
|
||||||
if (extension_loaded('pcntl')) {
|
|
||||||
pcntl_async_signals(true);
|
|
||||||
pcntl_signal(SIGINT, [$this, 'handleSignal']);
|
|
||||||
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查锁,如果已被占用则退出
|
if (!$this->acquireLock()) {
|
||||||
$lockInfo = $this->getLock();
|
|
||||||
if ($lockInfo) {
|
|
||||||
$this->error("命令已在运行中,开始时间: {$lockInfo['started_at']}");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setLock();
|
|
||||||
|
|
||||||
// 清除索引
|
// 清除索引
|
||||||
if ($this->option('c')) {
|
if ($this->option('c')) {
|
||||||
$this->info('清除索引...');
|
$this->info('清除索引...');
|
||||||
@ -72,30 +59,6 @@ class SyncFileToManticore extends Command
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLock(): ?array
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
return Cache::has($lockKey) ? Cache::get($lockKey) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 1800);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function releaseLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
Cache::forget($lockKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleSignal(int $signal): void
|
|
||||||
{
|
|
||||||
$this->info("\n收到信号,将在当前批次完成后退出...");
|
|
||||||
$this->shouldStop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步文件数据
|
* 同步文件数据
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Console\Commands\Traits\ManticoreSyncLock;
|
||||||
use App\Models\WebSocketDialogMsg;
|
use App\Models\WebSocketDialogMsg;
|
||||||
use App\Module\Apps;
|
use App\Module\Apps;
|
||||||
use App\Module\Manticore\ManticoreMsg;
|
use App\Module\Manticore\ManticoreMsg;
|
||||||
use App\Module\Manticore\ManticoreKeyValue;
|
use App\Module\Manticore\ManticoreKeyValue;
|
||||||
use Cache;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class SyncMsgToManticore extends Command
|
class SyncMsgToManticore extends Command
|
||||||
{
|
{
|
||||||
|
use ManticoreSyncLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
||||||
* --f: 全量更新 (默认)
|
* --f: 全量更新 (默认)
|
||||||
@ -27,11 +29,6 @@ class SyncMsgToManticore extends Command
|
|||||||
protected $signature = 'manticore:sync-msgs {--f} {--i} {--c} {--batch=100} {--dialog=} {--sleep=3}';
|
protected $signature = 'manticore:sync-msgs {--f} {--i} {--c} {--batch=100} {--dialog=} {--sleep=3}';
|
||||||
protected $description = '同步消息数据到 Manticore Search(MVA 权限方案)';
|
protected $description = '同步消息数据到 Manticore Search(MVA 权限方案)';
|
||||||
|
|
||||||
private bool $shouldStop = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
if (!Apps::isInstalled("manticore")) {
|
if (!Apps::isInstalled("manticore")) {
|
||||||
@ -39,22 +36,12 @@ class SyncMsgToManticore extends Command
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册信号处理器
|
$this->registerSignalHandlers();
|
||||||
if (extension_loaded('pcntl')) {
|
|
||||||
pcntl_async_signals(true);
|
|
||||||
pcntl_signal(SIGINT, [$this, 'handleSignal']);
|
|
||||||
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查锁
|
if (!$this->acquireLock()) {
|
||||||
$lockInfo = $this->getLock();
|
|
||||||
if ($lockInfo) {
|
|
||||||
$this->error("命令已在运行中,开始时间: {$lockInfo['started_at']}");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setLock();
|
|
||||||
|
|
||||||
// 清除索引
|
// 清除索引
|
||||||
if ($this->option('c')) {
|
if ($this->option('c')) {
|
||||||
$this->info('清除索引...');
|
$this->info('清除索引...');
|
||||||
@ -79,31 +66,6 @@ class SyncMsgToManticore extends Command
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLock(): ?array
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
return Cache::has($lockKey) ? Cache::get($lockKey) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
// 锁有效期 30 分钟,持续处理时会不断刷新
|
|
||||||
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 1800);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function releaseLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
Cache::forget($lockKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleSignal(int $signal): void
|
|
||||||
{
|
|
||||||
$this->info("\n收到信号,将在当前批次完成后退出...");
|
|
||||||
$this->shouldStop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步所有消息
|
* 同步所有消息
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Console\Commands\Traits\ManticoreSyncLock;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Module\Apps;
|
use App\Module\Apps;
|
||||||
use App\Module\Manticore\ManticoreProject;
|
use App\Module\Manticore\ManticoreProject;
|
||||||
use App\Module\Manticore\ManticoreKeyValue;
|
use App\Module\Manticore\ManticoreKeyValue;
|
||||||
use Cache;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class SyncProjectToManticore extends Command
|
class SyncProjectToManticore extends Command
|
||||||
{
|
{
|
||||||
|
use ManticoreSyncLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
||||||
* --f: 全量更新 (默认)
|
* --f: 全量更新 (默认)
|
||||||
@ -26,8 +28,6 @@ class SyncProjectToManticore extends Command
|
|||||||
protected $signature = 'manticore:sync-projects {--f} {--i} {--c} {--batch=100} {--sleep=3}';
|
protected $signature = 'manticore:sync-projects {--f} {--i} {--c} {--batch=100} {--sleep=3}';
|
||||||
protected $description = '同步项目数据到 Manticore Search(MVA 权限方案)';
|
protected $description = '同步项目数据到 Manticore Search(MVA 权限方案)';
|
||||||
|
|
||||||
private bool $shouldStop = false;
|
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
if (!Apps::isInstalled("manticore")) {
|
if (!Apps::isInstalled("manticore")) {
|
||||||
@ -35,20 +35,12 @@ class SyncProjectToManticore extends Command
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension_loaded('pcntl')) {
|
$this->registerSignalHandlers();
|
||||||
pcntl_async_signals(true);
|
|
||||||
pcntl_signal(SIGINT, [$this, 'handleSignal']);
|
|
||||||
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$lockInfo = $this->getLock();
|
if (!$this->acquireLock()) {
|
||||||
if ($lockInfo) {
|
|
||||||
$this->error("命令已在运行中,开始时间: {$lockInfo['started_at']}");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setLock();
|
|
||||||
|
|
||||||
if ($this->option('c')) {
|
if ($this->option('c')) {
|
||||||
$this->info('清除索引...');
|
$this->info('清除索引...');
|
||||||
ManticoreProject::clear();
|
ManticoreProject::clear();
|
||||||
@ -65,30 +57,6 @@ class SyncProjectToManticore extends Command
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLock(): ?array
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
return Cache::has($lockKey) ? Cache::get($lockKey) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 1800);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function releaseLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
Cache::forget($lockKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleSignal(int $signal): void
|
|
||||||
{
|
|
||||||
$this->info("\n收到信号,将在当前批次完成后退出...");
|
|
||||||
$this->shouldStop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function syncProjects(): void
|
private function syncProjects(): void
|
||||||
{
|
{
|
||||||
$lastKey = "sync:manticoreProjectLastId";
|
$lastKey = "sync:manticoreProjectLastId";
|
||||||
|
|||||||
@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Console\Commands\Traits\ManticoreSyncLock;
|
||||||
use App\Models\ProjectTask;
|
use App\Models\ProjectTask;
|
||||||
use App\Module\Apps;
|
use App\Module\Apps;
|
||||||
use App\Module\Manticore\ManticoreTask;
|
use App\Module\Manticore\ManticoreTask;
|
||||||
use App\Module\Manticore\ManticoreKeyValue;
|
use App\Module\Manticore\ManticoreKeyValue;
|
||||||
use Cache;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class SyncTaskToManticore extends Command
|
class SyncTaskToManticore extends Command
|
||||||
{
|
{
|
||||||
|
use ManticoreSyncLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
||||||
* --f: 全量更新 (默认)
|
* --f: 全量更新 (默认)
|
||||||
@ -26,8 +28,6 @@ class SyncTaskToManticore extends Command
|
|||||||
protected $signature = 'manticore:sync-tasks {--f} {--i} {--c} {--batch=100} {--sleep=3}';
|
protected $signature = 'manticore:sync-tasks {--f} {--i} {--c} {--batch=100} {--sleep=3}';
|
||||||
protected $description = '同步任务数据到 Manticore Search(MVA 权限方案)';
|
protected $description = '同步任务数据到 Manticore Search(MVA 权限方案)';
|
||||||
|
|
||||||
private bool $shouldStop = false;
|
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
if (!Apps::isInstalled("manticore")) {
|
if (!Apps::isInstalled("manticore")) {
|
||||||
@ -35,20 +35,12 @@ class SyncTaskToManticore extends Command
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension_loaded('pcntl')) {
|
$this->registerSignalHandlers();
|
||||||
pcntl_async_signals(true);
|
|
||||||
pcntl_signal(SIGINT, [$this, 'handleSignal']);
|
|
||||||
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$lockInfo = $this->getLock();
|
if (!$this->acquireLock()) {
|
||||||
if ($lockInfo) {
|
|
||||||
$this->error("命令已在运行中,开始时间: {$lockInfo['started_at']}");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setLock();
|
|
||||||
|
|
||||||
if ($this->option('c')) {
|
if ($this->option('c')) {
|
||||||
$this->info('清除索引...');
|
$this->info('清除索引...');
|
||||||
ManticoreTask::clear();
|
ManticoreTask::clear();
|
||||||
@ -65,30 +57,6 @@ class SyncTaskToManticore extends Command
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLock(): ?array
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
return Cache::has($lockKey) ? Cache::get($lockKey) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 1800);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function releaseLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
Cache::forget($lockKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleSignal(int $signal): void
|
|
||||||
{
|
|
||||||
$this->info("\n收到信号,将在当前批次完成后退出...");
|
|
||||||
$this->shouldStop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function syncTasks(): void
|
private function syncTasks(): void
|
||||||
{
|
{
|
||||||
$lastKey = "sync:manticoreTaskLastId";
|
$lastKey = "sync:manticoreTaskLastId";
|
||||||
|
|||||||
@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Console\Commands\Traits\ManticoreSyncLock;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Module\Apps;
|
use App\Module\Apps;
|
||||||
use App\Module\Manticore\ManticoreUser;
|
use App\Module\Manticore\ManticoreUser;
|
||||||
use App\Module\Manticore\ManticoreKeyValue;
|
use App\Module\Manticore\ManticoreKeyValue;
|
||||||
use Cache;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class SyncUserToManticore extends Command
|
class SyncUserToManticore extends Command
|
||||||
{
|
{
|
||||||
|
use ManticoreSyncLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新数据
|
* 更新数据
|
||||||
* --f: 全量更新 (默认)
|
* --f: 全量更新 (默认)
|
||||||
@ -26,8 +28,6 @@ class SyncUserToManticore extends Command
|
|||||||
protected $signature = 'manticore:sync-users {--f} {--i} {--c} {--batch=100} {--sleep=3}';
|
protected $signature = 'manticore:sync-users {--f} {--i} {--c} {--batch=100} {--sleep=3}';
|
||||||
protected $description = '同步用户数据到 Manticore Search';
|
protected $description = '同步用户数据到 Manticore Search';
|
||||||
|
|
||||||
private bool $shouldStop = false;
|
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
if (!Apps::isInstalled("manticore")) {
|
if (!Apps::isInstalled("manticore")) {
|
||||||
@ -35,20 +35,12 @@ class SyncUserToManticore extends Command
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension_loaded('pcntl')) {
|
$this->registerSignalHandlers();
|
||||||
pcntl_async_signals(true);
|
|
||||||
pcntl_signal(SIGINT, [$this, 'handleSignal']);
|
|
||||||
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$lockInfo = $this->getLock();
|
if (!$this->acquireLock()) {
|
||||||
if ($lockInfo) {
|
|
||||||
$this->error("命令已在运行中,开始时间: {$lockInfo['started_at']}");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setLock();
|
|
||||||
|
|
||||||
if ($this->option('c')) {
|
if ($this->option('c')) {
|
||||||
$this->info('清除索引...');
|
$this->info('清除索引...');
|
||||||
ManticoreUser::clear();
|
ManticoreUser::clear();
|
||||||
@ -65,30 +57,6 @@ class SyncUserToManticore extends Command
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLock(): ?array
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
return Cache::has($lockKey) ? Cache::get($lockKey) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 1800);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function releaseLock(): void
|
|
||||||
{
|
|
||||||
$lockKey = md5($this->signature);
|
|
||||||
Cache::forget($lockKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleSignal(int $signal): void
|
|
||||||
{
|
|
||||||
$this->info("\n收到信号,将在当前批次完成后退出...");
|
|
||||||
$this->shouldStop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function syncUsers(): void
|
private function syncUsers(): void
|
||||||
{
|
{
|
||||||
$lastKey = "sync:manticoreUserLastId";
|
$lastKey = "sync:manticoreUserLastId";
|
||||||
|
|||||||
90
app/Console/Commands/Traits/ManticoreSyncLock.php
Normal file
90
app/Console/Commands/Traits/ManticoreSyncLock.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands\Traits;
|
||||||
|
|
||||||
|
use Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manticore 同步命令通用锁机制
|
||||||
|
*
|
||||||
|
* 提供:
|
||||||
|
* - 锁的获取、设置、释放
|
||||||
|
* - 信号处理(优雅退出)
|
||||||
|
* - 通用的命令初始化检查
|
||||||
|
*/
|
||||||
|
trait ManticoreSyncLock
|
||||||
|
{
|
||||||
|
private bool $shouldStop = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取锁信息
|
||||||
|
*/
|
||||||
|
private function getLock(): ?array
|
||||||
|
{
|
||||||
|
$lockKey = $this->getLockKey();
|
||||||
|
return Cache::has($lockKey) ? Cache::get($lockKey) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置锁(30分钟有效期,持续处理时需不断刷新)
|
||||||
|
*/
|
||||||
|
private function setLock(): void
|
||||||
|
{
|
||||||
|
$lockKey = $this->getLockKey();
|
||||||
|
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 1800);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放锁
|
||||||
|
*/
|
||||||
|
private function releaseLock(): void
|
||||||
|
{
|
||||||
|
$lockKey = $this->getLockKey();
|
||||||
|
Cache::forget($lockKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取锁的缓存键
|
||||||
|
*/
|
||||||
|
private function getLockKey(): string
|
||||||
|
{
|
||||||
|
return md5($this->signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 信号处理器(SIGINT/SIGTERM)
|
||||||
|
*/
|
||||||
|
public function handleSignal(int $signal): void
|
||||||
|
{
|
||||||
|
$this->info("\n收到信号,将在当前批次完成后退出...");
|
||||||
|
$this->shouldStop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册信号处理器
|
||||||
|
*/
|
||||||
|
private function registerSignalHandlers(): void
|
||||||
|
{
|
||||||
|
if (extension_loaded('pcntl')) {
|
||||||
|
pcntl_async_signals(true);
|
||||||
|
pcntl_signal(SIGINT, [$this, 'handleSignal']);
|
||||||
|
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查命令是否可以启动(锁检查)
|
||||||
|
*
|
||||||
|
* @return bool 返回 true 表示可以启动,false 表示已被占用
|
||||||
|
*/
|
||||||
|
private function acquireLock(): bool
|
||||||
|
{
|
||||||
|
$lockInfo = $this->getLock();
|
||||||
|
if ($lockInfo) {
|
||||||
|
$this->error("命令已在运行中,开始时间: {$lockInfo['started_at']}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->setLock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,8 @@
|
|||||||
namespace App\Module\Manticore;
|
namespace App\Module\Manticore;
|
||||||
|
|
||||||
use App\Module\Apps;
|
use App\Module\Apps;
|
||||||
use App\Module\Doo;
|
use App\Module\Base;
|
||||||
|
use App\Module\AI;
|
||||||
use PDO;
|
use PDO;
|
||||||
use PDOException;
|
use PDOException;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@ -2107,5 +2108,33 @@ class ManticoreBase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==============================
|
||||||
|
// 通用工具方法
|
||||||
|
// ==============================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文本的 Embedding 向量
|
||||||
|
*
|
||||||
|
* @param string $text 文本
|
||||||
|
* @return array 向量数组(空数组表示失败)
|
||||||
|
*/
|
||||||
|
public static function getEmbedding(string $text): array
|
||||||
|
{
|
||||||
|
if (empty($text)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = AI::getEmbedding($text);
|
||||||
|
if (Base::isSuccess($result)) {
|
||||||
|
return $result['data'] ?? [];
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::warning('Get embedding error: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -101,7 +101,7 @@ class ManticoreFile
|
|||||||
|
|
||||||
case 'vector':
|
case 'vector':
|
||||||
// 纯向量搜索(需要先获取 embedding)
|
// 纯向量搜索(需要先获取 embedding)
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
if (empty($embedding)) {
|
if (empty($embedding)) {
|
||||||
// embedding 获取失败,降级到全文搜索
|
// embedding 获取失败,降级到全文搜索
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
@ -115,7 +115,7 @@ class ManticoreFile
|
|||||||
case 'hybrid':
|
case 'hybrid':
|
||||||
default:
|
default:
|
||||||
// 混合搜索
|
// 混合搜索
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
ManticoreBase::hybridSearch($keyword, $embedding, $userid, $size)
|
ManticoreBase::hybridSearch($keyword, $embedding, $userid, $size)
|
||||||
);
|
);
|
||||||
@ -126,30 +126,6 @@ class ManticoreFile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文本的 Embedding 向量
|
|
||||||
*
|
|
||||||
* @param string $text 文本
|
|
||||||
* @return array 向量数组(空数组表示失败)
|
|
||||||
*/
|
|
||||||
private static function getEmbedding(string $text): array
|
|
||||||
{
|
|
||||||
if (empty($text)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 调用 AI 模块获取 embedding
|
|
||||||
$result = AI::getEmbedding($text);
|
|
||||||
if (Base::isSuccess($result)) {
|
|
||||||
return $result['data'] ?? [];
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::warning('Get embedding error: ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化搜索结果
|
* 格式化搜索结果
|
||||||
@ -275,7 +251,7 @@ class ManticoreFile
|
|||||||
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
||||||
$embedding = null;
|
$embedding = null;
|
||||||
if ($withVector && !empty($content) && Apps::isInstalled('ai')) {
|
if ($withVector && !empty($content) && Apps::isInstalled('ai')) {
|
||||||
$embeddingResult = self::getEmbedding($content);
|
$embeddingResult = ManticoreBase::getEmbedding($content);
|
||||||
if (!empty($embeddingResult)) {
|
if (!empty($embeddingResult)) {
|
||||||
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,7 +100,7 @@ class ManticoreMsg
|
|||||||
|
|
||||||
case 'vector':
|
case 'vector':
|
||||||
// 纯向量搜索(需要先获取 embedding)
|
// 纯向量搜索(需要先获取 embedding)
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
if (empty($embedding)) {
|
if (empty($embedding)) {
|
||||||
// embedding 获取失败,降级到全文搜索
|
// embedding 获取失败,降级到全文搜索
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
@ -114,7 +114,7 @@ class ManticoreMsg
|
|||||||
case 'hybrid':
|
case 'hybrid':
|
||||||
default:
|
default:
|
||||||
// 混合搜索
|
// 混合搜索
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
ManticoreBase::msgHybridSearch($keyword, $embedding, $userid, $size, $dialogId)
|
ManticoreBase::msgHybridSearch($keyword, $embedding, $userid, $size, $dialogId)
|
||||||
);
|
);
|
||||||
@ -125,30 +125,6 @@ class ManticoreMsg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文本的 Embedding 向量
|
|
||||||
*
|
|
||||||
* @param string $text 文本
|
|
||||||
* @return array 向量数组(空数组表示失败)
|
|
||||||
*/
|
|
||||||
private static function getEmbedding(string $text): array
|
|
||||||
{
|
|
||||||
if (empty($text)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 调用 AI 模块获取 embedding
|
|
||||||
$result = AI::getEmbedding($text);
|
|
||||||
if (Base::isSuccess($result)) {
|
|
||||||
return $result['data'] ?? [];
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::warning('Get embedding error: ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化搜索结果
|
* 格式化搜索结果
|
||||||
@ -380,7 +356,7 @@ class ManticoreMsg
|
|||||||
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
||||||
$embedding = null;
|
$embedding = null;
|
||||||
if ($withVector && !empty($content) && Apps::isInstalled('ai')) {
|
if ($withVector && !empty($content) && Apps::isInstalled('ai')) {
|
||||||
$embeddingResult = self::getEmbedding($content);
|
$embeddingResult = ManticoreBase::getEmbedding($content);
|
||||||
if (!empty($embeddingResult)) {
|
if (!empty($embeddingResult)) {
|
||||||
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,7 +57,7 @@ class ManticoreProject
|
|||||||
);
|
);
|
||||||
|
|
||||||
case 'vector':
|
case 'vector':
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
if (empty($embedding)) {
|
if (empty($embedding)) {
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
ManticoreBase::projectFullTextSearch($keyword, $userid, $limit, 0)
|
ManticoreBase::projectFullTextSearch($keyword, $userid, $limit, 0)
|
||||||
@ -69,7 +69,7 @@ class ManticoreProject
|
|||||||
|
|
||||||
case 'hybrid':
|
case 'hybrid':
|
||||||
default:
|
default:
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
ManticoreBase::projectHybridSearch($keyword, $embedding, $userid, $limit)
|
ManticoreBase::projectHybridSearch($keyword, $embedding, $userid, $limit)
|
||||||
);
|
);
|
||||||
@ -80,29 +80,6 @@ class ManticoreProject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文本的 Embedding 向量
|
|
||||||
*
|
|
||||||
* @param string $text 文本
|
|
||||||
* @return array 向量数组(空数组表示失败)
|
|
||||||
*/
|
|
||||||
private static function getEmbedding(string $text): array
|
|
||||||
{
|
|
||||||
if (empty($text)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$result = AI::getEmbedding($text);
|
|
||||||
if (Base::isSuccess($result)) {
|
|
||||||
return $result['data'] ?? [];
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::warning('Get embedding error: ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化搜索结果
|
* 格式化搜索结果
|
||||||
@ -169,7 +146,7 @@ class ManticoreProject
|
|||||||
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
||||||
$embedding = null;
|
$embedding = null;
|
||||||
if ($withVector && !empty($searchableContent) && Apps::isInstalled('ai')) {
|
if ($withVector && !empty($searchableContent) && Apps::isInstalled('ai')) {
|
||||||
$embeddingResult = self::getEmbedding($searchableContent);
|
$embeddingResult = ManticoreBase::getEmbedding($searchableContent);
|
||||||
if (!empty($embeddingResult)) {
|
if (!empty($embeddingResult)) {
|
||||||
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,7 +73,7 @@ class ManticoreTask
|
|||||||
);
|
);
|
||||||
|
|
||||||
case 'vector':
|
case 'vector':
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
if (empty($embedding)) {
|
if (empty($embedding)) {
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
ManticoreBase::taskFullTextSearch($keyword, $userid, $limit, 0)
|
ManticoreBase::taskFullTextSearch($keyword, $userid, $limit, 0)
|
||||||
@ -85,7 +85,7 @@ class ManticoreTask
|
|||||||
|
|
||||||
case 'hybrid':
|
case 'hybrid':
|
||||||
default:
|
default:
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
ManticoreBase::taskHybridSearch($keyword, $embedding, $userid, $limit)
|
ManticoreBase::taskHybridSearch($keyword, $embedding, $userid, $limit)
|
||||||
);
|
);
|
||||||
@ -96,29 +96,6 @@ class ManticoreTask
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文本的 Embedding 向量
|
|
||||||
*
|
|
||||||
* @param string $text 文本
|
|
||||||
* @return array 向量数组(空数组表示失败)
|
|
||||||
*/
|
|
||||||
private static function getEmbedding(string $text): array
|
|
||||||
{
|
|
||||||
if (empty($text)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$result = AI::getEmbedding($text);
|
|
||||||
if (Base::isSuccess($result)) {
|
|
||||||
return $result['data'] ?? [];
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::warning('Get embedding error: ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化搜索结果
|
* 格式化搜索结果
|
||||||
@ -243,7 +220,7 @@ class ManticoreTask
|
|||||||
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
||||||
$embedding = null;
|
$embedding = null;
|
||||||
if ($withVector && !empty($searchableContent) && Apps::isInstalled('ai')) {
|
if ($withVector && !empty($searchableContent) && Apps::isInstalled('ai')) {
|
||||||
$embeddingResult = self::getEmbedding($searchableContent);
|
$embeddingResult = ManticoreBase::getEmbedding($searchableContent);
|
||||||
if (!empty($embeddingResult)) {
|
if (!empty($embeddingResult)) {
|
||||||
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class ManticoreUser
|
|||||||
);
|
);
|
||||||
|
|
||||||
case 'vector':
|
case 'vector':
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
if (empty($embedding)) {
|
if (empty($embedding)) {
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
ManticoreBase::userFullTextSearch($keyword, $limit, 0)
|
ManticoreBase::userFullTextSearch($keyword, $limit, 0)
|
||||||
@ -64,7 +64,7 @@ class ManticoreUser
|
|||||||
|
|
||||||
case 'hybrid':
|
case 'hybrid':
|
||||||
default:
|
default:
|
||||||
$embedding = self::getEmbedding($keyword);
|
$embedding = ManticoreBase::getEmbedding($keyword);
|
||||||
return self::formatSearchResults(
|
return self::formatSearchResults(
|
||||||
ManticoreBase::userHybridSearch($keyword, $embedding, $limit)
|
ManticoreBase::userHybridSearch($keyword, $embedding, $limit)
|
||||||
);
|
);
|
||||||
@ -75,29 +75,6 @@ class ManticoreUser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文本的 Embedding 向量
|
|
||||||
*
|
|
||||||
* @param string $text 文本
|
|
||||||
* @return array 向量数组(空数组表示失败)
|
|
||||||
*/
|
|
||||||
private static function getEmbedding(string $text): array
|
|
||||||
{
|
|
||||||
if (empty($text)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$result = AI::getEmbedding($text);
|
|
||||||
if (Base::isSuccess($result)) {
|
|
||||||
return $result['data'] ?? [];
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::warning('Get embedding error: ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化搜索结果
|
* 格式化搜索结果
|
||||||
@ -156,7 +133,7 @@ class ManticoreUser
|
|||||||
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
// 只有明确要求时才生成向量(默认不生成,由后台任务处理)
|
||||||
$embedding = null;
|
$embedding = null;
|
||||||
if ($withVector && !empty($searchableContent) && Apps::isInstalled('ai')) {
|
if ($withVector && !empty($searchableContent) && Apps::isInstalled('ai')) {
|
||||||
$embeddingResult = self::getEmbedding($searchableContent);
|
$embeddingResult = ManticoreBase::getEmbedding($searchableContent);
|
||||||
if (!empty($embeddingResult)) {
|
if (!empty($embeddingResult)) {
|
||||||
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
$embedding = '[' . implode(',', $embeddingResult) . ']';
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user