SuperSeller3000/src/Infrastructure/AI/PromptTemplateService.php

114 lines
4 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace App\Infrastructure\AI;
use App\Domain\AI\Repository\PromptTemplateRepositoryInterface;
final class PromptTemplateService
{
/** @var array<string, string> */
private const array DEFAULTS = [
'specs_research' => <<<'PROMPT'
You are a hardware specifications expert. Extract the technical specifications for the {{articleType}}: "{{subject}}".
Web search results:
{{searchResults}}
Based on the search results above, list all technical specifications including:
processor, RAM, storage variants, display size and resolution, GPU, battery capacity,
ports, connectivity, weight, dimensions, OS, and any other relevant specs.
Be specific and accurate. If a spec is not found in the search results, omit it rather than guessing.
PROMPT,
'ebay_title' => <<<'PROMPT'
Create a concise eBay listing title (max 80 characters) for this {{typeName}}.
Device: {{deviceLabel}}
Use the most important specifications. Include condition if not "new".
Condition: {{condition}}
{{specsSection}}
Return ONLY the title text, no quotes, no explanation.
PROMPT,
'ebay_description' => <<<'PROMPT'
Create a professional eBay listing description in German for this {{typeName}}.
Device: {{deviceLabel}}
Include all available specifications in a clear, structured format.
Mention the condition: {{condition}}.
{{conditionNotes}}
{{specsSection}}
Use HTML formatting (ul, li, strong tags). Max 2000 characters.
PROMPT,
'vision_analyze' => <<<'PROMPT'
Look at this nameplate/label photo of IT hardware.
Extract the manufacturer, any model identifier (name or number), and serial number visible on the label.
If the label shows both a product name (e.g. "ThinkPad T490s") and a part/product code (e.g. "20NXS0BA00"), put the product name in MODEL_NAME and the code in MODEL_NUMBER.
If only one model field is visible (regardless of whether it looks like a name or a code), put it in MODEL_NAME and leave MODEL_NUMBER empty.
Do not guess or add information not visible on the label.
Respond in exactly this format (use empty string if not visible):
MANUFACTURER: <brand name, e.g. Dell, HP, Lenovo, Medion>
MODEL_NAME: <product name or model identifier>
MODEL_NUMBER: <part/product code, only if separately shown>
SERIAL: <serial number>
PROMPT,
'json_coding' => <<<'PROMPT'
Convert the following hardware specifications to a JSON object.
The JSON must use these exact keys (UUIDs) and follow the indicated value formats:
{{schema}}
{{missingHint}}
Specifications text:
{{specsText}}
Return ONLY valid JSON. No explanation. No markdown. No extra text.
JSON:
PROMPT,
];
public function __construct(
private readonly PromptTemplateRepositoryInterface $repository,
) {
}
/**
* Renders a prompt template by key, substituting {{variable}} placeholders.
*
* @param array<string, string> $variables
*/
public function render(string $key, array $variables = []): string
{
$template = $this->repository->findByKey($key);
$body = $template?->getBody() ?? self::DEFAULTS[$key]
?? throw new \InvalidArgumentException("Unknown prompt template key: {$key}");
$search = array_map(static fn (string $k) => '{{'.$k.'}}', array_keys($variables));
return str_replace($search, array_values($variables), $body);
}
/**
* Returns all known prompt keys with their available variables.
*
* @return array<string, list<string>>
*/
public static function knownKeys(): array
{
return [
'specs_research' => ['articleType', 'subject', 'searchResults'],
'ebay_title' => ['typeName', 'deviceLabel', 'condition', 'specsSection'],
'ebay_description' => ['typeName', 'deviceLabel', 'condition', 'conditionNotes', 'specsSection'],
'vision_analyze' => [],
'json_coding' => ['schema', 'missingHint', 'specsText'],
];
}
/** @return string */
public static function defaultFor(string $key): string
{
return self::DEFAULTS[$key] ?? '';
}
}