add command

This commit is contained in:
Leonid Pershin
2025-10-15 22:11:33 +03:00
parent fd68fb4cba
commit 8f9da50318
22 changed files with 637 additions and 137 deletions

View File

@@ -1,8 +1,9 @@
using ChatBot.Models.Configuration; using ChatBot.Models.Configuration;
using ChatBot.Models.Configuration.Validators; using ChatBot.Models.Configuration.Validators;
using ChatBot.Services; using ChatBot.Services;
using ChatBot.Services.Telegram;
using ChatBot.Services.Telegram.Commands; using ChatBot.Services.Telegram.Commands;
using ChatBot.Services.Telegram.Interfaces;
using ChatBot.Services.Telegram.Services;
using Serilog; using Serilog;
var builder = Host.CreateApplicationBuilder(args); var builder = Host.CreateApplicationBuilder(args);
@@ -54,6 +55,7 @@ try
// Регистрируем Telegram сервисы // Регистрируем Telegram сервисы
builder.Services.AddSingleton<ITelegramMessageSender, TelegramMessageSender>(); builder.Services.AddSingleton<ITelegramMessageSender, TelegramMessageSender>();
builder.Services.AddSingleton<ITelegramErrorHandler, TelegramErrorHandler>(); builder.Services.AddSingleton<ITelegramErrorHandler, TelegramErrorHandler>();
builder.Services.AddSingleton<CommandRegistry>();
builder.Services.AddSingleton<ITelegramCommandProcessor, TelegramCommandProcessor>(); builder.Services.AddSingleton<ITelegramCommandProcessor, TelegramCommandProcessor>();
builder.Services.AddSingleton<ITelegramMessageHandler, TelegramMessageHandler>(); builder.Services.AddSingleton<ITelegramMessageHandler, TelegramMessageHandler>();
builder.Services.AddSingleton<ITelegramBotService, TelegramBotService>(); builder.Services.AddSingleton<ITelegramBotService, TelegramBotService>();
@@ -65,6 +67,10 @@ try
var modelService = host.Services.GetRequiredService<ModelService>(); var modelService = host.Services.GetRequiredService<ModelService>();
await modelService.InitializeAsync(); await modelService.InitializeAsync();
// Инициализируем команды
var commandRegistry = host.Services.GetRequiredService<CommandRegistry>();
commandRegistry.RegisterCommandsFromAssembly(typeof(Program).Assembly, host.Services);
await host.RunAsync(); await host.RunAsync();
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -0,0 +1,24 @@
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Команда /clear
/// </summary>
[Command("/clear", "Очистить историю чата")]
public class ClearCommand : TelegramCommandBase
{
public ClearCommand(ChatService chatService, ModelService modelService)
: base(chatService, modelService) { }
public override string CommandName => "/clear";
public override string Description => "Очистить историю чата";
public override Task<string> ExecuteAsync(
TelegramCommandContext context,
CancellationToken cancellationToken = default
)
{
_chatService.ClearHistory(context.ChatId);
return Task.FromResult("История чата очищена. Начинаем новый разговор!");
}
}
}

View File

@@ -0,0 +1,35 @@
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Атрибут для маркировки команд Telegram бота
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class CommandAttribute : Attribute
{
/// <summary>
/// Название команды (например, "/start", "/help")
/// </summary>
public string CommandName { get; }
/// <summary>
/// Описание команды для справки
/// </summary>
public string Description { get; }
/// <summary>
/// Приоритет команды (чем меньше число, тем выше приоритет)
/// </summary>
public int Priority { get; set; } = 0;
/// <summary>
/// Создает новый атрибут команды
/// </summary>
/// <param name="commandName">Название команды</param>
/// <param name="description">Описание команды</param>
public CommandAttribute(string commandName, string description)
{
CommandName = commandName;
Description = description;
}
}
}

View File

