Backup #289

ID289
Dateipfad/var/www/dev.campus.systemische-tools.de/src/Controller/SemanticExplorerController.php
Version21
Typ modified
Größe7.1 KB
Hash41dc69a225cf0954cc2a81d62b46477c566a3abcac5aa9e9b3c622cf2eb4b348
Datum2025-12-22 08:00:29
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\AI\VectorSearchService;
use Infrastructure\SemanticExplorerRepository;

/**
 * SemanticExplorerController - Nutzdaten Explorer
 *
 * Zeigt Dokumente und Chunks aus Nextcloud (documents, chunks Tabellen).
 * Für Endnutzer - Coaching-Materialien, PDFs, später Mails.
 */
class SemanticExplorerController extends Controller
{
    private SemanticExplorerRepository $repository;
    private VectorSearchService $vectorSearchService;

    public function __construct()
    {
        $this->repository = new SemanticExplorerRepository();
        $this->vectorSearchService = new VectorSearchService();
    }

    /**
     * GET /semantic-explorer
     * Dashboard mit Statistiken
     */
    public function index(): void
    {
        $docStats = $this->repository->getDocumentStats();
        $chunkStats = $this->repository->getChunkStats();
        $documents = $this->repository->getDocuments();
        $recentChunks = $this->repository->getRecentChunks(5);

        $this->view('semantic-explorer.index', [
            'title' => 'Semantic Explorer',
            'docStats' => $docStats,
            'chunkStats' => $chunkStats,
            'documents' => $documents,
            'recentChunks' => $recentChunks,
        ]);
    }

    /**
     * GET /semantic-explorer/dokumente
     * Liste aller Dokumente
     */
    public function dokumente(): void
    {
        $status = $_GET['status'] ?? '';
        $search = $_GET['search'] ?? '';

        $documents = $this->repository->getDocumentsFiltered($status, $search);

        $this->view('semantic-explorer.dokumente.index', [
            'title' => 'Dokumente',
            'documents' => $documents,
            'currentStatus' => $status,
            'currentSearch' => $search,
        ]);
    }

    /**
     * GET /semantic-explorer/dokumente/{id}
     * Dokument-Details mit Chunks
     */
    public function dokumentShow(int $id): void
    {
        $document = $this->repository->getDocument($id);

        if ($document === null) {
            $this->notFound('Dokument nicht gefunden');
        }

        $chunks = $this->repository->getChunksForDocument($id);

        // Heading-Paths dekodieren
        foreach ($chunks as &$chunk) {
            $chunk['heading_path_decoded'] = $this->decodeJson($chunk['heading_path'] ?? null);
            $chunk['metadata_decoded'] = $this->decodeJson($chunk['metadata'] ?? null);
        }

        $this->view('semantic-explorer.dokumente.show', [
            'title' => $document['filename'],
            'document' => $document,
            'chunks' => $chunks,
        ]);
    }

    /**
     * GET /semantic-explorer/chunks
     * Liste aller Chunks
     */
    public function chunks(): void
    {
        $search = $_GET['search'] ?? '';
        $embedded = $_GET['embedded'] ?? '';
        $page = max(1, (int) ($_GET['page'] ?? 1));
        $limit = 50;
        $offset = ($page - 1) * $limit;

        $totalCount = $this->repository->getChunksCount($search, $embedded);
        $chunks = $this->repository->getChunksFiltered($search, $embedded, $limit, $offset);

        $this->view('semantic-explorer.chunks.index', [
            'title' => 'Chunks',
            'chunks' => $chunks,
            'currentSearch' => $search,
            'currentEmbedded' => $embedded,
            'currentPage' => $page,
            'totalCount' => $totalCount,
            'totalPages' => ceil($totalCount / $limit),
        ]);
    }

    /**
     * GET /semantic-explorer/chunks/{id}
     * Chunk-Details
     */
    public function chunkShow(int $id): void
    {
        $chunk = $this->repository->getChunk($id);

        if ($chunk === null) {
            $this->notFound('Chunk nicht gefunden');
        }

        // JSON-Felder dekodieren
        $chunk['heading_path_decoded'] = $this->decodeJson($chunk['heading_path'] ?? null);
        $chunk['metadata_decoded'] = $this->decodeJson($chunk['metadata'] ?? null);

        // Nachbar-Chunks
        $prevChunk = $this->repository->getChunkByDocumentAndIndex(
            $chunk['document_id'],
            $chunk['chunk_index'] - 1
        );
        $nextChunk = $this->repository->getChunkByDocumentAndIndex(
            $chunk['document_id'],
            $chunk['chunk_index'] + 1
        );

        $this->view('semantic-explorer.chunks.show', [
            'title' => 'Chunk #' . $chunk['id'],
            'chunk' => $chunk,
            'prevChunk' => $prevChunk,
            'nextChunk' => $nextChunk,
        ]);
    }

    /**
     * GET /semantic-explorer/suche
     * Semantische Suche in Nutzdaten
     */
    public function suche(): void
    {
        $query = $_GET['q'] ?? '';
        $limit = min(20, max(1, (int) ($_GET['limit'] ?? 10)));

        $results = [];

        if ($query !== '') {
            // Vektor-Suche via Qdrant
            $results = $this->vectorSearch($query, $limit);
        }

        $this->view('semantic-explorer.suche', [
            'title' => 'Semantische Suche',
            'query' => $query,
            'results' => $results,
            'limit' => $limit,
        ]);
    }

