Backup #548

ID548
Dateipfad/var/www/dev.campus.systemische-tools.de/src/UseCases/Chat/SendChatMessageUseCase.php
Version4
Typ modified
Größe7.3 KB
Hashdedbe0c102638f74cd3603a43fffb100969b548683eeaa41a2f443dcd614d9a6
Datum2025-12-23 02:38:36
Geändert vonclaude-code-hook
GrundClaude Code Pre-Hook Backup vor Edit-Operation
Datei existiert Ja

Dateiinhalt

<?php

namespace UseCases\Chat;

use Infrastructure\AI\ChatService;
use Infrastructure\Persistence\ChatMessageRepository;
use Infrastructure\Persistence\ChatSessionRepository;
use Infrastructure\Persistence\ContentConfigRepository;

/**
 * SendChatMessageUseCase - Orchestrates sending a chat message
 *
 * Handles:
 * - Validating session exists
 * - Saving user message
 * - Auto-setting session title from first message
 * - Getting AI response with context
 * - Saving assistant message with tracking data
 */
class SendChatMessageUseCase
{
    private ChatService $chatService;
    private ChatSessionRepository $sessionRepo;
    private ChatMessageRepository $messageRepo;
    private ContentConfigRepository $configRepo;

    public function __construct(
        ?ChatService $chatService = null,
        ?ChatSessionRepository $sessionRepo = null,
        ?ChatMessageRepository $messageRepo = null,
        ?ContentConfigRepository $configRepo = null
    ) {
        $this->chatService = $chatService ?? $this->createDefaultChatService();
        $this->sessionRepo = $sessionRepo ?? new ChatSessionRepository();
        $this->messageRepo = $messageRepo ?? new ChatMessageRepository();
        $this->configRepo = $configRepo ?? new ContentConfigRepository();
    }

    /**
     * Execute the use case
     *
     * @param string $sessionUuid Session UUID
     * @param string $message User message text
     * @param string $model AI model identifier
     * @param array<string> $collections Qdrant collections to search
     * @param int $contextLimit Number of context chunks
     * @param int $authorProfileId Author profile ID (0 = none)
     * @param int $systemPromptId System prompt config ID
     * @param float $temperature AI temperature setting
     * @param int $maxTokens Max tokens for response
     * @param int $structureId Output structure ID (0 = frei)
     * @return ChatResponse
     */
    public function execute(
        string $sessionUuid,
        string $message,
        string $model,
        array $collections = ['documents'],
        int $contextLimit = 5,
        int $authorProfileId = 0,
        int $systemPromptId = 1,
        float $temperature = 0.7,
        int $maxTokens = 4096,
        int $structureId = 0
    ): ChatResponse {
        // 1. Validate session
        $session = $this->sessionRepo->findByUuid($sessionUuid);
        if ($session === null) {
            return ChatResponse::error('Session nicht gefunden.');
        }

        // 2. Validate message
        $message = trim($message);
        if ($message === '') {
            return ChatResponse::error('Bitte gib eine Frage ein.');
        }

        // 3. Save user message
        $this->messageRepo->save(
            sessionId: $session['id'],
            role: 'user',
            content: $message,
            model: $model
        );

        // 4. Auto-set title from first message
        if ($session['title'] === null) {
            $title = mb_substr($message, 0, 50) . (mb_strlen($message) > 50 ? '...' : '');
            $this->sessionRepo->updateTitle($session['id'], $title);
        }

        // 5. Get style prompt from author profile
        $stylePrompt = $this->getStylePromptFromProfile($authorProfileId);

        // 6. Get system prompt
        $systemPrompt = $this->getSystemPromptById($systemPromptId);

        // 7. Track timing and get AI response
        $startTime = microtime(true);

        try {
            $result = $this->chatService->chat(
                question: $message,
                model: $model,
                collections: $collections,
                limit: $contextLimit,
                stylePrompt: $stylePrompt,
                customSystemPrompt: $systemPrompt,
                temperature: $temperature,
                maxTokens: $maxTokens
            );
        } catch (\Exception $e) {
            return ChatResponse::error('Chat-Service Fehler: ' . $e->getMessage());
        }

        $endTime = microtime(true);

        // 8. Prepare sources as JSON strings for storage
        /** @var array<int, non-empty-string> $sourcesForStorage */
        $sourcesForStorage = array_map(
            static fn (array $source): string => json_encode($source, JSON_THROW_ON_ERROR),
            $result['sources']
        );

        // 9. Save assistant message with tracking
        $collectionsJson = json_encode($collections);
        $this->messageRepo->save(
            sessionId: $session['id'],
            role: 'assistant',
            content: $result['answer'],
            model: $model,
            tokensInput: $result['usage']['input_tokens'] ?? null,
            tokensOutput: $result['usage']['output_tokens'] ?? null,
            sources: $sourcesForStorage,
            startMicrotime: $startTime,
            endMicrotime: $endTime,
            authorProfileId: $authorProfileId > 0 ? $authorProfileId : null,
            systemPromptId: $systemPromptId > 0 ? $systemPromptId : null,
            collectionsJson: $collectionsJson,
            contextLimit: $contextLimit
        );

        // 10. Return response
        return ChatResponse::fromServiceResponse($result, $endTime - $startTime);
    }