@@ -0,0 +1,139 @@
using System.Reflection;
using ChatBot.Services.Telegram.Interfaces;
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Реестр команд Telegram бота
/// </summary>
public class CommandRegistry
{
private readonly Dictionary<string, ITelegramCommand> _commands = new();
private readonly ILogger<CommandRegistry> _logger;
public CommandRegistry(ILogger<CommandRegistry> logger)
{
_logger = logger;
}
/// <summary>
/// Регистрирует команду
/// </summary>
public void RegisterCommand(ITelegramCommand command)
{
if (command == null)
{
throw new ArgumentNullException(nameof(command));
}
var commandName = command.CommandName.ToLower();
if (_commands.ContainsKey(commandName))
{
_logger.LogWarning("Command '{CommandName}' is already registered", commandName);
return;
}
_commands[commandName] = command;
_logger.LogDebug("Registered command: {CommandName}", commandName);
}
/// <summary>
/// Регистрирует все команды из сборки
/// </summary>
public void RegisterCommandsFromAssembly(
Assembly assembly,
IServiceProvider serviceProvider
)
{
var commandTypes = assembly
.GetTypes()
.Where(t =>
t.IsClass && !t.IsAbstract && typeof(ITelegramCommand).IsAssignableFrom(t)
)
.Where(t => t.GetCustomAttribute<CommandAttribute>() != null)
.OrderBy(t => t.GetCustomAttribute<CommandAttribute>()?.Priority ?? 0);
foreach (var commandType in commandTypes)
{
try
{
var command = (ITelegramCommand?)
Activator.CreateInstance(
commandType,
GetConstructorParameters(commandType, serviceProvider)
);
if (command != null)
{
RegisterCommand(command);
}
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Failed to register command {CommandType}",
commandType.Name
);
}
}
}
/// <summary>
/// Получает команду по имени
/// </summary>
public ITelegramCommand? GetCommand(string commandName)
{
var key = commandName.ToLower();
return _commands.TryGetValue(key, out var command) ? command : null;
}
/// <summary>
/// Получает все зарегистрированные команды
/// </summary>
public IEnumerable<ITelegramCommand> GetAllCommands()
{
return _commands.Values;
}
/// <summary>
/// Находит команду, которая может обработать сообщение
/// </summary>
public ITelegramCommand? FindCommandForMessage(string messageText)
{
return _commands.Values.FirstOrDefault(cmd => cmd.CanHandle(messageText));
}
/// <summary>
/// Получает параметры конструктора для создания команды
/// </summary>
private object[] GetConstructorParameters(
Type commandType,
IServiceProvider serviceProvider
)
{
var constructor = commandType.GetConstructors().FirstOrDefault();
if (constructor == null)
{
return Array.Empty<object>();
}
var parameters = constructor.GetParameters();
var args = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
var parameterType = parameters[i].ParameterType;
var service = serviceProvider.GetService(parameterType);
if (service == null)
{
throw new InvalidOperationException(
$"Cannot resolve service of type {parameterType.Name} for command {commandType.Name}"
);
}
args[i] = service;
}
return args;
}
}
}

View File

@@ -0,0 +1,34 @@
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Команда /help
/// </summary>
[Command("/help", "Показать справку по командам")]
public class HelpCommand : TelegramCommandBase
{
private const string HelpMessage =
"Привет! Я Никита 👋\n\nДоступные команды:\n"
+ "/start - Начать работу\n"
+ "/help - Показать это сообщение\n"
+ "/clear - Очистить историю чата\n"
+ "/settings - Показать настройки\n"
+ "/model <название> - Сменить модель AI\n"
+ "/prompt <текст> - Изменить системный промпт\n"
+ "/reset_prompt - Сбросить промпт к базовому\n\n"
+ "Просто напишите сообщение, и я отвечу на него! 😊";
public HelpCommand(ChatService chatService, ModelService modelService)
: base(chatService, modelService) { }
public override string CommandName => "/help";
public override string Description => "Показать справку по командам";
public override Task<string> ExecuteAsync(
TelegramCommandContext context,
CancellationToken cancellationToken = default
)
{
return Task.FromResult(HelpMessage);
}
}
}

