add model settings
This commit is contained in:
33
ChatBot/Models/Configuration/ModelSettings.cs
Normal file
33
ChatBot/Models/Configuration/ModelSettings.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace ChatBot.Models.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Настройки конкретной модели ИИ
|
||||
/// </summary>
|
||||
public class ModelSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Название модели
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Максимальное количество токенов для этой модели
|
||||
/// </summary>
|
||||
public int MaxTokens { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Температура генерации для этой модели (креативность от 0.0 до 2.0)
|
||||
/// </summary>
|
||||
public double Temperature { get; set; } = 0.7;
|
||||
|
||||
/// <summary>
|
||||
/// Описание модели
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Является ли модель активной (доступной для использования)
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,15 @@ namespace ChatBot.Models.Configuration
|
||||
public string Url { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Список доступных моделей ИИ
|
||||
/// Список доступных моделей ИИ (для обратной совместимости)
|
||||
/// </summary>
|
||||
public List<string> AvailableModels { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Настройки для каждой модели отдельно
|
||||
/// </summary>
|
||||
public List<ModelSettings> ModelConfigurations { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Модель по умолчанию для генерации ответов
|
||||
/// </summary>
|
||||
@@ -31,12 +36,12 @@ namespace ChatBot.Models.Configuration
|
||||
public int MaxRetries { get; set; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Максимальное количество токенов в ответе
|
||||
/// Максимальное количество токенов в ответе (по умолчанию, если не задано для конкретной модели)
|
||||
/// </summary>
|
||||
public int MaxTokens { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Температура генерации (креативность ответов от 0.0 до 2.0)
|
||||
/// Температура генерации по умолчанию (креативность ответов от 0.0 до 2.0)
|
||||
/// </summary>
|
||||
public double Temperature { get; set; } = 0.7;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace ChatBot.Models.Configuration.Validators
|
||||
ValidateToken(settings.Token, errors);
|
||||
ValidateUrl(settings.Url, errors);
|
||||
ValidateAvailableModels(settings.AvailableModels, errors);
|
||||
ValidateModelConfigurations(settings.ModelConfigurations, errors);
|
||||
ValidateDefaultModel(settings.DefaultModel, settings.AvailableModels, errors);
|
||||
ValidateNumericSettings(settings, errors);
|
||||
|
||||
@@ -137,6 +138,44 @@ namespace ChatBot.Models.Configuration.Validators
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// /// Валидирует конфигурации моделей
|
||||
/// </summary>
|
||||
/// <param name="modelConfigurations">Конфигурации моделей</param>
|
||||
/// <param name="errors">Список ошибок валидации</param>
|
||||
private static void ValidateModelConfigurations(
|
||||
IEnumerable<ModelSettings> modelConfigurations,
|
||||
List<string> errors
|
||||
)
|
||||
{
|
||||
if (modelConfigurations == null)
|
||||
{
|
||||
return; // Конфигурации моделей необязательны
|
||||
}
|
||||
|
||||
foreach (var modelConfig in modelConfigurations)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(modelConfig.Name))
|
||||
{
|
||||
errors.Add("OpenRouter:ModelConfigurations contains model with empty name");
|
||||
}
|
||||
|
||||
if (modelConfig.MaxTokens < 1 || modelConfig.MaxTokens > 100000)
|
||||
{
|
||||
errors.Add(
|
||||
$"OpenRouter:ModelConfigurations model '{modelConfig.Name}' MaxTokens must be between 1 and 100000"
|
||||
);
|
||||
}
|
||||
|
||||
if (modelConfig.Temperature < 0.0 || modelConfig.Temperature > 2.0)
|
||||
{
|
||||
errors.Add(
|
||||
$"OpenRouter:ModelConfigurations model '{modelConfig.Name}' Temperature must be between 0.0 and 2.0"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Валидирует модель по умолчанию
|
||||
/// </summary>
|
||||
|
||||
@@ -39,8 +39,9 @@ namespace ChatBot.Services
|
||||
int? maxTokens = null
|
||||
)
|
||||
{
|
||||
var tokens = maxTokens ?? _openRouterSettings.MaxTokens;
|
||||
var model = _modelService.GetCurrentModel();
|
||||
var modelSettings = _modelService.GetCurrentModelSettings();
|
||||
var tokens = maxTokens ?? modelSettings.MaxTokens;
|
||||
var model = modelSettings.Name;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -51,10 +52,10 @@ namespace ChatBot.Services
|
||||
Model = model,
|
||||
Messages = [new() { Role = role, Content = prompt }],
|
||||
MaxTokens = tokens,
|
||||
Temperature = _openRouterSettings.Temperature,
|
||||
Temperature = modelSettings.Temperature,
|
||||
}
|
||||
);
|
||||
return result.Choices.First().Message.Content;
|
||||
return result.Choices[0].Message.Content;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -83,9 +84,10 @@ namespace ChatBot.Services
|
||||
double? temperature = null
|
||||
)
|
||||
{
|
||||
var tokens = maxTokens ?? _openRouterSettings.MaxTokens;
|
||||
var temp = temperature ?? _openRouterSettings.Temperature;
|
||||
var model = _modelService.GetCurrentModel();
|
||||
var modelSettings = _modelService.GetCurrentModelSettings();
|
||||
var tokens = maxTokens ?? modelSettings.MaxTokens;
|
||||
var temp = temperature ?? modelSettings.Temperature;
|
||||
var model = modelSettings.Name;
|
||||
|
||||
for (int attempt = 1; attempt <= _openRouterSettings.MaxRetries; attempt++)
|
||||
{
|
||||
@@ -101,12 +103,13 @@ namespace ChatBot.Services
|
||||
Temperature = temp,
|
||||
}
|
||||
);
|
||||
return result.Choices.First().Message.Content;
|
||||
return result.Choices[0].Message.Content;
|
||||
}
|
||||
catch (Exception ex)
|
||||
when (ex.Message.Contains("429") || ex.Message.Contains("Too Many Requests"))
|
||||
{
|
||||
_logger.LogWarning(
|
||||
ex,
|
||||
"Rate limit exceeded (429) on attempt {Attempt}/{MaxRetries} for model {Model}. Retrying...",
|
||||
attempt,
|
||||
_openRouterSettings.MaxRetries,
|
||||
@@ -116,6 +119,7 @@ namespace ChatBot.Services
|
||||
if (attempt == _openRouterSettings.MaxRetries)
|
||||
{
|
||||
_logger.LogError(
|
||||
ex,
|
||||
"Failed to generate text after {MaxRetries} attempts due to rate limiting for model {Model}",
|
||||
_openRouterSettings.MaxRetries,
|
||||
model
|
||||
|
||||
@@ -29,22 +29,64 @@ namespace ChatBot.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
// Получаем доступные модели с OpenRouter API
|
||||
var response = await _client.GetAsync<dynamic>("/v1/models");
|
||||
var models = await LoadModelsFromApiAsync();
|
||||
_availableModels = models.Any()
|
||||
? models
|
||||
: _openRouterSettings.AvailableModels.ToList();
|
||||
|
||||
if (response != null)
|
||||
SetDefaultModel();
|
||||
_logger.LogInformation("Current model: {Model}", GetCurrentModel());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to initialize models, using configuration fallback");
|
||||
_availableModels = _openRouterSettings.AvailableModels.ToList();
|
||||
_currentModelIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<string>> LoadModelsFromApiAsync()
|
||||
{
|
||||
var response = await _client.GetAsync<dynamic>("/v1/models");
|
||||
if (response == null)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"Using {Count} models from configuration (API unavailable)",
|
||||
_openRouterSettings.AvailableModels.Count
|
||||
);
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
var models = ParseModelsFromResponse(response);
|
||||
if (models.Any())
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"Loaded {Count} models from OpenRouter API",
|
||||
(int)models.Count
|
||||
);
|
||||
return models;
|
||||
}
|
||||
|
||||
_logger.LogInformation(
|
||||
"Using {Count} models from configuration",
|
||||
_openRouterSettings.AvailableModels.Count
|
||||
);
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
private static List<string> ParseModelsFromResponse(dynamic response)
|
||||
{
|
||||
// Парсим ответ и извлекаем названия моделей
|
||||
var models = new List<string>();
|
||||
|
||||
// Если ответ содержит массив моделей
|
||||
if (response is System.Text.Json.JsonElement jsonElement)
|
||||
{
|
||||
if (response is not System.Text.Json.JsonElement jsonElement)
|
||||
return models;
|
||||
|
||||
if (
|
||||
jsonElement.TryGetProperty("data", out var dataElement)
|
||||
&& dataElement.ValueKind == System.Text.Json.JsonValueKind.Array
|
||||
!jsonElement.TryGetProperty("data", out var dataElement)
|
||||
|| dataElement.ValueKind != System.Text.Json.JsonValueKind.Array
|
||||
)
|
||||
{
|
||||
return models;
|
||||
|
||||
foreach (var modelElement in dataElement.EnumerateArray())
|
||||
{
|
||||
if (modelElement.TryGetProperty("id", out var idElement))
|
||||
@@ -56,57 +98,22 @@ namespace ChatBot.Services
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
// Если получили модели с API, используем их, иначе используем из конфига
|
||||
if (models.Any())
|
||||
private void SetDefaultModel()
|
||||
{
|
||||
_availableModels = models;
|
||||
_logger.LogInformation(
|
||||
"Loaded {Count} models from OpenRouter API",
|
||||
models.Count
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
_availableModels = _openRouterSettings.AvailableModels.ToList();
|
||||
_logger.LogInformation(
|
||||
"Using {Count} models from configuration",
|
||||
_availableModels.Count
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_availableModels = _openRouterSettings.AvailableModels.ToList();
|
||||
_logger.LogInformation(
|
||||
"Using {Count} models from configuration (API unavailable)",
|
||||
_availableModels.Count
|
||||
);
|
||||
}
|
||||
|
||||
// Устанавливаем модель по умолчанию
|
||||
if (
|
||||
!string.IsNullOrEmpty(_openRouterSettings.DefaultModel)
|
||||
&& _availableModels.Contains(_openRouterSettings.DefaultModel)
|
||||
string.IsNullOrEmpty(_openRouterSettings.DefaultModel)
|
||||
|| !_availableModels.Contains(_openRouterSettings.DefaultModel)
|
||||
)
|
||||
{
|
||||
_currentModelIndex = _availableModels.IndexOf(_openRouterSettings.DefaultModel);
|
||||
}
|
||||
else if (_availableModels.Any())
|
||||
{
|
||||
_currentModelIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Current model: {Model}", GetCurrentModel());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to initialize models, using configuration fallback");
|
||||
_availableModels = _openRouterSettings.AvailableModels.ToList();
|
||||
_currentModelIndex = 0;
|
||||
}
|
||||
_currentModelIndex = _availableModels.IndexOf(_openRouterSettings.DefaultModel);
|
||||
}
|
||||
|
||||
public string GetCurrentModel()
|
||||
@@ -114,6 +121,47 @@ namespace ChatBot.Services
|
||||
return _availableModels.Count > 0 ? _availableModels[_currentModelIndex] : string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает настройки для текущей модели
|
||||
/// </summary>
|
||||
/// <returns>Настройки модели или настройки по умолчанию</returns>
|
||||
public ModelSettings GetCurrentModelSettings()
|
||||
{
|
||||
var currentModel = GetCurrentModel();
|
||||
if (string.IsNullOrEmpty(currentModel))
|
||||
{
|
||||
return GetDefaultModelSettings();
|
||||
}
|
||||
|
||||
// Ищем настройки для текущей модели
|
||||
var modelConfig = _openRouterSettings.ModelConfigurations.FirstOrDefault(m =>
|
||||
m.Name.Equals(currentModel, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
|
||||
if (modelConfig != null)
|
||||
{
|
||||
return modelConfig;
|
||||
}
|
||||
|
||||
// Если настройки не найдены, возвращаем настройки по умолчанию
|
||||
return GetDefaultModelSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает настройки по умолчанию
|
||||
/// </summary>
|
||||
/// <returns>Настройки по умолчанию</returns>
|
||||
private ModelSettings GetDefaultModelSettings()
|
||||
{
|
||||
return new ModelSettings
|
||||
{
|
||||
Name = GetCurrentModel(),
|
||||
MaxTokens = _openRouterSettings.MaxTokens,
|
||||
Temperature = _openRouterSettings.Temperature,
|
||||
IsEnabled = true,
|
||||
};
|
||||
}
|
||||
|
||||
public bool TrySwitchToNextModel()
|
||||
{
|
||||
if (_availableModels.Count <= 1)
|
||||
|
||||
@@ -40,6 +40,36 @@
|
||||
"microsoft/phi-3-mini-128k-instruct: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",
|
||||
"MaxRetries": 3,
|
||||
"MaxTokens": 1000,
|
||||
|
||||
Reference in New Issue
Block a user