    /**
     * Vektor-Suche in documents Collection using VectorSearchService
     */
    private function vectorSearch(string $query, int $limit): array
    {
        // Search via service
        $response = $this->vectorSearchService->search($query, 'documents', $limit);

        if (empty($response)) {
            return [];
        }

        // Chunk-Details aus DB laden
        $results = [];
        foreach ($response as $point) {
            $chunkId = $point['payload']['chunk_id'] ?? null;
            if ($chunkId === null) {
                continue;
            }

            $chunk = $this->repository->getChunkById($chunkId);

            if ($chunk !== null) {
                $chunk['score'] = $point['score'];
                $chunk['heading_path_decoded'] = $this->decodeJson($chunk['heading_path'] ?? null);
                $results[] = $chunk;
            }
        }

        return $results;
    }

    /**
     * GET /semantic-explorer/semantik
     * Semantische Analyse pro Chunk
     */
    public function semantik(): void
    {
        $sentiment = $_GET['sentiment'] ?? '';
        $page = max(1, (int) ($_GET['page'] ?? 1));
        $limit = 50;
        $offset = ($page - 1) * $limit;

        $totalCount = $this->repository->getSemanticsCount($sentiment);
        $semantics = $this->repository->getSemanticsFiltered($sentiment, $limit, $offset);

        // JSON dekodieren
        foreach ($semantics as &$s) {
            $s['keywords_decoded'] = json_decode($s['keywords'] ?? '[]', true) ?: [];
            $s['topics_decoded'] = json_decode($s['topics'] ?? '[]', true) ?: [];
        }

        $stats = $this->repository->getSemanticStats();

        $this->view('semantic-explorer.semantik', [
            'title' => 'Semantik',
            'semantics' => $semantics,
            'stats' => $stats,
            'currentSentiment' => $sentiment,
            'currentPage' => $page,
            'totalCount' => $totalCount,
            'totalPages' => ceil($totalCount / $limit),
        ]);
    }
}

Vollständig herunterladen

Aktionen

Herunterladen

Andere Versionen dieser Datei

ID Version Typ Größe Datum
1991 56 modified 9.3 KB 2025-12-28 03:05
1982 55 modified 9.1 KB 2025-12-28 02:54
1699 54 modified 8.8 KB 2025-12-27 12:18
1107 53 modified 8.8 KB 2025-12-25 09:22
1106 52 modified 8.8 KB 2025-12-25 09:22
1105 51 modified 8.8 KB 2025-12-25 09:22
1104 50 modified 8.8 KB 2025-12-25 09:22
1099 49 modified 8.8 KB 2025-12-25 09:20
1098 48 modified 8.8 KB 2025-12-25 09:20
1097 47 modified 8.6 KB 2025-12-25 09:20
1082 46 modified 8.6 KB 2025-12-25 02:29
1081 45 modified 8.4 KB 2025-12-25 02:29
1071 44 modified 8.3 KB 2025-12-25 02:26
1070 43 modified 8.3 KB 2025-12-25 02:26
1069 42 modified 8.3 KB 2025-12-25 02:26
1068 41 modified 8.3 KB 2025-12-25 02:26
1067 40 modified 8.3 KB 2025-12-25 02:26
1066 39 modified 8.3 KB 2025-12-25 02:26
1065 38 modified 8.3 KB 2025-12-25 02:25
1064 37 modified 8.3 KB 2025-12-25 02:25
1063 36 modified 7.8 KB 2025-12-25 02:25
912 35 modified 7.7 KB 2025-12-23 16:41
910 34 modified 7.1 KB 2025-12-23 16:40
698 33 modified 7.2 KB 2025-12-23 07:53
676 32 modified 7.2 KB 2025-12-23 07:00
641 31 modified 7.2 KB 2025-12-23 04:47
612 30 modified 7.3 KB 2025-12-23 04:42
586 29 modified 7.2 KB 2025-12-23 04:24
339 28 modified 7.1 KB 2025-12-22 08:11
338 27 modified 7.0 KB 2025-12-22 08:11
337 26 modified 7.0 KB 2025-12-22 08:11
313 25 modified 7.0 KB 2025-12-22 08:05
312 24 modified 7.0 KB 2025-12-22 08:05
311 23 modified 7.0 KB 2025-12-22 08:05
310 22 modified 7.0 KB 2025-12-22 08:05
289 21 modified 7.1 KB 2025-12-22 08:00
288 20 modified 7.1 KB 2025-12-22 08:00
287 19 modified 7.1 KB 2025-12-22 08:00
286 18 modified 7.1 KB 2025-12-22 08:00
265 17 modified 8.5 KB 2025-12-22 02:07
264 16 modified 8.4 KB 2025-12-22 02:07
263 15 modified 14.7 KB 2025-12-22 02:06
262 14 modified 16.2 KB 2025-12-22 02:05
261 13 modified 19.2 KB 2025-12-22 02:04
260 12 modified 19.8 KB 2025-12-22 02:04
259 11 modified 22.8 KB 2025-12-22 02:02
258 10 modified 24.4 KB 2025-12-22 02:02
224 9 modified 24.4 KB 2025-12-22 01:44
223 8 modified 24.5 KB 2025-12-22 01:44
222 7 modified 24.5 KB 2025-12-22 01:44
221 6 modified 24.6 KB 2025-12-22 01:44
220 5 modified 24.6 KB 2025-12-22 01:44
219 4 modified 24.7 KB 2025-12-22 01:44
218 3 modified 24.7 KB 2025-12-22 01:44
46 2 modified 12.2 KB 2025-12-20 17:44
10 1 modified 23.5 KB 2025-12-20 16:35

← Zurück zur Übersicht