Abstract Vector database.

This commit is contained in:
Haiping Chen 2023-06-17 21:56:22 -05:00
parent dcffdd076d
commit 43dfc9b642
19 changed files with 215 additions and 72 deletions

View file

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>10</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Qdrant.Client" Version="0.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\src\Infrastructure\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,64 @@
using BotSharp.Abstraction.Knowledges;
using QdrantCSharp;
using QdrantCSharp.Enums;
using QdrantCSharp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BotSharp.Plugin.Qdrant;
public class QdrantDb : IVectorDb
{
private readonly QdrantHttpClient _client;
private readonly QdrantSetting _setting;
public QdrantDb(QdrantSetting setting)
{
_setting = setting;
_client = new QdrantHttpClient
(
url: _setting.Url,
apiKey: _setting.ApiKey
);
}
public async Task<List<string>> GetCollections()
{
// List all the collections
var collections = await _client.GetCollections();
return collections.Result.Collections.Select(x => x.Name).ToList();
}
public async Task CreateCollection(string collectionName)
{
var collections = await GetCollections();
if (!collections.Contains(collectionName))
{
// Create a new collection
await _client.CreateCollection(collectionName, new VectorParams(size: 300, distance: Distance.COSINE));
}
// Get collection info
var collectionInfo = await _client.GetCollection(collectionName);
if(collectionInfo == null)
{
throw new Exception($"Create {collectionName} failed.");
}
}
public async Task Upsert(string collectionName, int id, float[] vector)
{
// Insert vectors
await _client.Upsert(collectionName, points: new List<PointStruct>
{
new PointStruct(id: id, vector: vector)
});
}
public async Task<List<int>> Search(string collectionName, float[] vector, int limit = 10)
{
var result = await _client.Search(collectionName, vector, limit);
return result.Result.Select(x => x.Id).ToList();
}
}

View file

@ -0,0 +1,18 @@
using BotSharp.Abstraction.Knowledges;
using BotSharp.Abstraction.Plugins;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace BotSharp.Plugin.Qdrant;
public class QdrantPlugin : IBotSharpPlugin
{
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
var settings = new QdrantSetting();
config.Bind("Qdrant", settings);
services.AddSingleton(x => settings);
services.AddSingleton<IVectorDb, QdrantDb>();
}
}

View file

@ -0,0 +1,7 @@
namespace BotSharp.Plugin.Qdrant;
public class QdrantSetting
{
public string Url { get; set; }
public string ApiKey { get; set; }
}

View file

@ -35,6 +35,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "tests\UnitTest\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.MetaAI", "src\Plugins\BotSharp.Plugin.MetaAI\BotSharp.Plugin.MetaAI.csproj", "{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Databases", "Databases", "{53E7CD86-0D19-40D9-A0FA-AB4613837E89}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.Qdrant", "BotSharp.Plugin.Qdrant\BotSharp.Plugin.Qdrant.csproj", "{9686D771-CA9F-41B0-8508-C5B4E6E457A3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -123,6 +127,14 @@ Global
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Release|Any CPU.Build.0 = Release|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Release|x64.ActiveCfg = Release|Any CPU
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7}.Release|x64.Build.0 = Release|Any CPU
{9686D771-CA9F-41B0-8508-C5B4E6E457A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9686D771-CA9F-41B0-8508-C5B4E6E457A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9686D771-CA9F-41B0-8508-C5B4E6E457A3}.Debug|x64.ActiveCfg = Debug|Any CPU
{9686D771-CA9F-41B0-8508-C5B4E6E457A3}.Debug|x64.Build.0 = Debug|Any CPU
{9686D771-CA9F-41B0-8508-C5B4E6E457A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9686D771-CA9F-41B0-8508-C5B4E6E457A3}.Release|Any CPU.Build.0 = Release|Any CPU
{9686D771-CA9F-41B0-8508-C5B4E6E457A3}.Release|x64.ActiveCfg = Release|Any CPU
{9686D771-CA9F-41B0-8508-C5B4E6E457A3}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -140,6 +152,8 @@ Global
{2323A7A3-E938-488D-A57E-638638054BC4} = {64264688-0F5C-4AB0-8F2B-B59B717CCE00}
{0B6E1D7F-ABDE-47F6-8B2D-4483C2CFF2D6} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
{6D8D18A9-86D7-455E-81EC-9682C30AB7E7} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
{53E7CD86-0D19-40D9-A0FA-AB4613837E89} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C}
{9686D771-CA9F-41B0-8508-C5B4E6E457A3} = {53E7CD86-0D19-40D9-A0FA-AB4613837E89}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}