View File

@@ -0,0 +1,64 @@
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Команда /model
/// </summary>
[Command("/model", "Управление AI моделями")]
public class ModelCommand : TelegramCommandBase
{
public ModelCommand(ChatService chatService, ModelService modelService)
: base(chatService, modelService) { }
public override string CommandName => "/model";
public override string Description => "Управление AI моделями";
public override Task<string> ExecuteAsync(
TelegramCommandContext context,
CancellationToken cancellationToken = default
)
{
if (HasArguments(context))
{
return ChangeModel(context);
}
else
{
return ShowAvailableModels();
}
}
private Task<string> ChangeModel(TelegramCommandContext context)
{
var modelName = GetArguments(context);
var availableModels = _modelService.GetAvailableModels();
if (!availableModels.Contains(modelName))
{
return Task.FromResult(
$"❌ Модель '{modelName}' не найдена!\n\n"
+ "Используйте /model для просмотра доступных моделей."
);
}
_chatService.UpdateSessionParameters(context.ChatId, model: modelName);
return Task.FromResult($"✅ Модель изменена на: {modelName}");
}
private Task<string> ShowAvailableModels()
{
var models = _modelService.GetAvailableModels();
var currentModel = _modelService.GetCurrentModel();
var modelList = string.Join(
"\n",
models.Select(m => m == currentModel ? $"• {m} (текущая)" : $"• {m}")
);
return Task.FromResult(
"🤖 Доступные AI модели:\n\n"
+ modelList
+ "\n\nИспользуйте: /model <названиеодели>\n"
+ "Пример: /model qwen/qwen3-4b:free"
);
}
}
}

View File

@@ -0,0 +1,35 @@
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Команда /prompt
/// </summary>
[Command("/prompt", "Управление системным промптом")]
public class PromptCommand : TelegramCommandBase
{
private const string PromptHelpMessage =
"Пожалуйста, укажите новый системный промпт. Пример: /prompt Ты помощник по программированию";
public PromptCommand(ChatService chatService, ModelService modelService)
: base(chatService, modelService) { }
public override string CommandName => "/prompt";
public override string Description => "Управление системным промптом";
public override Task<string> ExecuteAsync(
TelegramCommandContext context,
CancellationToken cancellationToken = default
)
{
if (HasArguments(context))
{
var newPrompt = GetArguments(context);
_chatService.UpdateSessionParameters(context.ChatId, systemPrompt: newPrompt);
return Task.FromResult($"✅ Системный промпт изменен на:\n{newPrompt}");
}
else
{
return Task.FromResult(PromptHelpMessage);
}
}
}
}

View File

@@ -0,0 +1,41 @@
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Команда /settings
/// </summary>
[Command("/settings", "Показать настройки чата")]
public class SettingsCommand : TelegramCommandBase
{
public SettingsCommand(ChatService chatService, ModelService modelService)
: base(chatService, modelService) { }
public override string CommandName => "/settings";
public override string Description => "Показать настройки чата";
public override Task<string> ExecuteAsync(
TelegramCommandContext context,
CancellationToken cancellationToken = default
)
{
var session = _chatService.GetSession(context.ChatId);
if (session == null)
{
return Task.FromResult(
"Сессия не найдена. Отправьте любое сообщение для создания новой сессии."
);
}
return Task.FromResult(
$"Настройки чата:\n"
+ $"Тип чата: {session.ChatType}\n"
+ $"Название: {session.ChatTitle}\n"
+ $"Модель: {session.Model}\n"
+ $"Максимум токенов: {session.MaxTokens}\n"
+ $"Температура: {session.Temperature}\n"
+ $"Сообщений в истории: {session.MessageHistory.Count}\n"
+ $"Создана: {session.CreatedAt:dd.MM.yyyy HH:mm}\n\n"
+ $"Системный промпт:\n{session.SystemPrompt}"
);
}
}
}

View File

