add catalog mode
This commit is contained in:
138
src/Intent/CatalogIntentLite.php
Normal file
138
src/Intent/CatalogIntentLite.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Intent;
|
||||
|
||||
/**
|
||||
* CatalogIntentLite
|
||||
*
|
||||
* Minimal, deterministische Erkennung von Katalog-/Entity-Listenanfragen.
|
||||
*
|
||||
* Ziel:
|
||||
* - "Liste aller Geräte" / "Welche Indikatoren gibt es?" / "Zeig mir alle Funktionen"
|
||||
*
|
||||
* Guardrails:
|
||||
* - Kein Catalog-Mode bei Sales-/Pricing-/Comparison-/ROI-/Implementation-/Objection-Intents.
|
||||
* - Kein Catalog-Mode ohne expliziten Entity-Term.
|
||||
*
|
||||
* WICHTIG:
|
||||
* - Immer mit ORIGINAL-Prompt aufrufen.
|
||||
* - Kein LLM, kein ML.
|
||||
*/
|
||||
final class CatalogIntentLite
|
||||
{
|
||||
/**
|
||||
* Listensignale (leichtgewichtig) – IntentLite bleibt weiterhin für "allgemeine" List Detection zuständig.
|
||||
*/
|
||||
private const LIST_SIGNALS = [
|
||||
'liste',
|
||||
'auflisten',
|
||||
'aufzaehl',
|
||||
'aufzähl',
|
||||
'übersicht',
|
||||
'uebersicht',
|
||||
'welche gibt es',
|
||||
'welche sind',
|
||||
'zeig mir alle',
|
||||
'zeige mir alle',
|
||||
'alle',
|
||||
];
|
||||
|
||||
/**
|
||||
* Entity-Terms, die wir als Katalogtypen unterstützen.
|
||||
*
|
||||
* Left side: canonical term (für Tag-Suche)
|
||||
* Right side: Such-Synonyme, die im Prompt vorkommen dürfen.
|
||||
*/
|
||||
private const ENTITY_TERMS = [
|
||||
'geräte' => ['gerät', 'geräte', 'geraet', 'geraete', 'device', 'devices'],
|
||||
'indikatoren' => ['indikator', 'indikatoren', 'indicator', 'indicators'],
|
||||
'funktionen' => ['funktion', 'funktionen', 'feature', 'features', 'funktionalität', 'funktionalitaet'],
|
||||
'zubehör' => ['zubehör', 'zubehoer', 'accessory', 'accessories', 'zubehor'],
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
private readonly SalesIntentLite $salesIntentLite,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return string|null canonical entity term (z. B. "geräte") oder null wenn kein Catalog-Intent.
|
||||
*/
|
||||
public function detect(string $originalPrompt): ?string
|
||||
{
|
||||
$p = $this->normalize($originalPrompt);
|
||||
|
||||
// 1) Muss ein Listen-Signal enthalten
|
||||
if (!$this->containsAny($p, self::LIST_SIGNALS)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2) Guardrail: Kein Catalog-Mode bei Sales-Intents
|
||||
$sales = $this->salesIntentLite->detect($originalPrompt);
|
||||
$intent = (string)($sales['intent'] ?? SalesIntentLite::DISCOVERY);
|
||||
|
||||
if ($intent !== SalesIntentLite::DISCOVERY) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3) Expliziten Entity-Term extrahieren (sonst kein Catalog)
|
||||
foreach (self::ENTITY_TERMS as $canonical => $synonyms) {
|
||||
foreach ($synonyms as $syn) {
|
||||
if ($this->containsWord($p, $syn)) {
|
||||
return $canonical;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------
|
||||
|
||||
private function containsAny(string $haystack, array $needles): bool
|
||||
{
|
||||
foreach ($needles as $needle) {
|
||||
if ($needle === '') {
|
||||
continue;
|
||||
}
|
||||
if (str_contains($haystack, $needle)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function containsWord(string $haystack, string $word): bool
|
||||
{
|
||||
$word = trim($word);
|
||||
if ($word === '') {
|
||||
return false;
|
||||
}
|
||||
return preg_match('/\b' . preg_quote($word, '/') . '\b/u', $haystack) === 1;
|
||||
}
|
||||
|
||||
private function normalize(string $s): string
|
||||
{
|
||||
$s = mb_strtolower($s);
|
||||
|
||||
// Umlaute absichern (analog IntentLite/SalesIntentLite)
|
||||
$replacements = [
|
||||
'ä' => 'ae',
|
||||
'ö' => 'oe',
|
||||
'ü' => 'ue',
|
||||
'ß' => 'ss',
|
||||
];
|
||||
|
||||
foreach ($replacements as $umlaut => $alt) {
|
||||
if (str_contains($s, $umlaut)) {
|
||||
$s .= ' ' . str_replace($umlaut, $alt, $s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user