85 lines
3.3 KiB
C#
85 lines
3.3 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;
|
|
using NexusReader.Domain.Entities;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using NexusReader.Application.Security.Authorization;
|
|
|
|
namespace NexusReader.Infrastructure;
|
|
|
|
public static class DependencyInjection
|
|
{
|
|
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
|
{
|
|
var pgConnectionString = configuration.GetConnectionString("PostgresConnection");
|
|
if (!string.IsNullOrEmpty(pgConnectionString))
|
|
{
|
|
services.AddDbContext<AppDbContext>(options =>
|
|
options.UseNpgsql(pgConnectionString));
|
|
}
|
|
else
|
|
{
|
|
var sqliteConnectionString = configuration.GetConnectionString("SqliteConnection") ?? "Data Source=nexus.db";
|
|
services.AddDbContext<AppDbContext>(options =>
|
|
options.UseSqlite(sqliteConnectionString));
|
|
}
|
|
|
|
services.Configure<AiSettings>(configuration.GetSection(AiSettings.SectionName));
|
|
services.Configure<StripeSettings>(configuration.GetSection(StripeSettings.SectionName));
|
|
var aiSettings = configuration.GetSection(AiSettings.SectionName).Get<AiSettings>() ?? new AiSettings();
|
|
|
|
Console.WriteLine($"[Infrastructure] AI Configured: Model={aiSettings.Model}, KeyPresent={!string.IsNullOrWhiteSpace(aiSettings.ApiKey) && aiSettings.ApiKey != "PLACEHOLDER"}");
|
|
|
|
if (string.IsNullOrWhiteSpace(aiSettings.ApiKey) || aiSettings.ApiKey == "PLACEHOLDER")
|
|
{
|
|
Console.WriteLine("[Infrastructure] WARNING: AI API Key is missing or placeholder!");
|
|
}
|
|
|
|
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<IEpubService, EpubService>();
|
|
|
|
services.AddAuthorizationCore(options =>
|
|
{
|
|
options.AddPolicy("ProUser", policy => policy.Requirements.Add(new ProUserRequirement()));
|
|
});
|
|
|
|
services.AddScoped<IAuthorizationHandler, ProUserHandler>();
|
|
|
|
services.AddMediatR(config =>
|
|
{
|
|
config.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly);
|
|
});
|
|
|
|
return services;
|
|
}
|
|
}
|