feat(ai): add AiTaskLoopTask timer and register to crontab

This commit is contained in:
kuaifan 2026-01-21 01:43:00 +00:00
parent eef4c6fbe5
commit 106465b932
2 changed files with 122 additions and 0 deletions

View File

@ -23,6 +23,7 @@ use App\Tasks\CheckinRemindTask;
use App\Tasks\CloseMeetingRoomTask;
use App\Tasks\ManticoreSyncTask;
use App\Tasks\UnclaimedTaskRemindTask;
use App\Tasks\AiTaskLoopTask;
use Hhxsv5\LaravelS\Swoole\Task\Task;
use Laravolt\Avatar\Avatar;
@ -273,6 +274,8 @@ class IndexController extends InvokeController
Task::deliver(new CloseMeetingRoomTask());
// Manticore Search 同步
Task::deliver(new ManticoreSyncTask());
// AI 任务建议
Task::deliver(new AiTaskLoopTask());
return "success";
}

View File

@ -0,0 +1,119 @@
<?php
namespace App\Tasks;
use App\Models\Apps;
use App\Models\ProjectTask;
use App\Models\ProjectTaskAiEvent;
use App\Module\Base;
use Carbon\Carbon;
use Hhxsv5\LaravelS\Swoole\Task\Task;
/**
* AI 任务建议定时任务
* 扫描新建任务并投递分析任务
*/
class AiTaskLoopTask extends AbstractTask
{
/**
* 单次处理任务数量上限
*/
const BATCH_SIZE = 5;
/**
* 任务创建后多久开始分析(秒)
*/
const DELAY_SECONDS = 60;
public function __construct()
{
parent::__construct();
}
public function start()
{
// 检查 AI 插件是否安装
if (!Apps::isInstalled('ai')) {
return;
}
// 检查功能开关
if (Base::settingFind('aiAssistant', 'taskSuggestion') !== 'open') {
return;
}
// 查询待处理的任务
$tasks = $this->findPendingTasks();
foreach ($tasks as $task) {
// 为任务创建事件记录
$this->createEventRecords($task);
// 投递异步分析任务
Task::deliver(new AiTaskAnalyzeTask($task->id));
}
}
/**
* 查找待处理的任务
*/
private function findPendingTasks(): \Illuminate\Support\Collection
{
$delayTime = Carbon::now()->subSeconds(self::DELAY_SECONDS);
// 子查询:已经有 AI 事件记录的任务
$processedTaskIds = ProjectTaskAiEvent::select('task_id')
->distinct()
->pluck('task_id');
// 查询新建任务(未处理过的)
$newTasks = ProjectTask::where('parent_id', 0) // 只处理主任务
->whereNull('deleted_at')
->whereNull('archived_at')
->where('created_at', '<=', $delayTime) // 创建超过延迟时间
->where('created_at', '>=', Carbon::now()->subDays(1)) // 只处理1天内的
->whereNotNull('dialog_id') // 有对话ID
->whereNotIn('id', $processedTaskIds)
->orderBy('created_at', 'asc')
->take(self::BATCH_SIZE)
->get();
// 查询需要重试的任务(优先处理较早失败的)
$retryTaskIds = ProjectTaskAiEvent::where('status', ProjectTaskAiEvent::STATUS_FAILED)
->where('retry_count', '<', ProjectTaskAiEvent::MAX_RETRY)
->select('task_id')
->distinct()
->orderBy('updated_at', 'asc')
->take(self::BATCH_SIZE - $newTasks->count())
->pluck('task_id');
$retryTasks = ProjectTask::whereIn('id', $retryTaskIds)
->whereNull('deleted_at')
->get();
return $newTasks->merge($retryTasks)->take(self::BATCH_SIZE);
}
/**
* 为任务创建事件记录
*/
private function createEventRecords(ProjectTask $task): void
{
foreach (ProjectTaskAiEvent::getEventTypes() as $eventType) {
ProjectTaskAiEvent::firstOrCreate(
[
'task_id' => $task->id,
'event_type' => $eventType,
],
[
'status' => ProjectTaskAiEvent::STATUS_PENDING,
'retry_count' => 0,
]
);
}
}
public function end()
{
}
}