View file

@ -1,5 +0,0 @@
namespace BotSharp.Abstraction.Knowledges;
public interface IKnowledgeBase
{
}

View file

@ -0,0 +1,9 @@
namespace BotSharp.Abstraction.Knowledges;
public interface IVectorDb
{
Task<List<string>> GetCollections();
Task CreateCollection(string collectionName);
Task Upsert(string collectionName, int id, float[] vector);
Task<List<int>> Search(string collectionName, float[] vector, int limit = 10);
}

View file

@ -67,7 +67,6 @@
<PackageReference Include="LLamaSharp" Version="0.3.0" />
<PackageReference Include="LLamaSharp.Backend.Cuda11" Version="0.3.0" />
<PackageReference Include="PdfPig" Version="0.1.8" />
<PackageReference Include="Qdrant.Client" Version="0.1.0" />
<PackageReference Include="TensorFlow.Keras" Version="0.10.5" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
</ItemGroup>

View file

@ -1,15 +1,3 @@
using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
using BotSharp.Abstraction.Knowledges;
using BotSharp.Abstraction.Users;
using BotSharp.Core.Agents.Services;
using BotSharp.Core.Conversations.Services;
using BotSharp.Core.Infrastructures;
using BotSharp.Core.Knowledges.Services;
using BotSharp.Core.Plugins;
using BotSharp.Core.Users.Services;
using BotSharp.Plugins.LLamaSharp;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;

View file

@ -1,7 +1,24 @@
using BotSharp.Abstraction.Knowledges;
namespace BotSharp.Core.Knowledges;
public class KnowledgeBase : IKnowledgeBase
public class KnowledgeBase : IVectorDb
{
public Task CreateCollection(string collectionName)
{
throw new NotImplementedException();
}
public Task<List<string>> GetCollections()
{
throw new NotImplementedException();
}
public Task<List<int>> Search(string collectionName, float[] vector, int limit = 10)
{
throw new NotImplementedException();
}
public Task Upsert(string collectionName, int id, float[] vector)
{
throw new NotImplementedException();
}
}

View file

@ -1,8 +1,5 @@
using BotSharp.Abstraction.Knowledges;
using BotSharp.Abstraction.Knowledges.Models;
using QdrantCSharp.Enums;
using QdrantCSharp.Models;
using QdrantCSharp;
using System.IO;
using System.Collections;
using BotSharp.Abstraction.MLTasks;
@ -13,37 +10,19 @@ public class KnowledgeService : IKnowledgeService
{
private readonly ITextEmbedding _textEmbedding;
private readonly ITextCompletion _textCompletion;
private readonly IVectorDb _db;
string collectionName = "my_collection";
public KnowledgeService(ITextEmbedding textEmbedding, ITextCompletion textCompletion)
public KnowledgeService(ITextEmbedding textEmbedding,
ITextCompletion textCompletion,
IVectorDb db)
{
_textEmbedding = textEmbedding;
_textCompletion = textCompletion;
}
public QdrantHttpClient GetClient()
{
var client = new QdrantHttpClient
(
url: "",
apiKey: ""
);
return client;
_db = db;
}
public async Task Feed(KnowledgeFeedModel knowledge)
{
var client = GetClient();
// List all the collections
var collections = await client.GetCollections();
if (!collections.Result.Collections.Select(x => x.Name).Contains(collectionName))
{
// Create a new collection
await client.CreateCollection(collectionName, new VectorParams(size: 300, distance: Distance.COSINE));
}
// Get collection info
var collectionInfo = await client.GetCollection(collectionName);
var idStart = 0;
var lines = knowledge.Content.Split(". ");
lines = lines.Select((x, i) => $"{i+1} {x}").ToArray();
@ -52,33 +31,22 @@ public class KnowledgeService : IKnowledgeService
foreach (var line in lines)
{
idStart++;
// Insert vectors
/*await client.Upsert(collectionName, points: new List<PointStruct>
{
new PointStruct(id: idStart, vector: _textEmbedding.GetVector(line))
});*/
await _db.Upsert(collectionName, idStart, _textEmbedding.GetVector(line));
}
}
public async Task<string> GetAnswer(string question)
{
var client = GetClient();
var vector = _textEmbedding.GetVector(question);
// Vector search
var result = await client.Search
(
collectionName,
vector,
limit: 10
);
var result = await _db.Search(collectionName, vector);
var prompt = "";
var lines = File.ReadAllLines(collectionName + ".txt");
foreach (var r in result.Result)
foreach (var r in result)
{
prompt += lines[r.Id - 1] + "\n";
prompt += lines[r - 1] + "\n";
}
prompt += "###\r\n";

View file

@ -1,5 +1,4 @@
using BotSharp.Abstraction.ApiAdapters;
using BotSharp.Abstraction.Users;
using BotSharp.Abstraction.Users.Models;
using BotSharp.Core.Users.ViewModels;
using Microsoft.AspNetCore.Authorization;

View file

@ -6,7 +6,17 @@ global using System.Linq;
global using Microsoft.Extensions.DependencyInjection;
global using BotSharp.Abstraction.Plugins;
global using EntityFrameworkCore.BootKit;
global using BotSharp.Abstraction;
global using BotSharp.Abstraction.Agents;
global using BotSharp.Abstraction.Conversations;
global using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
global using BotSharp.Abstraction.Knowledges;
global using BotSharp.Abstraction.Users;
global using BotSharp.Core.Repository;
global using BotSharp.Core.Repository.Abstraction;
global using BotSharp.Core.Repository.DbTables;
global using BotSharp.Core.Repository.DbTables;
global using BotSharp.Core.Agents.Services;
global using BotSharp.Core.Conversations.Services;
global using BotSharp.Core.Infrastructures;
global using BotSharp.Core.Knowledges.Services;
global using BotSharp.Core.Plugins;
global using BotSharp.Core.Users.Services;

View file

@ -6,17 +6,12 @@
<LangVersion>10</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="C:\Users\haipi\.nuget\packages\fasttext.netwrapper\1.3.0\contentFiles\any\any\fasttext.dll" />
<None Remove="C:\Users\haipi\.nuget\packages\fasttext.netwrapper\1.3.0\contentFiles\any\any\libfasttext.dylib" />
<None Remove="C:\Users\haipi\.nuget\packages\fasttext.netwrapper\1.3.0\contentFiles\any\any\libfasttext.so" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Infrastructure\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FaissMask" Version="0.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="FastText.NetWrapper" Version="1.3.0" />
</ItemGroup>

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Knowledges;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Plugins;
using BotSharp.Plugin.MetaAI.Providers;
@ -18,5 +19,6 @@ public class MetaAiPlugin : IBotSharpPlugin
services.AddSingleton(x => settings.fastText);
services.AddSingleton<ITextEmbedding, fastTextEmbeddingProvider>();
services.AddSingleton<IVectorDb, FaissDb>();
}
}

