update SK Provider and UnitTest

This commit is contained in:
xbotter 2023-11-13 23:11:49 +08:00
parent 83e3c38999
commit 0dbecdf209
No known key found for this signature in database
GPG key ID: D299220A7FE5CF1E
9 changed files with 104 additions and 22 deletions

View file

@ -3,10 +3,14 @@
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>$(LangVersion)</LangVersion>
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SemanticKernel" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.SemanticKernel.Abstractions" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.6.11" />
</ItemGroup>
@ -15,7 +19,7 @@
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="BotSharp.Plugin.SemanticKernel.UnitTests"/>
<InternalsVisibleTo Include="BotSharp.Plugin.SemanticKernel.UnitTests" />
</ItemGroup>
</Project>

View file

@ -20,7 +20,7 @@ namespace BotSharp.Plugin.SemanticKernel
private ITokenStatistics _tokenStatistics;
private string? _model = null;
public string Provider => throw new NotImplementedException();
public string Provider => "semantic-kernel";
public SemanticKernelChatCompletionProvider(IKernel kernel,
IServiceProvider services,
@ -92,9 +92,11 @@ namespace BotSharp.Plugin.SemanticKernel
throw new NotImplementedException();
}
public void SetModelName(string model)
{
this._model = model;
if (!string.IsNullOrWhiteSpace(model))
this._model = model;
}
}
}

View file

@ -14,6 +14,9 @@ using System.Threading.Tasks;
namespace BotSharp.Plugin.SemanticKernel
{
/// <summary>
/// User Semantic Kernel as text completion provider
/// </summary>
public class SemanticKernelTextCompletionProvider : Abstraction.MLTasks.ITextCompletion
{
private readonly IKernel _kernel;
@ -21,19 +24,21 @@ namespace BotSharp.Plugin.SemanticKernel
private readonly ITokenStatistics _tokenStatistics;
private string? _model = null;
// <inheritdoc/>
public string Provider => "semantic-kernel";
public SemanticKernelTextCompletionProvider(IKernel kernel,
IServiceProvider services,
ITokenStatistics tokenStatistics)
{
Requires.NotNull(kernel, nameof(kernel));
Requires.NotNull(kernel, nameof(IKernel));
this._kernel = kernel;
this._services = services;
this._tokenStatistics = tokenStatistics;
}
/// <inheritdoc/>
public async Task<string> GetCompletion(string text, string agentId, string messageId)
{
var hooks = _services.GetServices<IContentGeneratingHook>().ToList();
@ -65,9 +70,11 @@ namespace BotSharp.Plugin.SemanticKernel
return result;
}
/// <inheritdoc/>
public void SetModelName(string model)
{
this._model = model;
if (!string.IsNullOrWhiteSpace(model))
this._model = model;
}
}
}

View file

@ -12,6 +12,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.0.0-beta6" />
<PackageReference Include="Moq" Version="4.20.69" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">

View file