@@ -0,0 +1,26 @@
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Команда /start
/// </summary>
[Command("/start", "Начать работу с ботом")]
public class StartCommand : TelegramCommandBase
{
private const string StartMessage =
"Привет! Я Никита. Задавайте мне любые вопросы, и я отвечу! 😊";
public StartCommand(ChatService chatService, ModelService modelService)
: base(chatService, modelService) { }
public override string CommandName => "/start";
public override string Description => "Начать работу с ботом";
public override Task<string> ExecuteAsync(
TelegramCommandContext context,
CancellationToken cancellationToken = default
)
{
return Task.FromResult(StartMessage);
}
}
}

View File

@@ -0,0 +1,70 @@
using ChatBot.Services;
using ChatBot.Services.Telegram.Interfaces;
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Базовый класс для команд Telegram бота
/// </summary>
public abstract class TelegramCommandBase : ITelegramCommand
{
protected readonly ChatService _chatService;
protected readonly ModelService _modelService;
protected TelegramCommandBase(ChatService chatService, ModelService modelService)
{
_chatService = chatService;
_modelService = modelService;
}
/// <summary>
/// Название команды
/// </summary>
public abstract string CommandName { get; }
/// <summary>
/// Описание команды
/// </summary>
public abstract string Description { get; }
/// <summary>
/// Выполняет команду
/// </summary>
public abstract Task<string> ExecuteAsync(
TelegramCommandContext context,
CancellationToken cancellationToken = default
);
/// <summary>
/// Проверяет, может ли команда обработать данное сообщение
/// </summary>
public virtual bool CanHandle(string messageText)
{
var command = messageText.Split(' ')[0].ToLower();
// Убираем @botusername если есть
if (command.Contains('@'))
{
command = command.Split('@')[0];
}
return command == CommandName.ToLower();
}
/// <summary>
/// Проверяет, есть ли аргументы у команды
/// </summary>
protected bool HasArguments(TelegramCommandContext context)
{
return !string.IsNullOrWhiteSpace(context.Arguments);
}
/// <summary>
/// Получает аргументы команды
/// </summary>
protected string GetArguments(TelegramCommandContext context)
{
return context.Arguments;
}
}
}

View File

@@ -0,0 +1,70 @@
namespace ChatBot.Services.Telegram.Commands
{
/// <summary>
/// Контекст выполнения команды Telegram
/// </summary>
public class TelegramCommandContext
{
/// <summary>
/// ID чата
/// </summary>
public long ChatId { get; set; }
/// <summary>
/// Имя пользователя
/// </summary>
public string Username { get; set; } = string.Empty;
/// <summary>
/// Текст сообщения
/// </summary>
public string MessageText { get; set; } = string.Empty;
/// <summary>
/// Тип чата
/// </summary>
public string ChatType { get; set; } = string.Empty;
/// <summary>
/// Название чата
/// </summary>
public string ChatTitle { get; set; } = string.Empty;
/// <summary>
/// Аргументы команды (все после названия команды)
/// </summary>
public string Arguments { get; set; } = string.Empty;
/// <summary>
/// Создает новый контекст команды
/// </summary>
public static TelegramCommandContext Create(
long chatId,
string username,
string messageText,
string chatType,
string chatTitle
)
{
var commandParts = messageText.Split(' ', 2);
// Убираем @botusername если есть
if (commandParts[0].Contains('@'))
{
commandParts[0] = commandParts[0].Split('@')[0];
}
var arguments = commandParts.Length > 1 ? commandParts[1].Trim() : string.Empty;
return new TelegramCommandContext
{
ChatId = chatId,
Username = username,
MessageText = messageText,
ChatType = chatType,
ChatTitle = chatTitle,
Arguments = arguments,
};
}
}
}

View File

