harden history find tokens
This commit is contained in:
@@ -212,20 +212,30 @@ final readonly class SearchRepairService
|
||||
$topPrimaryProductNumber = $primaryShopResults[0]->productNumber ?? null;
|
||||
$topPrimaryPhrase = trim($topPrimaryName . ' ' . ($topPrimaryProductNumber ?? ''));
|
||||
|
||||
$queries = [];
|
||||
|
||||
$queries = array_merge(
|
||||
$queries,
|
||||
$this->buildFocusedModelAccessoryQueries(
|
||||
prompt: $prompt,
|
||||
primaryQuery: $primaryQuery,
|
||||
knowledgeText: $knowledgeText,
|
||||
modelCandidates: $modelCandidates,
|
||||
accessoryCandidates: $accessoryCandidates,
|
||||
requestedAccessoryCodes: $requestedAccessoryCodes
|
||||
)
|
||||
$queries = $this->buildFocusedModelAccessoryQueries(
|
||||
prompt: $prompt,
|
||||
primaryQuery: $primaryQuery,
|
||||
knowledgeText: $knowledgeText,
|
||||
modelCandidates: $modelCandidates,
|
||||
accessoryCandidates: $accessoryCandidates,
|
||||
requestedAccessoryCodes: $requestedAccessoryCodes
|
||||
);
|
||||
|
||||
if ($requestedAccessoryCodes !== [] && $this->config->shouldRestrictRequestedAccessoryCodeRepair()) {
|
||||
foreach ($accessoryCandidates as $accessoryCandidate) {
|
||||
if ($this->candidateMatchesRequestedAccessoryCodes($accessoryCandidate, $requestedAccessoryCodes)) {
|
||||
$queries[] = $accessoryCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
$queries = array_merge(
|
||||
$queries,
|
||||
$this->buildRequestedAccessoryFallbackQueries($requestedAccessoryCodes)
|
||||
);
|
||||
|
||||
return $this->normalizeRepairQueries($queries, $primaryQuery);
|
||||
}
|
||||
|
||||
if ($topPrimaryPhrase !== '' && $this->containsModelLikePhrase($topPrimaryPhrase)) {
|
||||
$queries[] = $topPrimaryPhrase;
|
||||
} elseif ($topPrimaryName !== '' && $this->containsModelLikePhrase($topPrimaryName)) {
|
||||
@@ -246,6 +256,15 @@ final readonly class SearchRepairService
|
||||
}
|
||||
}
|
||||
|
||||
return $this->normalizeRepairQueries($queries, $primaryQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $queries
|
||||
* @return string[]
|
||||
*/
|
||||
private function normalizeRepairQueries(array $queries, string $primaryQuery): array
|
||||
{
|
||||
$queries = array_map(
|
||||
fn(string $query): string => $this->sanitizeQuery($query),
|
||||
$queries
|
||||
@@ -441,9 +460,7 @@ final readonly class SearchRepairService
|
||||
|
||||
$accessories = $accessoryCandidates;
|
||||
if ($accessories === []) {
|
||||
foreach ($requestedAccessoryCodes as $code) {
|
||||
$accessories[] = 'Indikator ' . $code;
|
||||
}
|
||||
$accessories = $this->buildRequestedAccessoryFallbackQueries($requestedAccessoryCodes);
|
||||
}
|
||||
|
||||
foreach ($models as $model) {
|
||||
@@ -469,7 +486,7 @@ final readonly class SearchRepairService
|
||||
{
|
||||
$codes = [];
|
||||
|
||||
if (preg_match_all('/\b(?:indikator|indicator|reagenz|reagent)\s*([A-Za-z]{0,3}\s*\d{1,5}[A-Za-z0-9\-]*)\b/iu', $text, $matches) !== false) {
|
||||
if (preg_match_all($this->config->getRequestedAccessoryCodePattern(), $text, $matches) !== false) {
|
||||
foreach ($matches[1] ?? [] as $code) {
|
||||
$normalized = $this->normalizeAccessoryCode((string) $code);
|
||||
if ($normalized !== '') {
|
||||
@@ -481,6 +498,51 @@ final readonly class SearchRepairService
|
||||
return array_values($codes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $requestedCodes
|
||||
* @return string[]
|
||||
*/
|
||||
private function buildRequestedAccessoryFallbackQueries(array $requestedCodes): array
|
||||
{
|
||||
$queries = [];
|
||||
$templates = $this->config->getRequestedAccessoryCodeFallbackQueryTemplates();
|
||||
$terms = $this->config->getRequestedAccessoryCodeFallbackTerms();
|
||||
|
||||
foreach ($requestedCodes as $code) {
|
||||
$normalizedCode = $this->normalizeAccessoryCode($code);
|
||||
if ($normalizedCode === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($templates as $template) {
|
||||
if (str_contains($template, '{term}')) {
|
||||
foreach ($terms as $term) {
|
||||
$queries[] = $this->applyRequestedAccessoryTemplate($template, $normalizedCode, $term);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$queries[] = $this->applyRequestedAccessoryTemplate($template, $normalizedCode, '');
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique(array_filter(
|
||||
array_map(fn(string $query): string => $this->sanitizeQuery($query), $queries),
|
||||
static fn(string $query): bool => $query !== ''
|
||||
)));
|
||||
}
|
||||
|
||||
private function applyRequestedAccessoryTemplate(string $template, string $code, string $term): string
|
||||
{
|
||||
$query = str_replace(
|
||||
['{code}', '{term}', '%code%', '%term%'],
|
||||
[$code, $term, $code, $term],
|
||||
$template
|
||||
);
|
||||
|
||||
return $this->sanitizeQuery($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $accessoryCandidates
|
||||
* @param string[] $requestedCodes
|
||||
@@ -505,7 +567,8 @@ final readonly class SearchRepairService
|
||||
array $modelCandidates,
|
||||
array $requestedCodes
|
||||
): array {
|
||||
$models = [];
|
||||
$promptAnchoredModels = [];
|
||||
$proximityModels = [];
|
||||
$normalizedPrompt = $this->normalizeForRepairMatching($prompt);
|
||||
|
||||
foreach ($modelCandidates as $candidate) {
|
||||
@@ -517,15 +580,24 @@ final readonly class SearchRepairService
|
||||
$normalizedCandidate = $this->normalizeForRepairMatching($candidate);
|
||||
$isPromptAnchored = $normalizedCandidate !== '' && str_contains($normalizedPrompt, $normalizedCandidate);
|
||||
|
||||
if ($isPromptAnchored) {
|
||||
$promptAnchoredModels[$candidate] = $candidate;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($requestedCodes as $code) {
|
||||
if ($isPromptAnchored || $this->modelAppearsNearAccessoryCode($knowledgeText, $candidate, $code)) {
|
||||
$models[$candidate] = $candidate;
|
||||
if ($this->modelAppearsNearAccessoryCode($knowledgeText, $candidate, $code)) {
|
||||
$proximityModels[$candidate] = $candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($models);
|
||||
if ($this->config->shouldPreferPromptAnchoredModelForRequestedAccessoryCode() && $promptAnchoredModels !== []) {
|
||||
return array_values($promptAnchoredModels);
|
||||
}
|
||||
|
||||
return array_values($promptAnchoredModels + $proximityModels);
|
||||
}
|
||||
|
||||
private function candidateMatchesRequestedAccessoryCodes(string $candidate, array $requestedCodes): bool
|
||||
@@ -564,17 +636,19 @@ final readonly class SearchRepairService
|
||||
return false;
|
||||
}
|
||||
|
||||
$codeNeedles = [
|
||||
'indikator ' . $normalizedCode,
|
||||
'indicator ' . $normalizedCode,
|
||||
'indikatortyp ' . $normalizedCode,
|
||||
$normalizedCode,
|
||||
];
|
||||
$codeNeedles = [$normalizedCode];
|
||||
foreach ($this->config->getRequestedAccessoryCodeContextPrefixTerms() as $term) {
|
||||
$normalizedTerm = $this->normalizeForRepairMatching($term);
|
||||
if ($normalizedTerm !== '') {
|
||||
$codeNeedles[] = trim($normalizedTerm . ' ' . $normalizedCode);
|
||||
}
|
||||
}
|
||||
$codeNeedles = array_values(array_unique($codeNeedles));
|
||||
|
||||
foreach ($codeNeedles as $needle) {
|
||||
foreach ($this->findNeedlePositions($normalizedText, $needle) as $codePos) {
|
||||
foreach ($modelPositions as $modelPos) {
|
||||
if (abs($codePos - $modelPos) <= 1600) {
|
||||
if (abs($codePos - $modelPos) <= $this->config->getRequestedAccessoryCodeProximityWindow()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -612,19 +686,18 @@ final readonly class SearchRepairService
|
||||
return '';
|
||||
}
|
||||
|
||||
$patterns = [
|
||||
'/\b(Testomat(?:®)?\s+(?:\d{3,4}|EVO(?:\s+[A-ZÄÖÜ]{1,8})?|ECO(?:[-\s]?(?:PLUS|C))?|DUO(?:\s+\d{3,4})?|LAB(?:\s+[A-ZÄÖÜ]{1,8})?))\b/iu',
|
||||
'/\b(Horiba\s+LAQUA\s+[A-Z0-9\-]+)\b/iu',
|
||||
];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
if (preg_match($pattern, $candidate, $matches) === 1) {
|
||||
return $this->sanitizeQuery((string) ($matches[1] ?? ''));
|
||||
$normalizedCandidate = $this->normalizeForRepairMatching($candidate);
|
||||
foreach ($this->config->getModelCandidateExcludeTerms() as $term) {
|
||||
$normalizedTerm = $this->normalizeForRepairMatching($term);
|
||||
if ($normalizedTerm !== '' && preg_match('/\b' . preg_quote($normalizedTerm, '/') . '\b/u', $normalizedCandidate) === 1) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/\b(?:indikator|indicator|reagenz|reagent|verfuegbarkeit|verfügbarkeit|shop)\b/iu', $candidate) === 1) {
|
||||
return '';
|
||||
foreach ($this->config->getSpecificModelCandidatePatterns() as $pattern) {
|
||||
if (preg_match($pattern, $candidate, $matches) === 1) {
|
||||
return $this->sanitizeQuery((string) ($matches[1] ?? ''));
|
||||
}
|
||||
}
|
||||
|
||||
return $candidate;
|
||||
|
||||
Reference in New Issue
Block a user