repository = new ContentRepository(); $this->pythonPath = $this->pipelinePath . '/venv/bin/python'; $config = AIConfig::fromCredentialsFile(); $this->qdrantService = $config->createQdrantService(); } /** * GET /content * List all content orders */ public function index(): void { $filters = []; if (isset($_GET['status']) && $_GET['status'] !== '') { $filters['status'] = $_GET['status']; } $orders = $this->repository->findAllOrders($filters); $stats = $this->repository->getStatistics(); $this->view('content.index', [ 'title' => 'Content Studio', 'orders' => $orders, 'stats' => $stats, 'currentStatus' => $_GET['status'] ?? '', ]); } /** * GET /content/new * Show create form */ public function contentNew(): void { $collections = $this->qdrantService->listCollections(); if ($collections === []) { $collections = ['documents']; } $this->view('content.new', [ 'title' => 'Neuer Content-Auftrag', 'profiles' => $this->repository->findAllProfiles(), 'contracts' => $this->repository->findAllContracts(), 'structures' => $this->repository->findAllStructures(), 'models' => ModelConfig::getAll(), 'defaultModel' => ModelConfig::DEFAULT_MODEL, 'collections' => $collections, ]); } /** * POST /content * Store new order */ public function store(): void { $this->requireCsrf(); $title = trim($_POST['title'] ?? ''); $briefing = trim($_POST['briefing'] ?? ''); if ($title === '' || $briefing === '') { $_SESSION['error'] = 'Titel und Briefing sind erforderlich.'; header('Location: /content/new'); exit; } // Auto-apply first active contract if none selected $contractId = $_POST['contract_id'] ?? null; if ($contractId === null || $contractId === '') { $contracts = $this->repository->findAllContracts(); if ($contracts !== []) { $contractId = $contracts[0]['id']; } } // Process collections (multi-select) $collections = $_POST['collections'] ?? ['documents']; if (!is_array($collections)) { $collections = [$collections]; } $model = ModelConfig::validate($_POST['model'] ?? ModelConfig::DEFAULT_MODEL); $contextLimit = (int) ($_POST['context_limit'] ?? 5); $orderId = $this->repository->createOrder([ 'title' => $title, 'briefing' => $briefing, 'author_profile_id' => $_POST['author_profile_id'] ?? null, 'contract_id' => $contractId, 'structure_id' => $_POST['structure_id'] ?? null, 'model' => $model, 'collections' => json_encode($collections), 'context_limit' => $contextLimit, ]); // If "generate" action: generate content immediately if (($_POST['action'] ?? 'save') === 'generate') { $collection = $collections[0] ?? 'documents'; $result = $this->callPython('generate', $orderId, [$model, $collection, $contextLimit]); if (isset($result['error'])) { $_SESSION['error'] = 'Generierung fehlgeschlagen: ' . $result['error']; } else { $_SESSION['success'] = 'Content wurde generiert.'; } } header('Location: /content/' . $orderId); exit; } /** * GET /content/{id} * Show order details */ public function show(int $id): void { $order = $this->repository->findOrder($id); if ($order === null) { http_response_code(404); echo '404 - Auftrag nicht gefunden'; return; } $versions = $this->repository->findVersionsByOrder($id); $latestVersion = $versions[0] ?? null; $critiques = $latestVersion ? $this->repository->findCritiquesByVersion($latestVersion['id']) : []; $sources = $this->repository->findSourcesByOrder($id); // Get available collections for the dropdown $availableCollections = $this->qdrantService->listCollections(); if ($availableCollections === []) { $availableCollections = ['documents']; } // Check for auto-generate flag $autoGenerate = $_SESSION['auto_generate'] ?? false; unset($_SESSION['auto_generate']); $this->view('content.show', [ 'title' => $order['title'], 'order' => $order, 'versions' => $versions, 'latestVersion' => $latestVersion, 'critiques' => $critiques, 'sources' => $sources, 'models' => ModelConfig::getAll(), 'availableCollections' => $availableCollections, 'autoGenerate' => $autoGenerate, ]); } /** * GET /content/{id}/edit * Show edit form */ public function edit(int $id): void { $order = $this->repository->findOrder($id); if ($order === null) { http_response_code(404); echo '404 - Auftrag nicht gefunden'; return; } $this->view('content.edit', [ 'title' => 'Auftrag bearbeiten', 'order' => $order, 'profiles' => $this->repository->findAllProfiles(), 'contracts' => $this->repository->findAllContracts(), 'structures' => $this->repository->findAllStructures(), ]); } /** * POST /content/{id}/generate * Generate content (HTMX) */ public function generate(int $id): void { $this->requireCsrf(); $model = $_POST['model'] ?? 'claude-opus-4-5-20251101'; $collection = $_POST['collection'] ?? 'documents'; $limit = (int) ($_POST['context_limit'] ?? 5); $result = $this->callPython('generate', $id, [$model, $collection, $limit]); if (isset($result['error'])) { echo '