diff --git a/src/Senparc.AI.Agents/Senparc.AI.Agents.csproj b/src/Senparc.AI.Agents/Senparc.AI.Agents.csproj index 98b8631..dfa1b71 100644 --- a/src/Senparc.AI.Agents/Senparc.AI.Agents.csproj +++ b/src/Senparc.AI.Agents/Senparc.AI.Agents.csproj @@ -1,7 +1,7 @@  netstandard2.1 - 0.1.3-beta1 + 0.1.4 enable 10.0 Senparc.AI.Agents diff --git a/src/Senparc.AI.Kernel.Tests/BaseSupport/KernelTestBase.cs b/src/Senparc.AI.Kernel.Tests/BaseSupport/KernelTestBase.cs index c5f6dbd..4491ea6 100644 --- a/src/Senparc.AI.Kernel.Tests/BaseSupport/KernelTestBase.cs +++ b/src/Senparc.AI.Kernel.Tests/BaseSupport/KernelTestBase.cs @@ -30,6 +30,7 @@ public class KernelTestBase : BaseTest { services.AddScoped(); }; + public KernelTestBase() : base(RegisterAction, getSenparcAiSettingFunc, serviceAction) { diff --git a/src/Senparc.AI.Kernel/Extensions.cs b/src/Senparc.AI.Kernel/Extensions.cs index 293010a..1b53615 100644 --- a/src/Senparc.AI.Kernel/Extensions.cs +++ b/src/Senparc.AI.Kernel/Extensions.cs @@ -8,6 +8,7 @@ using Microsoft.SemanticKernel.Connectors.OpenAI; using Microsoft.SemanticKernel.TextGeneration; using Microsoft.SemanticKernel; +using OllamaSharp; namespace Senparc.AI.Kernel { @@ -29,12 +30,41 @@ public static IKernelBuilder AddFastAPIChatCompletion(this IKernelBuilder builde string apiKey2 = apiKey; string orgId2 = orgId; - Func implementationFactory = - (IServiceProvider serviceProvider, object? _) => + Func implementationFactory = + (IServiceProvider serviceProvider, object? _) => new OpenAIChatCompletionService(modelId, new OpenAIClient(new Uri(endpoint), new Azure.AzureKeyCredential(apiKey)), serviceProvider.GetService()); builder.Services.AddKeyedSingleton((object?)serviceId, (Func)implementationFactory); builder.Services.AddKeyedSingleton((object?)serviceId, (Func)implementationFactory); return builder; } + + #region Ollama + + public static IKernelBuilder AddFOllamaChatCompletion(this IKernelBuilder builder, string modelId, string endpoint, string serviceId = null) + { + string modelId2 = modelId; + + Func implementationFactory = + (IServiceProvider serviceProvider, object? _) => + new OpenAIChatCompletionService(modelId: modelId, endpoint: new Uri(endpoint), apiKey: "none", loggerFactory: serviceProvider.GetService()); + builder.Services.AddKeyedSingleton((object?)serviceId, (Func)implementationFactory); + + return builder; + } + + public static IKernelBuilder AddFOllamaTextCompletion(this IKernelBuilder builder, string modelId, string endpoint, string serviceId = null) + { + string modelId2 = modelId; + + Func implementationFactory = + (IServiceProvider serviceProvider, object? _) => + new OpenAITextGenerationService(modelId: modelId, new OpenAIClient(endpoint: new Uri(endpoint), new Azure.AzureKeyCredential("none")), loggerFactory: serviceProvider.GetService()); + + builder.Services.AddKeyedSingleton((object?)serviceId, (Func)implementationFactory); + + return builder; + } + + #endregion } } diff --git a/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs b/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs index ce78896..4bf7f78 100644 --- a/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs +++ b/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs @@ -88,6 +88,11 @@ public IKernelBuilder ConfigChat(string userId, string modelName = null, ISenpar endpoint: senparcAiSetting.FastAPIEndpoint, serviceId: null ), + AiPlatform.Ollama => kernelBuilder.AddFOllamaChatCompletion( + modelId: modelName, + endpoint: senparcAiSetting.OllamaEndpoint, + serviceId: null + ), _ => throw new SenparcAiException($"没有处理当前 {nameof(AiPlatform)} 类型:{aiPlatForm}") }; @@ -153,6 +158,11 @@ public IKernelBuilder ConfigTextCompletion(string userId, string modelName = nul endpoint: senparcAiSetting.FastAPIEndpoint, serviceId: null ), + AiPlatform.Ollama => kernelBuilder.AddFOllamaTextCompletion( + modelId: modelName, + endpoint: senparcAiSetting.OllamaEndpoint, + serviceId: null + ), _ => throw new SenparcAiException($"没有处理当前 {nameof(AiPlatform)} 类型:{aiPlatForm}") }; diff --git a/src/Senparc.AI.Kernel/Ollama/OllamaChatCompletionService.cs b/src/Senparc.AI.Kernel/Ollama/OllamaChatCompletionService.cs new file mode 100644 index 0000000..56dc126 --- /dev/null +++ b/src/Senparc.AI.Kernel/Ollama/OllamaChatCompletionService.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.ChatCompletion; +using Microsoft.SemanticKernel.Services; +using Microsoft.SemanticKernel.TextGeneration; + +namespace Senparc.AI.Kernel.Ollama +{ + public class OllamaChatCompletionService : IChatCompletionService, IAIService, ITextGenerationService + { + private readonly OllamaSharp.OllamaApiClient _core; + + Dictionary _attributes = new Dictionary(); + + public IReadOnlyDictionary Attributes => _attributes; + + public OllamaChatCompletionService(string url, string modelId) + { + _core = new OllamaSharp.OllamaApiClient(url, modelId); + + _attributes["model"] = modelId; + } + + + public Task> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Microsoft.SemanticKernel.Kernel? kernel = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public IAsyncEnumerable GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Microsoft.SemanticKernel.Kernel? kernel = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public IAsyncEnumerable GetStreamingTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Microsoft.SemanticKernel.Kernel? kernel = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public Task> GetTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Microsoft.SemanticKernel.Kernel? kernel = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj b/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj index 3218143..b244da4 100644 --- a/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj +++ b/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj @@ -1,7 +1,7 @@ netstandard2.1 - 0.16.3-beta1 + 0.17.1 enable 10.0 Senparc.AI.Kernel @@ -46,6 +46,7 @@ v0.15.3 添加 IWantToRun.SetPromptConfigParameter() 方法 v0.15.4 升级到 SK 1.10.0,为 ImportPluginFromPromptDirectory() 方法添加已有对象的检测 v0.16.1 添加 RunAsync(kernelFunction) 方法 + v0.17.0 支持 Ollama https://github.com/Senparc/Senparc.AI.Kernel Debug;Release;Test @@ -68,6 +69,8 @@ + + diff --git a/src/Senparc.AI/Entities/Keys/OllamaKeys.cs b/src/Senparc.AI/Entities/Keys/OllamaKeys.cs new file mode 100644 index 0000000..1e94b70 --- /dev/null +++ b/src/Senparc.AI/Entities/Keys/OllamaKeys.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Senparc.AI.Entities.Keys; + +namespace Senparc.AI +{ + public class OllamaKeys : BaseKeys + { + public string Endpoint { get; set; } + } +} diff --git a/src/Senparc.AI/Entities/SenparcAiSettingBase.cs b/src/Senparc.AI/Entities/SenparcAiSettingBase.cs index 083a1d3..e18afbf 100644 --- a/src/Senparc.AI/Entities/SenparcAiSettingBase.cs +++ b/src/Senparc.AI/Entities/SenparcAiSettingBase.cs @@ -67,6 +67,10 @@ public class SenparcAiSettingBase : ISenparcAiSetting /// public virtual bool UseFastAPI => AiPlatform == AiPlatform.FastAPI; + /// + /// 是否使用 Ollama + /// + public virtual bool Ollama => AiPlatform == AiPlatform.Ollama; /// /// AI 平台类型 @@ -81,6 +85,7 @@ public class SenparcAiSettingBase : ISenparcAiSetting public virtual HuggingFaceKeys HuggingFaceKeys { get; set; } public virtual FastAPIKeys FastAPIKeys { get; set; } + public virtual OllamaKeys OllamaKeys { get; set; } /// /// Azure OpenAI 或 OpenAI API Key @@ -91,7 +96,8 @@ public class SenparcAiSettingBase : ISenparcAiSetting AiPlatform.NeuCharAI => NeuCharAIKeys?.ApiKey, AiPlatform.AzureOpenAI => AzureOpenAIKeys?.ApiKey, AiPlatform.HuggingFace => "", - AiPlatform.FastAPI => FastAPIKeys?.ApiKey, + AiPlatform.FastAPI => FastAPIKeys.ApiKey, + AiPlatform.Ollama => "", _ => "" }; @@ -156,6 +162,11 @@ public class SenparcAiSettingBase : ISenparcAiSetting #endregion + #region Ollama + public string OllamaEndpoint => OllamaKeys?.Endpoint; + + #endregion + public virtual bool IsOpenAiKeysSetted => OpenAIKeys != null && !OpenAIKeys.ApiKey.IsNullOrEmpty(); @@ -219,6 +230,18 @@ public ISenparcAiSetting SetFastAPI(FastAPIKeys fastAPIKeys) return this; } + /// + /// 设置 Ollama + /// + /// + /// + public ISenparcAiSetting SetOllama(OllamaKeys ollamaAPIKeys) + { + this.AiPlatform = AiPlatform.Ollama; + this.OllamaKeys = ollamaAPIKeys; + return this; + } + /// /// 设置其他平台 /// diff --git a/src/Senparc.AI/Enums.cs b/src/Senparc.AI/Enums.cs index 27cd244..5d4316b 100644 --- a/src/Senparc.AI/Enums.cs +++ b/src/Senparc.AI/Enums.cs @@ -19,7 +19,8 @@ public enum AiPlatform AzureOpenAI = 16, HuggingFace = 32, //Oobabooga = 64,//未实现 - FastAPI = 128 + FastAPI = 128, + Ollama = 256, } /// diff --git a/src/Senparc.AI/Interfaces/ISenparcAiSetting.cs b/src/Senparc.AI/Interfaces/ISenparcAiSetting.cs index eb3fa02..a016962 100644 --- a/src/Senparc.AI/Interfaces/ISenparcAiSetting.cs +++ b/src/Senparc.AI/Interfaces/ISenparcAiSetting.cs @@ -42,6 +42,7 @@ public interface ISenparcAiSetting AiPlatform.NeuCharAI => NeuCharEndpoint, AiPlatform.HuggingFace => HuggingFaceEndpoint, AiPlatform.FastAPI => FastAPIEndpoint, + AiPlatform.Ollama => OllamaEndpoint, _ => throw new SenparcAiException($"未配置 {AiPlatform} 的 Endpoint 输出") }; @@ -64,6 +65,7 @@ public interface ISenparcAiSetting OpenAIKeys OpenAIKeys { get; set; } HuggingFaceKeys HuggingFaceKeys { get; set; } FastAPIKeys FastAPIKeys { get; set; } + OllamaKeys OllamaKeys { get; set; } /// /// Neuchar OpenAI 或 Azure OpenAI 或 OpenAI API Key @@ -122,13 +124,18 @@ public interface ISenparcAiSetting #endregion - #region FastAPI string FastAPIEndpoint { get; } #endregion + #region Ollama + + string OllamaEndpoint { get; } + + #endregion + /// /// OpenAIKeys 是否已经设置 /// @@ -142,7 +149,8 @@ public interface ISenparcAiSetting AiPlatform.NeuCharAI => NeuCharAIKeys.ModelName, AiPlatform.HuggingFace => HuggingFaceKeys.ModelName, AiPlatform.FastAPI => FastAPIKeys.ModelName, - _ => throw new SenparcAiException($"100-未配置 {AiPlatform} 的 ModelName") + AiPlatform.Ollama => OllamaKeys.ModelName, + _ => throw new SenparcAiException($"100-未配置 {AiPlatform} 的 Endpoint 输出") }; #pragma warning disable CS8603 // 可能返回 null 引用。 @@ -153,7 +161,8 @@ public interface ISenparcAiSetting AiPlatform.NeuCharAI => null, AiPlatform.HuggingFace => null, AiPlatform.FastAPI => null, - _ => throw new SenparcAiException($"未配置 {AiPlatform} 的 DeploymentName") + AiPlatform.Ollama => null, + _ => throw new SenparcAiException($"未配置 {AiPlatform} 的 DeploymentName 输出") }; #pragma warning restore CS8603 // 可能返回 null 引用。 diff --git a/src/Senparc.AI/Senparc.AI.csproj b/src/Senparc.AI/Senparc.AI.csproj index 6e42489..5679500 100644 --- a/src/Senparc.AI/Senparc.AI.csproj +++ b/src/Senparc.AI/Senparc.AI.csproj @@ -1,7 +1,7 @@ netstandard2.1 - 0.16.3-beta1 + 0.16.4 enable 10.0 Senparc.AI