Backup #1215

ID1215
Dateipfad/var/www/dev.campus.systemische-tools.de/src/UseCases/Chat/ManageChatSessionsUseCase.php
Version9
Typ modified
Größe8.2 KB
Hashdd6e9029afe80e52a9dcb1269eb4df7c6049d026a4dc091ebe33cd1b05883adf
Datum2025-12-25 10:41:04
Geändert vonclaude-code-hook
GrundClaude Code Pre-Hook Backup vor Edit-Operation
Datei existiert Ja

Dateiinhalt

<?php

declare(strict_types=1);

namespace UseCases\Chat;

// @responsibility: Verwaltet Chat-Sessions (CRUD, Einstellungen, Collections)

use Domain\Entity\ChatMessage;
use Domain\Entity\ChatSession;
use Domain\Repository\ChatMessageRepositoryInterface;
use Domain\Repository\ChatSessionRepositoryInterface;
use Domain\Repository\CollectionRepositoryInterface;
use Infrastructure\AI\ModelConfig;
use Infrastructure\Persistence\ContentConfigRepository;
use Infrastructure\Validation\CollectionValidator;

final class ManageChatSessionsUseCase
{
    private ?array $collectionsCache = null;

    public function __construct(
        private ChatSessionRepositoryInterface $sessionRepo,
        private ChatMessageRepositoryInterface $messageRepo,
        private ContentConfigRepository $configRepo,
        private CollectionRepositoryInterface $collectionRepo,
        private CollectionValidator $collectionValidator,
        private \PDO $pdoDev
    ) {
    }

    public function createSession(): string
    {
        $uuid = $this->sessionRepo->generateUuid();
        $this->sessionRepo->create($uuid, 'claude-opus-4-5-20251101', '["documents"]', 5);

        return $uuid;
    }

    public function getSession(string $uuid): ?ChatSession
    {
        return $this->sessionRepo->findByUuid($uuid);
    }

    /**
     * Get all sessions as entities.
     *
     * @return array<int, ChatSession>
     */
    public function getAllSessions(int $limit = 50): array
    {
        return $this->sessionRepo->findAll($limit);
    }

    /**
     * Get all sessions with stats as arrays (for list views).
     *
     * @return array<int, array<string, mixed>>
     */
    public function getAllSessionsWithStats(int $limit = 50): array
    {
        return $this->sessionRepo->findAllWithStats($limit);
    }

    /**
     * Get messages for a session.
     *
     * @return array<int, ChatMessage>
     */
    public function getMessages(int $sessionId): array
    {
        return $this->messageRepo->findBySessionId($sessionId);
    }

    public function updateTitle(int $sessionId, string $title): string
    {
        $title = trim($title);

        if ($title === '') {
            $title = 'Neuer Chat';
        }

        $title = mb_substr($title, 0, 100);
        $this->sessionRepo->updateTitle($sessionId, $title);

        return $title;
    }

    public function updateSettings(
        int $sessionId,
        string $model,
        array $collections,
        int $contextLimit,
        int $authorProfileId,
        float $temperature,
        int $maxTokens
    ): void {
        $model = ModelConfig::validate($model);
        $collections = $this->validateCollections($collections);
        $contextLimit = $this->validateContextLimit($contextLimit);
        $authorProfileId = $this->validateAuthorProfileId($authorProfileId);
        $temperature = $this->validateTemperature($temperature);
        $maxTokens = $this->validateMaxTokens($maxTokens);

        $this->sessionRepo->updateSettings(
            $sessionId,
            $model,
            $collections,
            $contextLimit,
            $authorProfileId > 0 ? $authorProfileId : null,
            $temperature,
            $maxTokens
        );
    }

    public function updateSystemPrompt(int $sessionId, string $systemPrompt): ChatSessionResult
    {
        $maxLength = 2000;
        $wasTruncated = mb_strlen($systemPrompt) > $maxLength;
        $systemPrompt = trim(mb_substr($systemPrompt, 0, $maxLength));

        $this->logSystemPromptChange($systemPrompt, $wasTruncated);
        $this->sessionRepo->updateSystemPrompt($sessionId, $systemPrompt);

        return ChatSessionResult::success('System-Prompt gespeichert.');
    }

    public function deleteSession(int $sessionId): void
    {
        $this->sessionRepo->delete($sessionId);
    }

    public function getAuthorProfiles(): array
    {
        return $this->configRepo->getAuthorProfiles();
    }

    public function getSystemPrompts(): array
    {
        return $this->configRepo->getSystemPrompts();
    }

    public function getOutputStructures(): array
    {
        return $this->configRepo->getStructures();
    }

    public function getStructure(int $id): ?array
    {
        return $this->configRepo->getStructure($id);
    }

