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
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Threading;

namespace BotSharp.Abstraction.MLTasks;

public interface ITextEmbedding
{
int Dimension { get; }
float[] GetVector(string text);
List<float[]> GetVectors(List<string> texts);
Task<float[]> GetVectorAsync(string text);
Task<List<float[]>> GetVectorsAsync(List<string> texts);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public async Task Feed(KnowledgeFeedModel knowledge)
await db.CreateCollection(knowledge.AgentId, textEmbedding.Dimension);
foreach (var line in lines)
{
var vec = textEmbedding.GetVector(line);
var vec = await textEmbedding.GetVectorAsync(line);
await db.Upsert(knowledge.AgentId, idStart, vec, line);
idStart++;
Console.WriteLine($"Saved vector {idStart}/{lines.Count}: {line}\n");
Expand All @@ -41,7 +41,7 @@ public async Task Feed(KnowledgeFeedModel knowledge)
public async Task<string> GetKnowledges(KnowledgeRetrievalModel retrievalModel)
{
var textEmbedding = GetTextEmbedding();
var vector = textEmbedding.GetVector(retrievalModel.Question);
var vector = await textEmbedding.GetVectorAsync(retrievalModel.Question);

// Vector search
var result = await GetVectorDb().Search(retrievalModel.AgentId, vector, limit: 10);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ public TextEmbeddingProvider(IServiceProvider services, LlamaSharpSettings setti
_settings = settings;
}

public float[] GetVector(string text)
public Task<float[]> GetVectorAsync(string text)
{
if (_embedder == null)
{
var path = Path.Combine(_settings.ModelDir, _settings.DefaultModel);
_embedder = new LLamaEmbedder(new ModelParams(path));
}

return _embedder.GetEmbeddings(text);
return Task.FromResult(_embedder.GetEmbeddings(text));
}

public List<float[]> GetVectors(List<string> texts)
public Task<List<float[]>> GetVectorsAsync(List<string> texts)
{
throw new NotImplementedException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using FastText.NetWrapper;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace BotSharp.Plugin.MetaAI.Providers;

Expand All @@ -26,19 +27,19 @@ public fastTextEmbeddingProvider(fastTextSetting settings)

}

public float[] GetVector(string text)
public Task<float[]> GetVectorAsync(string text)
{
LoadModel();
return _fastText.GetSentenceVector(text);
return Task.FromResult(_fastText.GetSentenceVector(text));
}

public List<float[]> GetVectors(List<string> texts)
public async Task<List<float[]>> GetVectorsAsync(List<string> texts)
{
LoadModel();
var vectors = new List<float[]>();
for (int i = 0; i < texts.Count; i++)
{
vectors.Add(GetVector(texts[i]));
vectors.Add(await GetVectorAsync(texts[i]));
}
return vectors;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public class IntentClassifier
private string[] _labels;
public string[] Labels => _labels == null ? GetLabels() : _labels;

public IntentClassifier(IServiceProvider services,
ClassifierSetting settings,
public IntentClassifier(IServiceProvider services,
ClassifierSetting settings,
KnowledgeBaseSettings knowledgeBaseSettings,
ILogger logger)
{
Expand Down Expand Up @@ -140,7 +140,7 @@ public NDArray GetTextEmbedding(string text)
.FirstOrDefault(x => x.GetType().FullName.EndsWith(knowledgeSettings.TextEmbedding));

var x = np.zeros((1, embedding.Dimension), dtype: np.float32);
x[0] = embedding.GetVector(text);
x[0] = embedding.GetVectorAsync(text).GetAwaiter().GetResult();
return x;
}

Expand Down Expand Up @@ -178,7 +178,7 @@ public NDArray GetTextEmbedding(string text)
{
var texts = File.ReadAllLines(filePath, Encoding.UTF8).ToList();

vectorList.AddRange(vector.GetVectors(texts));
vectorList.AddRange(vector.GetVectorsAsync(texts).GetAwaiter().GetResult());
string fileName = Path.GetFileNameWithoutExtension(filePath);
labelList.AddRange(Enumerable.Repeat(fileName, texts.Count).ToList());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
Expand All @@ -10,8 +10,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SemanticKernel.Abstractions" Version="1.0.0-beta6" />
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.6.11" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.SemanticKernel.Abstractions" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace BotSharp.Plugin.SemanticKernel
/// </summary>
public class SemanticKernelChatCompletionProvider : IChatCompletion
{
private IKernel _kernel;
private Microsoft.SemanticKernel.AI.ChatCompletion.IChatCompletion _kernelChatCompletion;
private IServiceProvider _services;
private ITokenStatistics _tokenStatistics;
private string? _model = null;
Expand All @@ -29,14 +29,14 @@ public class SemanticKernelChatCompletionProvider : IChatCompletion
/// <summary>
/// Create a new instance of <see cref="SemanticKernelChatCompletionProvider"/>
/// </summary>
/// <param name="kernel"></param>
/// <param name="chatCompletion"></param>
/// <param name="services"></param>
/// <param name="tokenStatistics"></param>
public SemanticKernelChatCompletionProvider(IKernel kernel,
public SemanticKernelChatCompletionProvider(Microsoft.SemanticKernel.AI.ChatCompletion.IChatCompletion chatCompletion,
IServiceProvider services,
ITokenStatistics tokenStatistics)
{
this._kernel = kernel;
this._kernelChatCompletion = chatCompletion;
this._services = services;
this._tokenStatistics = tokenStatistics;
}
Expand All @@ -49,7 +49,7 @@ public RoleDialogModel GetChatCompletions(Agent agent, List<RoleDialogModel> con
Task.WaitAll(hooks.Select(hook =>
hook.BeforeGenerating(agent, conversations)).ToArray());

var completion = _kernel.GetService<Microsoft.SemanticKernel.AI.ChatCompletion.IChatCompletion>(_model);
var completion = this._kernelChatCompletion;

var agentService = _services.GetRequiredService<IAgentService>();
var instruction = agentService.RenderedInstruction(agent);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using BotSharp.Abstraction.VectorStorage;
using Microsoft.SemanticKernel.Memory;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace BotSharp.Plugin.SemanticKernel
{
internal class SemanticKernelMemoryStoreProvider : IVectorDb
{
private readonly IMemoryStore _memoryStore;

public SemanticKernelMemoryStoreProvider(IMemoryStore memoryStore)
{
this._memoryStore = memoryStore;
}
public async Task CreateCollection(string collectionName, int dim)
{
await _memoryStore.CreateCollectionAsync(collectionName);
}

public async Task<List<string>> GetCollections()
{
var result = new List<string>();
await foreach (var collection in _memoryStore.GetCollectionsAsync())
{
result.Add(collection);
}
return result;
}

public async Task<List<string>> Search(string collectionName, float[] vector, int limit = 5)
{
var results = _memoryStore.GetNearestMatchesAsync(collectionName, vector, limit);

var resultTexts = new List<string>();
await foreach (var (record, _) in results)
{
resultTexts.Add(record.Metadata.Text);
}

return resultTexts;

}

public async Task Upsert(string collectionName, int id, float[] vector, string text)
{
await _memoryStore.UpsertAsync(collectionName, MemoryRecord.LocalRecord(id.ToString(), text, null, vector));
}
}
}
32 changes: 30 additions & 2 deletions src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,47 @@
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Plugins;
using BotSharp.Abstraction.VectorStorage;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace BotSharp.Plugin.SemanticKernel
{
/// <summary>
/// Use Semantic Kernel as BotSharp plugin
/// </summary>
public class SemanticKernelPlugin : IBotSharpPlugin
{
/// <inheritdoc/>
public string Name => "Semantic Kernel";

/// <inheritdoc/>
public string Description => "Semantic Kernel Service";

/// <inheritdoc/>
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
services.AddScoped<ITextCompletion, SemanticKernelTextCompletionProvider>();
services.AddScoped<IChatCompletion, SemanticKernelChatCompletionProvider>();

var provider = services.BuildServiceProvider().CreateScope().ServiceProvider;

if (provider.GetService<Microsoft.SemanticKernel.AI.TextCompletion.ITextCompletion>() != null)
{
services.AddScoped<ITextCompletion, SemanticKernelTextCompletionProvider>();
}

if (provider.GetService<Microsoft.SemanticKernel.AI.ChatCompletion.IChatCompletion>() != null)
{
services.AddScoped<IChatCompletion, SemanticKernelChatCompletionProvider>();
}

if (provider.GetService<Microsoft.SemanticKernel.Memory.IMemoryStore>() != null)
{
services.AddScoped<IVectorDb, SemanticKernelMemoryStoreProvider>();
}

if (provider.GetService<Microsoft.SemanticKernel.AI.Embeddings.ITextEmbeddingGeneration>() != null)
{
services.AddScoped<ITextEmbedding, SemanticKernelTextEmbeddingProvider>();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace BotSharp.Plugin.SemanticKernel
/// </summary>
public class SemanticKernelTextCompletionProvider : Abstraction.MLTasks.ITextCompletion
{
private readonly IKernel _kernel;
private readonly Microsoft.SemanticKernel.AI.TextCompletion.ITextCompletion _kernelTextCompletion;
private readonly IServiceProvider _services;
private readonly ITokenStatistics _tokenStatistics;
private string? _model = null;
Expand All @@ -30,16 +30,14 @@ public class SemanticKernelTextCompletionProvider : Abstraction.MLTasks.ITextCom
/// <summary>
/// Create a new instance of <see cref="SemanticKernelTextCompletionProvider"/>
/// </summary>
/// <param name="kernel"></param>
/// <param name="textCompletion"></param>
/// <param name="services"></param>
/// <param name="tokenStatistics"></param>
public SemanticKernelTextCompletionProvider(IKernel kernel,
public SemanticKernelTextCompletionProvider(Microsoft.SemanticKernel.AI.TextCompletion.ITextCompletion textCompletion,
IServiceProvider services,
ITokenStatistics tokenStatistics)
{
Requires.NotNull(kernel, nameof(IKernel));

this._kernel = kernel;
this._kernelTextCompletion = textCompletion;
this._services = services;
this._tokenStatistics = tokenStatistics;
}
Expand All @@ -61,7 +59,7 @@ public async Task<string> GetCompletion(string text, string agentId, string mess
Task.WaitAll(hooks.Select(hook =>
hook.BeforeGenerating(agent, new List<RoleDialogModel> { userMessage })).ToArray());

var completion = _kernel.GetService<Microsoft.SemanticKernel.AI.TextCompletion.ITextCompletion>(_model);
var completion = this._kernelTextCompletion;
_tokenStatistics.StartTimer();
var result = await completion.CompleteAsync(text);
_tokenStatistics.StopTimer();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using BotSharp.Abstraction.MLTasks;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.AI.Embeddings;
using Microsoft.SemanticKernel.Memory;
using Microsoft.SemanticKernel.Plugins.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BotSharp.Plugin.SemanticKernel
{
/// <summary>
/// Use Semantic Kernel Memory as text embedding provider
/// </summary>
public class SemanticKernelTextEmbeddingProvider : ITextEmbedding
{
private readonly ITextEmbeddingGeneration _embedding;
private readonly IConfiguration _configuration;

/// <summary>
/// Constructor of <see cref="SemanticKernelTextEmbeddingProvider"/>
/// </summary>
public SemanticKernelTextEmbeddingProvider(ITextEmbeddingGeneration embedding, IConfiguration configuration)
{
this._embedding = embedding;
this._configuration = configuration;
this.Dimension = configuration.GetValue<int>("SemanticKernel:Dimension");
}

/// <inheritdoc/>
public int Dimension { get; set; }

/// <inheritdoc/>
public async Task<float[]> GetVectorAsync(string text)
{
return (await this._embedding.GenerateEmbeddingAsync(text)).ToArray();
}

/// <inheritdoc/>
public async Task<List<float[]>> GetVectorsAsync(List<string> texts)
{
var embeddings = await this._embedding.GenerateEmbeddingsAsync(texts);
return embeddings.Select(_ => _.ToArray())
.ToList();
}
}
}
2 changes: 2 additions & 0 deletions src/Plugins/BotSharp.Plugin.SemanticKernel/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Semantic Kernel For BotSharp

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public ResultHelper(string response)
_response = response;
}

public async Task<ChatMessageBase> GetChatMessageAsync(CancellationToken cancellationToken = default)
public async Task<ChatMessage> GetChatMessageAsync(CancellationToken cancellationToken = default)
{
return await Task.FromResult(new MockModelResult(_response));
}
Expand All @@ -25,7 +25,7 @@ public Task<string> GetCompletionAsync(CancellationToken cancellationToken = def
return Task.FromResult(_response);
}

public class MockModelResult : ChatMessageBase
public class MockModelResult : ChatMessage
{
public MockModelResult(string content) : base(AuthorRole.Assistant, content, null)
{
Expand Down
Loading