Files
Hy2026/backend/Infrastructure/DependencyInjection.cs
T
Rafał Tyński 03e2d66ca4 feat(backend): add LLM provider abstraction, contextual ranking and explanations
Add a pluggable LLM provider with an offline template fallback, prompt builder, contextual match scoring (area/location boosts, availability), per-solution explanations and in-memory request limiting for cost control.
2026-10-04 02:52:45 +02:00

87 lines
3.6 KiB
C#

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SurrealDb.Net;
using TarninaHub.Application.Abstractions;
using TarninaHub.Application.Matchmaking;
using TarninaHub.Infrastructure.Auth;
using TarninaHub.Infrastructure.Events;
using TarninaHub.Infrastructure.Llm;
using TarninaHub.Infrastructure.Persistence;
using TarninaHub.Infrastructure.Settings;
namespace TarninaHub.Infrastructure;
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration configuration)
{
services.Configure<SurrealDbSettings>(configuration.GetSection("SurrealDb"));
services.Configure<AuthSettings>(configuration.GetSection("Auth"));
var llmSettings = configuration.GetSection("Llm").Get<LlmSettings>() ?? new LlmSettings();
services.Configure<LlmSettings>(configuration.GetSection("Llm"));
services.AddSingleton<ILlmRequestLimiter>(
new InMemoryLlmRequestLimiter(llmSettings.MaxRequestsPerMinute));
if (llmSettings.IsConfigured)
{
services.AddHttpClient<OpenAiCompatibleLlmProvider>(
client => client.Timeout = TimeSpan.FromSeconds(llmSettings.TimeoutSeconds));
services.AddSingleton<ILlmProvider>(
provider => provider.GetRequiredService<OpenAiCompatibleLlmProvider>());
}
else
{
services.AddSingleton<ILlmProvider, NullLlmProvider>();
}
var settings = configuration.GetSection("SurrealDb").Get<SurrealDbSettings>()
?? new SurrealDbSettings();
var options = new SurrealDbOptions
{
Endpoint = SurrealDbEndpoint.Build(settings),
Namespace = settings.Namespace,
Database = settings.Database,
};
if (string.IsNullOrWhiteSpace(settings.RemoteUrl))
{
// Embedded RocksDB, persisted next to the running app (./data), never in memory.
var dataDirectory = Path.Combine(AppContext.BaseDirectory, settings.DataDirectory);
Directory.CreateDirectory(dataDirectory);
services
.AddSurreal(options, ServiceLifetime.Singleton)
.AddRocksDbProvider();
}
else
{
// Remote SurrealDB server on its own dedicated port (used for sync with the frontend).
options.Username = settings.Username;
options.Password = settings.Password;
services.AddSurreal(options, ServiceLifetime.Singleton);
}
services.AddSingleton<IStorageService, StorageService>();
services.AddSingleton<IMigrationRunner, MigrationRunner>();
services.AddSingleton<ITokenService, TokenService>();
services.AddSingleton<IUserService, UserService>();
services.AddSingleton<IConsentService, ConsentService>();
services.AddSingleton<IAuditLogService, AuditLogService>();
services.AddSingleton<ISubmissionEventPublisher, LoggingSubmissionEventPublisher>();
services.AddSingleton<ISubmissionService, SubmissionService>();
services.AddSingleton<IChallengeService, ChallengeService>();
services.AddSingleton<IKnowledgeItemService, KnowledgeItemService>();
services.AddSingleton<IInnovationService, InnovationService>();
services.AddSingleton<ITrendService, TrendService>();
services.AddSingleton<IEmbeddingProvider, HashingEmbeddingProvider>();
services.AddSingleton<IMatchmakingService, MatchmakingService>();
return services;
}
}