{
"tool_response": {
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ContentController.php",
"oldString": " \/**\n * Render critique partial\n *\/\n private function renderCritiquePartial(array $result): void\n {\n $critiques = $result['critiques'] ?? [];\n $allPassed = $result['all_passed'] ?? false;\n\n echo '<div class=\"critique-results\">';\n echo '<div class=\"critique-header\">';\n echo '<span>Kritik-Runde ' . ($result['round'] ?? '?') . '<\/span>';\n echo $allPassed\n ? '<span class=\"badge success\">Bestanden<\/span>'\n : '<span class=\"badge warning\">Revision nötig<\/span>';\n echo '<\/div>';\n\n foreach ($critiques as $critique) {\n $passed = $critique['passed'] ?? false;\n $icon = $passed ? '✓' : '⚠';\n $class = $passed ? 'passed' : 'failed';\n\n echo '<div class=\"critique-item ' . $class . '\">';\n echo '<div class=\"critique-title\">' . $icon . ' ' . htmlspecialchars($critique['critic_name'] ?? '') . '<\/div>';\n echo '<div class=\"critique-rating\">Bewertung: ' . ($critique['rating'] ?? 'N\/A') . '\/10<\/div>';\n\n if (isset($critique['issues']) && $critique['issues'] !== []) {\n echo '<div class=\"critique-issues\"><strong>Probleme:<\/strong><ul>';\n foreach ($critique['issues'] as $issue) {\n echo '<li>' . htmlspecialchars($issue) . '<\/li>';\n }\n echo '<\/ul><\/div>';\n }\n\n if (isset($critique['summary']) && $critique['summary'] !== '') {\n echo '<div class=\"critique-summary\">' . htmlspecialchars($critique['summary']) . '<\/div>';\n }\n\n echo '<\/div>';\n }\n\n echo '<\/div>';\n }",
"newString": " \/**\n * Render critique partial\n *\/\n private function renderCritiquePartial(array $result): void\n {\n $this->view('content.partials.critique', [\n 'critiques' => $result['critiques'] ?? [],\n 'allPassed' => $result['all_passed'] ?? false,\n 'round' => $result['round'] ?? '?',\n ]);\n }",
"originalFile": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\AI\\ModelConfig;\nuse Infrastructure\\Persistence\\CollectionRepository;\nuse Infrastructure\\Persistence\\ContentRepository;\nuse Infrastructure\\Validation\\CollectionValidator;\n\nclass ContentController extends Controller\n{\n private ContentRepository $repository;\n private CollectionRepository $collectionRepository;\n private CollectionValidator $collectionValidator;\n private string $pipelinePath = '\/opt\/scripts\/pipeline';\n private string $pythonPath;\n\n public function __construct()\n {\n $this->repository = new ContentRepository();\n $this->collectionRepository = new CollectionRepository();\n $this->collectionValidator = new CollectionValidator($this->collectionRepository);\n $this->pythonPath = $this->pipelinePath . '\/venv\/bin\/python';\n }\n\n \/**\n * GET \/content\n * List all content orders\n *\/\n public function index(): void\n {\n $filters = [];\n if (isset($_GET['status']) && $_GET['status'] !== '') {\n $filters['status'] = $_GET['status'];\n }\n\n $orders = $this->repository->findAllOrders($filters);\n $stats = $this->repository->getStatistics();\n\n $this->view('content.index', [\n 'title' => 'Content Studio',\n 'orders' => $orders,\n 'stats' => $stats,\n 'currentStatus' => $_GET['status'] ?? '',\n ]);\n }\n\n \/**\n * GET \/content\/new\n * Show create form\n *\/\n public function contentNew(): void\n {\n $collections = $this->getAvailableCollections();\n $lastSettings = $this->repository->getLastOrderSettings();\n\n $this->view('content.new', [\n 'title' => 'Neuer Content-Auftrag',\n 'profiles' => $this->repository->findAllProfiles(),\n 'contracts' => $this->repository->findAllContracts(),\n 'structures' => $this->repository->findAllStructures(),\n 'models' => ModelConfig::getAll(),\n 'collections' => $collections,\n \/\/ Defaults from last order\n 'defaultModel' => $lastSettings['model'],\n 'defaultCollections' => $lastSettings['collections'],\n 'defaultContextLimit' => $lastSettings['context_limit'],\n 'defaultProfileId' => $lastSettings['author_profile_id'],\n 'defaultContractId' => $lastSettings['contract_id'],\n 'defaultStructureId' => $lastSettings['structure_id'],\n ]);\n }\n\n \/**\n * POST \/content\n * Store new order\n *\/\n public function store(): void\n {\n $this->requireCsrf();\n\n $title = trim($_POST['title'] ?? '');\n $briefing = trim($_POST['briefing'] ?? '');\n\n if ($title === '' || $briefing === '') {\n $_SESSION['error'] = 'Titel und Briefing sind erforderlich.';\n header('Location: \/content\/new');\n exit;\n }\n\n \/\/ Auto-apply first active contract if none selected\n $contractId = $_POST['contract_id'] ?? null;\n if ($contractId === null || $contractId === '') {\n $contracts = $this->repository->findAllContracts();\n if ($contracts !== []) {\n $contractId = $contracts[0]['id'];\n }\n }\n\n \/\/ Process collections (multi-select)\n $collections = $_POST['collections'] ?? ['documents'];\n if (!is_array($collections)) {\n $collections = [$collections];\n }\n\n \/\/ Validate collection compatibility\n $collections = $this->validateCollections($collections);\n $compatibility = $this->validateCollectionCompatibility($collections);\n if (!$compatibility['valid']) {\n $_SESSION['error'] = 'Collection-Fehler: ' . $compatibility['error'];\n header('Location: \/content\/new');\n exit;\n }\n\n $model = ModelConfig::validate($_POST['model'] ?? ModelConfig::DEFAULT_MODEL);\n $contextLimit = (int) ($_POST['context_limit'] ?? 5);\n\n $orderId = $this->repository->createOrder([\n 'title' => $title,\n 'briefing' => $briefing,\n 'author_profile_id' => $_POST['author_profile_id'] ?? null,\n 'contract_id' => $contractId,\n 'structure_id' => $_POST['structure_id'] ?? null,\n 'model' => $model,\n 'collections' => json_encode($collections),\n 'context_limit' => $contextLimit,\n ]);\n\n \/\/ If \"generate\" action: generate content immediately\n if (($_POST['action'] ?? 'save') === 'generate') {\n $collection = $collections[0] ?? 'documents';\n $result = $this->callPython('generate', $orderId, [$model, $collection, $contextLimit]);\n\n if (isset($result['error'])) {\n $_SESSION['error'] = 'Generierung fehlgeschlagen: ' . $result['error'];\n } else {\n $_SESSION['success'] = 'Content wurde generiert.';\n }\n }\n\n header('Location: \/content\/' . $orderId);\n exit;\n }\n\n \/**\n * GET \/content\/{id}\n * Show order details\n *\/\n public function show(int $id): void\n {\n $order = $this->repository->findOrder($id);\n\n if ($order === null) {\n $this->notFound('Auftrag nicht gefunden');\n }\n\n $versions = $this->repository->findVersionsByOrder($id);\n $latestVersion = $versions[0] ?? null;\n $critiques = $latestVersion ? $this->repository->findCritiquesByVersion($latestVersion['id']) : [];\n $sources = $this->repository->findSourcesByOrder($id);\n\n \/\/ Get available collections for the dropdown\n $availableCollections = $this->getAvailableCollections();\n\n $this->view('content.show', [\n 'title' => $order['title'],\n 'order' => $order,\n 'versions' => $versions,\n 'latestVersion' => $latestVersion,\n 'critiques' => $critiques,\n 'sources' => $sources,\n 'models' => ModelConfig::getAll(),\n 'availableCollections' => $availableCollections,\n ]);\n }\n\n \/**\n * GET \/content\/{id}\/edit\n * Show edit form\n *\/\n public function edit(int $id): void\n {\n $order = $this->repository->findOrder($id);\n\n if ($order === null) {\n $this->notFound('Auftrag nicht gefunden');\n }\n\n $this->view('content.edit', [\n 'title' => 'Auftrag bearbeiten',\n 'order' => $order,\n 'profiles' => $this->repository->findAllProfiles(),\n 'contracts' => $this->repository->findAllContracts(),\n 'structures' => $this->repository->findAllStructures(),\n ]);\n }\n\n \/**\n * POST \/content\/{id}\/generate\n * Generate content (HTMX)\n *\/\n public function generate(int $id): void\n {\n $this->requireCsrf();\n\n $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';\n $collection = $_POST['collection'] ?? 'documents';\n $limit = (int) ($_POST['context_limit'] ?? 5);\n\n \/\/ Validate collection\n $collections = $this->validateCollections([$collection]);\n if (empty($collections)) {\n echo '<div class=\"alert error\">Ungültige Collection: ' . htmlspecialchars($collection) . '<\/div>';\n\n return;\n }\n $collection = $collections[0];\n\n \/\/ Validate compatibility (single collection always valid, but check exists)\n $compatibility = $this->validateCollectionCompatibility($collections);\n if (!$compatibility['valid']) {\n echo '<div class=\"alert error\">' . htmlspecialchars($compatibility['error']) . '<\/div>';\n\n return;\n }\n\n $result = $this->callPython('generate', $id, [$model, $collection, $limit]);\n\n if (isset($result['error'])) {\n echo '<div class=\"alert error\">Fehler: ' . htmlspecialchars($result['error']) . '<\/div>';\n\n return;\n }\n\n \/\/ Return updated content section\n $this->renderVersionPartial($result);\n }\n\n \/**\n * POST \/content\/{id}\/critique\n * Run critique round (HTMX)\n *\/\n public function critique(int $id): void\n {\n $this->requireCsrf();\n\n \/\/ Get latest version\n $version = $this->repository->findLatestVersion($id);\n\n if ($version === null) {\n echo '<div class=\"alert error\">Keine Version vorhanden.<\/div>';\n\n return;\n }\n\n $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';\n $result = $this->callPython('critique', $version['id'], [$model]);\n\n if (isset($result['error'])) {\n echo '<div class=\"alert error\">Fehler: ' . htmlspecialchars($result['error']) . '<\/div>';\n\n return;\n }\n\n \/\/ Return critique results\n $this->renderCritiquePartial($result);\n }\n\n \/**\n * POST \/content\/{id}\/revise\n * Create revision (HTMX)\n *\/\n public function revise(int $id): void\n {\n $this->requireCsrf();\n\n $version = $this->repository->findLatestVersion($id);\n\n if ($version === null) {\n echo '<div class=\"alert error\">Keine Version vorhanden.<\/div>';\n\n return;\n }\n\n $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';\n $result = $this->callPython('revise', $version['id'], [$model]);\n\n if (isset($result['error'])) {\n echo '<div class=\"alert error\">Fehler: ' . htmlspecialchars($result['error']) . '<\/div>';\n\n return;\n }\n\n $this->renderVersionPartial($result);\n }\n\n \/**\n * POST \/content\/{id}\/approve\n * Approve content\n *\/\n public function approve(int $id): void\n {\n $this->requireCsrf();\n\n $this->repository->updateOrderStatus($id, 'approve');\n echo '<div class=\"alert success\">Content genehmigt!<\/div>';\n echo '<script>setTimeout(() => window.location.reload(), 1000);<\/script>';\n }\n\n \/**\n * POST \/content\/{id}\/... [TRUNCATED-c036fc1d60886c21]",
"structuredPatch": [
{
"oldStart": 399,
"oldLines": 42,
"newStart": 399,
"newLines": 11,
"lines": [
" *\/",
" private function renderCritiquePartial(array $result): void",
" {",
"- $critiques = $result['critiques'] ?? [];",
"- $allPassed = $result['all_passed'] ?? false;",
"-",
"- echo '<div class=\"critique-results\">';",
"- echo '<div class=\"critique-header\">';",
"- echo '<span>Kritik-Runde ' . ($result['round'] ?? '?') . '<\/span>';",
"- echo $allPassed",
"- ? '<span class=\"badge success\">Bestanden<\/span>'",
"- : '<span class=\"badge warning\">Revision nötig<\/span>';",
"- echo '<\/div>';",
"-",
"- foreach ($critiques as $critique) {",
"- $passed = $critique['passed'] ?? false;",
"- $icon = $passed ? '✓' : '⚠';",
"- $class = $passed ? 'passed' : 'failed';",
"-",
"- echo '<div class=\"critique-item ' . $class . '\">';",
"- echo '<div class=\"critique-title\">' . $icon . ' ' . htmlspecialchars($critique['critic_name'] ?? '') . '<\/div>';",
"- echo '<div class=\"critique-rating\">Bewertung: ' . ($critique['rating'] ?? 'N\/A') . '\/10<\/div>';",
"-",
"- if (isset($critique['issues']) && $critique['issues'] !== []) {",
"- echo '<div class=\"critique-issues\"><strong>Probleme:<\/strong><ul>';",
"- foreach ($critique['issues'] as $issue) {",
"- echo '<li>' . htmlspecialchars($issue) . '<\/li>';",
"- }",
"- echo '<\/ul><\/div>';",
"- }",
"-",
"- if (isset($critique['summary']) && $critique['summary'] !== '') {",
"- echo '<div class=\"critique-summary\">' . htmlspecialchars($critique['summary']) . '<\/div>';",
"- }",
"-",
"- echo '<\/div>';",
"- }",
"-",
"- echo '<\/div>';",
"+ $this->view('content.partials.critique', [",
"+ 'critiques' => $result['critiques'] ?? [],",
"+ 'allPassed' => $result['all_passed'] ?? false,",
"+ 'round' => $result['round'] ?? '?',",
"+ ]);",
" }",
" ",
" \/**"
]
}
],
"userModified": false,
"replaceAll": false
}
}