@ -1,14 +1,15 @@
using Microsoft.SemanticKernel.AI.ChatCompletion;
using Microsoft.SemanticKernel.AI.TextCompletion;
using Microsoft.SemanticKernel.Orchestration;
namespace BotSharp.Plugin.SemanticKernel.UnitTests.Helpers
{
public class MockChatResult : IChatResult
public class ResultHelper : IChatResult, ITextResult
{
public ModelResult ModelResult { get; set; }
private string _response;
public MockChatResult(string response)
public ResultHelper(string response)
{
ModelResult = new ModelResult(response);
_response = response;
@ -19,6 +20,11 @@ namespace BotSharp.Plugin.SemanticKernel.UnitTests.Helpers
return await Task.FromResult(new MockModelResult(_response));
}
public Task<string> GetCompletionAsync(CancellationToken cancellationToken = default)
{
return Task.FromResult(_response);
}
public class MockModelResult : ChatMessageBase
{
public MockModelResult(string content) : base(AuthorRole.Assistant, content, null)

View file

@ -0,0 +1,47 @@
using Microsoft.SemanticKernel.AI;
using Microsoft.SemanticKernel.AI.ChatCompletion;
using Microsoft.SemanticKernel.AI.TextCompletion;
using Microsoft.SemanticKernel.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BotSharp.Plugin.SemanticKernel.UnitTests.Helpers
{
internal class SemanticKernelHelper : IChatCompletion, ITextCompletion, IAIService
{
private readonly string _excepted;
public SemanticKernelHelper(string excepted)
{
this._excepted = excepted;
}
public ChatHistory CreateNewChat(string? instructions = null)
{
return new ChatHistory();
}
public Task<IReadOnlyList<IChatResult>> GetChatCompletionsAsync(ChatHistory chat, AIRequestSettings? requestSettings = null, CancellationToken cancellationToken = default)
{
return Task.FromResult<IReadOnlyList<IChatResult>>( new List<IChatResult> { new ResultHelper(_excepted) });
}
public Task<IReadOnlyList<ITextResult>> GetCompletionsAsync(string text, AIRequestSettings? requestSettings = null, CancellationToken cancellationToken = default)
{
return Task.FromResult<IReadOnlyList<ITextResult>>(new List<ITextResult> { new ResultHelper(_excepted) });
}
public IAsyncEnumerable<IChatStreamingResult> GetStreamingChatCompletionsAsync(ChatHistory chat, AIRequestSettings? requestSettings = null, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public IAsyncEnumerable<ITextStreamingResult> GetStreamingCompletionsAsync(string text, AIRequestSettings? requestSettings = null, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
}
}

View file

@ -18,6 +18,7 @@ using BotSharp.Abstraction.Models;
using Microsoft.SemanticKernel.AI.ChatCompletion;
using Microsoft.SemanticKernel.AI;
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.AzureSdk;
using BotSharp.Plugin.SemanticKernel.UnitTests.Helpers;
namespace BotSharp.Plugin.SemanticKernel.Tests
{
@ -46,13 +47,20 @@ namespace BotSharp.Plugin.SemanticKernel.Tests
new RoleDialogModel(AgentRole.User, "Hello")
};
_servicesMock.Setup(x => x.GetService(typeof(IEnumerable<IContentGeneratingHook>)))
.Returns(new List<IContentGeneratingHook>());
var agentService = new Mock<IAgentService>();
agentService.Setup(x => x.RenderedInstruction(agent)).Returns("");
_servicesMock.Setup(x => x.GetService(typeof(IAgentService)))
.Returns(agentService.Object);
var chatHistoryMock = new Mock<ChatHistory>();
var chatCompletionMock = new Mock<Microsoft.SemanticKernel.AI.ChatCompletion.IChatCompletion>();
chatCompletionMock.Setup(x => x.CreateNewChat(It.IsAny<string>())).Returns(chatHistoryMock.Object);
chatCompletionMock.Setup(x => x.GetChatCompletionsAsync(chatHistoryMock.Object, It.IsAny<AIRequestSettings>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new List<IChatResult>
{
new MockChatResult("How can I help you?")
new ResultHelper("How can I help you?")
});
_kernelMock.Setup(x => x.GetService<Microsoft.SemanticKernel.AI.ChatCompletion.IChatCompletion>(null)).Returns(chatCompletionMock.Object);
@ -64,5 +72,5 @@ namespace BotSharp.Plugin.SemanticKernel.Tests
Assert.IsType<RoleDialogModel>(result);
}
}
}

View file

@ -1,6 +1,9 @@
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.MLTasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Moq;
namespace BotSharp.Plugin.SemanticKernel.Tests
{
@ -12,6 +15,14 @@ namespace BotSharp.Plugin.SemanticKernel.Tests
var services = new ServiceCollection();
var config = new ConfigurationBuilder().Build();
var plugin = new SemanticKernelPlugin();
services.AddScoped(x =>
{
return new KernelBuilder()
.WithAzureOpenAIChatCompletionService("test", "test", "test")
.Build();
});
services.AddScoped<ITokenStatistics>(x=> Mock.Of<ITokenStatistics>());
plugin.RegisterDI(services, config);

View file

@ -1,5 +1,4 @@
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Plugin.SemanticKernel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
@ -15,18 +14,18 @@ using System;
using System.Linq;
using Microsoft;
using Microsoft.SemanticKernel.AI;
using BotSharp.Plugin.SemanticKernel.UnitTests.Helpers;
namespace BotSharp.Plugin.SemanticKernel.Tests
{
public class SemanticKernelTextCompletionProviderTests
{
private readonly Mock<IKernel> _kernel;
private readonly IServiceProvider _services;
private readonly ITokenStatistics _tokenStatistics;
public SemanticKernelTextCompletionProviderTests()
{
_kernel = new Mock<IKernel>();
_services = new ServiceCollection().BuildServiceProvider();
_tokenStatistics = Mock.Of<ITokenStatistics>();
}
@ -35,22 +34,19 @@ namespace BotSharp.Plugin.SemanticKernel.Tests
public async Task GetCompletion_ReturnsExpectedResult()
{
// Arrange
var provider = new SemanticKernelTextCompletionProvider(_kernel.Object, _services, _tokenStatistics);
var text = "Hello";
var agentId = "agent1";
var messageId = "message1";
var expected = "Hello, world!";
var mockCompletion = new Mock<Microsoft.SemanticKernel.AI.TextCompletion.ITextCompletion>();
mockCompletion.Setup(c => c.CompleteAsync(text, It.IsAny<AIRequestSettings>(), It.IsAny<CancellationToken>())).ReturnsAsync(expected);
_kernel.Setup(c => c.GetService<Microsoft.SemanticKernel.AI.TextCompletion.ITextCompletion>(It.IsAny<string>())).Returns(mockCompletion.Object);
var _kernel = new KernelBuilder()
.WithAIService<ITextCompletion>("", new SemanticKernelHelper(expected))
.Build();
var provider = new SemanticKernelTextCompletionProvider(_kernel, _services, _tokenStatistics);
// Act
var result = await provider.GetCompletion(text, agentId, messageId);
var result = await provider.GetCompletion(text, "agent1", "message1");
// Assert
Assert.Equal(expected, result);
mockCompletion.Verify(c => c.CompleteAsync(text, null, default(CancellationToken)), Times.Once);
}
}