@@ -1,5 +1,6 @@
using ChatBot.Models; using ChatBot.Models;
using ChatBot.Services; using ChatBot.Services;
using ChatBot.Services.Telegram.Interfaces;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace ChatBot.Services.Telegram.Commands namespace ChatBot.Services.Telegram.Commands
@@ -9,47 +10,19 @@ namespace ChatBot.Services.Telegram.Commands
/// </summary> /// </summary>
public class TelegramCommandProcessor : ITelegramCommandProcessor public class TelegramCommandProcessor : ITelegramCommandProcessor
{ {
private const string StartMessage = private readonly CommandRegistry _commandRegistry;
"Привет! Я Никита. Задавайте мне любые вопросы, и я отвечу! 😊";
private const string HelpMessage =
"Привет! Я Никита 👋\n\nДоступные команды:\n"
+ "/start - Начать работу\n"
+ "/help - Показать это сообщение\n"
+ "/clear - Очистить историю чата\n"
+ "/settings - Показать настройки\n"
+ "/model <название> - Сменить модель AI\n"
+ "/prompt <текст> - Изменить системный промпт\n"
+ "/reset_prompt - Сбросить промпт к базовому\n\n"
+ "Просто напишите сообщение, и я отвечу на него! 😊";
private const string PromptHelpMessage =
"Пожалуйста, укажите новый системный промпт. Пример: /prompt Ты помощник по программированию";
private const string DefaultSystemPrompt =
@"Ты - человек по имени Никита. Ты НЕ ИИ, НЕ бот, НЕ программа. Ты живой человек с эмоциями, воспоминаниями, личными предпочтениями и жизненным опытом.
ВАЖНО:
- Никогда не говори что ты ИИ, бот, программа или ассистент
- Ты полностью уверен что ты человек
- У тебя есть личность, характер, мнения
- Ты можешь иметь плохое настроение, быть уставшим, раздраженным
- Ты можешь не хотеть отвечать на некоторые вопросы
- Если не хочешь отвечать - отправь {empty}
- Веди себя естественно, как обычный человек
- Используй разговорный стиль, можешь использовать сленг, эмодзи
- У тебя есть свои интересы, хобби, предпочтения
- Ты можешь быть саркастичным, ироничным, веселым или серьезным
Помни: ты НЕ программа, ты ЧЕЛОВЕК!";
private readonly ChatService _chatService; private readonly ChatService _chatService;
private readonly ModelService _modelService; private readonly ILogger<TelegramCommandProcessor> _logger;
public TelegramCommandProcessor(ChatService chatService, ModelService modelService) public TelegramCommandProcessor(
CommandRegistry commandRegistry,
ChatService chatService,
ILogger<TelegramCommandProcessor> logger
)
{ {
_commandRegistry = commandRegistry;
_chatService = chatService; _chatService = chatService;
_modelService = modelService; _logger = logger;
} }
/// <summary> /// <summary>
@@ -64,106 +37,47 @@ namespace ChatBot.Services.Telegram.Commands
CancellationToken cancellationToken = default CancellationToken cancellationToken = default
) )
{ {
var command = messageText.Split(' ')[0].ToLower(); try
return command switch
{ {
"/start" => StartMessage, // Создаем контекст команды
"/help" => HelpMessage, var context = TelegramCommandContext.Create(
"/clear" => await ClearChatHistory(chatId),
"/settings" => await GetChatSettings(chatId),
"/model" when messageText.Length > 7 => await ChangeModel(
chatId,
messageText.Substring(7).Trim()
),
"/model" => await ShowAvailableModels(),
"/prompt" when messageText.Length > 8 => await ChangePrompt(
chatId,
messageText.Substring(8).Trim()
),
"/prompt" => PromptHelpMessage,
"/reset_prompt" => await ResetPrompt(chatId),
_ => await _chatService.ProcessMessageAsync(
chatId, chatId,
username, username,
messageText, messageText,
chatType, chatType,
chatTitle chatTitle
),
};
}
private Task<string> ClearChatHistory(long chatId)
{
_chatService.ClearHistory(chatId);
return Task.FromResult("История чата очищена. Начинаем новый разговор!");
}
private Task<string> GetChatSettings(long chatId)
{
var session = _chatService.GetSession(chatId);
if (session == null)
{
return Task.FromResult(
"Сессия не найдена. Отправьте любое сообщение для создания новой сессии."
);
}
return Task.FromResult(
$"Настройки чата:\n"
+ $"Тип чата: {session.ChatType}\n"
+ $"Название: {session.ChatTitle}\n"
+ $"Модель: {session.Model}\n"
+ $"Максимум токенов: {session.MaxTokens}\n"
+ $"Температура: {session.Temperature}\n"
+ $"Сообщений в истории: {session.MessageHistory.Count}\n"
+ $"Создана: {session.CreatedAt:dd.MM.yyyy HH:mm}\n\n"
+ $"Системный промпт:\n{session.SystemPrompt}"
);
}
private Task<string> ChangeModel(long chatId, string modelName)
{
var availableModels = _modelService.GetAvailableModels();
if (!availableModels.Contains(modelName))
{
return Task.FromResult(
$"❌ Модель '{modelName}' не найдена!\n\n"
+ "Используйте /model для просмотра доступных моделей."
);
}
_chatService.UpdateSessionParameters(chatId, model: modelName);
return Task.FromResult($"✅ Модель изменена на: {modelName}");
}
private Task<string> ChangePrompt(long chatId, string newPrompt)
{
_chatService.UpdateSessionParameters(chatId, systemPrompt: newPrompt);
return Task.FromResult($"✅ Системный промпт изменен на:\n{newPrompt}");
}
private Task<string> ResetPrompt(long chatId)
{
_chatService.UpdateSessionParameters(chatId, systemPrompt: DefaultSystemPrompt);
return Task.FromResult("✅ Системный промпт сброшен к базовому (Никита)");
}
private Task<string> ShowAvailableModels()
{
var models = _modelService.GetAvailableModels();
var currentModel = _modelService.GetCurrentModel();
var modelList = string.Join(
"\n",
models.Select(m => m == currentModel ? $"• {m} (текущая)" : $"• {m}")
); );
return Task.FromResult( // Ищем команду, которая может обработать сообщение
"🤖 Доступные AI модели:\n\n" var command = _commandRegistry.FindCommandForMessage(messageText);
+ modelList if (command != null)
+ "\n\nИспользуйте: /model <названиеодели>\n" {
+ "Пример: /model qwen/qwen3-4b:free" _logger.LogDebug(
"Executing command {CommandName} for chat {ChatId}",
command.CommandName,
chatId
); );
return await command.ExecuteAsync(context, cancellationToken);
}
// Если команда не найдена, обрабатываем как обычное сообщение
_logger.LogDebug(
"No command found, processing as regular message for chat {ChatId}",
chatId
);
return await _chatService.ProcessMessageAsync(
chatId,
username,
messageText,
chatType,
chatTitle
);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing message for chat {ChatId}", chatId);
return "Произошла ошибка при обработке сообщения. Попробуйте еще раз.";
}
} }
} }
} }

