add docs
All checks were successful
SonarQube / Build and analyze (push) Successful in 3m22s

This commit is contained in:
Leonid Pershin
2025-10-21 05:08:40 +03:00
parent bc1b3c4015
commit e5e69470f8
12 changed files with 3550 additions and 6 deletions

View File

@@ -0,0 +1,369 @@
# 📊 Модели данных
Полное описание всех моделей и сущностей в ChatBot.
## 🗂️ Типы моделей
### 1. Domain Models (Доменные модели)
- `ChatSession` - Основная модель сессии чата
- `ChatMessage` - DTO для сообщений
### 2. Entity Models (Сущности БД)
- `ChatSessionEntity` - Сущность сессии в БД
- `ChatMessageEntity` - Сущность сообщения в БД
### 3. Configuration Models (Конфигурация)
- `TelegramBotSettings`
- `OllamaSettings`
- `AISettings`
- `DatabaseSettings`
## 📦 Domain Models
### ChatSession
Основная модель для работы с сессией чата.
```csharp
public class ChatSession
{
public string SessionId { get; set; } // Уникальный ID
public long ChatId { get; set; } // Telegram chat ID
public string ChatType { get; set; } // Тип чата
public string ChatTitle { get; set; } // Название
public string Model { get; set; } // AI модель
public DateTime CreatedAt { get; set; } // Создан
public DateTime LastUpdatedAt { get; set; } // Обновлен
public int MaxHistoryLength { get; set; } // Макс история
}
```
**Ключевые методы:**
#### Работа с сообщениями
```csharp
// Добавить сообщение (базовый)
void AddMessage(ChatMessage message)
// Добавить с компрессией
Task AddMessageWithCompressionAsync(ChatMessage message, int threshold, int target)
// Добавить user сообщение
void AddUserMessage(string content, string username)
Task AddUserMessageWithCompressionAsync(string content, string username, int threshold, int target)
// Добавить assistant сообщение
void AddAssistantMessage(string content)
Task AddAssistantMessageWithCompressionAsync(string content, int threshold, int target)
// Получить все сообщения
List<ChatMessage> GetAllMessages()
// Количество сообщений
int GetMessageCount()
// Очистить историю
void ClearHistory()
```
#### Управление компрессией
```csharp
void SetCompressionService(IHistoryCompressionService service)
```
**Thread Safety:**
Все операции с `_messageHistory` защищены `lock(_lock)`
**Управление историей:**
- Автоматическое обрезание при превышении `MaxHistoryLength`
- Сохранение system prompt при обрезке
- Поддержка асинхронной компрессии
### ChatMessage (DTO)
```csharp
public class ChatMessage
{
public ChatRole Role { get; set; } // user/assistant/system
public string Content { get; set; } // Текст сообщения
}
```
**ChatRole enum:**
```csharp
public enum ChatRole
{
System, // Системный промпт
User, // Сообщение пользователя
Assistant // Ответ бота
}
```
## 💾 Entity Models
### ChatSessionEntity
Сущность для хранения в PostgreSQL.
```csharp
public class ChatSessionEntity
{
public int Id { get; set; } // PK (auto-increment)
public string SessionId { get; set; } // Unique, indexed
public long ChatId { get; set; } // Indexed
public string ChatType { get; set; } // Max 20 chars
public string? ChatTitle { get; set; } // Max 200 chars
public string Model { get; set; } // Max 100 chars
public DateTime CreatedAt { get; set; } // Required
public DateTime LastUpdatedAt { get; set; } // Required
public List<ChatMessageEntity> Messages { get; set; } // Navigation property
}
```
**Индексы:**
- `SessionId` - Unique index
- `ChatId` - Index для быстрого поиска
**Constraints:**
- `SessionId` - Required, MaxLength(50)
- `ChatId` - Required
- `ChatType` - Required, MaxLength(20)
**Relationships:**
- One-to-Many с `ChatMessageEntity`
- Cascade Delete - удаление сессии удаляет сообщения
### ChatMessageEntity
```csharp
public class ChatMessageEntity
{
public int Id { get; set; } // PK
public int SessionId { get; set; } // FK
public string Content { get; set; } // Max 10000 chars
public string Role { get; set; } // Max 20 chars
public int MessageOrder { get; set; } // Порядок в диалоге
public DateTime CreatedAt { get; set; } // Время создания
public ChatSessionEntity Session { get; set; } // Navigation property
}
```
**Индексы:**
- `SessionId` - Index
- `CreatedAt` - Index для сортировки
- `(SessionId, MessageOrder)` - Composite index
**Constraints:**
- `Content` - Required, MaxLength(10000)
- `Role` - Required, MaxLength(20)
## ⚙️ Configuration Models
### TelegramBotSettings
```csharp
public class TelegramBotSettings
{
public string BotToken { get; set; } = string.Empty;
}
```
**Validator:**
```csharp
RuleFor(x => x.BotToken)
.NotEmpty()
.MinimumLength(10);
```
### OllamaSettings
```csharp
public class OllamaSettings
{
public string Url { get; set; } = string.Empty;
public string DefaultModel { get; set; } = string.Empty;
}
```
**Validator:**
```csharp
RuleFor(x => x.Url)
.NotEmpty()
.Must(BeValidUrl);
RuleFor(x => x.DefaultModel)
.NotEmpty();
```
### AISettings
```csharp
public class AISettings
{
public double Temperature { get; set; } = 0.9;
public string SystemPromptPath { get; set; } = "Prompts/system-prompt.txt";
public int MaxRetryAttempts { get; set; } = 3;
public int RetryDelayMs { get; set; } = 1000;
public int RequestTimeoutSeconds { get; set; } = 180;
// Compression settings
public bool EnableHistoryCompression { get; set; } = true;
public int CompressionThreshold { get; set; } = 20;
public int CompressionTarget { get; set; } = 10;
public int MinMessageLengthForSummarization { get; set; } = 50;
public int MaxSummarizedMessageLength { get; set; } = 200;
// Advanced
public bool EnableExponentialBackoff { get; set; } = true;
public int MaxRetryDelayMs { get; set; } = 30000;
public int CompressionTimeoutSeconds { get; set; } = 30;
public int StatusCheckTimeoutSeconds { get; set; } = 10;
}
```
**Validator:**
```csharp
RuleFor(x => x.Temperature)
.GreaterThanOrEqualTo(0.0)
.LessThanOrEqualTo(2.0);
RuleFor(x => x.MaxRetryAttempts)
.GreaterThanOrEqualTo(1)
.LessThanOrEqualTo(10);
```
### DatabaseSettings
```csharp
public class DatabaseSettings
{
public string ConnectionString { get; set; } = string.Empty;
public bool EnableSensitiveDataLogging { get; set; } = false;
public int CommandTimeout { get; set; } = 30;
}
```
**Validator:**
```csharp
RuleFor(x => x.ConnectionString)
.NotEmpty();
RuleFor(x => x.CommandTimeout)
.GreaterThanOrEqualTo(5)
.LessThanOrEqualTo(300);
```
## 🔄 Маппинг Entity ↔ Model
### Session Entity → Model
```csharp
public ChatSession ToModel()
{
var session = new ChatSession
{
SessionId = this.SessionId,
ChatId = this.ChatId,
ChatType = this.ChatType,
ChatTitle = this.ChatTitle ?? string.Empty,
Model = this.Model,
CreatedAt = this.CreatedAt,
LastUpdatedAt = this.LastUpdatedAt
};
// Восстановить сообщения
foreach (var msg in Messages.OrderBy(m => m.MessageOrder))
{
session.AddMessage(new ChatMessage
{
Role = ParseRole(msg.Role),
Content = msg.Content
});
}
return session;
}
```
### Session Model → Entity
```csharp
public ChatSessionEntity ToEntity()
{
return new ChatSessionEntity
{
SessionId = this.SessionId,
ChatId = this.ChatId,
ChatType = this.ChatType,
ChatTitle = this.ChatTitle,
Model = this.Model,
CreatedAt = this.CreatedAt,
LastUpdatedAt = this.LastUpdatedAt,
Messages = this.GetAllMessages()
.Select((msg, index) => new ChatMessageEntity
{
Content = msg.Content,
Role = msg.Role.ToString(),
MessageOrder = index,
CreatedAt = DateTime.UtcNow
})
.ToList()
};
}
```
## 📐 Database Schema
```sql
-- Таблица сессий
CREATE TABLE chat_sessions (
id SERIAL PRIMARY KEY,
session_id VARCHAR(50) UNIQUE NOT NULL,
chat_id BIGINT NOT NULL,
chat_type VARCHAR(20) NOT NULL,
chat_title VARCHAR(200),
model VARCHAR(100),
created_at TIMESTAMP NOT NULL,
last_updated_at TIMESTAMP NOT NULL
);
CREATE INDEX idx_chat_sessions_session_id ON chat_sessions(session_id);
CREATE INDEX idx_chat_sessions_chat_id ON chat_sessions(chat_id);
-- Таблица сообщений
CREATE TABLE chat_messages (
id SERIAL PRIMARY KEY,
session_id INTEGER NOT NULL REFERENCES chat_sessions(id) ON DELETE CASCADE,
content VARCHAR(10000) NOT NULL,
role VARCHAR(20) NOT NULL,
message_order INTEGER NOT NULL,
created_at TIMESTAMP NOT NULL
);
CREATE INDEX idx_chat_messages_session_id ON chat_messages(session_id);
CREATE INDEX idx_chat_messages_created_at ON chat_messages(created_at);
CREATE INDEX idx_chat_messages_session_order ON chat_messages(session_id, message_order);
```
## 🎯 Жизненный цикл Session
```
1. Создание (GetOrCreate)
2. Добавление сообщений (AddMessage)
3. Проверка длины истории
4. Компрессия (если нужно)
5. Сохранение в БД (SaveSessionAsync)
6. Обновление LastUpdatedAt
```
## 📚 См. также
- [Архитектура слоев](./layers.md)
- [База данных](./database.md)
- [Сервисы](../development/services.md)