select(['kp_code', 'name'])->limit(200)->get()->toArray(); } foreach ($pool as $item) { $name = is_array($item) ? ($item['name'] ?? '') : ($item->name ?? ''); $kpCode = is_array($item) ? ($item['kp_code'] ?? '') : ($item->kp_code ?? ''); if ($name !== '' && mb_strpos($questionText, $name) !== false) { $matched[] = [ 'kp_code' => $kpCode, 'weight' => 1, ]; } } return $matched; } public function matchKnowledgePointsByAi(string $questionText, array $candidates = [], ?string $context = null): array { if (empty($candidates)) { $candidates = $this->getCandidateKnowledgePoints(); } $prompt = app(QuestionPromptService::class)->buildKnowledgeMatchPrompt($questionText, $candidates, $context); try { $result = app(AiClientService::class)->callJson($prompt); } catch (\Throwable $e) { return []; } $items = $result['knowledge_points'] ?? []; $matches = []; foreach ($items as $item) { $kpCode = $item['kp_code'] ?? null; if (!$kpCode) { continue; } $matches[] = [ 'kp_code' => $kpCode, 'weight' => $item['weight'] ?? 1, ]; } return $matches; } public function isValidKnowledgePoint(?string $kpCode): bool { if (!$kpCode) { return false; } $cacheKey = "kp-valid-{$kpCode}"; return Cache::remember($cacheKey, now()->addMinutes(30), function () use ($kpCode) { return KnowledgePoint::query()->where('kp_code', $kpCode)->exists(); }); } public function getCandidateKnowledgePoints(int $limit = 300): array { return KnowledgePoint::query() ->select(['kp_code', 'name']) ->orderBy('kp_code') ->limit($limit) ->get() ->toArray(); } public function inferKnowledgeWeights(array $questionStruct): array { $kps = $questionStruct['knowledge_points'] ?? []; return array_map(function ($kp) { return [ 'kp_code' => $kp, 'weight' => 1, ]; }, $kps); } }