optimize as sales rag

This commit is contained in:
team2
2026-02-27 21:03:59 +01:00
parent efa9b17c2f
commit 3a5804e44c
6 changed files with 541 additions and 213 deletions

View File

@@ -0,0 +1,160 @@
<?php
declare(strict_types=1);
namespace App\Intent;
/**
* SalesIntentLite
*
* Deterministische Vertriebs-Intent-Erkennung.
* Kein LLM, kein ML, nur regelbasierte Klassifikation.
*
* WICHTIG:
* - Immer mit ORIGINAL-Prompt aufrufen.
* - Nicht mit gereinigter Query.
*/
final class SalesIntentLite
{
public const DISCOVERY = 'discovery';
public const PRICING = 'pricing';
public const COMPARISON = 'comparison';
public const OBJECTION = 'objection';
public const IMPLEMENTATION = 'implementation';
public const ROI = 'roi';
public function detect(string $originalPrompt): array
{
$p = $this->normalize($originalPrompt);
$scores = [
self::PRICING => 0,
self::COMPARISON => 0,
self::OBJECTION => 0,
self::IMPLEMENTATION => 0,
self::ROI => 0,
];
// ------------------------------------------------------------
// PRICING
// ------------------------------------------------------------
$pricingWords = [
'preis', 'preise', 'kosten', 'lizenz', 'lizenzmodell',
'paket', 'pakete', 'tarif', 'tarife',
'gebühr', 'gebuehr', 'monatlich', 'jährlich', 'jaehrlich',
'abo', 'subscription'
];
foreach ($pricingWords as $word) {
if (preg_match('/\b' . preg_quote($word, '/') . '\b/u', $p)) {
$scores[self::PRICING] += 2;
}
}
// ------------------------------------------------------------
// COMPARISON
// ------------------------------------------------------------
$comparisonPatterns = [
'/\bvergleich\b/u',
'/\bvs\b/u',
'/\boder\b/u',
'/\balternative(n)?\b/u',
'/\bunterschied(e)?\b/u',
'/\bbesser\b/u',
];
foreach ($comparisonPatterns as $pattern) {
if (preg_match($pattern, $p)) {
$scores[self::COMPARISON] += 2;
}
}
// ------------------------------------------------------------
// OBJECTION
// ------------------------------------------------------------
$objectionWords = [
'problem', 'risiko', 'nachteil', 'datenschutz',
'dsgvo', 'sicherheit', 'compliance',
'kritik', 'zweifel', 'unsicher'
];
foreach ($objectionWords as $word) {
if (preg_match('/\b' . preg_quote($word, '/') . '\b/u', $p)) {
$scores[self::OBJECTION] += 2;
}
}
// ------------------------------------------------------------
// IMPLEMENTATION
// ------------------------------------------------------------
$implementationWords = [
'implementierung', 'einführung', 'einfuehrung',
'integration', 'aufwand', 'setup',
'rollout', 'migration', 'installation',
'technisch', 'api', 'schnittstelle'
];
foreach ($implementationWords as $word) {
if (preg_match('/\b' . preg_quote($word, '/') . '\b/u', $p)) {
$scores[self::IMPLEMENTATION] += 2;
}
}
// ------------------------------------------------------------
// ROI / Business Case
// ------------------------------------------------------------
$roiWords = [
'roi', 'rentabilität', 'rentabilitaet',
'business case', 'nutzen',
'effizienz', 'einsparung', 'umsatz',
'wert', 'vorteil'
];
foreach ($roiWords as $word) {
if (preg_match('/\b' . preg_quote($word, '/') . '\b/u', $p)) {
$scores[self::ROI] += 2;
}
}
// ------------------------------------------------------------
// Entscheidung
// ------------------------------------------------------------
arsort($scores);
$topIntent = array_key_first($scores);
$topScore = $scores[$topIntent] ?? 0;
if ($topScore <= 0) {
return [
'intent' => self::DISCOVERY,
'score' => 0,
];
}
return [
'intent' => $topIntent,
'score' => $topScore,
];
}
private function normalize(string $s): string
{
$s = mb_strtolower($s);
$replacements = [
'ä' => 'ae',
'ö' => 'oe',
'ü' => 'ue',
'ß' => 'ss',
];
foreach ($replacements as $umlaut => $alt) {
if (str_contains($s, $umlaut)) {
$s .= ' ' . str_replace($umlaut, $alt, $s);
break;
}
}
return $s;
}
}