Backup #111

ID111
Dateipfad/var/www/dev.campus.systemische-tools.de/src/Controller/ContentController.php
Version4
Typ modified
Größe10.3 KB
Hash2675bd5b8089560c894be41a920ec4501bc1437bacdad9d4bd08cf8596a556a3
Datum2025-12-20 19:20:07
Geändert vonclaude-code-hook
GrundClaude Code Pre-Hook Backup vor Edit-Operation
Datei existiert Ja

Dateiinhalt

<?php

namespace Controller;

use Framework\Controller;
use Infrastructure\Persistence\ContentRepository;

class ContentController extends Controller
{
    private ContentRepository $repository;
    private string $pipelinePath = '/opt/scripts/pipeline';
    private string $pythonPath;

    public function __construct()
    {
        $this->repository = new ContentRepository();
        $this->pythonPath = $this->pipelinePath . '/venv/bin/python';
    }

    /**
     * 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
    {
        $this->view('content.new', [
            'title' => 'Neuer Content-Auftrag',
            'profiles' => $this->repository->findAllProfiles(),
            'contracts' => $this->repository->findAllContracts(),
            'structures' => $this->repository->findAllStructures(),
        ]);
    }

    /**
     * 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'];
            }
        }

        $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,
        ]);

        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);

        $this->view('content.show', [
            'title' => $order['title'],
            'order' => $order,
            'versions' => $versions,
            'latestVersion' => $latestVersion,
            'critiques' => $critiques,
            'sources' => $sources,
        ]);
    }

    /**
     * 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 '<div class="alert error">Fehler: ' . htmlspecialchars($result['error']) . '</div>';

            return;
        }

        // Return updated content section
        $this->renderVersionPartial($result);
    }

    /**
     * POST /content/{id}/critique
     * Run critique round (HTMX)
     */
    public function critique(int $id): void
    {
        $this->requireCsrf();

        // Get latest version
        $version = $this->repository->findLatestVersion($id);

        if ($version === null) {
            echo '<div class="alert error">Keine Version vorhanden.</div>';

            return;
        }

        $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';
        $result = $this->callPython('critique', $version['id'], [$model]);

        if (isset($result['error'])) {
            echo '<div class="alert error">Fehler: ' . htmlspecialchars($result['error']) . '</div>';

            return;
        }

        // Return critique results
        $this->renderCritiquePartial($result);
    }

    /**
     * POST /content/{id}/revise
     * Create revision (HTMX)
     */
    public function revise(int $id): void
    {
        $version = $this->repository->findLatestVersion($id);

        if ($version === null) {
            echo '<div class="alert error">Keine Version vorhanden.</div>';

            return;
        }

        $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';
        $result = $this->callPython('revise', $version['id'], [$model]);

        if (isset($result['error'])) {
            echo '<div class="alert error">Fehler: ' . htmlspecialchars($result['error']) . '</div>';

            return;
        }

        $this->renderVersionPartial($result);
    }

    /**
     * POST /content/{id}/approve
     * Approve content
     */
    public function approve(int $id): void
    {
        $this->repository->updateOrderStatus($id, 'approve');
        echo '<div class="alert success">Content genehmigt!</div>';
        echo '<script>setTimeout(() => window.location.reload(), 1000);</script>';
    }

    /**
     * POST /content/{id}/decline
     * Decline content
     */
    public function decline(int $id): void
    {
        $this->repository->updateOrderStatus($id, 'draft');
        echo '<div class="alert warning">Content abgelehnt. Zurück zu Entwurf.</div>';
        echo '<script>setTimeout(() => window.location.reload(), 1000);</script>';
    }

    /**
     * Call Python script
     */
    private function callPython(string $command, int $entityId, array $args = []): array
    {
        $scriptPath = $this->pipelinePath . '/web_generate.py';

        $cmdArgs = array_map('escapeshellarg', $args);
        $cmd = "{$this->pythonPath} {$scriptPath} {$command} {$entityId} " . implode(' ', $cmdArgs) . ' 2>&1';

        $output = shell_exec($cmd);

        if ($output === null) {
            return ['error' => 'Script konnte nicht ausgeführt werden'];
        }

        if (preg_match('/\{[\s\S]*\}/', $output, $matches)) {
            $result = json_decode($matches[0], true);
            if (json_last_error() === JSON_ERROR_NONE) {
                return $result;
            }
        }

        return ['error' => 'Ungültige Antwort: ' . substr($output, 0, 500)];
    }

    /**
     * Render version partial
     */
    private function renderVersionPartial(array $result): void
    {
        $content = $result['content'] ?? '';
        $sources = $result['sources'] ?? [];

        echo '<div class="version-content">';
        echo '<div class="version-header">';
        echo '<span class="version-number">Version ' . ($result['version_number'] ?? '?') . '</span>';
        echo '<span class="badge success">Generiert</span>';
        echo '</div>';
        echo '<div class="content-text">' . nl2br(htmlspecialchars($content)) . '</div>';

        if (count($sources) > 0) {
            echo '<div class="sources">';
            echo '<strong>Quellen:</strong><ul>';
            foreach ($sources as $src) {
                $score = round(($src['score'] ?? 0) * 100);
                echo '<li>' . htmlspecialchars($src['source'] ?? '') . ' (' . $score . '%)</li>';
            }
            echo '</ul></div>';
        }

        echo '</div>';
    }

    /**
     * Render critique partial
     */
    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>';
    }
}

Vollständig herunterladen

Aktionen

Herunterladen

Andere Versionen dieser Datei

ID Version Typ Größe Datum
139 10 modified 11.4 KB 2025-12-20 19:58
138 9 modified 11.3 KB 2025-12-20 19:57
137 8 modified 10.8 KB 2025-12-20 19:57
134 7 modified 10.4 KB 2025-12-20 19:55
113 6 modified 10.4 KB 2025-12-20 19:20
112 5 modified 10.3 KB 2025-12-20 19:20
111 4 modified 10.3 KB 2025-12-20 19:20
110 3 modified 10.3 KB 2025-12-20 19:20
109 2 modified 10.2 KB 2025-12-20 19:19
108 1 modified 10.2 KB 2025-12-20 19:19

← Zurück zur Übersicht