optimize technical truth
This commit is contained in:
@@ -52,6 +52,7 @@ final readonly class PromptBuilder
|
||||
$hasKnowledge = $knowledgeChunks !== [] || $urlContent !== '';
|
||||
$isTechnicalProductQuestion = $this->isLikelyTechnicalProductQuestion($prompt);
|
||||
$asksForAccessoryOrBundle = $this->asksForAccessoryOrBundle($prompt);
|
||||
$requestedProductRole = $this->resolveRequestedProductRole($prompt);
|
||||
$reliabilityState = $this->resolveReliabilityState(
|
||||
hasKnowledge: $hasKnowledge,
|
||||
hasShopResults: $hasShopResults,
|
||||
@@ -60,13 +61,13 @@ final readonly class PromptBuilder
|
||||
);
|
||||
|
||||
$systemBlock = $this->buildSystemBlock();
|
||||
$shopBlock = $this->buildShopBlock($prompt, $shopResults, $swagFullOutPut);
|
||||
$productRoleGuardBlock = $this->buildProductRoleGuardBlock($prompt, $shopResults);
|
||||
$shopBlock = $this->buildShopBlock($prompt, $shopResults, $swagFullOutPut, $requestedProductRole);
|
||||
$measurementEvidenceBlock = $this->buildMeasurementEvidenceBlock(
|
||||
prompt: $prompt,
|
||||
knowledgeChunks: $knowledgeChunks,
|
||||
urlContent: $urlContent,
|
||||
shopResults: $shopResults
|
||||
shopResults: $shopResults,
|
||||
requestedRole: $requestedProductRole
|
||||
);
|
||||
$outputPriorityBlock = $this->buildOutputPriorityBlock(
|
||||
hasShopResults: $hasShopResults,
|
||||
@@ -95,7 +96,6 @@ final readonly class PromptBuilder
|
||||
$fixedPrompt = $this->implodeBlocks([
|
||||
$systemBlock,
|
||||
$shopBlock,
|
||||
$productRoleGuardBlock,
|
||||
$measurementEvidenceBlock,
|
||||
$outputPriorityBlock,
|
||||
$fallbackEscalationBlock,
|
||||
@@ -113,7 +113,6 @@ final readonly class PromptBuilder
|
||||
return $this->implodeBlocks([
|
||||
$systemBlock,
|
||||
$shopBlock,
|
||||
$productRoleGuardBlock,
|
||||
$measurementEvidenceBlock,
|
||||
$outputPriorityBlock,
|
||||
$fallbackEscalationBlock,
|
||||
@@ -189,7 +188,7 @@ final readonly class PromptBuilder
|
||||
* Shop data is the most current source for commercial details.
|
||||
* It should not override technical matching logic.
|
||||
*/
|
||||
private function buildShopBlock(string $prompt, array $shopResults, ?string $swagFullOutPut): string
|
||||
private function buildShopBlock(string $prompt, array $shopResults, ?string $swagFullOutPut, ?string $requestedProductRole = null): string
|
||||
{
|
||||
$parts = [];
|
||||
|
||||
@@ -213,7 +212,7 @@ final readonly class PromptBuilder
|
||||
$totalCount = count($normalizedShopResults);
|
||||
$limitedShopResults = array_slice($normalizedShopResults, 0, $this->config->getMaxShopResultsInPrompt());
|
||||
$isDetailed = count($limitedShopResults) <= $this->config->getDetailedShopResultsMaxCount();
|
||||
$requestedRole = $this->resolveRequestedProductRole($prompt);
|
||||
$requestedRole = $requestedProductRole ?? $this->resolveRequestedProductRole($prompt);
|
||||
$measurementGuard = $this->resolveRequestedMeasurementGuard($prompt);
|
||||
$lines = [];
|
||||
|
||||
@@ -507,7 +506,7 @@ final readonly class PromptBuilder
|
||||
}
|
||||
}
|
||||
|
||||
$measurementEvidenceLine = $this->buildShopMeasurementEvidenceLine($product, $measurementGuard, $requestedRole);
|
||||
$measurementEvidenceLine = $this->buildShopMeasurementEvidenceLine($product, $measurementGuard);
|
||||
if ($measurementEvidenceLine !== '') {
|
||||
$entryParts[] = $measurementEvidenceLine;
|
||||
}
|
||||
@@ -517,9 +516,6 @@ final readonly class PromptBuilder
|
||||
|
||||
if ($suppressCommercialFields) {
|
||||
$entryParts[] = $this->config->getShopRoleIncompatibleCommercialSuppressionNote();
|
||||
$entryParts[] = $this->config->getProductRoleGuardIncompatibleRecordNote();
|
||||
|
||||
return implode("\n", $entryParts);
|
||||
}
|
||||
|
||||
if (!$suppressCommercialFields && $product->productNumber) {
|
||||
@@ -544,11 +540,13 @@ final readonly class PromptBuilder
|
||||
: $this->config->getShopAvailabilityNoLabel());
|
||||
}
|
||||
|
||||
foreach ($product->highlights as $highlight) {
|
||||
$highlight = $this->normalizeBlockText((string) $highlight);
|
||||
if (!$suppressCommercialFields) {
|
||||
foreach ($product->highlights as $highlight) {
|
||||
$highlight = $this->normalizeBlockText((string) $highlight);
|
||||
|
||||
if ($highlight !== '') {
|
||||
$entryParts[] = $this->config->getShopHighlightPrefix() . $highlight;
|
||||
if ($highlight !== '') {
|
||||
$entryParts[] = $this->config->getShopHighlightPrefix() . $highlight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,70 +573,6 @@ final readonly class PromptBuilder
|
||||
return implode("\n", $entryParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ShopProductResult[] $shopResults
|
||||
*/
|
||||
private function buildProductRoleGuardBlock(string $prompt, array $shopResults): string
|
||||
{
|
||||
$requestedRole = $this->resolveRequestedProductRole($prompt);
|
||||
|
||||
if ($requestedRole !== 'main_device') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$records = array_values(array_filter(
|
||||
$shopResults,
|
||||
static fn(mixed $product): bool => $product instanceof ShopProductResult
|
||||
));
|
||||
|
||||
if ($records === []) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$compatibleMainDeviceRecords = [];
|
||||
$incompatibleAccessoryRecords = [];
|
||||
$unknownRecords = [];
|
||||
|
||||
foreach ($records as $index => $product) {
|
||||
$inferredRole = $this->resolveShopProductRole($product);
|
||||
$roleCompatibility = $this->resolveShopRoleCompatibility($requestedRole, $inferredRole);
|
||||
$name = $this->normalizeBlockText($product->name);
|
||||
$label = sprintf('record %d%s', $index + 1, $name !== '' ? ' (' . $name . ')' : '');
|
||||
|
||||
if ($roleCompatibility === 'compatible' && $inferredRole === 'main_device') {
|
||||
$compatibleMainDeviceRecords[] = $label;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($roleCompatibility === 'incompatible_accessory_for_main_device_request') {
|
||||
$incompatibleAccessoryRecords[] = $label;
|
||||
continue;
|
||||
}
|
||||
|
||||
$unknownRecords[] = $label . ' role=' . $inferredRole . ' compatibility=' . $roleCompatibility;
|
||||
}
|
||||
|
||||
$rules = $this->config->getProductRoleGuardMainDeviceRules();
|
||||
$rules[] = '- Requested product role resolved from the user question: main_device.';
|
||||
$rules[] = '- Compatible main-device shop records: ' . ($compatibleMainDeviceRecords !== [] ? implode('; ', $compatibleMainDeviceRecords) : 'none') . '.';
|
||||
$rules[] = '- Role-incompatible accessory/consumable shop records: ' . ($incompatibleAccessoryRecords !== [] ? implode('; ', $incompatibleAccessoryRecords) : 'none') . '.';
|
||||
|
||||
if ($unknownRecords !== []) {
|
||||
$rules[] = '- Unknown or ambiguous shop records must be kept separate and must not be upgraded into a main-device recommendation: ' . implode('; ', $unknownRecords) . '.';
|
||||
}
|
||||
|
||||
if ($compatibleMainDeviceRecords === [] && $incompatibleAccessoryRecords !== []) {
|
||||
$rules[] = '- Mandatory answer behavior: ' . $this->config->getProductRoleGuardNoMainDeviceTemplate();
|
||||
$rules[] = '- Start with the no-match finding for the requested main device. Do not start with an accessory product name.';
|
||||
$rules[] = '- If mentioning incompatible shop hits, use a short separate section like "Nur Zubehörtreffer gefunden" and do not include price, availability, URL, product number, or recommendation wording for those records.';
|
||||
}
|
||||
|
||||
return $this->buildRuleBlock(
|
||||
$this->config->getProductRoleGuardSectionLabel(),
|
||||
$rules
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $knowledgeChunks
|
||||
* @param ShopProductResult[] $shopResults
|
||||
@@ -647,14 +581,9 @@ final readonly class PromptBuilder
|
||||
string $prompt,
|
||||
array $knowledgeChunks,
|
||||
string $urlContent,
|
||||
array $shopResults
|
||||
array $shopResults,
|
||||
?string $requestedRole = null
|
||||
): string {
|
||||
$requestedRole = $this->resolveRequestedProductRole($prompt);
|
||||
|
||||
if ($requestedRole === 'accessory_or_consumable') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$guard = $this->resolveRequestedMeasurementGuard($prompt);
|
||||
|
||||
if ($guard === null) {
|
||||
@@ -662,14 +591,19 @@ final readonly class PromptBuilder
|
||||
}
|
||||
|
||||
$positiveTerms = $this->extractMeasurementGuardStringList($guard, 'positive_terms');
|
||||
$positiveContextTerms = $this->extractMeasurementGuardStringList($guard, 'positive_context_terms');
|
||||
$negativeContextTerms = $this->extractMeasurementGuardStringList($guard, 'negative_context_terms');
|
||||
$nonEquivalentTerms = $this->extractMeasurementGuardStringList($guard, 'non_equivalent_terms');
|
||||
$label = $this->normalizeBlockText((string) ($guard['label'] ?? 'requested measurement parameter'));
|
||||
$safeNoEvidenceAnswer = $this->normalizeBlockText((string) ($guard['safe_no_evidence_answer_de'] ?? ''));
|
||||
$resolvedRequestedRole = $requestedRole ?? $this->resolveRequestedProductRole($prompt);
|
||||
$safeNoEvidenceAnswer = $this->normalizeBlockText((string) (
|
||||
$resolvedRequestedRole === 'accessory_or_consumable'
|
||||
? ($guard['safe_no_accessory_evidence_answer_de'] ?? $guard['safe_no_evidence_answer_de'] ?? '')
|
||||
: ($guard['safe_no_evidence_answer_de'] ?? '')
|
||||
));
|
||||
|
||||
$knowledgeText = $this->normalizeBlockText(implode("\n\n", array_map('strval', $knowledgeChunks)) . "\n\n" . $urlContent);
|
||||
$knowledgeHasEvidence = $this->containsMeasurementPositiveEvidence($knowledgeText, $positiveTerms);
|
||||
$knowledgeHasOnlyWeakMention = !$knowledgeHasEvidence
|
||||
&& $this->containsAnyMeasurementWeakMention($knowledgeText, $guard);
|
||||
$knowledgeHasEvidence = $this->containsMeasurementPositiveEvidence($knowledgeText, $positiveTerms, $positiveContextTerms, $negativeContextTerms);
|
||||
|
||||
$shopEvidenceLines = [];
|
||||
$shopHasEvidence = false;
|
||||
@@ -679,7 +613,7 @@ final readonly class PromptBuilder
|
||||
continue;
|
||||
}
|
||||
|
||||
$hasEvidence = $this->shopProductHasMeasurementEvidence($product, $positiveTerms);
|
||||
$hasEvidence = $this->shopProductHasMeasurementEvidence($product, $positiveTerms, $positiveContextTerms, $negativeContextTerms);
|
||||
$productName = $this->normalizeBlockText($product->name);
|
||||
|
||||
if ($hasEvidence) {
|
||||
@@ -702,16 +636,19 @@ final readonly class PromptBuilder
|
||||
|
||||
$rules = $this->config->getMeasurementEvidenceIntroRules();
|
||||
$rules[] = '- User requested measurement parameter: ' . $label . '.';
|
||||
$rules[] = '- Positive evidence terms that count for this request: ' . implode(', ', $positiveTerms) . '.';
|
||||
$rules[] = '- Positive parameter terms for this request: ' . implode(', ', $positiveTerms) . '.';
|
||||
if ($positiveContextTerms !== []) {
|
||||
$rules[] = '- These parameter terms count as suitability evidence only in a measurement-purpose context such as: ' . implode(', ', $positiveContextTerms) . '.';
|
||||
}
|
||||
if ($negativeContextTerms !== []) {
|
||||
$rules[] = '- These contexts are not suitability evidence by themselves: ' . implode(', ', $negativeContextTerms) . '.';
|
||||
}
|
||||
|
||||
if ($nonEquivalentTerms !== []) {
|
||||
$rules[] = '- Terms that must NOT be treated as equivalent positive evidence: ' . implode(', ', $nonEquivalentTerms) . '.';
|
||||
}
|
||||
|
||||
$rules[] = '- RAG/URL evidence scan for this exact measurement capability: ' . ($knowledgeHasEvidence ? 'explicit positive capability evidence found.' : 'no explicit positive capability evidence found.');
|
||||
if ($knowledgeHasOnlyWeakMention) {
|
||||
$rules[] = '- RAG/URL weak mention scan: the parameter is mentioned, but only as a weak/non-capability mention. Do not use this as suitability evidence.';
|
||||
}
|
||||
$rules[] = '- RAG/URL evidence scan for this exact parameter: ' . ($knowledgeHasEvidence ? 'explicit positive evidence found.' : 'no explicit positive evidence found.');
|
||||
$rules = array_merge($rules, $shopEvidenceLines);
|
||||
|
||||
if (!$knowledgeHasEvidence && !$shopHasEvidence) {
|
||||
@@ -719,11 +656,14 @@ final readonly class PromptBuilder
|
||||
if ($safeNoEvidenceAnswer !== '') {
|
||||
$rules[] = '- Start the answer with this meaning in the user language: ' . $safeNoEvidenceAnswer;
|
||||
}
|
||||
$rules[] = '- You may list exact shop hits only as commercial/search hits under a heading such as "Shop-Treffer (technische Eignung nicht sicher belegt)".';
|
||||
if ($resolvedRequestedRole === 'accessory_or_consumable') {
|
||||
$rules[] = '- Do not recommend accessories for a different measurement parameter just because they are accessories. If only accessories for other parameters are present, say that only non-matching accessory hits were found.';
|
||||
} else {
|
||||
$rules[] = '- You may list exact shop hits only as commercial/search hits under a heading such as "Shop-Treffer (technische Eignung nicht sicher belegt)".';
|
||||
}
|
||||
}
|
||||
|
||||
$rules[] = '- Do not output measurement ranges, methods, application areas, advantages, or alternative suitable models unless the same source record contains explicit positive capability evidence for the requested measurement parameter.';
|
||||
$rules[] = '- Do not list products as relevant just because the requested parameter appears in an operating range, reagent/indicator property, output-transfer field, metadata, or generic mention.';
|
||||
$rules[] = '- Do not output measurement ranges, methods, application areas, advantages, or alternative suitable models unless the same source record contains explicit positive evidence for the requested measurement parameter.';
|
||||
$rules[] = '- The generated shop search query, search intent, ranking position, and user question are not factual evidence for product suitability.';
|
||||
|
||||
return $this->buildRuleBlock(
|
||||
@@ -732,20 +672,22 @@ final readonly class PromptBuilder
|
||||
);
|
||||
}
|
||||
|
||||
private function buildShopMeasurementEvidenceLine(ShopProductResult $product, ?array $guard, string $requestedRole = 'unknown'): string
|
||||
private function buildShopMeasurementEvidenceLine(ShopProductResult $product, ?array $guard): string
|
||||
{
|
||||
if ($guard === null || $requestedRole === 'accessory_or_consumable') {
|
||||
if ($guard === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$positiveTerms = $this->extractMeasurementGuardStringList($guard, 'positive_terms');
|
||||
$positiveContextTerms = $this->extractMeasurementGuardStringList($guard, 'positive_context_terms');
|
||||
$negativeContextTerms = $this->extractMeasurementGuardStringList($guard, 'negative_context_terms');
|
||||
$label = $this->normalizeBlockText((string) ($guard['label'] ?? 'requested measurement parameter'));
|
||||
|
||||
if ($positiveTerms === []) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($this->shopProductHasMeasurementEvidence($product, $positiveTerms)) {
|
||||
if ($this->shopProductHasMeasurementEvidence($product, $positiveTerms, $positiveContextTerms, $negativeContextTerms)) {
|
||||
return sprintf(
|
||||
'Requested measurement evidence: explicit positive evidence for %s is present in this same SHOP PRODUCT RECORD.',
|
||||
$label
|
||||
@@ -803,36 +745,86 @@ final readonly class PromptBuilder
|
||||
|
||||
/**
|
||||
* @param string[] $positiveTerms
|
||||
* @param string[] $positiveContextTerms
|
||||
* @param string[] $negativeContextTerms
|
||||
*/
|
||||
private function shopProductHasMeasurementEvidence(ShopProductResult $product, array $positiveTerms): bool
|
||||
{
|
||||
return $this->containsMeasurementPositiveEvidence(
|
||||
$this->buildShopProductEvidenceText($product),
|
||||
$positiveTerms
|
||||
);
|
||||
private function shopProductHasMeasurementEvidence(
|
||||
ShopProductResult $product,
|
||||
array $positiveTerms,
|
||||
array $positiveContextTerms,
|
||||
array $negativeContextTerms
|
||||
): bool {
|
||||
foreach ($this->buildShopProductEvidenceFragments($product) as $fragment) {
|
||||
if ($this->containsMeasurementPositiveEvidence($fragment, $positiveTerms, $positiveContextTerms, $negativeContextTerms)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function buildShopProductEvidenceText(ShopProductResult $product): string
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function buildShopProductEvidenceFragments(ShopProductResult $product): array
|
||||
{
|
||||
return $this->normalizeBlockText(implode(' ', array_filter([
|
||||
$fragments = array_filter([
|
||||
$product->name,
|
||||
$product->productNumber,
|
||||
$product->manufacturer,
|
||||
$product->url,
|
||||
implode(' ', array_map('strval', $product->highlights)),
|
||||
$product->description,
|
||||
$product->customFields,
|
||||
$product->url,
|
||||
], static fn($value): bool => is_scalar($value) && trim((string) $value) !== '')));
|
||||
], static fn($value): bool => is_scalar($value) && trim((string) $value) !== '');
|
||||
|
||||
$out = [];
|
||||
foreach ($fragments as $fragment) {
|
||||
foreach ($this->splitMeasurementEvidenceFragments((string) $fragment) as $part) {
|
||||
if ($part !== '') {
|
||||
$out[] = $part;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $positiveTerms
|
||||
* @param string[] $positiveContextTerms
|
||||
* @param string[] $negativeContextTerms
|
||||
*/
|
||||
private function containsMeasurementPositiveEvidence(string $text, array $positiveTerms): bool
|
||||
{
|
||||
$normalizedText = $this->normalizeForMeasurementMatching($text);
|
||||
private function containsMeasurementPositiveEvidence(
|
||||
string $text,
|
||||
array $positiveTerms,
|
||||
array $positiveContextTerms,
|
||||
array $negativeContextTerms
|
||||
): bool {
|
||||
foreach ($this->splitMeasurementEvidenceFragments($text) as $fragment) {
|
||||
$normalizedFragment = $this->normalizeForMeasurementMatching($fragment);
|
||||
|
||||
foreach ($positiveTerms as $term) {
|
||||
if ($normalizedFragment === '' || !$this->containsAnyMeasurementTerm($normalizedFragment, $positiveTerms)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($negativeContextTerms !== [] && $this->containsAnyMeasurementTerm($normalizedFragment, $negativeContextTerms)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($positiveContextTerms === [] || $this->containsAnyMeasurementTerm($normalizedFragment, $positiveContextTerms)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $terms
|
||||
*/
|
||||
private function containsAnyMeasurementTerm(string $normalizedText, array $terms): bool
|
||||
{
|
||||
foreach ($terms as $term) {
|
||||
if ($this->containsMeasurementTerm($normalizedText, $term)) {
|
||||
return true;
|
||||
}
|
||||
@@ -842,29 +834,21 @@ final readonly class PromptBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when a measurement parameter is mentioned only as request wording or as a known non-equivalent/weak term.
|
||||
* This is used for prompt diagnostics and must not be treated as positive suitability evidence.
|
||||
* @return string[]
|
||||
*/
|
||||
private function containsAnyMeasurementWeakMention(string $text, array $guard): bool
|
||||
private function splitMeasurementEvidenceFragments(string $text): array
|
||||
{
|
||||
$weakTerms = array_merge(
|
||||
$this->extractMeasurementGuardStringList($guard, 'request_terms'),
|
||||
$this->extractMeasurementGuardStringList($guard, 'non_equivalent_terms')
|
||||
);
|
||||
|
||||
if ($weakTerms === []) {
|
||||
return false;
|
||||
$text = $this->normalizeBlockText($text);
|
||||
if ($text === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$normalizedText = $this->normalizeForMeasurementMatching($text);
|
||||
$parts = preg_split('/[\n.;|]+/u', $text) ?: [$text];
|
||||
|
||||
foreach ($weakTerms as $term) {
|
||||
if ($this->containsMeasurementTerm($normalizedText, $term)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return array_values(array_filter(
|
||||
array_map(fn(string $part): string => $this->normalizeBlockText($part), $parts),
|
||||
static fn(string $part): bool => $part !== ''
|
||||
));
|
||||
}
|
||||
|
||||
private function containsMeasurementTerm(string $normalizedText, string $term): bool
|
||||
@@ -945,21 +929,42 @@ final readonly class PromptBuilder
|
||||
|
||||
private function resolveRequestedProductRole(string $prompt): string
|
||||
{
|
||||
$normalized = mb_strtolower($prompt, 'UTF-8');
|
||||
$asksForAccessory = $this->containsAnyPromptKeyword($normalized, $this->config->getAccessoryRequestKeywords())
|
||||
|| $this->containsAnyPromptKeyword($normalized, $this->config->getAccessoryProductRoleKeywords());
|
||||
$normalized = mb_strtolower($this->normalizeBlockText($prompt), 'UTF-8');
|
||||
$hasAccessoryIntent = $this->containsAnyPromptKeyword($normalized, $this->config->getAccessoryProductRoleKeywords());
|
||||
$hasMainDeviceIntent = $this->containsAnyPromptKeyword($normalized, $this->config->getMainDeviceRequestRoleKeywords());
|
||||
|
||||
if ($asksForAccessory) {
|
||||
if ($hasAccessoryIntent && !$this->hasDirectMainDeviceRequest($normalized)) {
|
||||
return 'accessory_or_consumable';
|
||||
}
|
||||
|
||||
if ($this->containsAnyPromptKeyword($normalized, $this->config->getMainDeviceRequestRoleKeywords())) {
|
||||
if ($hasMainDeviceIntent) {
|
||||
return 'main_device';
|
||||
}
|
||||
|
||||
if ($hasAccessoryIntent) {
|
||||
return 'accessory_or_consumable';
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
private function hasDirectMainDeviceRequest(string $normalizedPrompt): bool
|
||||
{
|
||||
$patterns = [
|
||||
'/\b(welcher|welches|welche)\s+[^?.!,;]{0,40}(testomat|messgerät|messgeraet|analysegerät|analysegeraet|gerät|geraet|analysator)\b/u',
|
||||
'/\b(suche|finde|empfiehl|empfehle)\s+[^?.!,;]{0,40}(testomat|messgerät|messgeraet|analysegerät|analysegeraet|gerät|geraet|analysator)\b/u',
|
||||
'/\b(testomat|messgerät|messgeraet|analysegerät|analysegeraet|gerät|geraet|analysator)\s+[^?.!,;]{0,40}(messen|misst|überwachen|ueberwachen|kann|für|fuer)\b/u',
|
||||
];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
if (preg_match($pattern, $normalizedPrompt) === 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function resolveShopProductRole(ShopProductResult $product): string
|
||||
{
|
||||
$primaryRole = $this->resolveShopPrimaryProductRole($product);
|
||||
@@ -1113,4 +1118,4 @@ final readonly class PromptBuilder
|
||||
{
|
||||
return max($min, min($max, $value));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user