Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Cellm.Models/Cellm.Models.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
<Compile Include="$(MSBuildThisFileDirectory)Providers\Ollama\OllamaRequest.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Providers\Ollama\OllamaRequestHandler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Providers\Ollama\OllamaResponse.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Providers\ChatClientFactory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Providers\IChatClientFactory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Providers\OpenAiCompatible\OpenAiCompatibleConfiguration.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Providers\OpenAiCompatible\OpenAiCompatibleRequest.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Providers\OpenAiCompatible\OpenAiCompatibleRequestHandler.cs" />
Expand Down
13 changes: 13 additions & 0 deletions src/Cellm.Models/Providers/ChatClientFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;


namespace Cellm.Models.Providers.OpenAiCompatible;

public class ChatClientFactory(IServiceProvider serviceProvider) : IChatClientFactory
{
public IChatClient GetClient(Provider provider)
{
return serviceProvider.GetRequiredKeyedService<IChatClient>(provider);
}
}
8 changes: 8 additions & 0 deletions src/Cellm.Models/Providers/IChatClientFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Microsoft.Extensions.AI;

namespace Cellm.Models.Providers.OpenAiCompatible;

public interface IChatClientFactory
{
IChatClient GetClient(Provider provider);
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
using Cellm.Models.Prompts;
using Cellm.Services;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;

namespace Cellm.Models.Providers.OpenAiCompatible;

internal class OpenAiCompatibleRequestHandler
internal class OpenAiCompatibleRequestHandler(IChatClientFactory chatClientFactory)
: IModelRequestHandler<OpenAiCompatibleRequest, OpenAiCompatibleResponse>
{

public async Task<OpenAiCompatibleResponse> Handle(OpenAiCompatibleRequest request, CancellationToken cancellationToken)
{
var chatClient = ServiceLocator.ServiceProvider.GetRequiredKeyedService<IChatClient>(request.Provider);
var chatClient = chatClientFactory.GetClient(request.Provider);

var chatResponse = await chatClient.GetResponseAsync(
request.Prompt.Messages,
Expand Down
15 changes: 7 additions & 8 deletions src/Cellm.Models/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
using Cellm.Models.Providers.OpenAi;
using Cellm.Models.Providers.OpenAiCompatible;
using Cellm.Models.Resilience;
using Cellm.Services;
using Cellm.User;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
Expand Down Expand Up @@ -123,7 +122,7 @@ public static IServiceCollection AddAnthropicChatClient(this IServiceCollection
services
.AddKeyedChatClient(Provider.Anthropic, serviceProvider =>
{
var account = ServiceLocator.ServiceProvider.GetRequiredService<Account>();
var account = serviceProvider.GetRequiredService<Account>();
account.RequireEntitlement(Entitlement.EnableAnthropicProvider);

var anthropicConfiguration = serviceProvider.GetRequiredService<IOptionsMonitor<AnthropicConfiguration>>();
Expand All @@ -144,7 +143,7 @@ public static IServiceCollection AddCellmChatClient(this IServiceCollection serv
services
.AddKeyedChatClient(Provider.Cellm, serviceProvider =>
{
var account = ServiceLocator.ServiceProvider.GetRequiredService<Account>();
var account = serviceProvider.GetRequiredService<Account>();
account.RequireEntitlement(Entitlement.EnableCellmProvider);

var cellmConfiguration = serviceProvider.GetRequiredService<IOptionsMonitor<CellmConfiguration>>();
Expand All @@ -170,7 +169,7 @@ public static IServiceCollection AddDeepSeekChatClient(this IServiceCollection s
services
.AddKeyedChatClient(Provider.DeepSeek, serviceProvider =>
{
var account = ServiceLocator.ServiceProvider.GetRequiredService<Account>();
var account = serviceProvider.GetRequiredService<Account>();
account.RequireEntitlement(Entitlement.EnableDeepSeekProvider);

var deepSeekConfiguration = serviceProvider.GetRequiredService<IOptionsMonitor<DeepSeekConfiguration>>();
Expand All @@ -196,7 +195,7 @@ public static IServiceCollection AddMistralChatClient(this IServiceCollection se
services
.AddKeyedChatClient(Provider.Mistral, serviceProvider =>
{
var account = ServiceLocator.ServiceProvider.GetRequiredService<Account>();
var account = serviceProvider.GetRequiredService<Account>();
account.RequireEntitlement(Entitlement.EnableMistralProvider);

var mistralConfiguration = serviceProvider.GetRequiredService<IOptionsMonitor<MistralConfiguration>>();
Expand All @@ -217,7 +216,7 @@ public static IServiceCollection AddOllamaChatClient(this IServiceCollection ser
services
.AddKeyedChatClient(Provider.Ollama, serviceProvider =>
{
var account = ServiceLocator.ServiceProvider.GetRequiredService<Account>();
var account = serviceProvider.GetRequiredService<Account>();
account.RequireEntitlement(Entitlement.EnableOllamaProvider);

var ollamaConfiguration = serviceProvider.GetRequiredService<IOptionsMonitor<OllamaConfiguration>>();
Expand All @@ -238,7 +237,7 @@ public static IServiceCollection AddOpenAiChatClient(this IServiceCollection ser
services
.AddKeyedChatClient(Provider.OpenAi, serviceProvider =>
{
var account = ServiceLocator.ServiceProvider.GetRequiredService<Account>();
var account = serviceProvider.GetRequiredService<Account>();
account.RequireEntitlement(Entitlement.EnableOpenAiProvider);

var openAiConfiguration = serviceProvider.GetRequiredService<IOptionsMonitor<OpenAiConfiguration>>();
Expand All @@ -257,7 +256,7 @@ public static IServiceCollection AddOpenAiCompatibleChatClient(this IServiceColl
services
.AddKeyedChatClient(Provider.OpenAiCompatible, serviceProvider =>
{
var account = ServiceLocator.ServiceProvider.GetRequiredService<Account>();
var account = serviceProvider.GetRequiredService<Account>();
account.RequireEntitlement(Entitlement.EnableOpenAiCompatibleProvider);

var openAiCompatibleConfiguration = serviceProvider.GetRequiredService<IOptionsMonitor<OpenAiCompatibleConfiguration>>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Reflection;
using Cellm.AddIn;
using Cellm.AddIn.Configuration;
using Cellm.AddIn.Exceptions;
using Cellm.Models;
using Cellm.Models.Behaviors;
Expand All @@ -13,28 +13,42 @@
using Cellm.Models.Providers.OpenAiCompatible;
using Cellm.Models.Resilience;
using Cellm.Models.Tools;
using Cellm.Services.Configuration;
using Cellm.Tools;
using Cellm.Tools.FileReader;
using Cellm.Tools.ModelContextProtocol;
using Cellm.User;
using ExcelDna.Integration;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Sentry.Infrastructure;

namespace Cellm.Services;
namespace Cellm.AddIn;

internal static class ServiceLocator
public class CellmAddIn : IExcelAddIn
{
internal static string ConfigurationPath { get; set; } = ExcelDnaUtil.XllPathInfo?.Directory?.FullName ?? throw new NullReferenceException("Could not get Cellm path");

private static readonly Lazy<IServiceProvider> _serviceProvider = new(() => ConfigureServices(new ServiceCollection()).BuildServiceProvider());
public static IServiceProvider Services => _serviceProvider.Value;

internal static string ConfigurationPath { get; set; } = ExcelDnaUtil.XllPathInfo?.Directory?.FullName ?? throw new NullReferenceException("Could not get Cellm path");

public static IServiceProvider ServiceProvider => _serviceProvider.Value;
public void AutoOpen()
{
ExcelIntegration.RegisterUnhandledExceptionHandler(obj =>
{
var e = (Exception)obj;
SentrySdk.CaptureException(e);
return e.Message;
});
}

public void AutoClose()
{
DisposeServices();
SentrySdk.Flush();
}

private static IServiceCollection ConfigureServices(IServiceCollection services)
{
Expand Down Expand Up @@ -115,6 +129,7 @@ private static IServiceCollection ConfigureServices(IServiceCollection services)

// Add providers
services
.AddSingleton<IChatClientFactory, ChatClientFactory>()
.AddAnthropicChatClient()
.AddCellmChatClient()
.AddDeepSeekChatClient()
Expand Down Expand Up @@ -154,11 +169,12 @@ public static string GetReleaseVersion()
.InformationalVersion ?? "unknown";
}

public static void Dispose()
public static void DisposeServices()
{
if (_serviceProvider.IsValueCreated)
{
(_serviceProvider.Value as IDisposable)?.Dispose();
}
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Cellm.Services.Configuration;
namespace Cellm.AddIn.Configuration;

internal class SentryConfiguration
{
Expand Down
25 changes: 0 additions & 25 deletions src/Cellm/AddIn/ExcelAddin.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
using Cellm.Models;
using Cellm.Models.Prompts;
using Cellm.Models.Providers;
using Cellm.Services;
using ExcelDna.Integration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace Cellm.AddIn;

public static class ExcelFunctions
public static class Functions
{
/// <summary>
/// Sends a prompt to the default model configured in CellmConfiguration.
Expand All @@ -35,7 +34,7 @@ public static object Prompt(
[ExcelArgument(Name = "InstructionsOrTemperature", Description = "A cell or range of cells with instructions or a temperature")] object instructionsOrTemperature,
[ExcelArgument(Name = "Temperature", Description = "Temperature")] object temperature)
{
var configuration = ServiceLocator.ServiceProvider.GetRequiredService<IConfiguration>();
var configuration = CellmAddIn.Services.GetRequiredService<IConfiguration>();

var provider = configuration.GetSection(nameof(ProviderConfiguration)).GetValue<string>(nameof(ProviderConfiguration.DefaultProvider))
?? throw new ArgumentException(nameof(ProviderConfiguration.DefaultProvider));
Expand Down Expand Up @@ -75,8 +74,8 @@ public static object PromptWith(
{
try
{
var argumentParser = ServiceLocator.ServiceProvider.GetRequiredService<ArgumentParser>();
var providerConfiguration = ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<ProviderConfiguration>>();
var argumentParser = CellmAddIn.Services.GetRequiredService<ArgumentParser>();
var providerConfiguration = CellmAddIn.Services.GetRequiredService<IOptionsMonitor<ProviderConfiguration>>();

var arguments = argumentParser
.AddProvider(providerAndModel)
Expand Down Expand Up @@ -125,7 +124,7 @@ public static object PromptWith(

internal static async Task<string> GetResponseAsync(Prompt prompt, Provider provider)
{
var client = ServiceLocator.ServiceProvider.GetRequiredService<Client>();
var client = CellmAddIn.Services.GetRequiredService<Client>();
var response = await client.Send(prompt, provider, CancellationToken.None);
return response.Messages.Last().Text ?? throw new NullReferenceException("No text response");
}
Expand Down
29 changes: 14 additions & 15 deletions src/Cellm/AddIn/ExcelRibbon.cs → src/Cellm/AddIn/Ribbon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using Cellm.Models.Providers.Ollama;
using Cellm.Models.Providers.OpenAi;
using Cellm.Models.Providers.OpenAiCompatible;
using Cellm.Services;
using Cellm.User;
using ExcelDna.Integration.CustomUI;
using Microsoft.Extensions.Caching.Hybrid;
Expand All @@ -22,14 +21,14 @@
namespace Cellm.AddIn.RibbonController;

[ComVisible(true)]
public class ExcelRibbon : ExcelDna.Integration.CustomUI.ExcelRibbon
public class Ribbon : ExcelRibbon
{
private IRibbonUI? _ribbonUi;

private static readonly string _appSettingsPath = Path.Combine(ServiceLocator.ConfigurationPath, "appsettings.json");
private static readonly string _appsettingsLocalPath = Path.Combine(ServiceLocator.ConfigurationPath, "appsettings.Local.json");
private static readonly string _appSettingsPath = Path.Combine(CellmAddIn.ConfigurationPath, "appsettings.json");
private static readonly string _appsettingsLocalPath = Path.Combine(CellmAddIn.ConfigurationPath, "appsettings.Local.json");

public ExcelRibbon()
public Ribbon()
{
EnsureDefaultProvider();
EnsureDefaultCache();
Expand Down Expand Up @@ -109,21 +108,21 @@ public string ModelGroup()
{
var providerAndModels = new List<string>();

var accountConfiguration = ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<AccountConfiguration>>().CurrentValue;
var accountConfiguration = CellmAddIn.Services.GetRequiredService<IOptionsMonitor<AccountConfiguration>>().CurrentValue;

if (accountConfiguration.IsEnabled)
{
var cellmConfiguration = ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<CellmConfiguration>>().CurrentValue;
var cellmConfiguration = CellmAddIn.Services.GetRequiredService<IOptionsMonitor<CellmConfiguration>>().CurrentValue;
providerAndModels.AddRange(cellmConfiguration.Models.Select(m => $"{nameof(Provider.Cellm)}/{m}"));
}

var anthropicConfiguration = ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<AnthropicConfiguration>>().CurrentValue;
var anthropicConfiguration = CellmAddIn.Services.GetRequiredService<IOptionsMonitor<AnthropicConfiguration>>().CurrentValue;

var deepSeekConfiguration = ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<DeepSeekConfiguration>>().CurrentValue;
var mistralConfiguration = ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<MistralConfiguration>>().CurrentValue;
var ollamaConfiguration = ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<OllamaConfiguration>>().CurrentValue;
var openAiConfiguration = ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<OpenAiConfiguration>>().CurrentValue;
var openAiCompatibleConfiguration = ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<OpenAiCompatibleConfiguration>>().CurrentValue;
var deepSeekConfiguration = CellmAddIn.Services.GetRequiredService<IOptionsMonitor<DeepSeekConfiguration>>().CurrentValue;
var mistralConfiguration = CellmAddIn.Services.GetRequiredService<IOptionsMonitor<MistralConfiguration>>().CurrentValue;
var ollamaConfiguration = CellmAddIn.Services.GetRequiredService<IOptionsMonitor<OllamaConfiguration>>().CurrentValue;
var openAiConfiguration = CellmAddIn.Services.GetRequiredService<IOptionsMonitor<OpenAiConfiguration>>().CurrentValue;
var openAiCompatibleConfiguration = CellmAddIn.Services.GetRequiredService<IOptionsMonitor<OpenAiCompatibleConfiguration>>().CurrentValue;

providerAndModels.AddRange(anthropicConfiguration.Models.Select(m => $"{nameof(Provider.Anthropic)}/{m}"));
providerAndModels.AddRange(deepSeekConfiguration.Models.Select(m => $"{nameof(Provider.DeepSeek)}/{m}"));
Expand Down Expand Up @@ -232,7 +231,7 @@ public async Task OnCacheToggled(IRibbonControl control, bool enabled)
{
if (!enabled)
{
var cache = ServiceLocator.ServiceProvider.GetRequiredService<HybridCache>();
var cache = CellmAddIn.Services.GetRequiredService<HybridCache>();
await cache.RemoveByTagAsync(nameof(IModelResponse));

}
Expand Down Expand Up @@ -274,7 +273,7 @@ private Provider GetCurrentProvider()

private static T GetProviderConfiguration<T>()
{
return ServiceLocator.ServiceProvider.GetRequiredService<IOptionsMonitor<T>>().CurrentValue;
return CellmAddIn.Services.GetRequiredService<IOptionsMonitor<T>>().CurrentValue;
}

private static Provider GetProvider(string providerAndModel)
Expand Down