📄 src/Infrastructure/Ai/ServiceCollectionExtensions.cs
using System;
using System.Net.Http;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OllamaSharp;

namespace Slopper.Infrastructure.Ai;

public static class ServiceCollectionExtensions
{
    extension(IServiceCollection services)
    {
        public IServiceCollection AddAi()
        {
            services.AddOptions<AiOptions>().BindConfiguration("Ai").ValidateOnStart();
            services.AddTransient<IValidateOptions<AiOptions>, AiOptionsValidator>();

            services
                .AddHttpClient("Ollama")
                .ConfigureHttpClient(
                    (sp, client) =>
                    {
                        var options = sp.GetRequiredService<IOptions<AiOptions>>().Value;
                        client.BaseAddress = options.Endpoint;
                        client.Timeout = TimeSpan.FromMinutes(10);
                        if (options.BasicAuth is not null)
                        {
                            client.DefaultRequestHeaders.Authorization = new("Basic", options.BasicAuth);
                        }
                    }
                );

            services
                .AddEmbeddingGenerator(sp =>
                {
                    var factory = sp.GetRequiredService<IHttpClientFactory>();
                    var options = sp.GetRequiredService<IOptions<AiOptions>>().Value;
                    return new OllamaApiClient(factory.CreateClient("Ollama"), options.EmbeddingModel);
                })
                .UseOpenTelemetry();

            services
                .AddChatClient(sp =>
                {
                    var factory = sp.GetRequiredService<IHttpClientFactory>();
                    var options = sp.GetRequiredService<IOptions<AiOptions>>().Value;
                    return new OllamaApiClient(factory.CreateClient("Ollama"), options.DescriptionModel);
                })
                .UseOpenTelemetry();

            return services;
        }
    }
}