    public function getAvailableCollections(): array
    {
        if ($this->collectionsCache === null) {
            $this->collectionsCache = $this->collectionRepo->getSearchable();

            if ($this->collectionsCache === []) {
                $this->collectionsCache = [
                    ['collection_id' => 'documents', 'display_name' => 'Dokumente', 'points_count' => 0, 'vector_size' => 1024],
                ];
            }
        }

        return $this->collectionsCache;
    }

    public function validateCollectionCompatibility(array $collectionIds): array
    {
        if (empty($collectionIds)) {
            return ['valid' => true, 'error' => null];
        }

        $result = $this->collectionValidator->validateSelection($collectionIds);

        return [
            'valid' => $result->isValid(),
            'error' => $result->getError(),
        ];
    }

    public function getDefaultSystemPrompt(): string
    {
        return <<<'PROMPT'
            Du bist ein hilfreicher Assistent für Fragen zu systemischem Teamcoaching und Teamentwicklung.

            Beantworte die Frage des Nutzers basierend auf dem bereitgestellten Kontext.
            - Antworte auf Deutsch
            - Sei präzise und hilfreich
            - Wenn der Kontext die Frage nicht beantwortet, sage das ehrlich
            - Verweise auf die Quellen wenn passend
            PROMPT;
    }

    /**
     * Check if settings have changed.
     *
     * @param array<string> $collections
     */
    public function settingsHaveChanged(
        ChatSession $session,
        string $model,
        array $collections,
        int $contextLimit,
        int $authorProfileId,
        float $temperature,
        int $maxTokens
    ): bool {
        return $model !== $session->getModel()
            || $collections !== $session->getCollections()
            || $contextLimit !== $session->getContextLimit()
            || $authorProfileId !== ($session->getAuthorProfileId() ?? 0)
            || $temperature !== $session->getTemperature()
            || $maxTokens !== $session->getMaxTokens();
    }

    private function validateCollections(array|string $collections): array
    {
        $availableIds = array_column($this->getAvailableCollections(), 'collection_id');

        if (is_string($collections)) {
            $collections = [$collections];
        }

        $valid = array_filter($collections, fn ($c) => in_array($c, $availableIds, true));

        return array_values($valid);
    }

    private function validateContextLimit(int $limit): int
    {
        $allowedLimits = [3, 5, 10, 15];

        return in_array($limit, $allowedLimits, true) ? $limit : 5;
    }

    private function validateAuthorProfileId(int $profileId): int
    {
        if ($profileId === 0) {
            return 0;
        }

        $profile = $this->configRepo->getAuthorProfile($profileId);

        return $profile !== null ? $profileId : 0;
    }

    private function validateTemperature(float $temperature): float
    {
        return max(0.0, min(1.0, $temperature));
    }

    private function validateMaxTokens(int $maxTokens): int
    {
        $allowedValues = [1024, 2048, 4096, 8192];

        return in_array($maxTokens, $allowedValues, true) ? $maxTokens : 4096;
    }

    private function logSystemPromptChange(string $prompt, bool $wasTruncated): void
    {
        $logData = [
            'prompt_length' => mb_strlen($prompt),
            'truncated' => $wasTruncated,
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            'timestamp' => date('c'),
        ];

        try {
            $devDb = \Infrastructure\Config\DatabaseFactory::dev();
            $stmt = $devDb->prepare(
                "INSERT INTO mcp_log (tool, operation, parameters, result, logged_at)
                 VALUES ('chat', 'system_prompt_change', :params, 'logged', NOW())"
            );
            $stmt->execute(['params' => json_encode($logData)]);
        } catch (\Exception $e) {
            // Silently fail
        }
    }
}

Vollständig herunterladen

Aktionen

Herunterladen

Andere Versionen dieser Datei

ID Version Typ Größe Datum
1841 14 modified 8.2 KB 2025-12-27 23:21
1838 13 modified 8.2 KB 2025-12-27 23:20
1443 12 modified 8.2 KB 2025-12-25 17:00
1303 11 modified 8.2 KB 2025-12-25 13:29
1302 10 modified 8.1 KB 2025-12-25 13:29
1215 9 modified 8.2 KB 2025-12-25 10:41
1214 8 modified 8.1 KB 2025-12-25 10:40
1143 7 modified 7.9 KB 2025-12-25 09:45
1134 6 modified 8.1 KB 2025-12-25 09:41
1133 5 modified 7.9 KB 2025-12-25 09:41
1132 4 modified 7.8 KB 2025-12-25 09:41
832 3 modified 8.5 KB 2025-12-23 08:16
713 2 modified 8.4 KB 2025-12-23 07:55
545 1 modified 8.1 KB 2025-12-23 02:37

← Zurück zur Übersicht