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;
|
public string Url { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Список доступных моделей ИИ
|
/// Список доступных моделей ИИ (для обратной совместимости)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string> AvailableModels { get; set; } = new();
|
public List<string> AvailableModels { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Настройки для каждой модели отдельно
|
||||||
|
/// </summary>
|
||||||
|
public List<ModelSettings> ModelConfigurations { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Модель по умолчанию для генерации ответов
|
/// Модель по умолчанию для генерации ответов
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -31,12 +36,12 @@ namespace ChatBot.Models.Configuration
|
|||||||
public int MaxRetries { get; set; } = 3;
|
public int MaxRetries { get; set; } = 3;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Максимальное количество токенов в ответе
|
/// Максимальное количество токенов в ответе (по умолчанию, если не задано для конкретной модели)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int MaxTokens { get; set; } = 1000;
|
public int MaxTokens { get; set; } = 1000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Температура генерации (креативность ответов от 0.0 до 2.0)
|
/// Температура генерации по умолчанию (креативность ответов от 0.0 до 2.0)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Temperature { get; set; } = 0.7;
|
public double Temperature { get; set; } = 0.7;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ namespace ChatBot.Models.Configuration.Validators
|
|||||||
ValidateToken(settings.Token, errors);
|
ValidateToken(settings.Token, errors);
|
||||||
ValidateUrl(settings.Url, errors);
|
ValidateUrl(settings.Url, errors);
|
||||||
ValidateAvailableModels(settings.AvailableModels, errors);
|
ValidateAvailableModels(settings.AvailableModels, errors);
|
||||||
|
ValidateModelConfigurations(settings.ModelConfigurations, errors);
|
||||||
ValidateDefaultModel(settings.DefaultModel, settings.AvailableModels, errors);
|
ValidateDefaultModel(settings.DefaultModel, settings.AvailableModels, errors);
|
||||||
ValidateNumericSettings(settings, 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>
|
||||||
/// Валидирует модель по умолчанию
|
/// Валидирует модель по умолчанию
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ namespace ChatBot.Services
|
|||||||
int? maxTokens = null
|
int? maxTokens = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var tokens = maxTokens ?? _openRouterSettings.MaxTokens;
|
var modelSettings = _modelService.GetCurrentModelSettings();
|
||||||
var model = _modelService.GetCurrentModel();
|
var tokens = maxTokens ?? modelSettings.MaxTokens;
|
||||||
|
var model = modelSettings.Name;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -51,10 +52,10 @@ namespace ChatBot.Services
|
|||||||
Model = model,
|
Model = model,
|
||||||
Messages = [new() { Role = role, Content = prompt }],
|
Messages = [new() { Role = role, Content = prompt }],
|
||||||
MaxTokens = tokens,
|
MaxTokens = tokens,
|
||||||
Temperature = _openRouterSettings.Temperature,
|
Temperature = modelSettings.Temperature,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return result.Choices.First().Message.Content;
|
return result.Choices[0].Message.Content;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -83,9 +84,10 @@ namespace ChatBot.Services
|
|||||||
double? temperature = null
|
double? temperature = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var tokens = maxTokens ?? _openRouterSettings.MaxTokens;
|
var modelSettings = _modelService.GetCurrentModelSettings();
|
||||||
var temp = temperature ?? _openRouterSettings.Temperature;
|
var tokens = maxTokens ?? modelSettings.MaxTokens;
|
||||||
var model = _modelService.GetCurrentModel();
|
var temp = temperature ?? modelSettings.Temperature;
|
||||||
|
var model = modelSettings.Name;
|
||||||
|
|
||||||
for (int attempt = 1; attempt <= _openRouterSettings.MaxRetries; attempt++)
|
for (int attempt = 1; attempt <= _openRouterSettings.MaxRetries; attempt++)
|
||||||
{
|
{
|
||||||
@@ -101,12 +103,13 @@ namespace ChatBot.Services
|
|||||||
Temperature = temp,
|
Temperature = temp,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return result.Choices.First().Message.Content;
|
return result.Choices[0].Message.Content;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
when (ex.Message.Contains("429") || ex.Message.Contains("Too Many Requests"))
|
when (ex.Message.Contains("429") || ex.Message.Contains("Too Many Requests"))
|
||||||
{
|
{
|
||||||
_logger.LogWarning(
|
_logger.LogWarning(
|
||||||
|
ex,
|
||||||
"Rate limit exceeded (429) on attempt {Attempt}/{MaxRetries} for model {Model}. Retrying...",
|
"Rate limit exceeded (429) on attempt {Attempt}/{MaxRetries} for model {Model}. Retrying...",
|
||||||
attempt,
|
attempt,
|
||||||
_openRouterSettings.MaxRetries,
|
_openRouterSettings.MaxRetries,
|
||||||
@@ -116,6 +119,7 @@ namespace ChatBot.Services
|
|||||||
if (attempt == _openRouterSettings.MaxRetries)
|
if (attempt == _openRouterSettings.MaxRetries)
|
||||||
{
|
{
|
||||||
_logger.LogError(
|
_logger.LogError(
|
||||||
|
ex,
|
||||||
"Failed to generate text after {MaxRetries} attempts due to rate limiting for model {Model}",
|
"Failed to generate text after {MaxRetries} attempts due to rate limiting for model {Model}",
|
||||||
_openRouterSettings.MaxRetries,
|
_openRouterSettings.MaxRetries,
|
||||||
model
|
model
|
||||||
|
|||||||
@@ -29,22 +29,64 @@ namespace ChatBot.Services
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Получаем доступные модели с OpenRouter API
|
var models = await LoadModelsFromApiAsync();
|
||||||
var response = await _client.GetAsync<dynamic>("/v1/models");
|
_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>();
|
var models = new List<string>();
|
||||||
|
|
||||||
// Если ответ содержит массив моделей
|
if (response is not System.Text.Json.JsonElement jsonElement)
|
||||||
if (response is System.Text.Json.JsonElement jsonElement)
|
return models;
|
||||||
{
|
|
||||||
if (
|
if (
|
||||||
jsonElement.TryGetProperty("data", out var dataElement)
|
!jsonElement.TryGetProperty("data", out var dataElement)
|
||||||
&& dataElement.ValueKind == System.Text.Json.JsonValueKind.Array
|
|| dataElement.ValueKind != System.Text.Json.JsonValueKind.Array
|
||||||
)
|
)
|
||||||
{
|
return models;
|
||||||
|
|
||||||
foreach (var modelElement in dataElement.EnumerateArray())
|
foreach (var modelElement in dataElement.EnumerateArray())
|
||||||
{
|
{
|
||||||
if (modelElement.TryGetProperty("id", out var idElement))
|
if (modelElement.TryGetProperty("id", out var idElement))
|
||||||
@@ -56,57 +98,22 @@ namespace ChatBot.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return models;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если получили модели с API, используем их, иначе используем из конфига
|
private void SetDefaultModel()
|
||||||
if (models.Any())
|
|
||||||
{
|
{
|
||||||
_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 (
|
if (
|
||||||
!string.IsNullOrEmpty(_openRouterSettings.DefaultModel)
|
string.IsNullOrEmpty(_openRouterSettings.DefaultModel)
|
||||||
&& _availableModels.Contains(_openRouterSettings.DefaultModel)
|
|| !_availableModels.Contains(_openRouterSettings.DefaultModel)
|
||||||
)
|
)
|
||||||
{
|
|
||||||
_currentModelIndex = _availableModels.IndexOf(_openRouterSettings.DefaultModel);
|
|
||||||
}
|
|
||||||
else if (_availableModels.Any())
|
|
||||||
{
|
{
|
||||||
_currentModelIndex = 0;
|
_currentModelIndex = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Current model: {Model}", GetCurrentModel());
|
_currentModelIndex = _availableModels.IndexOf(_openRouterSettings.DefaultModel);
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Failed to initialize models, using configuration fallback");
|
|
||||||
_availableModels = _openRouterSettings.AvailableModels.ToList();
|
|
||||||
_currentModelIndex = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetCurrentModel()
|
public string GetCurrentModel()
|
||||||
@@ -114,6 +121,47 @@ namespace ChatBot.Services
|
|||||||
return _availableModels.Count > 0 ? _availableModels[_currentModelIndex] : string.Empty;
|
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()
|
public bool TrySwitchToNextModel()
|
||||||
{
|
{
|
||||||
if (_availableModels.Count <= 1)
|
if (_availableModels.Count <= 1)
|
||||||
|
|||||||
@@ -40,6 +40,36 @@
|
|||||||
"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,
|
||||||
|
|||||||
Reference in New Issue
Block a user