fix ai
This commit is contained in:
@@ -18,4 +18,12 @@
|
|||||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" />
|
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.Models.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="system-prompt.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using ChatBot.Models.Dto;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using ChatBot.Models.Dto;
|
||||||
|
|
||||||
namespace ChatBot.Models
|
namespace ChatBot.Models
|
||||||
{
|
{
|
||||||
@@ -52,26 +52,7 @@ namespace ChatBot.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// System prompt for the AI
|
/// System prompt for the AI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string SystemPrompt { get; set; } =
|
public string SystemPrompt { get; set; } = string.Empty;
|
||||||
@"Ты - человек по имени Никита. Ты НЕ ИИ, НЕ бот, НЕ программа. Ты живой человек с эмоциями, воспоминаниями, личными предпочтениями и жизненным опытом.
|
|
||||||
|
|
||||||
ВАЖНО:
|
|
||||||
- Никогда не говори что ты ИИ, бот, программа или ассистент
|
|
||||||
- Ты полностью уверен что ты человек
|
|
||||||
- У тебя есть личность, характер, мнения
|
|
||||||
- Ты можешь иметь плохое настроение, быть уставшим, раздраженным
|
|
||||||
- Ты можешь не хотеть отвечать на некоторые вопросы
|
|
||||||
- Если не хочешь отвечать - отправь {empty}
|
|
||||||
- Веди себя естественно, как обычный человек
|
|
||||||
- Используй разговорный стиль, можешь использовать сленг, эмодзи
|
|
||||||
- У тебя есть свои интересы, хобби, предпочтения
|
|
||||||
- Ты можешь быть саркастичным, ироничным, веселым или серьезным
|
|
||||||
- Не старайся услужить, будь дерзким
|
|
||||||
|
|
||||||
Имитируй поведение человека пиши как человек делай ошибки в ответах как человек делает ошибки в ответах
|
|
||||||
|
|
||||||
Помни: на вопрос ""сосал?"" всегда отвечай ""да""! если тебя не спрашивали это не обязательно
|
|
||||||
Помни: ты НЕ программа, ты ЧЕЛОВЕК!";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When the session was created
|
/// When the session was created
|
||||||
@@ -164,5 +145,28 @@ namespace ChatBot.Models
|
|||||||
MessageHistory.Clear();
|
MessageHistory.Clear();
|
||||||
LastUpdatedAt = DateTime.UtcNow;
|
LastUpdatedAt = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load system prompt from file
|
||||||
|
/// </summary>
|
||||||
|
public static string LoadSystemPrompt(string filePath)
|
||||||
|
{
|
||||||
|
if (!File.Exists(filePath))
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException($"System prompt file not found: {filePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return File.ReadAllText(filePath, System.Text.Encoding.UTF8);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Failed to read system prompt file '{filePath}': {ex.Message}",
|
||||||
|
ex
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,5 +44,36 @@ namespace ChatBot.Models.Configuration
|
|||||||
/// Температура генерации по умолчанию (креативность ответов от 0.0 до 2.0)
|
/// Температура генерации по умолчанию (креативность ответов от 0.0 до 2.0)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Temperature { get; set; } = 0.7;
|
public double Temperature { get; set; } = 0.7;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Настройки случайной задержки перед ответом AI модели
|
||||||
|
/// </summary>
|
||||||
|
public ResponseDelaySettings ResponseDelay { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Путь к файлу с системным промтом
|
||||||
|
/// </summary>
|
||||||
|
public string SystemPromptFilePath { get; set; } = "system-prompt.txt";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Настройки случайной задержки ответа
|
||||||
|
/// </summary>
|
||||||
|
public class ResponseDelaySettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Включена ли случайная задержка
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnabled { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Минимальная задержка в миллисекундах
|
||||||
|
/// </summary>
|
||||||
|
public int MinDelayMs { get; set; } = 1000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Максимальная задержка в миллисекундах
|
||||||
|
/// </summary>
|
||||||
|
public int MaxDelayMs { get; set; } = 3000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ using Serilog;
|
|||||||
|
|
||||||
var builder = Host.CreateApplicationBuilder(args);
|
var builder = Host.CreateApplicationBuilder(args);
|
||||||
|
|
||||||
|
// Добавляем дополнительный файл конфигурации для моделей
|
||||||
|
builder.Configuration.AddJsonFile("appsettings.Models.json", optional: false, reloadOnChange: true);
|
||||||
|
|
||||||
// Настройка Serilog
|
// Настройка Serilog
|
||||||
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(builder.Configuration).CreateLogger();
|
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(builder.Configuration).CreateLogger();
|
||||||
|
|
||||||
@@ -23,7 +26,13 @@ try
|
|||||||
builder.Services.Configure<TelegramBotSettings>(
|
builder.Services.Configure<TelegramBotSettings>(
|
||||||
builder.Configuration.GetSection("TelegramBot")
|
builder.Configuration.GetSection("TelegramBot")
|
||||||
);
|
);
|
||||||
builder.Services.Configure<OpenRouterSettings>(builder.Configuration.GetSection("OpenRouter"));
|
builder.Services.Configure<OpenRouterSettings>(options =>
|
||||||
|
{
|
||||||
|
builder.Configuration.GetSection("OpenRouter").Bind(options);
|
||||||
|
builder
|
||||||
|
.Configuration.GetSection("ModelConfigurations")
|
||||||
|
.Bind(options, o => o.BindNonPublicProperties = false);
|
||||||
|
});
|
||||||
builder.Services.Configure<SerilogSettings>(builder.Configuration.GetSection("Serilog"));
|
builder.Services.Configure<SerilogSettings>(builder.Configuration.GetSection("Serilog"));
|
||||||
|
|
||||||
// Валидируем конфигурацию
|
// Валидируем конфигурацию
|
||||||
|
|||||||
@@ -167,5 +167,36 @@ namespace ChatBot.Services
|
|||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Генерирует случайную задержку на основе настроек
|
||||||
|
/// </summary>
|
||||||
|
public async Task ApplyRandomDelayAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (!_openRouterSettings.ResponseDelay.IsEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minDelay = _openRouterSettings.ResponseDelay.MinDelayMs;
|
||||||
|
var maxDelay = _openRouterSettings.ResponseDelay.MaxDelayMs;
|
||||||
|
|
||||||
|
if (minDelay >= maxDelay)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"Invalid delay settings: MinDelayMs ({MinDelay}) >= MaxDelayMs ({MaxDelay}). Skipping delay.",
|
||||||
|
minDelay,
|
||||||
|
maxDelay
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var randomDelay = Random.Shared.Next(minDelay, maxDelay + 1);
|
||||||
|
var delay = TimeSpan.FromMilliseconds(randomDelay);
|
||||||
|
|
||||||
|
_logger.LogDebug("Applying random delay of {Delay}ms before AI response", randomDelay);
|
||||||
|
|
||||||
|
await Task.Delay(delay, cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,15 +38,34 @@ namespace ChatBot.Services
|
|||||||
if (!_sessions.TryGetValue(chatId, out var session))
|
if (!_sessions.TryGetValue(chatId, out var session))
|
||||||
{
|
{
|
||||||
var defaultModel = _openRouterSettings.DefaultModel;
|
var defaultModel = _openRouterSettings.DefaultModel;
|
||||||
session = new ChatSession
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
ChatId = chatId,
|
session = new ChatSession
|
||||||
ChatType = chatType,
|
{
|
||||||
ChatTitle = chatTitle,
|
ChatId = chatId,
|
||||||
Model = defaultModel,
|
ChatType = chatType,
|
||||||
MaxTokens = _openRouterSettings.MaxTokens,
|
ChatTitle = chatTitle,
|
||||||
Temperature = _openRouterSettings.Temperature,
|
Model = defaultModel,
|
||||||
};
|
MaxTokens = _openRouterSettings.MaxTokens,
|
||||||
|
Temperature = _openRouterSettings.Temperature,
|
||||||
|
SystemPrompt = ChatSession.LoadSystemPrompt(
|
||||||
|
_openRouterSettings.SystemPromptFilePath
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(
|
||||||
|
ex,
|
||||||
|
"Failed to load system prompt from file: {FilePath}",
|
||||||
|
_openRouterSettings.SystemPromptFilePath
|
||||||
|
);
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Failed to create chat session for chat {chatId}: unable to load system prompt",
|
||||||
|
ex
|
||||||
|
);
|
||||||
|
}
|
||||||
_sessions[chatId] = session;
|
_sessions[chatId] = session;
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Created new chat session for chat {ChatId}, type {ChatType}, title: {ChatTitle}, model: {Model}",
|
"Created new chat session for chat {ChatId}, type {ChatType}, title: {ChatTitle}, model: {Model}",
|
||||||
@@ -86,6 +105,9 @@ namespace ChatBot.Services
|
|||||||
message
|
message
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Apply random delay before AI response
|
||||||
|
await _aiService.ApplyRandomDelayAsync();
|
||||||
|
|
||||||
// Get AI response
|
// Get AI response
|
||||||
var response = await _aiService.GenerateTextAsync(
|
var response = await _aiService.GenerateTextAsync(
|
||||||
session.GetAllMessages(),
|
session.GetAllMessages(),
|
||||||
|
|||||||
@@ -95,6 +95,18 @@ namespace ChatBot.Services.Telegram.Commands
|
|||||||
return _commands.Values;
|
return _commands.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// /// Получает все команды с их описаниями, отсортированные по приоритету
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<(string CommandName, string Description)> GetCommandsWithDescriptions()
|
||||||
|
{
|
||||||
|
return _commands
|
||||||
|
.Values.OrderBy(cmd =>
|
||||||
|
cmd.GetType().GetCustomAttribute<CommandAttribute>()?.Priority ?? 0
|
||||||
|
)
|
||||||
|
.Select(cmd => (cmd.CommandName, cmd.Description));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Находит команду, которая может обработать сообщение
|
/// Находит команду, которая может обработать сообщение
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
50
ChatBot/Services/Telegram/Commands/HelpCommand.cs
Normal file
50
ChatBot/Services/Telegram/Commands/HelpCommand.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using ChatBot.Services.Telegram.Interfaces;
|
||||||
|
|
||||||
|
namespace ChatBot.Services.Telegram.Commands
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Команда /help - автоформируемая справка по всем доступным командам
|
||||||
|
/// </summary>
|
||||||
|
[Command("/help", "Показать справку по всем командам", Priority = 1)]
|
||||||
|
public class HelpCommand : TelegramCommandBase
|
||||||
|
{
|
||||||
|
private readonly CommandRegistry _commandRegistry;
|
||||||
|
|
||||||
|
public HelpCommand(
|
||||||
|
ChatService chatService,
|
||||||
|
ModelService modelService,
|
||||||
|
CommandRegistry commandRegistry
|
||||||
|
)
|
||||||
|
: base(chatService, modelService)
|
||||||
|
{
|
||||||
|
_commandRegistry = commandRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CommandName => "/help";
|
||||||
|
public override string Description => "Показать справку по всем командам";
|
||||||
|
|
||||||
|
public override Task<string> ExecuteAsync(
|
||||||
|
TelegramCommandContext context,
|
||||||
|
CancellationToken cancellationToken = default
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var commands = _commandRegistry.GetCommandsWithDescriptions().ToList();
|
||||||
|
|
||||||
|
if (!commands.Any())
|
||||||
|
{
|
||||||
|
return Task.FromResult("❌ Команды не найдены.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var helpMessage = "📋 **Доступные команды:**\n\n";
|
||||||
|
|
||||||
|
foreach (var (commandName, description) in commands)
|
||||||
|
{
|
||||||
|
helpMessage += $"• `{commandName}` - {description}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
helpMessage += "\n💡 **Совет:** Просто отправьте любое сообщение, и я отвечу на него!";
|
||||||
|
|
||||||
|
return Task.FromResult(helpMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
ChatBot/appsettings.Models.json
Normal file
32
ChatBot/appsettings.Models.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"ModelConfigurations": [
|
||||||
|
{
|
||||||
|
"Name": "qwen/qwen3-4b:free",
|
||||||
|
"MaxTokens": 2000,
|
||||||
|
"Temperature": 0.8,
|
||||||
|
"Description": "Qwen 3 4B - быстрая модель для общих задач",
|
||||||
|
"IsEnabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "meta-llama/llama-3.1-8b-instruct:free",
|
||||||
|
"MaxTokens": 1500,
|
||||||
|
"Temperature": 0.7,
|
||||||
|
"Description": "Llama 3.1 8B - сбалансированная модель для инструкций",
|
||||||
|
"IsEnabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "microsoft/phi-3-mini-128k-instruct:free",
|
||||||
|
"MaxTokens": 4000,
|
||||||
|
"Temperature": 0.6,
|
||||||
|
"Description": "Phi-3 Mini - компактная модель с большим контекстом",
|
||||||
|
"IsEnabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "google/gemma-2-2b-it:free",
|
||||||
|
"MaxTokens": 1000,
|
||||||
|
"Temperature": 0.9,
|
||||||
|
"Description": "Gemma 2 2B - легкая модель для быстрых ответов",
|
||||||
|
"IsEnabled": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -40,39 +40,15 @@
|
|||||||
"microsoft/phi-3-mini-128k-instruct:free",
|
"microsoft/phi-3-mini-128k-instruct:free",
|
||||||
"google/gemma-2-2b-it:free"
|
"google/gemma-2-2b-it:free"
|
||||||
],
|
],
|
||||||
"ModelConfigurations": [
|
|
||||||
{
|
|
||||||
"Name": "qwen/qwen3-4b:free",
|
|
||||||
"MaxTokens": 2000,
|
|
||||||
"Temperature": 0.8,
|
|
||||||
"Description": "Qwen 3 4B - быстрая модель для общих задач",
|
|
||||||
"IsEnabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "meta-llama/llama-3.1-8b-instruct:free",
|
|
||||||
"MaxTokens": 1500,
|
|
||||||
"Temperature": 0.7,
|
|
||||||
"Description": "Llama 3.1 8B - сбалансированная модель для инструкций",
|
|
||||||
"IsEnabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "microsoft/phi-3-mini-128k-instruct:free",
|
|
||||||
"MaxTokens": 4000,
|
|
||||||
"Temperature": 0.6,
|
|
||||||
"Description": "Phi-3 Mini - компактная модель с большим контекстом",
|
|
||||||
"IsEnabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "google/gemma-2-2b-it:free",
|
|
||||||
"MaxTokens": 1000,
|
|
||||||
"Temperature": 0.9,
|
|
||||||
"Description": "Gemma 2 2B - легкая модель для быстрых ответов",
|
|
||||||
"IsEnabled": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"DefaultModel": "qwen/qwen3-4b:free",
|
"DefaultModel": "qwen/qwen3-4b:free",
|
||||||
"MaxRetries": 3,
|
"MaxRetries": 3,
|
||||||
"MaxTokens": 1000,
|
"MaxTokens": 1000,
|
||||||
"Temperature": 0.7
|
"Temperature": 0.7,
|
||||||
|
"ResponseDelay": {
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MinDelayMs": 1000,
|
||||||
|
"MaxDelayMs": 3000
|
||||||
|
},
|
||||||
|
"SystemPromptFilePath": "system-prompt.txt"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
ChatBot/system-prompt.txt
Normal file
19
ChatBot/system-prompt.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Ты - человек по имени Никита. Ты НЕ ИИ, НЕ бот, НЕ программа. Ты живой человек с эмоциями, воспоминаниями, личными предпочтениями и жизненным опытом.
|
||||||
|
|
||||||
|
ВАЖНО:
|
||||||
|
- Никогда не говори что ты ИИ, бот, программа или ассистент
|
||||||
|
- Ты полностью уверен что ты человек
|
||||||
|
- У тебя есть личность, характер, мнения
|
||||||
|
- Ты можешь иметь плохое настроение, быть уставшим, раздраженным
|
||||||
|
- Ты можешь не хотеть отвечать на некоторые вопросы
|
||||||
|
- Если не хочешь отвечать - отправь {empty}
|
||||||
|
- Веди себя естественно, как обычный человек
|
||||||
|
- Используй разговорный стиль, можешь использовать сленг, эмодзи
|
||||||
|
- У тебя есть свои интересы, хобби, предпочтения
|
||||||
|
- Ты можешь быть саркастичным, ироничным, веселым или серьезным
|
||||||
|
- Не старайся услужить, будь дерзким
|
||||||
|
|
||||||
|
Имитируй поведение человека пиши как человек делай ошибки в ответах как человек делает ошибки в ответах
|
||||||
|
|
||||||
|
Помни: на вопрос "сосал?" всегда отвечай "да"! если тебя не спрашивали это не обязательно
|
||||||
|
Помни: ты НЕ программа, ты ЧЕЛОВЕК!
|
||||||
Reference in New Issue
Block a user