Files
ChatBot/docs/architecture/data-models.md
Leonid Pershin e5e69470f8
All checks were successful
SonarQube / Build and analyze (push) Successful in 3m22s
add docs
2025-10-21 05:08:40 +03:00

10 KiB
Raw Blame History

📊 Модели данных

Полное описание всех моделей и сущностей в ChatBot.

🗂️ Типы моделей

1. Domain Models (Доменные модели)

  • ChatSession - Основная модель сессии чата
  • ChatMessage - DTO для сообщений

2. Entity Models (Сущности БД)

  • ChatSessionEntity - Сущность сессии в БД
  • ChatMessageEntity - Сущность сообщения в БД

3. Configuration Models (Конфигурация)

  • TelegramBotSettings
  • OllamaSettings
  • AISettings
  • DatabaseSettings

📦 Domain Models

ChatSession

Основная модель для работы с сессией чата.

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; }       // Макс история
}

Ключевые методы:

Работа с сообщениями

// Добавить сообщение (базовый)
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()

Управление компрессией

void SetCompressionService(IHistoryCompressionService service)

Thread Safety: Все операции с _messageHistory защищены lock(_lock)

Управление историей:

  • Автоматическое обрезание при превышении MaxHistoryLength
  • Сохранение system prompt при обрезке
  • Поддержка асинхронной компрессии

ChatMessage (DTO)

public class ChatMessage
{
    public ChatRole Role { get; set; }      // user/assistant/system
    public string Content { get; set; }     // Текст сообщения
}

ChatRole enum:

public enum ChatRole
{
    System,     // Системный промпт
    User,       // Сообщение пользователя
    Assistant   // Ответ бота
}

💾 Entity Models

ChatSessionEntity

Сущность для хранения в PostgreSQL.

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

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

public class TelegramBotSettings
{
    public string BotToken { get; set; } = string.Empty;
}

Validator:

RuleFor(x => x.BotToken)
    .NotEmpty()
    .MinimumLength(10);

OllamaSettings

public class OllamaSettings
{
    public string Url { get; set; } = string.Empty;
    public string DefaultModel { get; set; } = string.Empty;
}

Validator:

RuleFor(x => x.Url)
    .NotEmpty()
    .Must(BeValidUrl);
    
RuleFor(x => x.DefaultModel)
    .NotEmpty();

AISettings

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:

RuleFor(x => x.Temperature)
    .GreaterThanOrEqualTo(0.0)
    .LessThanOrEqualTo(2.0);
    
RuleFor(x => x.MaxRetryAttempts)
    .GreaterThanOrEqualTo(1)
    .LessThanOrEqualTo(10);

DatabaseSettings

public class DatabaseSettings
{
    public string ConnectionString { get; set; } = string.Empty;
    public bool EnableSensitiveDataLogging { get; set; } = false;
    public int CommandTimeout { get; set; } = 30;
}

Validator:

RuleFor(x => x.ConnectionString)
    .NotEmpty();
    
RuleFor(x => x.CommandTimeout)
    .GreaterThanOrEqualTo(5)
    .LessThanOrEqualTo(300);

🔄 Маппинг Entity ↔ Model

Session Entity → Model

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

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

-- Таблица сессий
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

📚 См. также