fixes
This commit is contained in:
@@ -7,6 +7,9 @@ namespace ChatBot.Models
|
||||
/// </summary>
|
||||
public class ChatSession
|
||||
{
|
||||
private readonly object _lock = new object();
|
||||
private readonly List<ChatMessage> _messageHistory = new List<ChatMessage>();
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifier for the chat session
|
||||
/// </summary>
|
||||
@@ -27,11 +30,6 @@ namespace ChatBot.Models
|
||||
/// </summary>
|
||||
public string ChatTitle { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// History of messages in this chat session
|
||||
/// </summary>
|
||||
public List<ChatMessage> MessageHistory { get; set; } = new List<ChatMessage>();
|
||||
|
||||
/// <summary>
|
||||
/// AI model to use for this session
|
||||
/// </summary>
|
||||
@@ -53,29 +51,32 @@ namespace ChatBot.Models
|
||||
public int MaxHistoryLength { get; set; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// Add a message to the history and manage history length
|
||||
/// Add a message to the history and manage history length (thread-safe)
|
||||
/// </summary>
|
||||
public void AddMessage(ChatMessage message)
|
||||
{
|
||||
MessageHistory.Add(message);
|
||||
LastUpdatedAt = DateTime.UtcNow;
|
||||
|
||||
// Trim history if it exceeds max length
|
||||
if (MessageHistory.Count > MaxHistoryLength)
|
||||
lock (_lock)
|
||||
{
|
||||
// Keep system message if it exists, then keep the most recent messages
|
||||
var systemMessage = MessageHistory.FirstOrDefault(m => m.Role == "system");
|
||||
var recentMessages = MessageHistory
|
||||
.Where(m => m.Role != "system")
|
||||
.TakeLast(MaxHistoryLength - (systemMessage != null ? 1 : 0))
|
||||
.ToList();
|
||||
_messageHistory.Add(message);
|
||||
LastUpdatedAt = DateTime.UtcNow;
|
||||
|
||||
MessageHistory.Clear();
|
||||
if (systemMessage != null)
|
||||
// Trim history if it exceeds max length
|
||||
if (_messageHistory.Count > MaxHistoryLength)
|
||||
{
|
||||
MessageHistory.Add(systemMessage);
|
||||
// Keep system message if it exists, then keep the most recent messages
|
||||
var systemMessage = _messageHistory.FirstOrDefault(m => m.Role == "system");
|
||||
var recentMessages = _messageHistory
|
||||
.Where(m => m.Role != "system")
|
||||
.TakeLast(MaxHistoryLength - (systemMessage != null ? 1 : 0))
|
||||
.ToList();
|
||||
|
||||
_messageHistory.Clear();
|
||||
if (systemMessage != null)
|
||||
{
|
||||
_messageHistory.Add(systemMessage);
|
||||
}
|
||||
_messageHistory.AddRange(recentMessages);
|
||||
}
|
||||
MessageHistory.AddRange(recentMessages);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,20 +103,37 @@ namespace ChatBot.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all messages
|
||||
/// Get all messages (thread-safe)
|
||||
/// </summary>
|
||||
public List<ChatMessage> GetAllMessages()
|
||||
{
|
||||
return new List<ChatMessage>(MessageHistory);
|
||||
lock (_lock)
|
||||
{
|
||||
return new List<ChatMessage>(_messageHistory);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear message history
|
||||
/// Get the count of messages in history (thread-safe)
|
||||
/// </summary>
|
||||
public int GetMessageCount()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _messageHistory.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear message history (thread-safe)
|
||||
/// </summary>
|
||||
public void ClearHistory()
|
||||
{
|
||||
MessageHistory.Clear();
|
||||
LastUpdatedAt = DateTime.UtcNow;
|
||||
lock (_lock)
|
||||
{
|
||||
_messageHistory.Clear();
|
||||
LastUpdatedAt = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,5 @@ namespace ChatBot.Models.Configuration
|
||||
/// Название модели по умолчанию
|
||||
/// </summary>
|
||||
public string DefaultModel { get; set; } = "llama3";
|
||||
|
||||
/// <summary>
|
||||
/// Максимальное количество повторных попыток при ошибках
|
||||
/// </summary>
|
||||
public int MaxRetries { get; set; } = 3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace ChatBot.Models.Configuration.Validators
|
||||
var errors = new List<string>();
|
||||
|
||||
ValidateUrl(options, errors);
|
||||
ValidateRetryAndTokenSettings(options, errors);
|
||||
ValidateDefaultModel(options, errors);
|
||||
|
||||
return errors.Count > 0
|
||||
@@ -28,18 +27,6 @@ namespace ChatBot.Models.Configuration.Validators
|
||||
errors.Add($"Invalid Ollama URL format: {options.Url}");
|
||||
}
|
||||
|
||||
private static void ValidateRetryAndTokenSettings(
|
||||
OllamaSettings options,
|
||||
List<string> errors
|
||||
)
|
||||
{
|
||||
if (options.MaxRetries < 1)
|
||||
errors.Add($"MaxRetries must be at least 1, got: {options.MaxRetries}");
|
||||
|
||||
if (options.MaxRetries > 10)
|
||||
errors.Add($"MaxRetries should not exceed 10, got: {options.MaxRetries}");
|
||||
}
|
||||
|
||||
private static void ValidateDefaultModel(OllamaSettings options, List<string> errors)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(options.DefaultModel))
|
||||
|
||||
@@ -68,8 +68,13 @@ try
|
||||
builder.Services.AddSingleton<BotInfoService>();
|
||||
builder.Services.AddSingleton<ITelegramCommandProcessor, TelegramCommandProcessor>();
|
||||
builder.Services.AddSingleton<ITelegramMessageHandler, TelegramMessageHandler>();
|
||||
builder.Services.AddSingleton<ITelegramBotService, TelegramBotService>();
|
||||
builder.Services.AddHostedService<TelegramBotService>();
|
||||
|
||||
// Регистрируем TelegramBotService как singleton и используем один экземпляр для интерфейса и HostedService
|
||||
builder.Services.AddSingleton<TelegramBotService>();
|
||||
builder.Services.AddSingleton<ITelegramBotService>(sp =>
|
||||
sp.GetRequiredService<TelegramBotService>()
|
||||
);
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<TelegramBotService>());
|
||||
|
||||
// Регистрируем Health Checks
|
||||
builder
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace ChatBot.Services.Telegram.Commands
|
||||
+ $"Тип чата: {session.ChatType}\n"
|
||||
+ $"Название: {session.ChatTitle}\n"
|
||||
+ $"Модель: {session.Model}\n"
|
||||
+ $"Сообщений в истории: {session.MessageHistory.Count}\n"
|
||||
+ $"Сообщений в истории: {session.GetMessageCount()}\n"
|
||||
+ $"Создана: {session.CreatedAt:dd.MM.yyyy HH:mm}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Telegram.Bot.Types;
|
||||
namespace ChatBot.Services.Telegram.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Сервис для получения информации о боте
|
||||
/// Сервис для получения информации о боте с улучшенным кэшированием
|
||||
/// </summary>
|
||||
public class BotInfoService
|
||||
{
|
||||
@@ -12,6 +12,8 @@ namespace ChatBot.Services.Telegram.Services
|
||||
private readonly ILogger<BotInfoService> _logger;
|
||||
private readonly SemaphoreSlim _semaphore = new(1, 1);
|
||||
private User? _cachedBotInfo;
|
||||
private DateTime? _cacheExpirationTime;
|
||||
private readonly TimeSpan _cacheLifetime = TimeSpan.FromHours(1);
|
||||
|
||||
public BotInfoService(ITelegramBotClient botClient, ILogger<BotInfoService> logger)
|
||||
{
|
||||
@@ -20,32 +22,60 @@ namespace ChatBot.Services.Telegram.Services
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает информацию о боте (с кешированием)
|
||||
/// Получает информацию о боте (с кэшированием и автоматической инвалидацией)
|
||||
/// </summary>
|
||||
public async Task<User?> GetBotInfoAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_cachedBotInfo != null)
|
||||
// Проверяем, есть ли валидный кэш
|
||||
if (
|
||||
_cachedBotInfo != null
|
||||
&& _cacheExpirationTime.HasValue
|
||||
&& DateTime.UtcNow < _cacheExpirationTime.Value
|
||||
)
|
||||
{
|
||||
return _cachedBotInfo;
|
||||
}
|
||||
|
||||
await _semaphore.WaitAsync(cancellationToken);
|
||||
try
|
||||
{
|
||||
if (_cachedBotInfo != null)
|
||||
// Double-check после получения блокировки
|
||||
if (
|
||||
_cachedBotInfo != null
|
||||
&& _cacheExpirationTime.HasValue
|
||||
&& DateTime.UtcNow < _cacheExpirationTime.Value
|
||||
)
|
||||
{
|
||||
return _cachedBotInfo;
|
||||
}
|
||||
|
||||
_logger.LogDebug("Fetching bot info from Telegram API");
|
||||
_cachedBotInfo = await _botClient.GetMe(cancellationToken: cancellationToken);
|
||||
_cacheExpirationTime = DateTime.UtcNow.Add(_cacheLifetime);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Bot info loaded: @{BotUsername} (ID: {BotId})",
|
||||
"Bot info loaded and cached: @{BotUsername} (ID: {BotId}). Cache expires at {ExpirationTime}",
|
||||
_cachedBotInfo.Username,
|
||||
_cachedBotInfo.Id
|
||||
_cachedBotInfo.Id,
|
||||
_cacheExpirationTime
|
||||
);
|
||||
|
||||
return _cachedBotInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to get bot info");
|
||||
_logger.LogError(ex, "Failed to get bot info from Telegram API");
|
||||
|
||||
// Если есть устаревший кэш, используем его
|
||||
if (_cachedBotInfo != null)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Using stale cached bot info due to API error: @{BotUsername}",
|
||||
_cachedBotInfo.Username
|
||||
);
|
||||
return _cachedBotInfo;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
@@ -53,5 +83,28 @@ namespace ChatBot.Services.Telegram.Services
|
||||
_semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Принудительно инвалидирует кэш информации о боте
|
||||
/// </summary>
|
||||
public void InvalidateCache()
|
||||
{
|
||||
lock (_semaphore)
|
||||
{
|
||||
_cachedBotInfo = null;
|
||||
_cacheExpirationTime = null;
|
||||
_logger.LogInformation("Bot info cache invalidated");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверяет, есть ли валидная информация о боте в кэше
|
||||
/// </summary>
|
||||
public bool IsCacheValid()
|
||||
{
|
||||
return _cachedBotInfo != null
|
||||
&& _cacheExpirationTime.HasValue
|
||||
&& DateTime.UtcNow < _cacheExpirationTime.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
},
|
||||
"Ollama": {
|
||||
"Url": "http://10.10.1.202:11434",
|
||||
"DefaultModel": "llama3",
|
||||
"MaxRetries": 3
|
||||
"DefaultModel": "llama3chat"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user