diff --git a/src/Infrastructure/AI/Agent/OllamaVisionAgent.php b/src/Infrastructure/AI/Agent/OllamaVisionAgent.php index 2f483d0..3d6dd5d 100644 --- a/src/Infrastructure/AI/Agent/OllamaVisionAgent.php +++ b/src/Infrastructure/AI/Agent/OllamaVisionAgent.php @@ -16,7 +16,7 @@ final class OllamaVisionAgent ) { } - /** @return array{manufacturer: string, model: string, serial: string} */ + /** @return array{manufacturer: string, modelName: string, modelNumber: string, serial: string} */ public function analyze(string $imagePath): array { $prompt = $this->prompts->render('vision_analyze'); @@ -25,7 +25,8 @@ final class OllamaVisionAgent return [ 'manufacturer' => $this->extractField($response, 'MANUFACTURER'), - 'model' => $this->extractField($response, 'MODEL'), + 'modelName' => $this->extractField($response, 'MODEL_NAME'), + 'modelNumber' => $this->extractField($response, 'MODEL_NUMBER'), 'serial' => $this->extractField($response, 'SERIAL'), ]; } diff --git a/src/Infrastructure/AI/PromptTemplateService.php b/src/Infrastructure/AI/PromptTemplateService.php index 5fadb06..a4dfb7e 100644 --- a/src/Infrastructure/AI/PromptTemplateService.php +++ b/src/Infrastructure/AI/PromptTemplateService.php @@ -43,11 +43,14 @@ PROMPT, 'vision_analyze' => <<<'PROMPT' Look at this nameplate/label photo of IT hardware. -Extract the manufacturer (brand), model number/designation, and serial number visible on the label. -Do not guess or add information not on the label. +Extract the manufacturer, model name, model number, and serial number visible on the label. +- MODEL_NAME is the human-readable product name (e.g. "ThinkPad T490s", "EliteBook 840 G6", "Galaxy S24 Ultra"). +- MODEL_NUMBER is the part/product code or designation (e.g. "20NXS0BA00", "5SS67UC", "SM-S928B"). Often printed as "Model No.", "Part No.", "Type", or "P/N". +Do not guess or add information not visible on the label. Respond in exactly this format (use empty string if not visible): MANUFACTURER: -MODEL: +MODEL_NAME: +MODEL_NUMBER: SERIAL: PROMPT, diff --git a/src/Infrastructure/Messenger/Handler/DraftArticleHandler.php b/src/Infrastructure/Messenger/Handler/DraftArticleHandler.php index b4840c6..fa0b87e 100644 --- a/src/Infrastructure/Messenger/Handler/DraftArticleHandler.php +++ b/src/Infrastructure/Messenger/Handler/DraftArticleHandler.php @@ -67,8 +67,11 @@ final class DraftArticleHandler if (isset($vision['manufacturer']) && '' !== $vision['manufacturer']) { $article->setManufacturer((string) $vision['manufacturer']); } - if (isset($vision['model']) && '' !== $vision['model']) { - $article->setModelNumber((string) $vision['model']); + if (isset($vision['modelNumber']) && '' !== $vision['modelNumber']) { + $article->setModelNumber((string) $vision['modelNumber']); + } + if (isset($vision['modelName']) && '' !== $vision['modelName']) { + $article->setModelName((string) $vision['modelName']); } if ([] !== $message->attributes) { diff --git a/src/Infrastructure/Messenger/Handler/PhotoUploadHandler.php b/src/Infrastructure/Messenger/Handler/PhotoUploadHandler.php index 1565db8..9eaacd7 100644 --- a/src/Infrastructure/Messenger/Handler/PhotoUploadHandler.php +++ b/src/Infrastructure/Messenger/Handler/PhotoUploadHandler.php @@ -37,13 +37,14 @@ final class PhotoUploadHandler $job->recordStep('vision', [ 'manufacturer' => $result['manufacturer'], - 'model' => $result['model'], + 'modelName' => $result['modelName'], + 'modelNumber' => $result['modelNumber'], 'serial' => $result['serial'], ]); $this->jobRepository->save($job); - if ('' === $result['model']) { - $job->markNeedsReview('OllamaVisionAgent: no model name detected on nameplate'); + if ('' === $result['modelNumber'] && '' === $result['modelName']) { + $job->markNeedsReview('OllamaVisionAgent: no model detected on nameplate'); $this->jobRepository->save($job); return; @@ -52,7 +53,8 @@ final class PhotoUploadHandler $this->bus->dispatch(new SpecsResearchMessage( jobId: $message->jobId, articleTypeId: $message->articleTypeId, - modelName: $result['model'], + modelNumber: $result['modelNumber'], + modelName: $result['modelName'], serialNumber: $result['serial'], manufacturer: $result['manufacturer'], )); diff --git a/src/Infrastructure/Messenger/Handler/SpecsResearchHandler.php b/src/Infrastructure/Messenger/Handler/SpecsResearchHandler.php index e9de043..c719cc5 100644 --- a/src/Infrastructure/Messenger/Handler/SpecsResearchHandler.php +++ b/src/Infrastructure/Messenger/Handler/SpecsResearchHandler.php @@ -39,9 +39,11 @@ final class SpecsResearchHandler return; } + $searchSubject = $message->modelNumber !== '' ? $message->modelNumber : $message->modelName; + try { $specsText = $this->specsAgent->research( - $message->modelName, + $searchSubject, $articleType->getName(), $message->manufacturer, ); diff --git a/src/Infrastructure/Messenger/Message/SpecsResearchMessage.php b/src/Infrastructure/Messenger/Message/SpecsResearchMessage.php index 40e402b..e452856 100644 --- a/src/Infrastructure/Messenger/Message/SpecsResearchMessage.php +++ b/src/Infrastructure/Messenger/Message/SpecsResearchMessage.php @@ -9,6 +9,7 @@ final readonly class SpecsResearchMessage public function __construct( public string $jobId, public string $articleTypeId, + public string $modelNumber, public string $modelName, public string $serialNumber, public string $manufacturer = '',