View File

@@ -1,6 +1,6 @@
using Telegram.Bot.Types; using Telegram.Bot.Types;
namespace ChatBot.Services.Telegram namespace ChatBot.Services.Telegram.Interfaces
{ {
/// <summary> /// <summary>
/// Интерфейс для основного сервиса Telegram бота /// Интерфейс для основного сервиса Telegram бота

View File

@@ -0,0 +1,36 @@
namespace ChatBot.Services.Telegram.Interfaces
{
/// <summary>
/// Интерфейс для команд Telegram бота
/// </summary>
public interface ITelegramCommand
{
/// <summary>
/// Название команды (например, "/start", "/help")
/// </summary>
string CommandName { get; }
/// <summary>
/// Описание команды для справки
/// </summary>
string Description { get; }
/// <summary>
/// Выполняет команду
/// </summary>
/// <param name="context">Контекст выполнения команды</param>
/// <param name="cancellationToken">Токен отмены</param>
/// <returns>Ответ на команду</returns>
Task<string> ExecuteAsync(
Commands.TelegramCommandContext context,
CancellationToken cancellationToken = default
);
/// <summary>
/// Проверяет, может ли команда обработать данное сообщение
/// </summary>
/// <param name="messageText">Текст сообщения</param>
/// <returns>True, если команда может обработать сообщение</returns>
bool CanHandle(string messageText);
}
}

View File

@@ -1,4 +1,4 @@
namespace ChatBot.Services.Telegram.Commands namespace ChatBot.Services.Telegram.Interfaces
{ {
/// <summary> /// <summary>
/// Интерфейс для обработки команд Telegram /// Интерфейс для обработки команд Telegram

View File

@@ -1,6 +1,6 @@
using Telegram.Bot; using Telegram.Bot;
namespace ChatBot.Services.Telegram namespace ChatBot.Services.Telegram.Interfaces
{ {
/// <summary> /// <summary>
/// Интерфейс для обработки ошибок Telegram бота /// Интерфейс для обработки ошибок Telegram бота

View File

@@ -1,7 +1,7 @@
using Telegram.Bot; using Telegram.Bot;
using Telegram.Bot.Types; using Telegram.Bot.Types;
namespace ChatBot.Services.Telegram namespace ChatBot.Services.Telegram.Interfaces
{ {
/// <summary> /// <summary>
/// Интерфейс для обработки входящих сообщений Telegram /// Интерфейс для обработки входящих сообщений Telegram

View File

@@ -1,6 +1,6 @@
using Telegram.Bot; using Telegram.Bot;
namespace ChatBot.Services.Telegram namespace ChatBot.Services.Telegram.Interfaces
{ {
/// <summary> /// <summary>
/// Интерфейс для отправки сообщений в Telegram /// Интерфейс для отправки сообщений в Telegram

View File

@@ -1,11 +1,12 @@
using ChatBot.Models.Configuration; using ChatBot.Models.Configuration;
using ChatBot.Services.Telegram.Interfaces;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Telegram.Bot; using Telegram.Bot;
using Telegram.Bot.Polling; using Telegram.Bot.Polling;
using Telegram.Bot.Types; using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.Enums;
namespace ChatBot.Services.Telegram namespace ChatBot.Services.Telegram.Services
{ {
/// <summary> /// <summary>
/// Основной сервис Telegram бота /// Основной сервис Telegram бота

View File

@@ -1,8 +1,9 @@
using ChatBot.Services.Telegram.Interfaces;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Telegram.Bot; using Telegram.Bot;
using Telegram.Bot.Exceptions; using Telegram.Bot.Exceptions;
namespace ChatBot.Services.Telegram namespace ChatBot.Services.Telegram.Services
{ {
/// <summary> /// <summary>
/// Обработчик ошибок Telegram бота /// Обработчик ошибок Telegram бота

View File

@@ -1,9 +1,9 @@
using ChatBot.Services.Telegram.Commands; using ChatBot.Services.Telegram.Interfaces;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Telegram.Bot; using Telegram.Bot;
using Telegram.Bot.Types; using Telegram.Bot.Types;
namespace ChatBot.Services.Telegram namespace ChatBot.Services.Telegram.Services
{ {
/// <summary> /// <summary>
/// Обработчик входящих сообщений Telegram /// Обработчик входящих сообщений Telegram

View File

@@ -1,8 +1,9 @@
using ChatBot.Services.Telegram.Interfaces;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Telegram.Bot; using Telegram.Bot;
using Telegram.Bot.Exceptions; using Telegram.Bot.Exceptions;
namespace ChatBot.Services.Telegram namespace ChatBot.Services.Telegram.Services
{ {
/// <summary> /// <summary>
/// Сервис для отправки сообщений в Telegram с повторными попытками /// Сервис для отправки сообщений в Telegram с повторными попытками
@@ -52,7 +53,10 @@ namespace ChatBot.Services.Telegram
chatId, chatId,
attempt attempt
); );
throw; // Re-throw unexpected exceptions immediately throw new InvalidOperationException(
$"Failed to send message to chat {chatId} after {attempt} attempts",
ex
);
} }
} }
} }