Skip to content

Commit

Permalink
feat: Added ability to use all SemanticKernel connectors databases (#421
Browse files Browse the repository at this point in the history
)

* refactoring semantic kernel connectors databases

* refactor: Renamed Connectors to SemanticKernel.

* style: Format .csproj.

---------

Co-authored-by: HavenDV <[email protected]>
  • Loading branch information
danijerez and HavenDV authored Aug 4, 2024
1 parent 385ec29 commit 937cbe1
Show file tree
Hide file tree
Showing 23 changed files with 347 additions and 335 deletions.
32 changes: 20 additions & 12 deletions LangChain.sln
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
.github\dependabot.yml = .github\dependabot.yml
.github\workflows\dotnet.yml = .github\workflows\dotnet.yml
.github\workflows\github-releases-to-discord.yml = .github\workflows\github-releases-to-discord.yml
.github\workflows\mkdocs.yml = .github\workflows\mkdocs.yml
.github\workflows\open-router.yml = .github\workflows\open-router.yml
.github\workflows\pull-request.yml = .github\workflows\pull-request.yml
.github\workflows\together.yml = .github\workflows\together.yml
.github\workflows\mkdocs.yml = .github\workflows\mkdocs.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Providers", "Providers", "{E2B9833C-0397-4FAF-A3A8-116E58749750}"
Expand Down Expand Up @@ -345,33 +345,35 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Google.
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Fireworks", "Fireworks", "{2DFDBF23-50E2-41DB-B2D5-CB2CC46D8C3B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LangChain.Providers.Fireworks", "src\Providers\Fireworks\src\LangChain.Providers.Fireworks.csproj", "{90BC5243-139D-4CB2-8B68-3794070C1955}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Fireworks", "src\Providers\Fireworks\src\LangChain.Providers.Fireworks.csproj", "{90BC5243-139D-4CB2-8B68-3794070C1955}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{20D58A8D-DB93-47AC-956B-9EB89EA75928}"
ProjectSection(SolutionItems) = preProject
mkdocs.yml = mkdocs.yml
docs\index.md = docs\index.md
docs\css\extra.css = docs\css\extra.css
docs\media\icon128.png = docs\media\icon128.png
docs\index.md = docs\index.md
mkdocs.yml = mkdocs.yml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenerateDocs", "src\Helpers\GenerateDocs\GenerateDocs.csproj", "{EFFC19CE-9519-492D-A5CC-E1C90EB410E0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenerateDocs", "src\Helpers\GenerateDocs\GenerateDocs.csproj", "{EFFC19CE-9519-492D-A5CC-E1C90EB410E0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LangChain.Providers.Generators", "src\Providers\Abstractions\generators\LangChain.Providers.Generators\LangChain.Providers.Generators.csproj", "{FCD9A4CB-C70A-499F-8179-A50836B809D6}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Generators", "src\Providers\Abstractions\generators\LangChain.Providers.Generators\LangChain.Providers.Generators.csproj", "{FCD9A4CB-C70A-499F-8179-A50836B809D6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LangChain.Providers.Generators.SnapshotTests", "src\Providers\Abstractions\test\LangChain.Providers.Generators.SnapshotTests\LangChain.Providers.Generators.SnapshotTests.csproj", "{F78D9189-24B8-4403-89D2-7FBBB5D83556}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Generators.SnapshotTests", "src\Providers\Abstractions\test\LangChain.Providers.Generators.SnapshotTests\LangChain.Providers.Generators.SnapshotTests.csproj", "{F78D9189-24B8-4403-89D2-7FBBB5D83556}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LangChain.Providers.Anthropic", "src\Providers\Anthropic\src\LangChain.Providers.Anthropic.csproj", "{BD9AF0B6-15C5-4365-9B78-6EF0C9CC3E2F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Providers.Anthropic", "src\Providers\Anthropic\src\LangChain.Providers.Anthropic.csproj", "{BD9AF0B6-15C5-4365-9B78-6EF0C9CC3E2F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Elasticsearch", "Elasticsearch", "{3FCA798D-2CBE-41E7-B5F7-65B4AF6EBC8A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LangChain.Databases.Elasticsearch", "src\Databases\Elasticsearch\src\LangChain.Databases.Elasticsearch.csproj", "{6C053245-EB8B-4C98-85AC-B00BA222ABBB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Milvus", "Milvus", "{911357BA-532A-43B8-9EA8-B32C0C2273EC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Databases.Elasticsearch", "src\Databases\Elasticsearch\src\LangChain.Databases.Elasticsearch.csproj", "{6C053245-EB8B-4C98-85AC-B00BA222ABBB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Milvus", "Milvus", "{3CB20A37-5E76-40D1-91F6-47C96FA06AE5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LangChain.Databases.Milvus", "src\Databases\Milvus\src\LangChain.Databases.Milvus.csproj", "{259C2E5D-6AA9-4384-8F55-24C4D4F1CF18}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChain.Databases.Milvus", "src\Databases\Milvus\src\LangChain.Databases.Milvus.csproj", "{259C2E5D-6AA9-4384-8F55-24C4D4F1CF18}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SemanticKernel", "SemanticKernel", "{3F426832-2CF3-4921-819F-13342F69A6E6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LangChain.Databases.SemanticKernel", "src\Databases\SemanticKernel\src\LangChain.Databases.SemanticKernel.csproj", "{D1D3D997-AD91-45E6-9610-8C5080750CB0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -735,6 +737,10 @@ Global
{259C2E5D-6AA9-4384-8F55-24C4D4F1CF18}.Debug|Any CPU.Build.0 = Debug|Any CPU
{259C2E5D-6AA9-4384-8F55-24C4D4F1CF18}.Release|Any CPU.ActiveCfg = Release|Any CPU
{259C2E5D-6AA9-4384-8F55-24C4D4F1CF18}.Release|Any CPU.Build.0 = Release|Any CPU
{D1D3D997-AD91-45E6-9610-8C5080750CB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1D3D997-AD91-45E6-9610-8C5080750CB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1D3D997-AD91-45E6-9610-8C5080750CB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1D3D997-AD91-45E6-9610-8C5080750CB0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -881,6 +887,8 @@ Global
{6C053245-EB8B-4C98-85AC-B00BA222ABBB} = {3FCA798D-2CBE-41E7-B5F7-65B4AF6EBC8A}
{3CB20A37-5E76-40D1-91F6-47C96FA06AE5} = {A098FF69-D8B5-4B2B-83D5-F777D3817F15}
{259C2E5D-6AA9-4384-8F55-24C4D4F1CF18} = {3CB20A37-5E76-40D1-91F6-47C96FA06AE5}
{3F426832-2CF3-4921-819F-13342F69A6E6} = {A098FF69-D8B5-4B2B-83D5-F777D3817F15}
{D1D3D997-AD91-45E6-9610-8C5080750CB0} = {3F426832-2CF3-4921-819F-13342F69A6E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5C00D0F1-6138-4ED9-846B-97E43D6DFF1C}
Expand Down
61 changes: 3 additions & 58 deletions src/Databases/DuckDb/src/DuckDbVectorCollection.cs
Original file line number Diff line number Diff line change
@@ -1,65 +1,10 @@
using Microsoft.SemanticKernel.Connectors.DuckDB;
using Microsoft.SemanticKernel.Memory;
using LangChain.Databases.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.DuckDB;

namespace LangChain.Databases.DuckDb
{
public class DuckDbVectorCollection(
DuckDBMemoryStore store,
string name = VectorCollection.DefaultName,
string? id = null) : VectorCollection(name, id), IVectorCollection
{
public async Task<IReadOnlyCollection<string>> AddAsync(IReadOnlyCollection<Vector> items, CancellationToken cancellationToken = default)
{
items = items ?? throw new ArgumentNullException(nameof(items));

List<string> list = [];
foreach (var item in items)
{
string? metadata = null;
//TODO: review way to map metadata
if (item.Metadata != null)
metadata = string.Join("#", item.Metadata.Select(kv => kv.Key + "&" + kv.Value));
var record = MemoryRecord.LocalRecord(item.Id, item.Text, null, item.Embedding, metadata);
var insert = await store.UpsertAsync(Name, record, cancellationToken).ConfigureAwait(false);
list.Add(insert);
}
return list;

}

public async Task<bool> DeleteAsync(IEnumerable<string> ids, CancellationToken cancellationToken = default)
{
await store.RemoveBatchAsync(Name, ids, cancellationToken).ConfigureAwait(false);
return true;
}

public async Task<Vector?> GetAsync(string id, CancellationToken cancellationToken = default)
{
var record = await store.GetAsync(Name, id, cancellationToken: cancellationToken).ConfigureAwait(false);

Dictionary<string, object>? metadata = null;
if(record?.Metadata?.AdditionalMetadata!=null)
metadata = record.Metadata.AdditionalMetadata
.Split('#')
.Select(part => part.Split('&'))
.ToDictionary(split => split[0], split => (object)split[1]);

return record != null ? new Vector { Id = id, Text = record.Metadata.Text, Metadata = metadata } : null;
}

public async Task<bool> IsEmptyAsync(CancellationToken cancellationToken = default)
{
var collections = store.GetCollectionsAsync(cancellationToken);
return !(await collections.CountAsync(cancellationToken).ConfigureAwait(false) > 0);
}

public async Task<VectorSearchResponse> SearchAsync(VectorSearchRequest request, VectorSearchSettings? settings = null, CancellationToken cancellationToken = default)
{
request = request ?? throw new ArgumentNullException(nameof(request));
settings ??= new VectorSearchSettings();
var results = await store.GetNearestMatchesAsync(Name, request.Embeddings.First(), limit: settings.NumberOfResults, cancellationToken: cancellationToken)
.ToListAsync(cancellationToken).ConfigureAwait(false);
return new VectorSearchResponse { Items = results.Select(x => new Vector { Text = x.Item1.Metadata.Text }).ToList() };
}
}
string? id = null) : SemanticKernelMemoryStoreCollection(store, name, id);
}
42 changes: 3 additions & 39 deletions src/Databases/DuckDb/src/DuckDbVectorDatabase.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,7 @@
using Microsoft.SemanticKernel.Connectors.DuckDB;
using LangChain.Databases.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.DuckDB;

namespace LangChain.Databases.DuckDb
{
public class DuckDbVectorDatabase(DuckDBMemoryStore store) : IVectorDatabase
{
public async Task CreateCollectionAsync(string collectionName, int dimensions, CancellationToken cancellationToken = default)
{
await store.CreateCollectionAsync(collectionName, cancellationToken).ConfigureAwait(false);
}

public async Task DeleteCollectionAsync(string collectionName, CancellationToken cancellationToken = default)
{
await store.DeleteCollectionAsync(collectionName, cancellationToken).ConfigureAwait(false);
}

public async Task<IVectorCollection> GetCollectionAsync(string collectionName, CancellationToken cancellationToken = default)
{
var collections = await ListCollectionsAsync(cancellationToken).ConfigureAwait(false);
var collection = collections.FirstOrDefault(x => x == collectionName);
return collection != null ? new DuckDbVectorCollection(store, collection)
: throw new InvalidOperationException("Collection not found");
}

public async Task<IVectorCollection> GetOrCreateCollectionAsync(string collectionName, int dimensions, CancellationToken cancellationToken = default)
{
if(!await IsCollectionExistsAsync(collectionName, cancellationToken).ConfigureAwait(false))
await store.CreateCollectionAsync(collectionName, cancellationToken).ConfigureAwait(false);
return new DuckDbVectorCollection(store, collectionName);
}

public async Task<bool> IsCollectionExistsAsync(string collectionName, CancellationToken cancellationToken = default)
{
return await store.DoesCollectionExistAsync(collectionName, cancellationToken).ConfigureAwait(false);
}

public async Task<IReadOnlyList<string>> ListCollectionsAsync(CancellationToken cancellationToken = default)
{
var collections = store.GetCollectionsAsync(cancellationToken);
return await collections.ToListAsync(cancellationToken).ConfigureAwait(false);
}
}
public class DuckDbVectorDatabase(DuckDBMemoryStore store) : SemanticKernelMemoryDatabase(store);
}
8 changes: 3 additions & 5 deletions src/Databases/DuckDb/src/LangChain.Databases.DuckDb.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
<NoWarn>$(NoWarn);SKEXP0020;SKEXP0001;CS3001</NoWarn>
<NoWarn>$(NoWarn);SKEXP0020;SKEXP0001;CS3001</NoWarn>
</PropertyGroup>

<PropertyGroup Label="NuGet">
Expand All @@ -11,10 +11,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SemanticKernel.Connectors.DuckDB" />
<PackageReference Include="System.Linq.Async" />
<ProjectReference Include="..\..\..\Utilities\Pollyfils\src\LangChain.Polyfills.csproj" />
<ProjectReference Include="..\..\Abstractions\src\LangChain.Databases.Abstractions.csproj" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.DuckDB"/>
<ProjectReference Include="..\..\SemanticKernel\src\LangChain.Databases.SemanticKernel.csproj"/>
</ItemGroup>

</Project>
7 changes: 1 addition & 6 deletions src/Databases/Milvus/src/LangChain.Databases.Milvus.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Milvus"/>
<PackageReference Include="System.Linq.Async"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\Utilities\Pollyfils\src\LangChain.Polyfills.csproj"/>
<ProjectReference Include="..\..\Abstractions\src\LangChain.Databases.Abstractions.csproj"/>
<ProjectReference Include="..\..\SemanticKernel\src\LangChain.Databases.SemanticKernel.csproj"/>
</ItemGroup>

</Project>
67 changes: 6 additions & 61 deletions src/Databases/Milvus/src/MilvusVectorCollection.cs
Original file line number Diff line number Diff line change
@@ -1,64 +1,9 @@
using Microsoft.SemanticKernel.Connectors.Milvus;
using Microsoft.SemanticKernel.Memory;
using LangChain.Databases.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.Milvus;

namespace LangChain.Databases.Milvus;

public sealed class MilvusVectorCollection(
MilvusMemoryStore store,
string name = VectorCollection.DefaultName,
string? id = null)
: VectorCollection(name, id), IVectorCollection
{
public async Task<IReadOnlyCollection<string>> AddAsync(IReadOnlyCollection<Vector> items, CancellationToken cancellationToken = default)
{
items = items ?? throw new ArgumentNullException(nameof(items));

List<string> list = [];
foreach (var item in items)
{
string? metadata = null;
//TODO: review way to map metadata
if (item.Metadata != null)
metadata = string.Join("#", item.Metadata.Select(kv => kv.Key + "&" + kv.Value));
var record = MemoryRecord.LocalRecord(item.Id, item.Text, null, item.Embedding, metadata);
var insert = await store.UpsertAsync(Name, record, cancellationToken).ConfigureAwait(false);
list.Add(insert);
}
return list;
}

public async Task<bool> DeleteAsync(IEnumerable<string> ids, CancellationToken cancellationToken = default)
{
await store.RemoveBatchAsync(Name, ids, cancellationToken).ConfigureAwait(false);
return true;
}

public async Task<Vector?> GetAsync(string id, CancellationToken cancellationToken = default)
{
var record = await store.GetAsync(Name, id, cancellationToken: cancellationToken).ConfigureAwait(false);

Dictionary<string, object>? metadata = null;
if (record?.Metadata?.AdditionalMetadata != null)
metadata = record.Metadata.AdditionalMetadata
.Split('#')
.Select(part => part.Split('&'))
.ToDictionary(split => split[0], split => (object)split[1]);

return record != null ? new Vector { Id = id, Text = record.Metadata.Text, Metadata = metadata } : null;
}

public async Task<bool> IsEmptyAsync(CancellationToken cancellationToken = default)
{
var collections = store.GetCollectionsAsync(cancellationToken);
return !(await collections.CountAsync(cancellationToken).ConfigureAwait(false) > 0);
}

public async Task<VectorSearchResponse> SearchAsync(VectorSearchRequest request, VectorSearchSettings? settings = null, CancellationToken cancellationToken = default)
{
request = request ?? throw new ArgumentNullException(nameof(request));
settings ??= new VectorSearchSettings();
var results = await store.GetNearestMatchesAsync(Name, request.Embeddings.First(), limit: settings.NumberOfResults, cancellationToken: cancellationToken)
.ToListAsync(cancellationToken).ConfigureAwait(false);
return new VectorSearchResponse { Items = results.Select(x => new Vector { Text = x.Item1.Metadata.Text }).ToList() };
}
}
public class MilvusVectorCollection(
MilvusMemoryStore store,
string name = VectorCollection.DefaultName,
string? id = null) : SemanticKernelMemoryStoreCollection(store, name, id);
44 changes: 3 additions & 41 deletions src/Databases/Milvus/src/MilvusVectorDatabase.cs
Original file line number Diff line number Diff line change
@@ -1,44 +1,6 @@
using Microsoft.SemanticKernel.Connectors.Milvus;
using LangChain.Databases.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.Milvus;

namespace LangChain.Databases.Milvus;

public class MilvusVectorDatabase(
MilvusMemoryStore store)
: IVectorDatabase
{
public async Task CreateCollectionAsync(string collectionName, int dimensions, CancellationToken cancellationToken = default)
{
await store.CreateCollectionAsync(collectionName, cancellationToken).ConfigureAwait(false);
}

public async Task DeleteCollectionAsync(string collectionName, CancellationToken cancellationToken = default)
{
await store.DeleteCollectionAsync(collectionName, cancellationToken).ConfigureAwait(false);
}

public async Task<IVectorCollection> GetCollectionAsync(string collectionName, CancellationToken cancellationToken = default)
{
var collections = await ListCollectionsAsync(cancellationToken).ConfigureAwait(false);
var collection = collections.FirstOrDefault(x => x == collectionName);
return collection != null ? new MilvusVectorCollection(store, collection)
: throw new InvalidOperationException("Collection not found");
}

public async Task<IVectorCollection> GetOrCreateCollectionAsync(string collectionName, int dimensions, CancellationToken cancellationToken = default)
{
if (!await IsCollectionExistsAsync(collectionName, cancellationToken).ConfigureAwait(false))
await store.CreateCollectionAsync(collectionName, cancellationToken).ConfigureAwait(false);
return new MilvusVectorCollection(store, collectionName);
}

public async Task<bool> IsCollectionExistsAsync(string collectionName, CancellationToken cancellationToken = default)
{
return await store.DoesCollectionExistAsync(collectionName, cancellationToken).ConfigureAwait(false);
}

public async Task<IReadOnlyList<string>> ListCollectionsAsync(CancellationToken cancellationToken = default)
{
var collections = store.GetCollectionsAsync(cancellationToken);
return await collections.ToListAsync(cancellationToken).ConfigureAwait(false);
}
}
public class MilvusVectorDatabase(MilvusMemoryStore store) : SemanticKernelMemoryDatabase(store);
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net4.6.2;netstandard2.0;net6.0;net8.0</TargetFrameworks>
<NoWarn>$(NoWarn);SKEXP0020;SKEXP0001;CS3001</NoWarn>
</PropertyGroup>

<PropertyGroup Label="NuGet">
Expand All @@ -10,7 +11,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Pinecone" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Pinecone"/>
<ProjectReference Include="..\..\SemanticKernel\src\LangChain.Databases.SemanticKernel.csproj"/>
</ItemGroup>

</Project>
Loading

0 comments on commit 937cbe1

Please sign in to comment.