diff --git a/ChatBot/ChatBot.csproj b/ChatBot/ChatBot.csproj
index bdf7edf..7846212 100644
--- a/ChatBot/ChatBot.csproj
+++ b/ChatBot/ChatBot.csproj
@@ -17,8 +17,6 @@
-
-
diff --git a/ChatBot/Common/Constants/RetryConstants.cs b/ChatBot/Common/Constants/RetryConstants.cs
deleted file mode 100644
index bb8272d..0000000
--- a/ChatBot/Common/Constants/RetryConstants.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace ChatBot.Common.Constants
-{
- ///
- /// Constants for retry logic
- ///
- public static class RetryConstants
- {
- public const int DefaultMaxRetries = 3;
- public const int DefaultBaseDelaySeconds = 1;
- public const int DefaultMaxJitterMs = 2000;
- }
-}
diff --git a/ChatBot/Common/Results/Result.cs b/ChatBot/Common/Results/Result.cs
deleted file mode 100644
index 4f498f8..0000000
--- a/ChatBot/Common/Results/Result.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-namespace ChatBot.Common.Results
-{
- ///
- /// Represents the result of an operation that can succeed or fail
- ///
- public class Result
- {
- public bool IsSuccess { get; }
- public string Error { get; }
-
- protected Result(bool isSuccess, string error)
- {
- IsSuccess = isSuccess;
- Error = error;
- }
-
- public static Result Success() => new(true, string.Empty);
-
- public static Result Failure(string error) => new(false, error);
- }
-
- ///
- /// Represents the result of an operation that returns a value
- ///
- public class Result : Result
- {
- public T? Value { get; }
-
- private Result(T? value, bool isSuccess, string error)
- : base(isSuccess, error)
- {
- Value = value;
- }
-
- public static Result Success(T value) => new(value, true, string.Empty);
-
- public static new Result Failure(string error) => new(default, false, error);
- }
-}
diff --git a/ChatBot/Models/Configuration/AppSettings.cs b/ChatBot/Models/Configuration/AppSettings.cs
deleted file mode 100644
index da1af0a..0000000
--- a/ChatBot/Models/Configuration/AppSettings.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace ChatBot.Models.Configuration
-{
- ///
- /// Основные настройки приложения
- ///
- public class AppSettings
- {
- ///
- /// Настройки Telegram бота
- ///
- public TelegramBotSettings TelegramBot { get; set; } = new();
-
- ///
- /// Настройки Ollama API
- ///
- public OllamaSettings Ollama { get; set; } = new();
-
- ///
- /// Настройки логирования Serilog
- ///
- public SerilogSettings Serilog { get; set; } = new();
- }
-}
diff --git a/ChatBot/Models/Configuration/SerilogSettings.cs b/ChatBot/Models/Configuration/SerilogSettings.cs
deleted file mode 100644
index a57b062..0000000
--- a/ChatBot/Models/Configuration/SerilogSettings.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-namespace ChatBot.Models.Configuration
-{
- ///
- /// Настройки логирования Serilog
- ///
- public class SerilogSettings
- {
- ///
- /// Список используемых sink'ов для логирования
- ///
- public List Using { get; set; } = new();
-
- ///
- /// Настройки минимального уровня логирования
- ///
- public MinimumLevelSettings MinimumLevel { get; set; } = new();
-
- ///
- /// Настройки получателей логов (куда писать логи)
- ///
- public List WriteTo { get; set; } = new();
-
- ///
- /// Список обогатителей логов (дополнительная информация)
- ///
- public List Enrich { get; set; } = new();
- }
-
- ///
- /// Настройки минимального уровня логирования
- ///
- public class MinimumLevelSettings
- {
- ///
- /// Уровень логирования по умолчанию
- ///
- public string Default { get; set; } = "Information";
-
- ///
- /// Переопределения уровня логирования для конкретных пространств имен
- ///
- public Dictionary Override { get; set; } = new();
- }
-
- ///
- /// Настройки получателя логов
- ///
- public class WriteToSettings
- {
- ///
- /// Название sink'а для записи логов
- ///
- public string Name { get; set; } = string.Empty;
-
- ///
- /// Аргументы для настройки sink'а
- ///
- public Dictionary Args { get; set; } = new();
- }
-}
diff --git a/ChatBot/Models/Configuration/Validators/ConfigurationValidator.cs b/ChatBot/Models/Configuration/Validators/ConfigurationValidator.cs
deleted file mode 100644
index ad48ee0..0000000
--- a/ChatBot/Models/Configuration/Validators/ConfigurationValidator.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-namespace ChatBot.Models.Configuration.Validators
-{
- ///
- /// Валидатор конфигурации приложения
- ///
- public static class ConfigurationValidator
- {
- ///
- /// Валидирует все настройки приложения
- ///
- /// Настройки приложения
- /// Результат валидации
- public static ValidationResult ValidateAppSettings(AppSettings settings)
- {
- var errors = new List();
-
- // Валидация настроек Telegram бота
- var telegramResult = ValidateTelegramBotSettings(settings.TelegramBot);
- errors.AddRange(telegramResult.Errors);
-
- // Валидация настроек Ollama
- var ollamaResult = ValidateOllamaSettings(settings.Ollama);
- errors.AddRange(ollamaResult.Errors);
-
- return new ValidationResult { IsValid = !errors.Any(), Errors = errors };
- }
-
- ///
- /// Валидирует настройки Telegram бота
- ///
- /// Настройки Telegram бота
- /// Результат валидации
- public static ValidationResult ValidateTelegramBotSettings(TelegramBotSettings settings)
- {
- var errors = new List();
-
- // Проверка наличия токена бота
- if (string.IsNullOrWhiteSpace(settings.BotToken))
- {
- errors.Add("TelegramBot:BotToken is required");
- }
- // Проверка формата токена (должен содержать ':' или начинаться с 'bot')
- else if (
- !settings.BotToken.StartsWith("bot", StringComparison.OrdinalIgnoreCase)
- && !settings.BotToken.Contains(":")
- )
- {
- errors.Add(
- "TelegramBot:BotToken appears to be invalid (should contain ':' or start with 'bot')"
- );
- }
-
- return new ValidationResult { IsValid = !errors.Any(), Errors = errors };
- }
-
- ///
- /// Валидирует настройки Ollama
- ///
- /// Настройки Ollama
- /// Результат валидации
- public static ValidationResult ValidateOllamaSettings(OllamaSettings settings)
- {
- var errors = new List();
-
- // Валидация основных компонентов настроек Ollama
- ValidateUrl(settings.Url, errors);
- ValidateNumericSettings(settings, errors);
-
- if (string.IsNullOrWhiteSpace(settings.DefaultModel))
- {
- errors.Add("Ollama:DefaultModel is required");
- }
-
- return new ValidationResult { IsValid = !errors.Any(), Errors = errors };
- }
-
- ///
- /// Валидирует URL Ollama
- ///
- /// URL для проверки
- /// Список ошибок валидации
- private static void ValidateUrl(string url, List errors)
- {
- // Проверка наличия URL
- if (string.IsNullOrWhiteSpace(url))
- {
- errors.Add("Ollama:Url is required");
- }
- // Проверка корректности URL (должен быть валидным HTTP/HTTPS URL)
- else if (
- !Uri.TryCreate(url, UriKind.Absolute, out var uri)
- || (uri.Scheme != "http" && uri.Scheme != "https")
- )
- {
- errors.Add("Ollama:Url must be a valid HTTP/HTTPS URL");
- }
- }
-
- ///
- /// Валидирует числовые параметры настроек Ollama
- ///
- /// Настройки Ollama
- /// Список ошибок валидации
- private static void ValidateNumericSettings(OllamaSettings settings, List errors)
- {
- // Проверка количества повторных попыток (1-10)
- if (settings.MaxRetries < 1 || settings.MaxRetries > 10)
- {
- errors.Add("Ollama:MaxRetries must be between 1 and 10");
- }
- }
- }
-
- ///
- /// Результат валидации конфигурации
- ///
- public class ValidationResult
- {
- ///
- /// Указывает, прошла ли валидация успешно
- ///
- public bool IsValid { get; set; }
-
- ///
- /// Список ошибок валидации
- ///
- public List Errors { get; set; } = new();
- }
-}
diff --git a/ChatBot/Models/Validation/ChatMessageValidator.cs b/ChatBot/Models/Validation/ChatMessageValidator.cs
deleted file mode 100644
index 3d41768..0000000
--- a/ChatBot/Models/Validation/ChatMessageValidator.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using ChatBot.Common.Constants;
-using ChatBot.Models.Dto;
-using FluentValidation;
-
-namespace ChatBot.Models.Validation
-{
- ///
- /// Validator for ChatMessage
- ///
- public class ChatMessageValidator : AbstractValidator
- {
- public ChatMessageValidator()
- {
- RuleFor(x => x.Content)
- .NotEmpty()
- .WithMessage("Message content cannot be empty")
- .MaximumLength(10000)
- .WithMessage("Message content is too long (max 10000 characters)");
-
- RuleFor(x => x.Role)
- .NotEmpty()
- .WithMessage("Message role cannot be empty")
- .Must(role =>
- role == ChatRoles.System
- || role == ChatRoles.User
- || role == ChatRoles.Assistant
- )
- .WithMessage(
- $"Invalid message role. Must be one of: {ChatRoles.System}, {ChatRoles.User}, {ChatRoles.Assistant}"
- );
- }
- }
-}
diff --git a/ChatBot/Program.cs b/ChatBot/Program.cs
index 53fd17d..adec8ff 100644
--- a/ChatBot/Program.cs
+++ b/ChatBot/Program.cs
@@ -1,14 +1,11 @@
using ChatBot.Models.Configuration;
using ChatBot.Models.Configuration.Validators;
-using ChatBot.Models.Validation;
using ChatBot.Services;
-using ChatBot.Services.ErrorHandlers;
using ChatBot.Services.HealthChecks;
using ChatBot.Services.Interfaces;
using ChatBot.Services.Telegram.Commands;
using ChatBot.Services.Telegram.Interfaces;
using ChatBot.Services.Telegram.Services;
-using FluentValidation;
using Microsoft.Extensions.Options;
using Serilog;
using Telegram.Bot;
@@ -26,8 +23,6 @@ try
builder.Services.AddSerilog();
// Конфигурируем настройки с валидацией
- builder.Services.Configure(builder.Configuration);
-
builder
.Services.Configure(builder.Configuration.GetSection("TelegramBot"))
.AddSingleton, TelegramBotSettingsValidator>();
@@ -36,36 +31,10 @@ try
.Services.Configure(builder.Configuration.GetSection("Ollama"))
.AddSingleton, OllamaSettingsValidator>();
- builder.Services.Configure(builder.Configuration.GetSection("Serilog"));
-
// Валидируем конфигурацию при старте
builder.Services.AddOptions().ValidateOnStart();
builder.Services.AddOptions().ValidateOnStart();
- // Валидируем конфигурацию (старый способ для совместимости)
- var appSettings = builder.Configuration.Get();
- if (appSettings == null)
- {
- Log.ForContext().Fatal("Failed to load configuration");
- return;
- }
-
- var validationResult = ConfigurationValidator.ValidateAppSettings(appSettings);
- if (!validationResult.IsValid)
- {
- Log.ForContext().Fatal("Configuration validation failed:");
- foreach (var error in validationResult.Errors)
- {
- Log.ForContext().Fatal(" - {Error}", error);
- }
- return;
- }
-
- Log.ForContext().Debug("Configuration validation passed");
-
- // Регистрируем FluentValidation валидаторы
- builder.Services.AddValidatorsFromAssemblyContaining();
-
// Регистрируем IOllamaClient
builder.Services.AddSingleton(sp =>
{
@@ -76,13 +45,6 @@ try
// Регистрируем интерфейсы и сервисы
builder.Services.AddSingleton();
- // Регистрируем error handlers
- builder.Services.AddSingleton();
- builder.Services.AddSingleton();
-
- // Регистрируем retry policy (использует error handlers)
- builder.Services.AddSingleton();
-
// Регистрируем основные сервисы
builder.Services.AddSingleton();
builder.Services.AddSingleton();
diff --git a/ChatBot/Services/ErrorHandlers/NetworkErrorHandler.cs b/ChatBot/Services/ErrorHandlers/NetworkErrorHandler.cs
deleted file mode 100644
index 011e7c6..0000000
--- a/ChatBot/Services/ErrorHandlers/NetworkErrorHandler.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using ChatBot.Services.Interfaces;
-
-namespace ChatBot.Services.ErrorHandlers
-{
- ///
- /// Error handler for network-related errors
- ///
- public class NetworkErrorHandler : IErrorHandler
- {
- private readonly ILogger _logger;
-
- public NetworkErrorHandler(ILogger logger)
- {
- _logger = logger;
- }
-
- public bool CanHandle(Exception exception)
- {
- return exception is HttpRequestException
- || exception is TaskCanceledException
- || exception.Message.Contains("timeout", StringComparison.OrdinalIgnoreCase)
- || exception.Message.Contains("connection", StringComparison.OrdinalIgnoreCase);
- }
-
- public async Task HandleAsync(
- Exception exception,
- int attempt,
- string currentModel,
- CancellationToken cancellationToken = default
- )
- {
- _logger.LogWarning(
- exception,
- "Network error on attempt {Attempt} for model {Model}",
- attempt,
- currentModel
- );
-
- // Apply exponential backoff for network errors
- var delay = TimeSpan.FromSeconds(Math.Pow(2, attempt - 1));
-
- _logger.LogInformation("Waiting {Delay} before retry due to network error", delay);
-
- await Task.Delay(delay, cancellationToken);
-
- return ErrorHandlingResult.Retry();
- }
- }
-}
diff --git a/ChatBot/Services/ErrorHandlers/RateLimitErrorHandler.cs b/ChatBot/Services/ErrorHandlers/RateLimitErrorHandler.cs
deleted file mode 100644
index 4aed920..0000000
--- a/ChatBot/Services/ErrorHandlers/RateLimitErrorHandler.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using ChatBot.Services.Interfaces;
-
-namespace ChatBot.Services.ErrorHandlers
-{
- ///
- /// Error handler for rate limit errors (HTTP 429)
- ///
- public class RateLimitErrorHandler : IErrorHandler
- {
- private readonly ILogger _logger;
-
- public RateLimitErrorHandler(ILogger logger)
- {
- _logger = logger;
- }
-
- public bool CanHandle(Exception exception)
- {
- return exception.Message.Contains("429")
- || exception.Message.Contains("Too Many Requests")
- || exception.Message.Contains("rate limit", StringComparison.OrdinalIgnoreCase);
- }
-
- public async Task HandleAsync(
- Exception exception,
- int attempt,
- string currentModel,
- CancellationToken cancellationToken = default
- )
- {
- _logger.LogWarning(
- exception,
- "Rate limit exceeded on attempt {Attempt} for model {Model}",
- attempt,
- currentModel
- );
-
- // Apply exponential backoff for rate limiting
- var delay = TimeSpan.FromSeconds(Math.Pow(2, attempt - 1));
- var jitter = TimeSpan.FromMilliseconds(Random.Shared.Next(0, 2000));
-
- _logger.LogInformation(
- "Rate limit hit, waiting {Delay} before retry",
- delay.Add(jitter)
- );
-
- await Task.Delay(delay.Add(jitter), cancellationToken);
-
- return ErrorHandlingResult.Retry();
- }
- }
-}
diff --git a/ChatBot/Services/ExponentialBackoffRetryPolicy.cs b/ChatBot/Services/ExponentialBackoffRetryPolicy.cs
deleted file mode 100644
index 7936a47..0000000
--- a/ChatBot/Services/ExponentialBackoffRetryPolicy.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-using ChatBot.Common.Constants;
-using ChatBot.Models.Configuration;
-using ChatBot.Services.Interfaces;
-using Microsoft.Extensions.Options;
-
-namespace ChatBot.Services
-{
- ///
- /// Retry policy with exponential backoff and jitter
- ///
- public class ExponentialBackoffRetryPolicy : IRetryPolicy
- {
- private readonly int _maxRetries;
- private readonly ILogger _logger;
- private readonly IEnumerable _errorHandlers;
-
- public ExponentialBackoffRetryPolicy(
- IOptions settings,
- ILogger logger,
- IEnumerable errorHandlers
- )
- {
- _maxRetries = settings.Value.MaxRetries;
- _logger = logger;
- _errorHandlers = errorHandlers;
- }
-
- public async Task ExecuteAsync(
- Func> action,
- CancellationToken cancellationToken = default
- )
- {
- Exception? lastException = null;
-
- for (int attempt = 1; attempt <= _maxRetries; attempt++)
- {
- try
- {
- return await action();
- }
- catch (Exception ex) when (attempt < _maxRetries)
- {
- lastException = ex;
- LogAttemptFailure(ex, attempt);
-
- if (!await HandleErrorAndDecideRetry(ex, attempt, cancellationToken))
- break;
- }
- catch (Exception ex)
- {
- lastException = ex;
- _logger.LogError(ex, "All {MaxRetries} attempts failed", _maxRetries);
- }
- }
-
- throw new InvalidOperationException(
- $"Failed after {_maxRetries} attempts",
- lastException
- );
- }
-
- private void LogAttemptFailure(Exception ex, int attempt)
- {
- _logger.LogWarning(ex, "Attempt {Attempt}/{MaxRetries} failed", attempt, _maxRetries);
- }
-
- private async Task HandleErrorAndDecideRetry(
- Exception ex,
- int attempt,
- CancellationToken cancellationToken
- )
- {
- var handler = _errorHandlers.FirstOrDefault(h => h.CanHandle(ex));
- if (handler == null)
- {
- await DelayWithBackoff(attempt, cancellationToken);
- return true;
- }
-
- var result = await handler.HandleAsync(ex, attempt, string.Empty, cancellationToken);
-
- if (result.IsFatal)
- {
- _logger.LogError("Fatal error occurred: {ErrorMessage}", result.ErrorMessage);
- return false;
- }
-
- return result.ShouldRetry;
- }
-
- private async Task DelayWithBackoff(int attempt, CancellationToken cancellationToken)
- {
- var baseDelay = TimeSpan.FromSeconds(
- Math.Pow(2, attempt - 1) * RetryConstants.DefaultBaseDelaySeconds
- );
- var jitter = TimeSpan.FromMilliseconds(
- Random.Shared.Next(0, RetryConstants.DefaultMaxJitterMs)
- );
- var delay = baseDelay.Add(jitter);
-
- _logger.LogInformation(
- "Waiting {Delay} before retry {NextAttempt}/{MaxRetries}",
- delay,
- attempt + 1,
- _maxRetries
- );
-
- await Task.Delay(delay, cancellationToken);
- }
- }
-}
diff --git a/ChatBot/Services/InMemorySessionStorage.cs b/ChatBot/Services/InMemorySessionStorage.cs
index f5799a8..77a1ee4 100644
--- a/ChatBot/Services/InMemorySessionStorage.cs
+++ b/ChatBot/Services/InMemorySessionStorage.cs
@@ -1,6 +1,6 @@
+using System.Collections.Concurrent;
using ChatBot.Models;
using ChatBot.Services.Interfaces;
-using System.Collections.Concurrent;
namespace ChatBot.Services
{
diff --git a/ChatBot/Services/Interfaces/IErrorHandler.cs b/ChatBot/Services/Interfaces/IErrorHandler.cs
deleted file mode 100644
index 910c5c5..0000000
--- a/ChatBot/Services/Interfaces/IErrorHandler.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-namespace ChatBot.Services.Interfaces
-{
- ///
- /// Interface for error handling strategy
- ///
- public interface IErrorHandler
- {
- ///
- /// Check if this handler can handle the exception
- ///
- bool CanHandle(Exception exception);
-
- ///
- /// Handle the exception and return result
- ///
- Task HandleAsync(
- Exception exception,
- int attempt,
- string currentModel,
- CancellationToken cancellationToken = default
- );
- }
-
- ///
- /// Result of error handling
- ///
- public class ErrorHandlingResult
- {
- public bool ShouldRetry { get; set; }
- public string? NewModel { get; set; }
- public bool IsFatal { get; set; }
- public string? ErrorMessage { get; set; }
-
- public static ErrorHandlingResult Retry(string? newModel = null) =>
- new() { ShouldRetry = true, NewModel = newModel };
-
- public static ErrorHandlingResult Fatal(string errorMessage) =>
- new() { IsFatal = true, ErrorMessage = errorMessage };
-
- public static ErrorHandlingResult NoRetry() => new() { ShouldRetry = false };
- }
-}
diff --git a/ChatBot/Services/Interfaces/IRetryPolicy.cs b/ChatBot/Services/Interfaces/IRetryPolicy.cs
deleted file mode 100644
index abb557a..0000000
--- a/ChatBot/Services/Interfaces/IRetryPolicy.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace ChatBot.Services.Interfaces
-{
- ///
- /// Interface for retry policy
- ///
- public interface IRetryPolicy
- {
- ///
- /// Execute an action with retry logic
- ///
- Task ExecuteAsync(
- Func> action,
- CancellationToken cancellationToken = default
- );
- }
-}
diff --git a/ChatBot/Services/Telegram/Services/TelegramBotService.cs b/ChatBot/Services/Telegram/Services/TelegramBotService.cs
index fcda393..e522d35 100644
--- a/ChatBot/Services/Telegram/Services/TelegramBotService.cs
+++ b/ChatBot/Services/Telegram/Services/TelegramBotService.cs
@@ -15,24 +15,20 @@ namespace ChatBot.Services.Telegram.Services
{
private readonly ILogger _logger;
private readonly ITelegramBotClient _botClient;
- private readonly TelegramBotSettings _telegramBotSettings;
private readonly ITelegramMessageHandler _messageHandler;
private readonly ITelegramErrorHandler _errorHandler;
public TelegramBotService(
ILogger logger,
- IOptions telegramBotSettings,
+ ITelegramBotClient botClient,
ITelegramMessageHandler messageHandler,
ITelegramErrorHandler errorHandler
)
{
_logger = logger;
- _telegramBotSettings = telegramBotSettings.Value;
+ _botClient = botClient;
_messageHandler = messageHandler;
_errorHandler = errorHandler;
-
- ValidateConfiguration();
- _botClient = new TelegramBotClient(_telegramBotSettings.BotToken);
}
///
@@ -98,15 +94,5 @@ namespace ChatBot.Services.Telegram.Services
await Task.Delay(1000, stoppingToken);
}
}
-
- private void ValidateConfiguration()
- {
- if (string.IsNullOrEmpty(_telegramBotSettings.BotToken))
- {
- throw new InvalidOperationException(
- "Bot token is not configured. Please set TelegramBot:BotToken in appsettings.json"
- );
- }
- }
}
}
diff --git a/README.md b/README.md
index fb01b6d..e69de29 100644
--- a/README.md
+++ b/README.md
@@ -1,248 +0,0 @@
-# Telegram ChatBot with Ollama AI
-
-A high-quality, production-ready Telegram chatbot powered by Ollama AI models. This bot provides natural conversation experiences using local AI models.
-
-## 🎯 Features
-
-- **Ollama Integration**: Uses OllamaSharp library for efficient AI model communication
-- **Multiple Model Support**: Automatically manages and switches between multiple AI models
-- **Session Management**: Maintains conversation history for each chat
-- **Command System**: Extensible command architecture for bot commands
-- **Smart Retry Logic**: Exponential backoff with jitter for failed requests
-- **Rate Limit Handling**: Automatic model switching on rate limits
-- **Natural Conversation**: Configurable response delays for human-like interactions
-- **Group Chat Support**: Works in both private and group conversations
-- **Robust Logging**: Comprehensive logging with Serilog
-
-## 📋 Prerequisites
-
-- .NET 9.0 or later
-- Ollama server running locally or remotely
-- Telegram Bot Token (from [@BotFather](https://t.me/botfather))
-
-## 🚀 Getting Started
-
-### 1. Install Ollama
-
-Download and install Ollama from [ollama.ai](https://ollama.ai)
-
-### 2. Pull an AI Model
-
-```bash
-ollama pull llama3
-```
-
-### 3. Configure the Bot
-
-Edit `appsettings.json`:
-
-```json
-{
- "TelegramBot": {
- "BotToken": "YOUR_BOT_TOKEN_HERE"
- },
- "Ollama": {
- "Url": "http://localhost:11434",
- "MaxRetries": 3,
- "MaxTokens": 1000,
- "Temperature": 0.7,
- "ResponseDelay": {
- "IsEnabled": true,
- "MinDelayMs": 1000,
- "MaxDelayMs": 3000
- },
- "SystemPromptFilePath": "system-prompt.txt"
- }
-}
-```
-
-Edit `appsettings.Models.json` to configure your models:
-
-```json
-{
- "ModelConfigurations": [
- {
- "Name": "llama3",
- "MaxTokens": 2000,
- "Temperature": 0.8,
- "Description": "Llama 3 Model",
- "IsEnabled": true
- }
- ]
-}
-```
-
-### 4. Customize System Prompt
-
-Edit `system-prompt.txt` to define your bot's personality and behavior.
-
-### 5. Run the Bot
-
-```bash
-cd ChatBot
-dotnet run
-```
-
-## 🏗️ Architecture
-
-### Core Services
-
-- **AIService**: Handles AI model communication and text generation
-- **ChatService**: Manages chat sessions and message history
-- **ModelService**: Handles model selection and switching
-- **TelegramBotService**: Main Telegram bot service
-
-### Command System
-
-Commands are automatically registered using attributes:
-
-```csharp
-[Command("start", "Start conversation with the bot")]
-public class StartCommand : TelegramCommandBase
-{
- // Implementation
-}
-```
-
-Available commands:
-- `/start` - Start conversation
-- `/help` - Show help information
-- `/clear` - Clear conversation history
-- `/settings` - View current settings
-
-## ⚙️ Configuration
-
-### Ollama Settings
-
-- **Url**: Ollama server URL
-- **MaxRetries**: Maximum retry attempts for failed requests
-- **MaxTokens**: Default maximum tokens for responses
-- **Temperature**: AI creativity level (0.0 - 2.0)
-- **ResponseDelay**: Add human-like delays before responses
-- **SystemPromptFilePath**: Path to system prompt file
-
-### Model Configuration
-
-Each model can have custom settings:
-
-- **Name**: Model name (must match Ollama model name)
-- **MaxTokens**: Maximum tokens for this model
-- **Temperature**: Temperature for this model
-- **Description**: Human-readable description
-- **IsEnabled**: Whether the model is available for use
-
-## 🔧 Advanced Features
-
-### Automatic Model Switching
-
-The bot automatically switches to alternative models when:
-- Rate limits are encountered
-- Current model becomes unavailable
-
-### Session Management
-
-- Automatic session creation per chat
-- Configurable message history length
-- Old session cleanup (default: 24 hours)
-
-### Error Handling
-
-- Exponential backoff with jitter for retries
-- Graceful degradation on failures
-- Comprehensive error logging
-
-## 📝 Development
-
-### Project Structure
-
-```
-ChatBot/
-├── Models/
-│ ├── Configuration/ # Configuration models
-│ │ └── Validators/ # Configuration validation
-│ └── Dto/ # Data transfer objects
-├── Services/
-│ ├── Telegram/ # Telegram-specific services
-│ │ ├── Commands/ # Bot commands
-│ │ ├── Interfaces/ # Service interfaces
-│ │ └── Services/ # Service implementations
-│ ├── AIService.cs # AI model communication
-│ ├── ChatService.cs # Chat session management
-│ └── ModelService.cs # Model management
-└── Program.cs # Application entry point
-```
-
-### Adding New Commands
-
-1. Create a new class in `Services/Telegram/Commands/`
-2. Inherit from `TelegramCommandBase`
-3. Add `[Command]` attribute
-4. Implement `ExecuteAsync` method
-
-Example:
-
-```csharp
-[Command("mycommand", "Description of my command")]
-public class MyCommand : TelegramCommandBase
-{
- public override async Task ExecuteAsync(TelegramCommandContext context)
- {
- await context.MessageSender.SendTextMessageAsync(
- context.Message.Chat.Id,
- "Command executed!"
- );
- }
-}
-```
-
-## 🐛 Troubleshooting
-
-### Bot doesn't respond
-
-1. Check if Ollama server is running: `ollama list`
-2. Verify bot token in `appsettings.json`
-3. Check logs in `logs/` directory
-
-### Model not found
-
-1. Pull the model: `ollama pull model-name`
-2. Verify model name matches in `appsettings.Models.json`
-3. Check model availability: `ollama list`
-
-### Connection errors
-
-1. Verify Ollama URL in configuration
-2. Check firewall settings
-3. Ensure Ollama server is accessible
-
-## 📦 Dependencies
-
-- **OllamaSharp** (v5.4.7): Ollama API client
-- **Telegram.Bot** (v22.7.2): Telegram Bot API
-- **Serilog** (v4.3.0): Structured logging
-- **Microsoft.Extensions.Hosting** (v9.0.10): Host infrastructure
-
-## 📄 License
-
-This project is licensed under the terms specified in [LICENSE.txt](LICENSE.txt).
-
-## 🤝 Contributing
-
-Contributions are welcome! Please ensure:
-- Code follows existing patterns
-- All tests pass
-- Documentation is updated
-- Commits are descriptive
-
-## 🔮 Future Enhancements
-
-- [ ] Multi-language support
-- [ ] Voice message handling
-- [ ] Image generation support
-- [ ] User preferences persistence
-- [ ] Advanced conversation analytics
-- [ ] Custom model fine-tuning support
-
----
-
-Built with ❤️ using .NET 9.0 and Ollama
diff --git a/REFACTORING_SUMMARY.md b/REFACTORING_SUMMARY.md
deleted file mode 100644
index 2c0b3b4..0000000
--- a/REFACTORING_SUMMARY.md
+++ /dev/null
@@ -1,449 +0,0 @@
-# Рефакторинг проекта ChatBot - Итоги
-
-## 📋 Выполненные улучшения
-
-Все рекомендации по улучшению проекта были реализованы, за исключением unit-тестов (как было запрошено).
-
----
-
-## ✅ Реализованные изменения
-
-### 1. **Константы для магических строк и значений**
-
-Созданы классы констант для улучшения читаемости и поддерживаемости:
-
-- `ChatBot/Common/Constants/AIResponseConstants.cs` - константы для AI ответов
-- `ChatBot/Common/Constants/ChatRoles.cs` - роли сообщений (system, user, assistant)
-- `ChatBot/Common/Constants/ChatTypes.cs` - типы чатов
-- `ChatBot/Common/Constants/RetryConstants.cs` - константы для retry логики
-
-**Преимущества:**
-- Нет магических строк в коде
-- Легко изменить значения в одном месте
-- IntelliSense помогает при разработке
-
----
-
-### 2. **Result Pattern**
-
-Создан класс `Result` для явного представления успеха/неудачи операций:
-
-**Файл:** `ChatBot/Common/Results/Result.cs`
-
-```csharp
-var result = Result.Success("данные");
-var failure = Result.Failure("ошибка");
-```
-
-**Преимущества:**
-- Явная обработка ошибок без exceptions
-- Более функциональный подход
-- Лучшая читаемость кода
-
----
-
-### 3. **SOLID Principles - Интерфейсы для всех сервисов**
-
-#### **Dependency Inversion Principle (DIP)**
-
-Созданы интерфейсы для всех основных сервисов:
-
-- `IAIService` - интерфейс для AI сервиса
-- `ISessionStorage` - интерфейс для хранения сессий
-- `IOllamaClient` - интерфейс для Ollama клиента
-- `ISystemPromptProvider` - интерфейс для загрузки системного промпта
-- `IRetryPolicy` - интерфейс для retry логики
-- `IResponseDelayService` - интерфейс для задержек
-- `IErrorHandler` - интерфейс для обработки ошибок
-
-**Преимущества:**
-- Слабая связанность компонентов
-- Легко тестировать с моками
-- Можно менять реализацию без изменения зависимых классов
-
----
-
-### 4. **Single Responsibility Principle (SRP)**
-
-#### **Разделение ответственностей в AIService**
-
-**До:** AIService делал все - генерацию, retry, задержки, переключение моделей
-
-**После:** Каждый класс отвечает за одну вещь:
-
-- `AIService` - только генерация текста
-- `ExponentialBackoffRetryPolicy` - retry логика
-- `RandomResponseDelayService` - задержки ответов
-- `RateLimitErrorHandler` / `NetworkErrorHandler` - обработка ошибок
-- `ModelService` - управление моделями
-
-#### **Удаление статического метода из ChatSession**
-
-**До:** `ChatSession.LoadSystemPrompt()` - нарушал SRP
-
-**После:** Создан `FileSystemPromptProvider` - отдельный сервис для загрузки промптов
-
-#### **Новая структура:**
-
-```
-ChatBot/Services/
-├── AIService.cs (упрощен)
-├── FileSystemPromptProvider.cs
-├── InMemorySessionStorage.cs
-├── ExponentialBackoffRetryPolicy.cs
-├── RandomResponseDelayService.cs
-└── ErrorHandlers/
- ├── RateLimitErrorHandler.cs
- └── NetworkErrorHandler.cs
-```
-
----
-
-### 5. **Open/Closed Principle (OCP)**
-
-#### **Strategy Pattern для обработки ошибок**
-
-**До:** Жестко закодированная проверка `if (ex.Message.Contains("429"))`
-
-**После:** Расширяемая система с интерфейсом `IErrorHandler`
-
-```csharp
-public interface IErrorHandler
-{
- bool CanHandle(Exception exception);
- Task HandleAsync(...);
-}
-```
-
-**Реализации:**
-- `RateLimitErrorHandler` - обработка HTTP 429
-- `NetworkErrorHandler` - сетевые ошибки
-
-**Преимущества:**
-- Легко добавить новый обработчик без изменения существующего кода
-- Каждый обработчик независим
-- Цепочка ответственности (Chain of Responsibility)
-
----
-
-### 6. **Устранение анти-паттернов**
-
-#### **6.1. Service Locator в CommandRegistry (КРИТИЧНО)**
-
-**До:**
-```csharp
-// Service Locator - анти-паттерн
-var service = serviceProvider.GetService(parameterType);
-var command = Activator.CreateInstance(commandType, args);
-```
-
-**После:**
-```csharp
-// Proper Dependency Injection
-public CommandRegistry(IEnumerable commands)
-{
- foreach (var command in commands)
- RegisterCommand(command);
-}
-```
-
-В `Program.cs`:
-```csharp
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-```
-
-#### **6.2. Threading Issue в BotInfoService (КРИТИЧНО)**
-
-**До:**
-```csharp
-lock (_lock) // lock с async - deadlock!
-{
- var task = _botClient.GetMe();
- task.Wait(); // блокировка потока
-}
-```
-
-**После:**
-```csharp
-private readonly SemaphoreSlim _semaphore = new(1, 1);
-
-await _semaphore.WaitAsync(cancellationToken);
-try
-{
- _cachedBotInfo = await _botClient.GetMe(...);
-}
-finally
-{
- _semaphore.Release();
-}
-```
-
-**Преимущества:**
-- Нет риска deadlock
-- Асинхронный код работает правильно
-- Поддержка CancellationToken
-
----
-
-### 7. **FluentValidation**
-
-Добавлены валидаторы для моделей данных:
-
-**Файлы:**
-- `ChatBot/Models/Validation/ChatMessageValidator.cs`
-- `ChatBot/Models/Configuration/Validators/OllamaSettingsValidator.cs`
-- `ChatBot/Models/Configuration/Validators/TelegramBotSettingsValidator.cs`
-
-**Пример:**
-```csharp
-public class ChatMessageValidator : AbstractValidator
-{
- public ChatMessageValidator()
- {
- RuleFor(x => x.Content)
- .NotEmpty()
- .MaximumLength(10000);
-
- RuleFor(x => x.Role)
- .Must(role => new[] { "system", "user", "assistant" }.Contains(role));
- }
-}
-```
-
----
-
-### 8. **Options Pattern Validation**
-
-Валидация конфигурации при старте приложения:
-
-```csharp
-builder.Services
- .Configure(...)
- .AddSingleton, OllamaSettingsValidator>()
- .ValidateOnStart();
-```
-
-**Преимущества:**
-- Приложение не стартует с невалидной конфигурацией
-- Ошибки конфигурации обнаруживаются сразу
-- Детальные сообщения об ошибках
-
----
-
-### 9. **Health Checks**
-
-Добавлены проверки работоспособности внешних зависимостей:
-
-**Файлы:**
-- `ChatBot/Services/HealthChecks/OllamaHealthCheck.cs` - проверка Ollama API
-- `ChatBot/Services/HealthChecks/TelegramBotHealthCheck.cs` - проверка Telegram Bot API
-
-**Регистрация:**
-```csharp
-builder.Services
- .AddHealthChecks()
- .AddCheck("ollama", tags: new[] { "api", "ollama" })
- .AddCheck("telegram", tags: new[] { "api", "telegram" });
-```
-
-**Преимущества:**
-- Мониторинг состояния сервисов
-- Быстрое обнаружение проблем
-- Интеграция с системами мониторинга
-
----
-
-### 10. **CancellationToken Support**
-
-Добавлена поддержка отмены операций во всех асинхронных методах:
-
-```csharp
-public async Task GenerateChatCompletionAsync(
- List messages,
- int? maxTokens = null,
- double? temperature = null,
- CancellationToken cancellationToken = default) // ✓
-```
-
-**Преимущества:**
-- Graceful shutdown приложения
-- Отмена долгих операций
-- Экономия ресурсов
-
----
-
-### 11. **Новые пакеты**
-
-Добавлены в `ChatBot.csproj`:
-
-```xml
-
-
-
-```
-
----
-
-## 📊 Сравнение "До" и "После"
-
-### **AIService**
-
-**До:** 237 строк, 8 ответственностей
-**После:** 104 строки, 1 ответственность (генерация текста)
-
-### **ChatService**
-
-**До:** Зависит от конкретных реализаций
-**После:** Зависит только от интерфейсов
-
-### **Program.cs**
-
-**До:** 101 строка, Service Locator
-**После:** 149 строк, Proper DI с валидацией и Health Checks
-
----
-
-## 🎯 Соблюдение SOLID Principles
-
-### ✅ **S - Single Responsibility Principle**
-- Каждый класс имеет одну ответственность
-- AIService упрощен с 237 до 104 строк
-- Логика вынесена в специализированные сервисы
-
-### ✅ **O - Open/Closed Principle**
-- Strategy Pattern для обработки ошибок
-- Легко добавить новый ErrorHandler без изменения существующего кода
-
-### ✅ **L - Liskov Substitution Principle**
-- Все реализации интерфейсов взаимозаменяемы
-- Mock-объекты для тестирования
-
-### ✅ **I - Interface Segregation Principle**
-- Интерфейсы специфичны и минимальны
-- Никто не зависит от методов, которые не использует
-
-### ✅ **D - Dependency Inversion Principle**
-- Все зависимости через интерфейсы
-- Высокоуровневые модули не зависят от низкоуровневых
-
----
-
-## 🏗️ Паттерны проектирования
-
-1. **Dependency Injection** - через Microsoft.Extensions.DependencyInjection
-2. **Strategy Pattern** - IErrorHandler для разных типов ошибок
-3. **Adapter Pattern** - OllamaClientAdapter оборачивает OllamaApiClient
-4. **Provider Pattern** - ISystemPromptProvider для загрузки промптов
-5. **Repository Pattern** - ISessionStorage для хранения сессий
-6. **Command Pattern** - ITelegramCommand для команд бота
-7. **Chain of Responsibility** - ErrorHandlingChain для обработки ошибок
-
----
-
-## 📝 Структура проекта после рефакторинга
-
-```
-ChatBot/
-├── Common/
-│ ├── Constants/
-│ │ ├── AIResponseConstants.cs
-│ │ ├── ChatRoles.cs
-│ │ ├── ChatTypes.cs
-│ │ └── RetryConstants.cs
-│ └── Results/
-│ └── Result.cs
-├── Models/
-│ ├── Configuration/
-│ │ └── Validators/
-│ │ ├── OllamaSettingsValidator.cs
-│ │ └── TelegramBotSettingsValidator.cs
-│ └── Validation/
-│ └── ChatMessageValidator.cs
-├── Services/
-│ ├── Interfaces/
-│ │ ├── IAIService.cs
-│ │ ├── IErrorHandler.cs
-│ │ ├── IOllamaClient.cs
-│ │ ├── IResponseDelayService.cs
-│ │ ├── IRetryPolicy.cs
-│ │ ├── ISessionStorage.cs
-│ │ └── ISystemPromptProvider.cs
-│ ├── ErrorHandlers/
-│ │ ├── RateLimitErrorHandler.cs
-│ │ └── NetworkErrorHandler.cs
-│ ├── HealthChecks/
-│ │ ├── OllamaHealthCheck.cs
-│ │ └── TelegramBotHealthCheck.cs
-│ ├── AIService.cs (refactored)
-│ ├── ChatService.cs (refactored)
-│ ├── ExponentialBackoffRetryPolicy.cs
-│ ├── FileSystemPromptProvider.cs
-│ ├── InMemorySessionStorage.cs
-│ ├── OllamaClientAdapter.cs
-│ └── RandomResponseDelayService.cs
-└── Program.cs (updated)
-```
-
----
-
-## 🚀 Преимущества после рефакторинга
-
-### Для разработки:
-- ✅ Код легче читать и понимать
-- ✅ Легко добавлять новые функции
-- ✅ Проще писать unit-тесты
-- ✅ Меньше дублирования кода
-
-### Для поддержки:
-- ✅ Проще находить и исправлять баги
-- ✅ Изменения не влияют на другие части системы
-- ✅ Логи более структурированы
-
-### Для производительности:
-- ✅ Нет риска deadlock'ов
-- ✅ Правильная работа с async/await
-- ✅ Поддержка отмены операций
-
-### Для надежности:
-- ✅ Валидация конфигурации при старте
-- ✅ Health checks для мониторинга
-- ✅ Правильная обработка ошибок
-
----
-
-## 🔧 Что дальше?
-
-### Рекомендации для дальнейшего развития:
-
-1. **Unit-тесты** - покрыть тестами новые сервисы
-2. **Integration тесты** - тестирование с реальными зависимостями
-3. **Метрики** - добавить Prometheus metrics
-4. **Distributed Tracing** - добавить OpenTelemetry
-5. **Circuit Breaker** - для защиты от каскадных ошибок
-6. **Rate Limiting** - ограничение запросов к AI
-7. **Caching** - кэширование ответов AI
-8. **Background Jobs** - для cleanup старых сессий
-
----
-
-## ✨ Итоги
-
-Проект был полностью отрефакторен согласно принципам SOLID и best practices .NET:
-
-- ✅ 14 задач выполнено
-- ✅ 0 критичных проблем
-- ✅ Код компилируется без ошибок
-- ✅ Следует принципам SOLID
-- ✅ Использует современные паттерны
-- ✅ Готов к масштабированию и тестированию
-
-**Время выполнения:** ~40 минут
-**Файлов создано:** 23
-**Файлов изменено:** 8
-**Строк кода:** +1500 / -300
-
-🎉 **Проект готов к production использованию!**
-