Files
Nexus.Reader/src/NexusReader.Infrastructure/DependencyInjection.cs
T

57 lines
2.2 KiB
C#

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.AI;
using GeminiDotnet;
using GeminiDotnet.Extensions.AI;
using NexusReader.Infrastructure.Persistence;
using NexusReader.Application.Abstractions.Services;
using NexusReader.Infrastructure.Services;
using NexusReader.Infrastructure.Configuration;
using Polly;
using Polly.Retry;
namespace NexusReader.Infrastructure;
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
var connectionString = configuration.GetConnectionString("SqliteConnection") ?? "Data Source=nexus.db";
services.AddDbContext<AppDbContext>(options =>
options.UseSqlite(connectionString));
services.Configure<AiSettings>(configuration.GetSection(AiSettings.SectionName));
var aiSettings = configuration.GetSection(AiSettings.SectionName).Get<AiSettings>() ?? new AiSettings();
if (string.IsNullOrWhiteSpace(aiSettings.ApiKey) || aiSettings.ApiKey == "PLACEHOLDER")
{
// We don't throw here to allow the app to start, but services using AI will fail gracefully
}
services.AddResiliencePipeline("ai-retry", builder =>
{
builder.AddRetry(new RetryStrategyOptions
{
ShouldHandle = new PredicateBuilder().Handle<Exception>(ex =>
ex.Message.Contains("429") || ex.Message.Contains("Too Many Requests") || ex.Message.Contains("quota")),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
MaxRetryAttempts = aiSettings.RetryAttempts,
Delay = TimeSpan.FromSeconds(2)
});
});
services.AddChatClient(new GeminiChatClient(new GeminiClientOptions
{
ApiKey = aiSettings.ApiKey,
ModelId = aiSettings.Model
}));
services.AddScoped<IKnowledgeService, KnowledgeService>();
services.AddTransient<IAiGenerateQuizService, FakeAiGenerateQuizService>();
services.AddTransient<IEpubService, EpubService>();
return services;
}
}