    /**
     * Create default ChatService from credentials
     */
    private function createDefaultChatService(): ChatService
    {
        $config = \Infrastructure\AI\AIConfig::fromCredentialsFile();

        return $config->createChatService();
    }

    /**
     * Get style prompt from author profile
     */
    private function getStylePromptFromProfile(int $profileId): ?string
    {
        if ($profileId === 0) {
            return null;
        }

        $profile = $this->configRepo->findByIdAndType($profileId, 'author_profile');
        if ($profile === null) {
            return null;
        }

        $config = json_decode($profile['content'] ?? '{}', true);
        if ($config === null) {
            return null;
        }

        $parts = [];

        if (isset($config['stimme']['ton'])) {
            $parts[] = 'Ton: ' . $config['stimme']['ton'];
        }
        if (isset($config['stimme']['perspektive'])) {
            $parts[] = 'Perspektive: ' . $config['stimme']['perspektive'];
        }
        if (isset($config['stil']['fachsprache']) && $config['stil']['fachsprache']) {
            $parts[] = 'Verwende Fachsprache';
        }
        if (isset($config['stil']['beispiele']) && $config['stil']['beispiele'] === 'häufig') {
            $parts[] = 'Nutze häufig Beispiele';
        }
        if (isset($config['stil']['listen']) && $config['stil']['listen'] === 'bevorzugt') {
            $parts[] = 'Bevorzuge Listen und Bullet-Points';
        }
        if (isset($config['tabus']) && is_array($config['tabus'])) {
            $parts[] = 'Vermeide: ' . implode(', ', $config['tabus']);
        }

        if ($parts === []) {
            return null;
        }

        return 'Schreibstil (' . ($profile['name'] ?? 'Profil') . '): ' . implode('. ', $parts) . '.';
    }

    /**
     * Get system prompt by ID
     */
    private function getSystemPromptById(int $promptId): ?string
    {
        if ($promptId === 0) {
            return null;
        }

        $prompt = $this->configRepo->findByIdAndType($promptId, 'system_prompt');
        if ($prompt === null) {
            return null;
        }

        $content = json_decode($prompt['content'] ?? '{}', true);

        return $content['prompt'] ?? null;
    }
}

Vollständig herunterladen

Aktionen

Herunterladen

Andere Versionen dieser Datei

ID Version Typ Größe Datum
2084 27 modified 11.4 KB 2025-12-29 00:09
2083 26 modified 11.4 KB 2025-12-29 00:09
2082 25 modified 11.4 KB 2025-12-29 00:08
2081 24 modified 11.5 KB 2025-12-29 00:08
1947 23 modified 11.5 KB 2025-12-28 02:21
1946 22 modified 11.5 KB 2025-12-28 02:21
1945 21 modified 11.5 KB 2025-12-28 02:21
1944 20 modified 11.5 KB 2025-12-28 02:21
1943 19 modified 11.5 KB 2025-12-28 02:21
1942 18 modified 11.5 KB 2025-12-28 02:20
1941 17 modified 11.5 KB 2025-12-28 02:20
1614 16 modified 9.7 KB 2025-12-27 01:34
1131 15 modified 9.7 KB 2025-12-25 09:41
1130 14 modified 9.6 KB 2025-12-25 09:41
842 13 modified 10.2 KB 2025-12-23 08:17
708 12 modified 10.4 KB 2025-12-23 07:54
568 11 modified 10.4 KB 2025-12-23 03:37
563 10 modified 9.6 KB 2025-12-23 03:35
562 9 modified 9.4 KB 2025-12-23 03:35
561 8 modified 9.4 KB 2025-12-23 03:35
555 7 modified 9.3 KB 2025-12-23 03:33
554 6 modified 9.2 KB 2025-12-23 03:33
549 5 modified 7.6 KB 2025-12-23 02:38
548 4 modified 7.3 KB 2025-12-23 02:38
547 3 modified 7.2 KB 2025-12-23 02:38
471 2 modified 7.2 KB 2025-12-22 14:43
396 1 modified 7.1 KB 2025-12-22 08:47

← Zurück zur Übersicht