From 2797834a5f5c3114b5c080845e47aaad005481bc Mon Sep 17 00:00:00 2001 From: team2 Date: Sat, 25 Apr 2026 22:47:50 +0200 Subject: [PATCH] optimize cleanup search query shop api extends part 2 --- public/assets/js/base.js | 61 ++++++++++++++++++++++-- src/Agent/AgentRunner.php | 11 +++-- src/Commerce/CommerceQueryParser.php | 23 +++++++-- src/Config/CommerceIntentConfig.php | 17 +++++++ src/Config/CommerceQueryParserConfig.php | 19 +++++++- 5 files changed, 119 insertions(+), 12 deletions(-) diff --git a/public/assets/js/base.js b/public/assets/js/base.js index f54eac9..53aba97 100644 --- a/public/assets/js/base.js +++ b/public/assets/js/base.js @@ -179,6 +179,59 @@ document.addEventListener('DOMContentLoaded', () => { cleanupEmptyBlocks(container); } + function hasVisibleContentAfterNode(container, markerNode) { + const walker = document.createTreeWalker( + container, + NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, + null + ); + + let afterMarker = false; + + while (walker.nextNode()) { + const node = walker.currentNode; + + if (node === markerNode) { + afterMarker = true; + continue; + } + + if (!afterMarker) { + continue; + } + + if (node.nodeType === Node.TEXT_NODE) { + if (node.parentElement?.closest('.think')) { + continue; + } + + if ((node.textContent || '').trim() !== '') { + return true; + } + + continue; + } + + if (node.nodeType !== Node.ELEMENT_NODE) { + continue; + } + + if (node.classList?.contains('think') || node.closest?.('.think')) { + continue; + } + + if (node.tagName === 'BR') { + continue; + } + + if ((node.textContent || '').trim() !== '' || hasMeaningfulChildContent(node)) { + return true; + } + } + + return false; + } + function cleanupThinkSpans(container) { if (!container) { return; @@ -191,12 +244,14 @@ document.addEventListener('DOMContentLoaded', () => { return; } - if (hasNonThinkContent(container)) { - removeThinkSpansOnly(container); + const lastThink = thinkSpans[thinkSpans.length - 1]; + + if (!hasVisibleContentAfterNode(container, lastThink)) { + keepOnlyLastThink(container); return; } - keepOnlyLastThink(container); + removeThinkSpansOnly(container); } function renderBubbleContent(bubble, raw) { diff --git a/src/Agent/AgentRunner.php b/src/Agent/AgentRunner.php index 0196504..c473208 100644 --- a/src/Agent/AgentRunner.php +++ b/src/Agent/AgentRunner.php @@ -765,11 +765,14 @@ final readonly class AgentRunner private function streamFinalAnswer(string $finalPrompt): Generator { $fullOutput = ''; - $firstThinkLoop = true; + $thinkingNoticeShown = false; $chunker = new StreamChunker(); $this->thinkSuppressor->reset(); + yield $this->systemMsg($this->agentRunnerConfig->getThinkingWhileStreamingMessage(), 'think'); + $thinkingNoticeShown = true; + foreach ($this->ollamaClient->stream($finalPrompt) as $token) { if (!is_string($token)) { continue; @@ -778,9 +781,9 @@ final readonly class AgentRunner $cleanToken = $this->thinkSuppressor->filter($token); if ($cleanToken === '') { - if ($firstThinkLoop) { + if (!$thinkingNoticeShown) { yield $this->systemMsg($this->agentRunnerConfig->getThinkingWhileStreamingMessage(), 'think'); - $firstThinkLoop = false; + $thinkingNoticeShown = true; } continue; @@ -902,7 +905,7 @@ final readonly class AgentRunner return '
' . '
Live-Shopdaten
' - . '
Shopware-Suche wird ausgeführt
' + . '
Shop-Suche wird ausgeführt
' . '
' . '' . htmlspecialchars($badge, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . '' . 'Intent: ' . htmlspecialchars($intentLabel, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . '' diff --git a/src/Commerce/CommerceQueryParser.php b/src/Commerce/CommerceQueryParser.php index ead10d2..d620afe 100644 --- a/src/Commerce/CommerceQueryParser.php +++ b/src/Commerce/CommerceQueryParser.php @@ -79,7 +79,6 @@ final readonly class CommerceQueryParser private function normalize(string $prompt): string { $value = $this->textNormalizer->normalize($prompt); - $value = $this->queryCleaner->clean($value); $value = mb_strtolower(trim($value)); $value = str_replace( $this->config->getNormalizationSearch(), @@ -274,7 +273,16 @@ final readonly class CommerceQueryParser for ($offset = 1; $offset <= $this->config->getModelContextTokenWindow(); $offset++) { $previousIndex = $index - $offset; - if (!isset($tokens[$previousIndex]) || !$this->isLikelyModelContextToken($tokens[$previousIndex])) { + if (!isset($tokens[$previousIndex])) { + break; + } + + if ($this->isSemanticShopToken($tokens[$previousIndex])) { + $keep[$previousIndex] = true; + continue; + } + + if (!$this->isLikelyModelContextToken($tokens[$previousIndex])) { break; } @@ -287,7 +295,7 @@ final readonly class CommerceQueryParser } } - if ($this->isSemanticShopToken($token) || $this->isKnownBrandToken($token)) { + if ($this->isSemanticShopToken($token) || $this->isKnownBrandToken($token) || $this->isMeasurementValueToken($token)) { $keep[$index] = true; } } @@ -314,6 +322,10 @@ final readonly class CommerceQueryParser return true; } + if ($this->isMeasurementValueToken($token)) { + return false; + } + if (preg_match($this->config->getContainsDigitPattern(), $token) === 1) { return false; } @@ -334,6 +346,11 @@ final readonly class CommerceQueryParser return preg_match($this->config->getModelNumberTokenPattern(), $token) === 1; } + private function isMeasurementValueToken(string $token): bool + { + return preg_match($this->config->getMeasurementValueTokenPattern(), $token) === 1; + } + private function isLikelyModelContextToken(string $token): bool { if ($this->isQueryNoiseToken($token)) { diff --git a/src/Config/CommerceIntentConfig.php b/src/Config/CommerceIntentConfig.php index 05f4f4c..84a6054 100644 --- a/src/Config/CommerceIntentConfig.php +++ b/src/Config/CommerceIntentConfig.php @@ -37,6 +37,13 @@ final class CommerceIntentConfig 'kalibrierlösung', 'kalibrierloesung', 'kalibrierung', + 'chemie', + 'reagenz', + 'reagenzien', + 'verbrauchsmaterial', + 'zubehör', + 'zubehoer', + 'ersatzteil', ]; } @@ -50,6 +57,10 @@ final class CommerceIntentConfig 'eignet', 'besser', 'besten', + 'gut für', + 'gut fuer', + 'passend für', + 'passend fuer', 'geeignet', 'geeigent', 'empfiehl', @@ -195,6 +206,12 @@ final class CommerceIntentConfig '/\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', ]; } diff --git a/src/Config/CommerceQueryParserConfig.php b/src/Config/CommerceQueryParserConfig.php index 438eb17..3e611c9 100644 --- a/src/Config/CommerceQueryParserConfig.php +++ b/src/Config/CommerceQueryParserConfig.php @@ -133,6 +133,14 @@ final class CommerceQueryParserConfig 'kostet', 'kosten', 'ua', + 'also', + 'gut', + 'gute', + 'guten', + 'guter', + 'gutes', + 'passen', + 'passend', ]; } @@ -297,7 +305,7 @@ final class CommerceQueryParserConfig public function getModelContextTokenWindow(): int { - return 2; + return 4; } public function getMinMeaningfulAlphaTokenLength(): int @@ -312,7 +320,11 @@ final class CommerceQueryParserConfig public function getInstructionOrPresentationTokenPattern(): string { - return '/^(?:zeig(?:e)?|such(?:e)?|find(?:e)?|gib|gebe|nenn(?:e)?|liefer(?:e)?|erstelle?|mach(?:e)?|brauch(?:e)?|will|möchte|moechte|hätte|haette|kannst|bitte|mal|alle|alles|komplett|vollständig|vollstaendig|gesamt|ganze|ganzen|liste|listung|auflistung|tabelle|tabellarisch|übersicht|uebersicht|anzeigen?|ausgeben?|darstellen?|antwort(?:e)?|erklär(?:e)?|erklaer(?:e)?|info|infos|informationen|dazu|hierzu|damit|davon|an|als|mit|ohne|inkl|inklusive)$/u'; + return '/^(?:zeig(?:e)?|such(?:e)?|find(?:e)?|gib|gebe|nenn(?:e)?|liefer(?:e)?|erstelle?|mach(?:e)?|brauch(?:e)?|will|möchte|moechte|hätte|haette|kannst|bitte|mal|alle|alles|komplett|vollständig|vollstaendig|gesamt|ganze|ganzen|liste|listung|auflistung|tabelle|tabellarisch|übersicht|uebersicht|anzeigen?|ausgeben?|darstellen?|antwort(?:e)?|erklär(?:e)?|erklaer(?:e)?|info|infos|informationen|dazu|hierzu|damit|davon|an|als|mit|ohne|inkl|inklusive|also|gut|gute|guten|guter|gutes|passend|passen)$/u'; + } + public function getMeasurementValueTokenPattern(): string + { + return '/^\d+[.,]\d+$/u'; } /** @@ -332,6 +344,9 @@ final class CommerceQueryParserConfig 'zubehor', 'ersatzteil', 'verbrauchsmaterial', + 'chemie', + 'indikatorchemie', + 'reagenzchemie', 'kit', 'set', 'filter',