add shopware store-api
This commit is contained in:
@@ -4,9 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Agent;
|
||||
|
||||
use App\Commerce\ShopSearchService;
|
||||
use App\Context\ContextService;
|
||||
use App\Context\UrlAnalyzer;
|
||||
use App\Infrastructure\OllamaClient;
|
||||
use App\Intent\CommerceIntentLite;
|
||||
use App\Knowledge\Retrieval\RetrieverInterface;
|
||||
use Generator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
@@ -21,6 +23,8 @@ final readonly class AgentRunner
|
||||
private ContextService $contextService,
|
||||
private UrlAnalyzer $urlAnalyzer,
|
||||
private RetrieverInterface $retriever,
|
||||
private ShopSearchService $shopSearchService,
|
||||
private CommerceIntentLite $commerceIntentLite,
|
||||
private OllamaClient $ollamaClient,
|
||||
private LoggerInterface $agentLogger,
|
||||
private bool $debug,
|
||||
@@ -33,6 +37,7 @@ final readonly class AgentRunner
|
||||
public function run(string $prompt, string $userId, ?bool $includeFullContext = false): Generator
|
||||
{
|
||||
$prompt = trim($prompt);
|
||||
$shopResults = [];
|
||||
|
||||
if ($prompt === '') {
|
||||
yield '❌ Empty prompt.';
|
||||
@@ -57,16 +62,46 @@ final readonly class AgentRunner
|
||||
// ---------------------------------------------------------
|
||||
// 3) Retrieve RAG knowledge
|
||||
// ---------------------------------------------------------
|
||||
yield "Hole Daten aus dem RAG Wissen... \n";
|
||||
|
||||
$knowledgeChunks = $this->retriever->retrieve($prompt);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 4) Build final prompt
|
||||
// 4) Optional commerce/shop search
|
||||
// ---------------------------------------------------------
|
||||
|
||||
$commerceMeta = $this->commerceIntentLite->detect($prompt);
|
||||
$commerceIntent = (string) ($commerceMeta['intent'] ?? CommerceIntentLite::NONE);
|
||||
|
||||
if($commerceIntent === CommerceIntentLite::ADVISORY_PRODUCT_SEARCH || $commerceIntent === CommerceIntentLite::PRODUCT_SEARCH){
|
||||
yield "Rufe Shop auf (type: ".$commerceIntent.")... \n";
|
||||
$shopResults = $this->shopSearchService->search($prompt,$commerceIntent);
|
||||
}
|
||||
|
||||
if ($commerceIntent === CommerceIntentLite::PRODUCT_SEARCH) {
|
||||
$knowledgeChunks = array_slice($knowledgeChunks, 0, 2);
|
||||
} elseif ($commerceIntent === CommerceIntentLite::ADVISORY_PRODUCT_SEARCH) {
|
||||
$knowledgeChunks = array_slice($knowledgeChunks, 0, 3);
|
||||
}
|
||||
|
||||
if($shopResults){
|
||||
yield "Verarbeite Shopdaten... \n<hr>\n";
|
||||
}else{
|
||||
yield "Keine releveanten Shopdaten gefunden... \n<hr>\n";
|
||||
}
|
||||
|
||||
yield "Denke nach...\n<hr>\n";
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 5) Build final prompt
|
||||
// ---------------------------------------------------------
|
||||
$finalPrompt = $this->promptBuilder->build(
|
||||
prompt: $prompt,
|
||||
userId: $userId,
|
||||
urlContent: $urlContent,
|
||||
knowledgeChunks: $knowledgeChunks,
|
||||
shopResults: $shopResults,
|
||||
fullContext: $includeFullContext
|
||||
);
|
||||
|
||||
@@ -84,7 +119,7 @@ final readonly class AgentRunner
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 5) Stream tokens from the LLM backend (chunked streaming)
|
||||
// 6) Stream tokens from the LLM backend (chunked streaming)
|
||||
// ---------------------------------------------------------
|
||||
$fullOutput = '';
|
||||
$chunker = new StreamChunker();
|
||||
@@ -120,7 +155,7 @@ final readonly class AgentRunner
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 6) Persist conversation history
|
||||
// 7) Persist conversation history
|
||||
// ---------------------------------------------------------
|
||||
$this->contextService->appendHistory(
|
||||
$userId,
|
||||
@@ -132,6 +167,8 @@ final readonly class AgentRunner
|
||||
'userId' => $userId,
|
||||
'outputLength' => mb_strlen($fullOutput),
|
||||
'contextMode' => 'recent',
|
||||
'commerceIntent' => $commerceIntent,
|
||||
'shopResultsCount' => count($shopResults),
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
$this->agentLogger->error('Agent run failed', [
|
||||
@@ -142,4 +179,4 @@ final readonly class AgentRunner
|
||||
yield "\n❌ An internal error occurred while processing the request. \nError: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Agent;
|
||||
|
||||
use App\Commerce\Dto\ShopProductResult;
|
||||
use App\Context\ContextService;
|
||||
use App\Repository\SystemPromptRepository;
|
||||
use DateTimeImmutable;
|
||||
@@ -24,6 +25,7 @@ final readonly class PromptBuilder
|
||||
* @param string $userId
|
||||
* @param string $urlContent
|
||||
* @param string[] $knowledgeChunks
|
||||
* @param ShopProductResult[] $shopResults
|
||||
* @param bool $fullContext
|
||||
* @return string
|
||||
*/
|
||||
@@ -32,6 +34,7 @@ final readonly class PromptBuilder
|
||||
string $userId,
|
||||
string $urlContent,
|
||||
array $knowledgeChunks,
|
||||
array $shopResults = [],
|
||||
?bool $fullContext = false,
|
||||
): string
|
||||
{
|
||||
@@ -69,7 +72,59 @@ final readonly class PromptBuilder
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// 3) EXTERNAL KNOWLEDGE (SUPPORTING)
|
||||
// 3) LIVE SHOP RESULTS (AUTHORITATIVE FOR PRODUCTS)
|
||||
// ------------------------------------------------------------
|
||||
$shopBlock = '';
|
||||
|
||||
if ($shopResults !== []) {
|
||||
$lines = [];
|
||||
|
||||
foreach ($shopResults as $i => $product) {
|
||||
if (!$product instanceof ShopProductResult) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$n = $i + 1;
|
||||
$parts = [
|
||||
"[{$n}] " . $product->name,
|
||||
];
|
||||
|
||||
if ($product->productNumber) {
|
||||
$parts[] = "Product number: " . $product->productNumber;
|
||||
}
|
||||
|
||||
if ($product->manufacturer) {
|
||||
$parts[] = "Manufacturer: " . $product->manufacturer;
|
||||
}
|
||||
|
||||
if ($product->price) {
|
||||
$parts[] = "Price: " . $product->price;
|
||||
}
|
||||
|
||||
if ($product->available !== null) {
|
||||
$parts[] = "Available: " . ($product->available ? 'yes' : 'no');
|
||||
}
|
||||
|
||||
foreach ($product->highlights as $highlight) {
|
||||
$parts[] = "- " . $highlight;
|
||||
}
|
||||
|
||||
if ($product->url) {
|
||||
$parts[] = "URL: " . $product->url;
|
||||
}
|
||||
|
||||
$lines[] = implode("\n", $parts);
|
||||
}
|
||||
|
||||
if ($lines !== []) {
|
||||
$shopBlock =
|
||||
"LIVE SHOP RESULTS (authoritative for products):\n" .
|
||||
implode("\n\n", $lines);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// 4) EXTERNAL KNOWLEDGE (SUPPORTING)
|
||||
// ------------------------------------------------------------
|
||||
$knowledgeParts = [];
|
||||
|
||||
@@ -98,22 +153,23 @@ final readonly class PromptBuilder
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// 4) USER QUESTION
|
||||
// 5) USER QUESTION
|
||||
// ------------------------------------------------------------
|
||||
$userBlock =
|
||||
"USER QUESTION:\n" .
|
||||
$prompt;
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// 5) FINAL PROMPT ASSEMBLY
|
||||
// 6) FINAL PROMPT ASSEMBLY
|
||||
// ------------------------------------------------------------
|
||||
$blocks = array_filter([
|
||||
$systemBlock,
|
||||
$contextBlock,
|
||||
$shopBlock,
|
||||
$knowledgeBlock,
|
||||
$userBlock,
|
||||
]);
|
||||
|
||||
return implode("\n\n", $blocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user