ChatPromptLoader.php
- Pfad:
src/UseCases/Chat/ChatPromptLoader.php - Namespace: UseCases\Chat
- Zeilen: 250 | Größe: 7,597 Bytes
- Geändert: 2025-12-29 00:08:12 | Gescannt: 2025-12-31 10:22:15
Code Hygiene Score: 90
- Dependencies: 100 (25%)
- LOC: 50 (20%)
- Methods: 100 (20%)
- Secrets: 100 (15%)
- Classes: 100 (10%)
- Magic Numbers: 100 (10%)
Keine Issues gefunden.
Dependencies 2
- constructor Domain\Repository\ContentConfigRepositoryInterface
- use Domain\Repository\ContentConfigRepositoryInterface
Klassen 1
-
ChatPromptLoaderclass Zeile 11
Funktionen 9
-
__construct()public Zeile 13 -
getStylePrompt()public Zeile 23 -
getSystemPrompt()public Zeile 72 -
getStructurePrompt()public Zeile 93 -
buildComplexStructurePrompt()Zeile 149 -
configToYaml()Zeile 163 -
isIndexedArray()Zeile 196 -
getStructureName()Zeile 208 -
composeSystemPrompt()Zeile 222
Verwendet von 3
- ChatServiceProvider.php use
- SendChatMessageUseCase.php constructor
- StreamingChatMessageUseCase.php constructor
Versionen 1
-
v1
2025-12-29 00:08 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation
Code
<?php
declare(strict_types=1);
namespace UseCases\Chat;
// @responsibility: Lädt Chat-Prompts aus ContentConfig-Repository
use Domain\Repository\ContentConfigRepositoryInterface;
final class ChatPromptLoader
{
public function __construct(
private ContentConfigRepositoryInterface $configRepo
) {
}
/**
* Load style prompt from author profile.
*
* @throws \RuntimeException When profile cannot be parsed
*/
public function getStylePrompt(int $profileId): ?string
{
if ($profileId === 0) {
return null;
}
$profile = $this->configRepo->getAuthorProfile($profileId);
if ($profile === null) {
return null;
}
$config = json_decode($profile['content'] ?? '{}', true);
if ($config === null) {
return null;
}
$parts = [];
if (isset($config['stimme']['ton'])) {
$parts[] = 'Ton: ' . $config['stimme']['ton'];
}
if (isset($config['stimme']['perspektive'])) {
$parts[] = 'Perspektive: ' . $config['stimme']['perspektive'];
}
if (isset($config['stil']['fachsprache']) && $config['stil']['fachsprache']) {
$parts[] = 'Verwende Fachsprache';
}
if (isset($config['stil']['beispiele']) && $config['stil']['beispiele'] === 'häufig') {
$parts[] = 'Nutze häufig Beispiele';
}
if (isset($config['stil']['listen']) && $config['stil']['listen'] === 'bevorzugt') {
$parts[] = 'Bevorzuge Listen und Bullet-Points';
}
if (isset($config['tabus']) && is_array($config['tabus'])) {
$parts[] = 'Vermeide: ' . implode(', ', $config['tabus']);
}
if ($parts === []) {
return null;
}
return 'Schreibstil (' . ($profile['name'] ?? 'Profil') . '): ' . implode('. ', $parts) . '.';
}
/**
* Load system prompt by ID.
*
* @throws \RuntimeException When prompt cannot be parsed
*/
public function getSystemPrompt(int $promptId): ?string
{
if ($promptId === 0) {
return null;
}
$prompt = $this->configRepo->getSystemPrompt($promptId);
if ($prompt === null) {
return null;
}
$content = json_decode($prompt['content'] ?? '{}', true);
return $content['prompt'] ?? null;
}
/**
* Load structure prompt.
*
* @throws \RuntimeException When structure cannot be parsed
*/
public function getStructurePrompt(int $structureId): ?string
{
if ($structureId === 0) {
return null;
}
$structure = $this->configRepo->getStructure($structureId);
if ($structure === null) {
return null;
}
$name = $structure['name'] ?? 'Struktur';
$config = json_decode($structure['content'] ?? '{}', true);
if ($config === null) {
return null;
}
// Complex structure (Blog-Beitrag, LinkedIn-Beitrag etc.)
if (isset($config['ausgabe']) || isset($config['aufbau']) || isset($config['gesamtaufbau'])) {
return $this->buildComplexStructurePrompt($name, $config);
}
// Simple structure (legacy format)
$parts = ["Formatiere deine Antwort als: {$name}"];
if (isset($config['sections']) && is_array($config['sections'])) {
$parts[] = 'Struktur: ' . implode(' → ', $config['sections']);
}
if (isset($config['max_chars'])) {
$parts[] = 'Maximale Länge: ' . $config['max_chars'] . ' Zeichen';
}
if (isset($config['min_words'])) {
$parts[] = 'Mindestens ' . $config['min_words'] . ' Wörter';
}
if (isset($config['max_words'])) {
$parts[] = 'Maximal ' . $config['max_words'] . ' Wörter';
}
if (isset($config['format']) && $config['format'] === 'qa') {
$min = $config['min_questions'] ?? 3;
$parts[] = "Formatiere als FAQ mit mindestens {$min} Frage-Antwort-Paaren";
}
if (isset($config['hashtags']) && $config['hashtags']) {
$parts[] = 'Füge passende Hashtags hinzu';
}
if (isset($config['cta']) && $config['cta']) {
$parts[] = 'Schließe mit einem Call-to-Action ab';
}
return implode('. ', $parts) . '.';
}
/**
* Build prompt from complex structure config.
*
* @param array<string, mixed> $config
*/
private function buildComplexStructurePrompt(string $name, array $config): string
{
$prompt = "## Ausgabeformat: {$name}\n\n";
$prompt .= "Befolge diese Struktur-Vorgaben exakt:\n\n";
$prompt .= $this->configToYaml($config, 0);
return $prompt;
}
/**
* Convert config array to readable YAML-like format.
*
* @param array<string, mixed> $config
*/
private function configToYaml(array $config, int $indent): string
{
$result = '';
$prefix = str_repeat(' ', $indent);
foreach ($config as $key => $value) {
if (is_array($value)) {
if ($this->isIndexedArray($value)) {
$result .= "{$prefix}{$key}:\n";
foreach ($value as $item) {
if (is_array($item)) {
$result .= "{$prefix}- " . trim($this->configToYaml($item, 0)) . "\n";
} else {
$result .= "{$prefix}- {$item}\n";
}
}
} else {
$result .= "{$prefix}{$key}:\n";
$result .= $this->configToYaml($value, $indent + 1);
}
} else {
$result .= "{$prefix}{$key}: {$value}\n";
}
}
return $result;
}
/**
* Check if array is indexed (list) vs associative.
*
* @param array<mixed> $arr
*/
private function isIndexedArray(array $arr): bool
{
if ($arr === []) {
return true;
}
return array_keys($arr) === range(0, count($arr) - 1);
}
/**
* Get structure name by ID.
*/
public function getStructureName(int $structureId): ?string
{
if ($structureId === 0) {
return null;
}
$structure = $this->configRepo->getStructure($structureId);
return $structure['name'] ?? null;
}
/**
* Compose effective system prompt from components.
*/
public function composeSystemPrompt(
int $systemPromptId,
int $structureId,
int $authorProfileId,
bool $hasContext,
string $defaultRagPrompt,
string $defaultNoContextPrompt
): string {
$systemPrompt = $this->getSystemPrompt($systemPromptId);
$structurePrompt = $this->getStructurePrompt($structureId);
$stylePrompt = $this->getStylePrompt($authorProfileId);
// Add structure to system prompt
if ($structurePrompt !== null) {
$systemPrompt = ($systemPrompt ?? '') . "\n\n" . $structurePrompt;
}
// Use default if no system prompt
$effectivePrompt = $systemPrompt ?? ($hasContext ? $defaultRagPrompt : $defaultNoContextPrompt);
// Add style prompt
if ($stylePrompt !== null && $stylePrompt !== '') {
$effectivePrompt .= "\n\n" . $stylePrompt;
}
return $effectivePrompt;
}
}