pdo = $pdo; } public function findByUuid(string $uuid): ?ChatSession { $stmt = $this->pdo->prepare('SELECT * FROM chat_sessions WHERE uuid = ?'); $stmt->execute([$uuid]); $result = $stmt->fetch(\PDO::FETCH_ASSOC); return $result !== false ? ChatSessionFactory::fromArray($result) : null; } public function findAll(int $limit = 50): array { $stmt = $this->pdo->query( 'SELECT * FROM chat_sessions ORDER BY last_activity DESC LIMIT ' . $limit ); $sessions = []; foreach ($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) { $sessions[] = ChatSessionFactory::fromArray($row); } return $sessions; } public function findAllWithStats(int $limit = 50): array { $stmt = $this->pdo->query( 'SELECT s.*, (SELECT COUNT(*) FROM chat_messages WHERE session_id = s.id) as message_count, (SELECT COALESCE(SUM(tokens_input), 0) FROM chat_messages WHERE session_id = s.id) as total_input_tokens, (SELECT COALESCE(SUM(tokens_output), 0) FROM chat_messages WHERE session_id = s.id) as total_output_tokens, (SELECT COALESCE(SUM(end_microtime - start_microtime), 0) FROM chat_messages WHERE session_id = s.id AND start_microtime IS NOT NULL) as total_duration, (SELECT model FROM chat_messages WHERE session_id = s.id AND role = "assistant" ORDER BY id DESC LIMIT 1) as last_model FROM chat_sessions s ORDER BY s.last_activity DESC LIMIT ' . $limit ); return $stmt->fetchAll(\PDO::FETCH_ASSOC); } public function save(ChatSession $session): int { if ($session->getId() !== null) { // Update $stmt = $this->pdo->prepare( 'UPDATE chat_sessions SET title = ?, model = ?, collections = ?, context_limit = ?, temperature = ?, max_tokens = ?, author_profile_id = ?, system_prompt_id = ?, updated_at = NOW() WHERE id = ?' ); $stmt->execute([ $session->getTitle(), $session->getModel(), json_encode($session->getCollections()), $session->getContextLimit(), $session->getTemperature(), $session->getMaxTokens(), $session->getAuthorProfileId(), $session->getSystemPromptId(), $session->getId(), ]); return $session->getId(); } // Insert $stmt = $this->pdo->prepare( 'INSERT INTO chat_sessions (uuid, model, collections, context_limit, temperature, max_tokens) VALUES (?, ?, ?, ?, ?, ?)' ); $stmt->execute([ $session->getUuid(), $session->getModel(), json_encode($session->getCollections()), $session->getContextLimit(), $session->getTemperature(), $session->getMaxTokens(), ]); return (int) $this->pdo->lastInsertId(); } public function create(string $uuid, string $model, string $collections, int $contextLimit): int { $stmt = $this->pdo->prepare( 'INSERT INTO chat_sessions (uuid, model, collections, context_limit) VALUES (?, ?, ?, ?)' ); $stmt->execute([$uuid, $model, $collections, $contextLimit]); return (int) $this->pdo->lastInsertId(); } public function updateTitle(int $sessionId, string $title): void { $stmt = $this->pdo->prepare('UPDATE chat_sessions SET title = ? WHERE id = ?'); $stmt->execute([$title, $sessionId]); } public function updateSettings( int $sessionId, string $model, array $collections, int $contextLimit, ?int $authorProfileId, float $temperature, int $maxTokens ): void { $collectionsJson = json_encode($collections); $stmt = $this->pdo->prepare( 'UPDATE chat_sessions SET model = ?, collections = ?, context_limit = ?, author_profile_id = ?, temperature = ?, max_tokens = ? WHERE id = ?' ); $stmt->execute([ $model, $collectionsJson, $contextLimit, $authorProfileId > 0 ? $authorProfileId : null, $temperature, $maxTokens, $sessionId, ]); } public function updateSystemPrompt(int $sessionId, ?string $systemPrompt): void { $stmt = $this->pdo->prepare('UPDATE chat_sessions SET system_prompt = ? WHERE id = ?'); $stmt->execute([$systemPrompt !== '' ? $systemPrompt : null, $sessionId]); } public function delete(int $sessionId): void { $stmt = $this->pdo->prepare('DELETE FROM chat_sessions WHERE id = ?'); $stmt->execute([$sessionId]); } public function touch(int $sessionId): void { $stmt = $this->pdo->prepare('UPDATE chat_sessions SET updated_at = NOW() WHERE id = ?'); $stmt->execute([$sessionId]); } public function generateUuid(): string { $data = random_bytes(16); $data[6] = chr(ord($data[6]) & 0x0f | 0x40); $data[8] = chr(ord($data[8]) & 0x3f | 0x80); return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); } }