queryCleaner->clean($prompt)); if ($cleanQuery === '') { return null; } $catalogHits = $this->filterCatalogEntityHits( $this->tagVectorClient->search($cleanQuery, $this->config->getIntentSearchLimit()) ); if ($catalogHits === []) { return null; } $best = $catalogHits[0]; $bestScore = (float) ($best['score'] ?? 0.0); if (!$this->config->isScoreAccepted($bestScore)) { return null; } if (isset($catalogHits[1])) { $secondScore = (float) ($catalogHits[1]['score'] ?? 0.0); if ($this->config->isAmbiguous($bestScore, $secondScore)) { return null; } } $label = $this->normalizeLabel((string) ($best['label'] ?? '')); return $label !== '' ? $label : null; } /** * @param array $hits * * @return list */ private function filterCatalogEntityHits(array $hits): array { $filtered = []; foreach ($hits as $hit) { $tagId = trim((string) ($hit['tag_id'] ?? '')); $score = (float) ($hit['score'] ?? 0.0); $tagType = TagTypes::normalize((string) ($hit['tag_type'] ?? TagTypes::GENERIC)); if ($tagId === '') { continue; } if ($tagType !== TagTypes::CATALOG_ENTITY) { continue; } $filtered[] = [ 'tag_id' => $tagId, 'score' => $score, 'label' => isset($hit['label']) ? (string) $hit['label'] : null, 'tag_type' => $tagType, ]; } usort( $filtered, static fn (array $left, array $right): int => ($right['score'] <=> $left['score']) ); return $filtered; } private function normalizeLabel(string $label): string { $label = mb_strtolower(trim($label)); $label = preg_replace('/\s+/u', ' ', $label) ?? $label; return trim($label); } }