370 lines
10 KiB
Markdown
370 lines
10 KiB
Markdown
# 📊 Модели данных
|
||
|
||
Полное описание всех моделей и сущностей в 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)
|