View file

@ -0,0 +1,29 @@
using BotSharp.Abstraction.Knowledges;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace BotSharp.Plugin.MetaAI.Providers;
public class FaissDb : IVectorDb
{
public Task CreateCollection(string collectionName)
{
throw new NotImplementedException();
}
public Task<List<string>> GetCollections()
{
throw new NotImplementedException();
}
public Task<List<int>> Search(string collectionName, float[] vector, int limit = 10)
{
throw new NotImplementedException();
}
public Task Upsert(string collectionName, int id, float[] vector)
{
throw new NotImplementedException();
}
}

View file

@ -1,6 +1,7 @@
using BotSharp.Abstraction.MLTasks;
using BotSharp.Plugin.MetaAI.Settings;
using FastText.NetWrapper;
using System.IO;
namespace BotSharp.Plugin.MetaAI.Providers;
@ -14,6 +15,11 @@ public class fastTextEmbeddingProvider : ITextEmbedding
_settings = settings;
_fastText = new FastTextWrapper();
if (!File.Exists(settings.ModelPath))
{
throw new FileNotFoundException($"Can't load pre-trained word vectors from {settings.ModelPath}.\n Try to download from https://fasttext.cc/docs/en/english-vectors.html.");
}
if (!_fastText.IsModelReady())
{
_fastText.LoadModel(settings.ModelPath);

View file

@ -27,6 +27,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\BotSharp.Plugin.Qdrant\BotSharp.Plugin.Qdrant.csproj" />
<ProjectReference Include="..\Infrastructure\BotSharp.Core\BotSharp.Core.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.AzureOpenAI\BotSharp.Plugin.AzureOpenAI.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.ChatbotUI\BotSharp.Plugin.ChatbotUI.csproj" />

View file

@ -48,11 +48,17 @@
"Assemblies": [ "BotSharp.Core" ]
},
"Qdrant": {
"Url": "",
"ApiKey": ""
},
"PluginLoader": {
"Assemblies": [
"BotSharp.Core",
"BotSharp.Plugin.AzureOpenAI",
"BotSharp.Plugin.MetaAI"
"BotSharp.Plugin.MetaAI",
"BotSharp.Plugin.Qdrant"
]
}
}