central config part 2
This commit is contained in:
16
RETRIEX_CONFIG_CENTRALIZATION_FIX_README.md
Normal file
16
RETRIEX_CONFIG_CENTRALIZATION_FIX_README.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# RetrieX configuration centralization fix
|
||||||
|
|
||||||
|
This patch centralizes additional low-risk word and pattern lists without changing their defaults.
|
||||||
|
|
||||||
|
## Changed areas
|
||||||
|
|
||||||
|
- `SearchRepairConfig` now reads repair vocabulary from `config/retriex/vocabulary.yaml` via `DomainVocabularyConfig`.
|
||||||
|
- `CommerceIntentConfig`, `IntentLightConfig`, and `SalesIntentConfig` now read their lists from `config/retriex/intent.yaml`.
|
||||||
|
- Existing PHP defaults remain in the classes as fallbacks.
|
||||||
|
- Existing scalar thresholds and prompt wording are unchanged.
|
||||||
|
|
||||||
|
## Safety notes
|
||||||
|
|
||||||
|
The YAML values mirror the previous PHP defaults 1:1. The patch is meant to simplify maintenance and configuration, not to broaden or alter matching behavior.
|
||||||
|
|
||||||
|
After installing, clear the Symfony cache and run the known 1.4.2 regression prompts.
|
||||||
216
config/retriex/intent.yaml
Normal file
216
config/retriex/intent.yaml
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
# Intent vocabulary and pattern configuration.
|
||||||
|
# Lists mirror the previous PHP defaults exactly; PHP defaults remain as fallback.
|
||||||
|
parameters:
|
||||||
|
retriex.intent.commerce.config:
|
||||||
|
strong_signals:
|
||||||
|
- shop
|
||||||
|
- alle
|
||||||
|
- preis
|
||||||
|
- kunde
|
||||||
|
- online
|
||||||
|
- produkt
|
||||||
|
- artikel
|
||||||
|
- sku
|
||||||
|
- kaufen
|
||||||
|
- kostet
|
||||||
|
- suche
|
||||||
|
- such
|
||||||
|
- finde
|
||||||
|
- finden
|
||||||
|
- analysegerät
|
||||||
|
- analysegeraet
|
||||||
|
- messgerät
|
||||||
|
- messgeraet
|
||||||
|
- analysator
|
||||||
|
- analyzer
|
||||||
|
- puffer
|
||||||
|
- kalibrierpuffer
|
||||||
|
- kalibrierlösung
|
||||||
|
- kalibrierloesung
|
||||||
|
- kalibrierung
|
||||||
|
- chemie
|
||||||
|
- reagenz
|
||||||
|
- reagenzien
|
||||||
|
- verbrauchsmaterial
|
||||||
|
- zubehör
|
||||||
|
- zubehoer
|
||||||
|
- ersatzteil
|
||||||
|
advisory_signals:
|
||||||
|
- passt
|
||||||
|
- eignet
|
||||||
|
- besser
|
||||||
|
- besten
|
||||||
|
- gut für
|
||||||
|
- gut fuer
|
||||||
|
- passend für
|
||||||
|
- passend fuer
|
||||||
|
- geeignet
|
||||||
|
- geeigent
|
||||||
|
- empfiehl
|
||||||
|
- empfehl
|
||||||
|
price_terms:
|
||||||
|
- euro
|
||||||
|
- €
|
||||||
|
- eur
|
||||||
|
- teuer
|
||||||
|
- preis
|
||||||
|
- kosten
|
||||||
|
- kostet
|
||||||
|
color_terms:
|
||||||
|
- schwarz
|
||||||
|
- weiß
|
||||||
|
- weis
|
||||||
|
- blau
|
||||||
|
- grau
|
||||||
|
- beige
|
||||||
|
- rosa
|
||||||
|
- pink
|
||||||
|
- gruen
|
||||||
|
- orange
|
||||||
|
- braun
|
||||||
|
size_token_terms:
|
||||||
|
- xs
|
||||||
|
- s
|
||||||
|
- m
|
||||||
|
- l
|
||||||
|
- xl
|
||||||
|
- xxl
|
||||||
|
- xxxxl
|
||||||
|
size_terms:
|
||||||
|
- größe
|
||||||
|
- groesse
|
||||||
|
- grösse
|
||||||
|
support_diagnostic_patterns:
|
||||||
|
- '/\bfehler\b/u'
|
||||||
|
- '/\bfehlercode\b/u'
|
||||||
|
- '/\berror\b/u'
|
||||||
|
- '/\bstörung\b/u'
|
||||||
|
- '/\bstoerung\b/u'
|
||||||
|
- '/\balarm\b/u'
|
||||||
|
- '/\bstörungsmeldung\b/u'
|
||||||
|
- '/\bstoerungsmeldung\b/u'
|
||||||
|
- '/\bmeldung\b/u'
|
||||||
|
- '/\bwarnung\b/u'
|
||||||
|
- '/\bwarncode\b/u'
|
||||||
|
- '/\bcode\b/u'
|
||||||
|
- '/\bwas bedeutet\b/u'
|
||||||
|
- '/\bwarum\b/u'
|
||||||
|
- '/\bblinkt\b/u'
|
||||||
|
- '/\bzeigt\b/u'
|
||||||
|
- '/\bzeigt an\b/u'
|
||||||
|
- '/\bursache\b/u'
|
||||||
|
- '/\bdiagnose\b/u'
|
||||||
|
- '/\bservicefall\b/u'
|
||||||
|
- '/\bproblem\b/u'
|
||||||
|
- '/\bstörung beheben\b/u'
|
||||||
|
- '/\bstoerung beheben\b/u'
|
||||||
|
- '/\be\d{1,3}\b/u'
|
||||||
|
explicit_commerce_intent_patterns:
|
||||||
|
- '/\bshop\b/u'
|
||||||
|
- '/\bpreis\b/u'
|
||||||
|
- '/\bkosten\b/u'
|
||||||
|
- '/\bkostet\b/u'
|
||||||
|
- '/\bkaufen\b/u'
|
||||||
|
- '/\bbestellen\b/u'
|
||||||
|
- '/\bprodukt\b/u'
|
||||||
|
- '/\bartikel\b/u'
|
||||||
|
- '/\bsku\b/u'
|
||||||
|
- '/\bonline\b/u'
|
||||||
|
- '/\bchemie\b/u'
|
||||||
|
- '/\breagenz(?:ien)?\b/u'
|
||||||
|
- '/\bverbrauchsmaterial(?:ien)?\b/u'
|
||||||
|
- '/\bzubehör\b/u'
|
||||||
|
- '/\bzubehoer\b/u'
|
||||||
|
- '/\bersatzteil(?:e)?\b/u'
|
||||||
|
|
||||||
|
retriex.intent.light.config:
|
||||||
|
quantity_words:
|
||||||
|
- alle
|
||||||
|
- sämtliche
|
||||||
|
- saemtliche
|
||||||
|
- mehrere
|
||||||
|
- verschiedene
|
||||||
|
- einige
|
||||||
|
- viele
|
||||||
|
- optionen
|
||||||
|
- möglichkeiten
|
||||||
|
- moeglichkeiten
|
||||||
|
- varianten
|
||||||
|
- arten
|
||||||
|
- modelle
|
||||||
|
- funktionen
|
||||||
|
- punkte
|
||||||
|
- schritte
|
||||||
|
- kategorien
|
||||||
|
- übersicht
|
||||||
|
- uebersicht
|
||||||
|
strong_patterns:
|
||||||
|
- '/\bliste(n)?\b/u'
|
||||||
|
- '/\bauflisten\b/u'
|
||||||
|
- '/\baufz(a|ä)hl(en)?\b/u'
|
||||||
|
- '/\bnenn(e)?\b/u'
|
||||||
|
- '/\bzeig(e)?\b/u'
|
||||||
|
- '/\bwelche\s+sind\b/u'
|
||||||
|
- '/\bwelche\s+gibt\s+es\b/u'
|
||||||
|
- '/\bwas\s+sind\b/u'
|
||||||
|
- '/\bwie\s+viele\b/u'
|
||||||
|
- '/\branking\b/u'
|
||||||
|
- '/\btop\s*\d+\b/u'
|
||||||
|
|
||||||
|
retriex.intent.sales.config:
|
||||||
|
sales_signals:
|
||||||
|
- preis
|
||||||
|
- preise
|
||||||
|
- kosten
|
||||||
|
- lizenz
|
||||||
|
- lizenzmodell
|
||||||
|
- tarif
|
||||||
|
- tarife
|
||||||
|
- gebuehr
|
||||||
|
- gebühr
|
||||||
|
- monatlich
|
||||||
|
- jaehrlich
|
||||||
|
- jährlich
|
||||||
|
- abo
|
||||||
|
- subscription
|
||||||
|
comparison_signals:
|
||||||
|
- '/\bvergleich(en)?\b/u'
|
||||||
|
- '/\bvs\b/u'
|
||||||
|
- '/\bgegenueber\b/u'
|
||||||
|
- '/\balternative(n)?\b/u'
|
||||||
|
- '/\bunterschied(e)?\b/u'
|
||||||
|
- '/\bbesser\b/u'
|
||||||
|
objection_signals:
|
||||||
|
- problem
|
||||||
|
- risiko
|
||||||
|
- nachteil
|
||||||
|
- datenschutz
|
||||||
|
- dsgvo
|
||||||
|
- sicherheit
|
||||||
|
- compliance
|
||||||
|
- kritik
|
||||||
|
- zweifel
|
||||||
|
- unsicher
|
||||||
|
implementation_signals:
|
||||||
|
- implementierung
|
||||||
|
- implementieren
|
||||||
|
- integration
|
||||||
|
- integrieren
|
||||||
|
- einführung
|
||||||
|
- einfuehrung
|
||||||
|
- aufwand
|
||||||
|
- setup
|
||||||
|
- rollout
|
||||||
|
- migration
|
||||||
|
- installation
|
||||||
|
- api
|
||||||
|
- schnittstelle
|
||||||
|
roi_signals:
|
||||||
|
- roi
|
||||||
|
- rentabilitaet
|
||||||
|
- rentabilität
|
||||||
|
- business case
|
||||||
|
- einsparung
|
||||||
|
- kosten senken
|
||||||
|
- umsatz steigern
|
||||||
|
- effizienz steigern
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
# Views preserve the previous 1.4.2-tuned ordering exactly; per-service configs may still override them.
|
# Views preserve the previous 1.4.2-tuned ordering exactly; per-service configs may still override them.
|
||||||
parameters:
|
parameters:
|
||||||
retriex.commerce_query.config: {}
|
retriex.commerce_query.config: {}
|
||||||
|
retriex.search_repair.config: {}
|
||||||
retriex.vocabulary.config:
|
retriex.vocabulary.config:
|
||||||
classes:
|
classes:
|
||||||
device:
|
device:
|
||||||
@@ -485,6 +486,55 @@ parameters:
|
|||||||
- überwachung
|
- überwachung
|
||||||
- online
|
- online
|
||||||
- monitor
|
- monitor
|
||||||
|
search_repair:
|
||||||
|
generic_candidate_tokens:
|
||||||
|
add:
|
||||||
|
- wasser
|
||||||
|
- messgerät
|
||||||
|
- messgeraet
|
||||||
|
- produkt
|
||||||
|
- geräte
|
||||||
|
- geraete
|
||||||
|
- gerät
|
||||||
|
- geraet
|
||||||
|
- resthärte
|
||||||
|
- resthaerte
|
||||||
|
- preis
|
||||||
|
- infos
|
||||||
|
- wissen
|
||||||
|
accessory_candidate_terms:
|
||||||
|
add:
|
||||||
|
- indikator
|
||||||
|
- indicator
|
||||||
|
- reagenz
|
||||||
|
- reagent
|
||||||
|
- kit
|
||||||
|
- set
|
||||||
|
accessory_or_bundle_terms:
|
||||||
|
add:
|
||||||
|
- passend
|
||||||
|
- passende
|
||||||
|
- zubehor
|
||||||
|
- zubehör
|
||||||
|
- dazu
|
||||||
|
- zusatz
|
||||||
|
- erganzung
|
||||||
|
- ergänzung
|
||||||
|
- indikator
|
||||||
|
- reagenz
|
||||||
|
- kit
|
||||||
|
- set
|
||||||
|
- auch\s+das
|
||||||
|
- mit\s+preis\s+und\s+allen\s+infos
|
||||||
|
specificity_boost_terms:
|
||||||
|
add:
|
||||||
|
- indikator
|
||||||
|
- indicator
|
||||||
|
- testomat
|
||||||
|
- tritromat
|
||||||
|
- titromat
|
||||||
|
- reagenz
|
||||||
|
- reagent
|
||||||
prompt:
|
prompt:
|
||||||
technical_product_keywords:
|
technical_product_keywords:
|
||||||
add:
|
add:
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ imports:
|
|||||||
- { resource: 'retriex/language.yaml' }
|
- { resource: 'retriex/language.yaml' }
|
||||||
- { resource: 'retriex/query_enrichment.yaml' }
|
- { resource: 'retriex/query_enrichment.yaml' }
|
||||||
- { resource: 'retriex/vocabulary.yaml' }
|
- { resource: 'retriex/vocabulary.yaml' }
|
||||||
|
- { resource: 'retriex/intent.yaml' }
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Parameters
|
# Parameters
|
||||||
@@ -183,6 +184,10 @@ services:
|
|||||||
|
|
||||||
App\Intent\CommerceIntentLite: ~
|
App\Intent\CommerceIntentLite: ~
|
||||||
|
|
||||||
|
App\Config\CommerceIntentConfig:
|
||||||
|
arguments:
|
||||||
|
$config: '%retriex.intent.commerce.config%'
|
||||||
|
|
||||||
App\Config\CommerceQueryParserConfig:
|
App\Config\CommerceQueryParserConfig:
|
||||||
arguments:
|
arguments:
|
||||||
$config: '%retriex.commerce_query.config%'
|
$config: '%retriex.commerce_query.config%'
|
||||||
@@ -195,9 +200,19 @@ services:
|
|||||||
$enabled: '%retriex.commerce.search_repair.enabled%'
|
$enabled: '%retriex.commerce.search_repair.enabled%'
|
||||||
$maxRepairQueries: '%retriex.commerce.search_repair.max_queries%'
|
$maxRepairQueries: '%retriex.commerce.search_repair.max_queries%'
|
||||||
$minPrimaryResultsWithoutRepair: '%retriex.commerce.search_repair.min_primary_results_without_repair%'
|
$minPrimaryResultsWithoutRepair: '%retriex.commerce.search_repair.min_primary_results_without_repair%'
|
||||||
|
$config: '%retriex.search_repair.config%'
|
||||||
|
$vocabulary: '@App\Config\DomainVocabularyConfig'
|
||||||
|
|
||||||
App\Commerce\SearchRepairService: ~
|
App\Commerce\SearchRepairService: ~
|
||||||
|
|
||||||
|
App\Config\IntentLightConfig:
|
||||||
|
arguments:
|
||||||
|
$config: '%retriex.intent.light.config%'
|
||||||
|
|
||||||
|
App\Config\SalesIntentConfig:
|
||||||
|
arguments:
|
||||||
|
$config: '%retriex.intent.sales.config%'
|
||||||
|
|
||||||
App\Shopware\ShopwareCriteriaBuilder: ~
|
App\Shopware\ShopwareCriteriaBuilder: ~
|
||||||
|
|
||||||
App\Shopware\StoreApiClient:
|
App\Shopware\StoreApiClient:
|
||||||
|
|||||||
@@ -6,12 +6,7 @@ namespace App\Config;
|
|||||||
|
|
||||||
final class CommerceIntentConfig
|
final class CommerceIntentConfig
|
||||||
{
|
{
|
||||||
/**
|
private const STRONG_SIGNALS = [
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getStrongSignalsList(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'shop',
|
'shop',
|
||||||
'alle',
|
'alle',
|
||||||
'preis',
|
'preis',
|
||||||
@@ -45,14 +40,8 @@ final class CommerceIntentConfig
|
|||||||
'zubehoer',
|
'zubehoer',
|
||||||
'ersatzteil',
|
'ersatzteil',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private const ADVISORY_SIGNALS = [
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getAdvisorySignals(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'passt',
|
'passt',
|
||||||
'eignet',
|
'eignet',
|
||||||
'besser',
|
'besser',
|
||||||
@@ -66,14 +55,8 @@ final class CommerceIntentConfig
|
|||||||
'empfiehl',
|
'empfiehl',
|
||||||
'empfehl',
|
'empfehl',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private const PRICE_TERMS = [
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getPriceTerms(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'euro',
|
'euro',
|
||||||
'€',
|
'€',
|
||||||
'eur',
|
'eur',
|
||||||
@@ -82,19 +65,8 @@ final class CommerceIntentConfig
|
|||||||
'kosten',
|
'kosten',
|
||||||
'kostet',
|
'kostet',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public function getPricePattern(): string
|
private const COLOR_TERMS = [
|
||||||
{
|
|
||||||
return implode('|', $this->getPriceTerms());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getColorTerms(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'schwarz',
|
'schwarz',
|
||||||
'weiß',
|
'weiß',
|
||||||
'weis',
|
'weis',
|
||||||
@@ -107,19 +79,8 @@ final class CommerceIntentConfig
|
|||||||
'orange',
|
'orange',
|
||||||
'braun',
|
'braun',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public function getColorPattern(): string
|
private const SIZE_TOKEN_TERMS = [
|
||||||
{
|
|
||||||
return implode('|', $this->getColorTerms());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getSizeTokenTerms(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'xs',
|
'xs',
|
||||||
's',
|
's',
|
||||||
'm',
|
'm',
|
||||||
@@ -128,41 +89,14 @@ final class CommerceIntentConfig
|
|||||||
'xxl',
|
'xxl',
|
||||||
'xxxxl',
|
'xxxxl',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public function getSizeTokenPattern(): string
|
private const SIZE_TERMS = [
|
||||||
{
|
|
||||||
return implode('|', $this->getSizeTokenTerms());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getSizeTerms(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'größe',
|
'größe',
|
||||||
'groesse',
|
'groesse',
|
||||||
'grösse',
|
'grösse',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public function getSizePattern(): string
|
private const SUPPORT_DIAGNOSTIC_PATTERNS = [
|
||||||
{
|
|
||||||
return implode('|', $this->getSizeTerms());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSizeExtractionPattern(): string
|
|
||||||
{
|
|
||||||
return '/\b(?:' . $this->getSizePattern() . ')\s*([a-z0-9.-]+)\b/u';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getSupportDiagnosticPatterns(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'/\bfehler\b/u',
|
'/\bfehler\b/u',
|
||||||
'/\bfehlercode\b/u',
|
'/\bfehlercode\b/u',
|
||||||
'/\berror\b/u',
|
'/\berror\b/u',
|
||||||
@@ -188,14 +122,8 @@ final class CommerceIntentConfig
|
|||||||
'/\bstoerung beheben\b/u',
|
'/\bstoerung beheben\b/u',
|
||||||
'/\be\d{1,3}\b/u',
|
'/\be\d{1,3}\b/u',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private const EXPLICIT_COMMERCE_INTENT_PATTERNS = [
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getExplicitCommerceIntentPatterns(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'/\bshop\b/u',
|
'/\bshop\b/u',
|
||||||
'/\bpreis\b/u',
|
'/\bpreis\b/u',
|
||||||
'/\bkosten\b/u',
|
'/\bkosten\b/u',
|
||||||
@@ -213,6 +141,85 @@ final class CommerceIntentConfig
|
|||||||
'/\bzubehoer\b/u',
|
'/\bzubehoer\b/u',
|
||||||
'/\bersatzteil(?:e)?\b/u',
|
'/\bersatzteil(?:e)?\b/u',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $config
|
||||||
|
*/
|
||||||
|
public function __construct(private readonly array $config = [])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getStrongSignalsList(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('strong_signals', self::STRONG_SIGNALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getAdvisorySignals(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('advisory_signals', self::ADVISORY_SIGNALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getPriceTerms(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('price_terms', self::PRICE_TERMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPricePattern(): string
|
||||||
|
{
|
||||||
|
return implode('|', $this->getPriceTerms());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getColorTerms(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('color_terms', self::COLOR_TERMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getColorPattern(): string
|
||||||
|
{
|
||||||
|
return implode('|', $this->getColorTerms());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getSizeTokenTerms(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('size_token_terms', self::SIZE_TOKEN_TERMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSizeTokenPattern(): string
|
||||||
|
{
|
||||||
|
return implode('|', $this->getSizeTokenTerms());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getSizeTerms(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('size_terms', self::SIZE_TERMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSizePattern(): string
|
||||||
|
{
|
||||||
|
return implode('|', $this->getSizeTerms());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSizeExtractionPattern(): string
|
||||||
|
{
|
||||||
|
return '/\b(?:' . $this->getSizePattern() . ')\s*([a-z0-9.-]+)\b/u';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getSupportDiagnosticPatterns(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('support_diagnostic_patterns', self::SUPPORT_DIAGNOSTIC_PATTERNS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getExplicitCommerceIntentPatterns(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('explicit_commerce_intent_patterns', self::EXPLICIT_COMMERCE_INTENT_PATTERNS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSkuLikePattern(): string
|
public function getSkuLikePattern(): string
|
||||||
@@ -334,4 +341,29 @@ final class CommerceIntentConfig
|
|||||||
{
|
{
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
private function stringList(string $key, array $default): array
|
||||||
|
{
|
||||||
|
$value = $this->config[$key] ?? $default;
|
||||||
|
if (!is_array($value)) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = [];
|
||||||
|
foreach ($value as $item) {
|
||||||
|
if (!is_scalar($item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = trim((string) $item);
|
||||||
|
if ($item === '' || in_array($item, $out, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out !== [] ? $out : $default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Config;
|
namespace App\Config;
|
||||||
|
|
||||||
class IntentLightConfig
|
class IntentLightConfig
|
||||||
{
|
{
|
||||||
public const LIST_THRESHOLD = 4;
|
public const LIST_THRESHOLD = 4;
|
||||||
|
|
||||||
public function getQuantityWords(): array
|
private const QUANTITY_WORDS = [
|
||||||
{
|
|
||||||
return [
|
|
||||||
'alle',
|
'alle',
|
||||||
'sämtliche',
|
'sämtliche',
|
||||||
'saemtliche',
|
'saemtliche',
|
||||||
@@ -29,11 +29,8 @@ class IntentLightConfig
|
|||||||
'übersicht',
|
'übersicht',
|
||||||
'uebersicht',
|
'uebersicht',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public function getStrongPatterns(): array
|
private const STRONG_PATTERNS = [
|
||||||
{
|
|
||||||
return [
|
|
||||||
'/\bliste(n)?\b/u',
|
'/\bliste(n)?\b/u',
|
||||||
'/\bauflisten\b/u',
|
'/\bauflisten\b/u',
|
||||||
'/\baufz(a|ä)hl(en)?\b/u',
|
'/\baufz(a|ä)hl(en)?\b/u',
|
||||||
@@ -46,5 +43,48 @@ class IntentLightConfig
|
|||||||
'/\branking\b/u',
|
'/\branking\b/u',
|
||||||
'/\btop\s*\d+\b/u',
|
'/\btop\s*\d+\b/u',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $config
|
||||||
|
*/
|
||||||
|
public function __construct(private readonly array $config = [])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getQuantityWords(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('quantity_words', self::QUANTITY_WORDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getStrongPatterns(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('strong_patterns', self::STRONG_PATTERNS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
private function stringList(string $key, array $default): array
|
||||||
|
{
|
||||||
|
$value = $this->config[$key] ?? $default;
|
||||||
|
if (!is_array($value)) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = [];
|
||||||
|
foreach ($value as $item) {
|
||||||
|
if (!is_scalar($item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = trim((string) $item);
|
||||||
|
if ($item === '' || in_array($item, $out, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out !== [] ? $out : $default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,65 +1,142 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Config;
|
namespace App\Config;
|
||||||
|
|
||||||
class SalesIntentConfig
|
class SalesIntentConfig
|
||||||
{
|
{
|
||||||
|
|
||||||
// Minimum gap between Top 1 and Top 2 so that an intent is truly dominant.
|
// Minimum gap between Top 1 and Top 2 so that an intent is truly dominant.
|
||||||
public const DOMINANCE_DELTA = 2;
|
public const DOMINANCE_DELTA = 2;
|
||||||
|
|
||||||
// Minimum score required for any non-discovery intent to be accepted.
|
// Minimum score required for any non-discovery intent to be accepted.
|
||||||
public const MIN_SCORE_THRESHOLD = 3;
|
public const MIN_SCORE_THRESHOLD = 3;
|
||||||
|
|
||||||
|
private const SALES_SIGNALS = [
|
||||||
public function getSalesSignals(): array
|
'preis',
|
||||||
{
|
'preise',
|
||||||
return [
|
'kosten',
|
||||||
'preis', 'preise', 'kosten', 'lizenz', 'lizenzmodell',
|
'lizenz',
|
||||||
'tarif', 'tarife', 'gebuehr', 'gebühr',
|
'lizenzmodell',
|
||||||
'monatlich', 'jaehrlich', 'jährlich', 'abo', 'subscription'
|
'tarif',
|
||||||
|
'tarife',
|
||||||
|
'gebuehr',
|
||||||
|
'gebühr',
|
||||||
|
'monatlich',
|
||||||
|
'jaehrlich',
|
||||||
|
'jährlich',
|
||||||
|
'abo',
|
||||||
|
'subscription',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public function getComparisonSignals(): array
|
private const COMPARISON_SIGNALS = [
|
||||||
{
|
|
||||||
return [
|
|
||||||
'/\bvergleich(en)?\b/u',
|
'/\bvergleich(en)?\b/u',
|
||||||
'/\bvs\b/u',
|
'/\bvs\b/u',
|
||||||
'/\bgegenueber\b/u',
|
'/\bgegenueber\b/u',
|
||||||
'/\balternative(n)?\b/u',
|
'/\balternative(n)?\b/u',
|
||||||
'/\bunterschied(e)?\b/u',
|
'/\bunterschied(e)?\b/u',
|
||||||
'/\bbesser\b/u'
|
'/\bbesser\b/u',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private const OBJECTION_SIGNALS = [
|
||||||
|
'problem',
|
||||||
|
'risiko',
|
||||||
|
'nachteil',
|
||||||
|
'datenschutz',
|
||||||
|
'dsgvo',
|
||||||
|
'sicherheit',
|
||||||
|
'compliance',
|
||||||
|
'kritik',
|
||||||
|
'zweifel',
|
||||||
|
'unsicher',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const IMPLEMENTATION_SIGNALS = [
|
||||||
|
'implementierung',
|
||||||
|
'implementieren',
|
||||||
|
'integration',
|
||||||
|
'integrieren',
|
||||||
|
'einführung',
|
||||||
|
'einfuehrung',
|
||||||
|
'aufwand',
|
||||||
|
'setup',
|
||||||
|
'rollout',
|
||||||
|
'migration',
|
||||||
|
'installation',
|
||||||
|
'api',
|
||||||
|
'schnittstelle',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const ROI_SIGNALS = [
|
||||||
|
'roi',
|
||||||
|
'rentabilitaet',
|
||||||
|
'rentabilität',
|
||||||
|
'business case',
|
||||||
|
'einsparung',
|
||||||
|
'kosten senken',
|
||||||
|
'umsatz steigern',
|
||||||
|
'effizienz steigern',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $config
|
||||||
|
*/
|
||||||
|
public function __construct(private readonly array $config = [])
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getSalesSignals(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('sales_signals', self::SALES_SIGNALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getComparisonSignals(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('comparison_signals', self::COMPARISON_SIGNALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
public function getObjectionSignals(): array
|
public function getObjectionSignals(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->stringList('objection_signals', self::OBJECTION_SIGNALS);
|
||||||
'problem', 'risiko', 'nachteil', 'datenschutz',
|
|
||||||
'dsgvo', 'sicherheit', 'compliance',
|
|
||||||
'kritik', 'zweifel', 'unsicher'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
public function getImplementationSignals(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'implementierung', 'implementieren',
|
|
||||||
'integration', 'integrieren',
|
|
||||||
'einführung', 'einfuehrung',
|
|
||||||
'aufwand', 'setup', 'rollout',
|
|
||||||
'migration', 'installation',
|
|
||||||
'api', 'schnittstelle'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
public function getRoiSignals(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'roi', 'rentabilitaet', 'rentabilität',
|
|
||||||
'business case', 'einsparung',
|
|
||||||
'kosten senken', 'umsatz steigern',
|
|
||||||
'effizienz steigern'
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getImplementationSignals(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('implementation_signals', self::IMPLEMENTATION_SIGNALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
public function getRoiSignals(): array
|
||||||
|
{
|
||||||
|
return $this->stringList('roi_signals', self::ROI_SIGNALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
private function stringList(string $key, array $default): array
|
||||||
|
{
|
||||||
|
$value = $this->config[$key] ?? $default;
|
||||||
|
if (!is_array($value)) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = [];
|
||||||
|
foreach ($value as $item) {
|
||||||
|
if (!is_scalar($item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = trim((string) $item);
|
||||||
|
if ($item === '' || in_array($item, $out, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out !== [] ? $out : $default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,67 @@ namespace App\Config;
|
|||||||
|
|
||||||
final class SearchRepairConfig
|
final class SearchRepairConfig
|
||||||
{
|
{
|
||||||
|
private const GENERIC_CANDIDATE_TOKENS = [
|
||||||
|
'wasser',
|
||||||
|
'messgerät',
|
||||||
|
'messgeraet',
|
||||||
|
'produkt',
|
||||||
|
'geräte',
|
||||||
|
'geraete',
|
||||||
|
'gerät',
|
||||||
|
'geraet',
|
||||||
|
'resthärte',
|
||||||
|
'resthaerte',
|
||||||
|
'preis',
|
||||||
|
'infos',
|
||||||
|
'wissen',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const ACCESSORY_CANDIDATE_TERMS = [
|
||||||
|
'indikator',
|
||||||
|
'indicator',
|
||||||
|
'reagenz',
|
||||||
|
'reagent',
|
||||||
|
'kit',
|
||||||
|
'set',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const ACCESSORY_OR_BUNDLE_TERMS = [
|
||||||
|
'passend',
|
||||||
|
'passende',
|
||||||
|
'zubehor',
|
||||||
|
'zubehör',
|
||||||
|
'dazu',
|
||||||
|
'zusatz',
|
||||||
|
'erganzung',
|
||||||
|
'ergänzung',
|
||||||
|
'indikator',
|
||||||
|
'reagenz',
|
||||||
|
'kit',
|
||||||
|
'set',
|
||||||
|
'auch\s+das',
|
||||||
|
'mit\s+preis\s+und\s+allen\s+infos',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const SPECIFICITY_BOOST_TERMS = [
|
||||||
|
'indikator',
|
||||||
|
'indicator',
|
||||||
|
'testomat',
|
||||||
|
'tritromat',
|
||||||
|
'titromat',
|
||||||
|
'reagenz',
|
||||||
|
'reagent',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $config
|
||||||
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly bool $enabled = true,
|
private readonly bool $enabled = true,
|
||||||
private readonly int $maxRepairQueries = 3,
|
private readonly int $maxRepairQueries = 3,
|
||||||
private readonly int $minPrimaryResultsWithoutRepair = 2,
|
private readonly int $minPrimaryResultsWithoutRepair = 2,
|
||||||
|
private readonly array $config = [],
|
||||||
|
private readonly ?DomainVocabularyConfig $vocabulary = null,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,26 +115,13 @@ final class SearchRepairConfig
|
|||||||
return '/\b(?:' . implode('|', $this->getSpecificityBoostTerms()) . ')\b/iu';
|
return '/\b(?:' . implode('|', $this->getSpecificityBoostTerms()) . ')\b/iu';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @return string[] */
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getGenericCandidateTokens(): array
|
public function getGenericCandidateTokens(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->stringList(
|
||||||
'wasser',
|
'generic_candidate_tokens',
|
||||||
'messgerät',
|
$this->vocabularyView('search_repair.generic_candidate_tokens', self::GENERIC_CANDIDATE_TOKENS)
|
||||||
'messgeraet',
|
);
|
||||||
'produkt',
|
|
||||||
'geräte',
|
|
||||||
'geraete',
|
|
||||||
'gerät',
|
|
||||||
'geraet',
|
|
||||||
'resthärte',
|
|
||||||
'resthaerte',
|
|
||||||
'preis',
|
|
||||||
'infos',
|
|
||||||
'wissen',
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSanitizeTrimCharacters(): string
|
public function getSanitizeTrimCharacters(): string
|
||||||
@@ -155,57 +199,61 @@ final class SearchRepairConfig
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @return string[] */
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getAccessoryCandidateTerms(): array
|
public function getAccessoryCandidateTerms(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->stringList(
|
||||||
'indikator',
|
'accessory_candidate_terms',
|
||||||
'indicator',
|
$this->vocabularyView('search_repair.accessory_candidate_terms', self::ACCESSORY_CANDIDATE_TERMS)
|
||||||
'reagenz',
|
);
|
||||||
'reagent',
|
|
||||||
'kit',
|
|
||||||
'set',
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @return string[] */
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getAccessoryOrBundleTerms(): array
|
public function getAccessoryOrBundleTerms(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->stringList(
|
||||||
'passend',
|
'accessory_or_bundle_terms',
|
||||||
'passende',
|
$this->vocabularyView('search_repair.accessory_or_bundle_terms', self::ACCESSORY_OR_BUNDLE_TERMS)
|
||||||
'zubehor',
|
);
|
||||||
'zubehör',
|
|
||||||
'dazu',
|
|
||||||
'zusatz',
|
|
||||||
'erganzung',
|
|
||||||
'ergänzung',
|
|
||||||
'indikator',
|
|
||||||
'reagenz',
|
|
||||||
'kit',
|
|
||||||
'set',
|
|
||||||
'auch\s+das',
|
|
||||||
'mit\s+preis\s+und\s+allen\s+infos',
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @return string[] */
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getSpecificityBoostTerms(): array
|
public function getSpecificityBoostTerms(): array
|
||||||
{
|
{
|
||||||
return [
|
return $this->stringList(
|
||||||
'indikator',
|
'specificity_boost_terms',
|
||||||
'indicator',
|
$this->vocabularyView('search_repair.specificity_boost_terms', self::SPECIFICITY_BOOST_TERMS)
|
||||||
'testomat',
|
);
|
||||||
'tritromat',
|
}
|
||||||
'titromat',
|
|
||||||
'reagenz',
|
/** @return string[] */
|
||||||
'reagent',
|
private function vocabularyView(string $path, array $fallback): array
|
||||||
];
|
{
|
||||||
|
return $this->vocabulary?->view($path, $fallback) ?? $fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] */
|
||||||
|
private function stringList(string $key, array $default): array
|
||||||
|
{
|
||||||
|
$value = $this->config[$key] ?? $default;
|
||||||
|
if (!is_array($value)) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = [];
|
||||||
|
foreach ($value as $item) {
|
||||||
|
if (!is_scalar($item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = trim((string) $item);
|
||||||
|
if ($item === '' || in_array($item, $out, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out !== [] ? $out : $default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user