chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace Memory.VectorStoreLangchainInterop;
|
||||
|
||||
/// <summary>
|
||||
/// Data model class that matches the data model used by Langchain.
|
||||
/// This data model is not decorated with vector store attributes since instead
|
||||
/// a different record definition is used with each vector store implementation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is used with the <see cref="VectorStore_Langchain_Interop"/> sample.
|
||||
/// </remarks>
|
||||
public class LangchainDocument<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique identifier of the record.
|
||||
/// </summary>
|
||||
public TKey Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The text content for which embeddings have been generated.
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The source of the content. E.g. where to find the original content.
|
||||
/// </summary>
|
||||
public string Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The embedding for the <see cref="Content"/>.
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<float> Embedding { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.VectorData;
|
||||
using Microsoft.SemanticKernel.Connectors.Pinecone;
|
||||
using Pinecone;
|
||||
|
||||
namespace Memory.VectorStoreLangchainInterop;
|
||||
|
||||
/// <summary>
|
||||
/// Contains a factory method that can be used to create a Pinecone vector store that is compatible with datasets ingested using Langchain.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is used with the <see cref="VectorStore_Langchain_Interop"/> sample.
|
||||
/// </remarks>
|
||||
public static class PineconeFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Record definition that matches the storage format used by Langchain for Pinecone.
|
||||
/// </summary>
|
||||
private static readonly VectorStoreCollectionDefinition s_definition = new()
|
||||
{
|
||||
Properties =
|
||||
[
|
||||
new VectorStoreKeyProperty("Key", typeof(string)),
|
||||
new VectorStoreDataProperty("Content", typeof(string)) { StorageName = "text" },
|
||||
new VectorStoreDataProperty("Source", typeof(string)) { StorageName = "source" },
|
||||
new VectorStoreVectorProperty("Embedding", typeof(ReadOnlyMemory<float>), 1536) { StorageName = "embedding" }
|
||||
]
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Pinecone-backed <see cref="VectorStore"/> that can be used to read data that was ingested using Langchain.
|
||||
/// </summary>
|
||||
/// <param name="pineconeClient">Pinecone client that can be used to manage the collections and points in a Pinecone store.</param>
|
||||
/// <returns>The <see cref="VectorStore"/>.</returns>
|
||||
public static VectorStore CreatePineconeLangchainInteropVectorStore(PineconeClient pineconeClient)
|
||||
=> new PineconeLangchainInteropVectorStore(new PineconeVectorStore(pineconeClient), pineconeClient);
|
||||
|
||||
private sealed class PineconeLangchainInteropVectorStore(
|
||||
VectorStore innerStore,
|
||||
PineconeClient pineconeClient)
|
||||
: VectorStore
|
||||
{
|
||||
private readonly PineconeClient _pineconeClient = pineconeClient;
|
||||
|
||||
public override VectorStoreCollection<TKey, TRecord> GetCollection<TKey, TRecord>(string name, VectorStoreCollectionDefinition? definition = null)
|
||||
{
|
||||
if (typeof(TKey) != typeof(string) || typeof(TRecord) != typeof(LangchainDocument<string>))
|
||||
{
|
||||
throw new NotSupportedException("This VectorStore is only usable with string keys and LangchainDocument<string> record types");
|
||||
}
|
||||
|
||||
// Create a Pinecone collection and pass in our custom record definition that matches
|
||||
// the schema used by Langchain so that the default mapper can use the storage names
|
||||
// in it, to map to the storage scheme.
|
||||
return (new PineconeCollection<TKey, TRecord>(
|
||||
_pineconeClient,
|
||||
name,
|
||||
new()
|
||||
{
|
||||
Definition = s_definition
|
||||
}) as VectorStoreCollection<TKey, TRecord>)!;
|
||||
}
|
||||
|
||||
public override VectorStoreCollection<object, Dictionary<string, object?>> GetDynamicCollection(string name, VectorStoreCollectionDefinition? definition = null)
|
||||
{
|
||||
// Create a Pinecone collection and pass in our custom record definition that matches
|
||||
// the schema used by Langchain so that the default mapper can use the storage names
|
||||
// in it, to map to the storage scheme.
|
||||
return new PineconeDynamicCollection(
|
||||
_pineconeClient,
|
||||
name,
|
||||
new()
|
||||
{
|
||||
Definition = s_definition
|
||||
});
|
||||
}
|
||||
|
||||
public override object? GetService(Type serviceType, object? serviceKey = null) => innerStore.GetService(serviceType, serviceKey);
|
||||
|
||||
public override IAsyncEnumerable<string> ListCollectionNamesAsync(CancellationToken cancellationToken = default) => innerStore.ListCollectionNamesAsync(cancellationToken);
|
||||
|
||||
public override Task<bool> CollectionExistsAsync(string name, CancellationToken cancellationToken = default) => innerStore.CollectionExistsAsync(name, cancellationToken);
|
||||
|
||||
public override Task EnsureCollectionDeletedAsync(string name, CancellationToken cancellationToken = default) => innerStore.EnsureCollectionDeletedAsync(name, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.VectorData;
|
||||
using Microsoft.SemanticKernel.Connectors.Redis;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Memory.VectorStoreLangchainInterop;
|
||||
|
||||
/// <summary>
|
||||
/// Contains a factory method that can be used to create a Redis vector store that is compatible with datasets ingested using Langchain.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is used with the <see cref="VectorStore_Langchain_Interop"/> sample.
|
||||
/// </remarks>
|
||||
public static class RedisFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Record definition that matches the storage format used by Langchain for Redis.
|
||||
/// </summary>
|
||||
private static readonly VectorStoreCollectionDefinition s_definition = new()
|
||||
{
|
||||
Properties =
|
||||
[
|
||||
new VectorStoreKeyProperty("Key", typeof(string)),
|
||||
new VectorStoreDataProperty("Content", typeof(string)) { StorageName = "text" },
|
||||
new VectorStoreDataProperty("Source", typeof(string)) { StorageName = "source" },
|
||||
new VectorStoreVectorProperty("Embedding", typeof(ReadOnlyMemory<float>), 1536) { StorageName = "embedding" }
|
||||
]
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Redis-backed <see cref="VectorStore"/> that can be used to read data that was ingested using Langchain.
|
||||
/// </summary>
|
||||
/// <param name="database">The redis database to read/write from.</param>
|
||||
/// <returns>The <see cref="VectorStore"/>.</returns>
|
||||
public static VectorStore CreateRedisLangchainInteropVectorStore(IDatabase database)
|
||||
=> new RedisLangchainInteropVectorStore(new RedisVectorStore(database), database);
|
||||
|
||||
private sealed class RedisLangchainInteropVectorStore(
|
||||
VectorStore innerStore,
|
||||
IDatabase database)
|
||||
: VectorStore
|
||||
{
|
||||
private readonly IDatabase _database = database;
|
||||
|
||||
public override VectorStoreCollection<TKey, TRecord> GetCollection<TKey, TRecord>(string name, VectorStoreCollectionDefinition? definition = null)
|
||||
{
|
||||
if (typeof(TKey) != typeof(string) || typeof(TRecord) != typeof(LangchainDocument<string>))
|
||||
{
|
||||
throw new NotSupportedException("This VectorStore is only usable with string keys and LangchainDocument<string> record types");
|
||||
}
|
||||
|
||||
// Create a hash set collection, since Langchain uses redis hashes for storing records.
|
||||
// Also pass in our custom record definition that matches the schema used by Langchain
|
||||
// so that the default mapper can use the storage names in it, to map to the storage
|
||||
// scheme.
|
||||
return (new RedisHashSetCollection<TKey, TRecord>(
|
||||
_database,
|
||||
name,
|
||||
new()
|
||||
{
|
||||
Definition = s_definition
|
||||
}) as VectorStoreCollection<TKey, TRecord>)!;
|
||||
}
|
||||
|
||||
public override VectorStoreCollection<object, Dictionary<string, object?>> GetDynamicCollection(string name, VectorStoreCollectionDefinition? definition = null)
|
||||
{
|
||||
// Create a hash set collection, since Langchain uses redis hashes for storing records.
|
||||
// Also pass in our custom record definition that matches the schema used by Langchain
|
||||
// so that the default mapper can use the storage names in it, to map to the storage
|
||||
// scheme.
|
||||
return new RedisHashSetDynamicCollection(
|
||||
_database,
|
||||
name,
|
||||
new()
|
||||
{
|
||||
Definition = s_definition
|
||||
});
|
||||
}
|
||||
|
||||
public override object? GetService(Type serviceType, object? serviceKey = null) => innerStore.GetService(serviceType, serviceKey);
|
||||
|
||||
public override IAsyncEnumerable<string> ListCollectionNamesAsync(CancellationToken cancellationToken = default) => innerStore.ListCollectionNamesAsync(cancellationToken);
|
||||
|
||||
public override Task<bool> CollectionExistsAsync(string name, CancellationToken cancellationToken = default) => innerStore.CollectionExistsAsync(name, cancellationToken);
|
||||
|
||||
public override Task EnsureCollectionDeletedAsync(string name, CancellationToken cancellationToken = default) => innerStore.EnsureCollectionDeletedAsync(name, cancellationToken);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user