Files
Foxel/Services/VectorDb/QdrantVectorDbService.cs

103 lines
3.6 KiB
C#

using Foxel.Models.Vector;
using Foxel.Services.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.Qdrant;
using Qdrant.Client;
namespace Foxel.Services.VectorDB;
public class QdrantVectorDbService(IDbContextFactory<MyDbContext> contextFactory, IConfigService configService)
: IVectorDbService
{
private VectorStore? _vectorStore;
private string? _currentHost;
private string? _currentApiKey;
private VectorStore GetVectorStore()
{
string host = configService["VectorDb:QdrantHost"];
string apiKey = configService["VectorDb:QdrantApiKey"];
if (_vectorStore == null || _currentHost != host || _currentApiKey != apiKey)
{
var qdrantClient = new QdrantClient(host, https: true, apiKey: apiKey);
_vectorStore = new QdrantVectorStore(qdrantClient, true);
_currentHost = host;
_currentApiKey = apiKey;
}
return _vectorStore;
}
public async Task BuildUserPictureVectorsAsync()
{
await using var dbContext = await contextFactory.CreateDbContextAsync();
var userPictures = dbContext.Pictures
.Where(p => p.UserId != null && p.Embedding != null)
.Select(p => new { p.Id, p.Name, p.Embedding, p.UserId })
.GroupBy(p => p.UserId!.Value)
.ToList();
foreach (var group in userPictures)
{
int userId = group.Key;
var collectionName = $"picture_{userId}";
var collection = GetVectorStore().GetCollection<ulong, PictureVector>(collectionName);
await collection.EnsureCollectionExistsAsync();
var picVectors = group.Select(p => new PictureVector
{
Id = (ulong)p.Id,
Name = p.Name,
Embedding = p.Embedding
}).ToList();
foreach (var picVector in picVectors)
{
await collection.UpsertAsync(picVector);
}
}
}
public async Task<List<PictureVector>> SearchAsync(ReadOnlyMemory<float> query, int? userId, int topK = 10)
{
var collectionName = $"picture_{userId}";
var collection = GetVectorStore().GetCollection<ulong, PictureVector>(collectionName);
var results = collection.SearchAsync(query, topK);
var res = new List<PictureVector>();
await foreach (var record in results)
{
res.Add(record.Record);
}
return res;
}
public async Task AddPictureToUserCollectionAsync(int userId, PictureVector pictureVector)
{
var collectionName = $"picture_{userId}";
var collection = GetVectorStore().GetCollection<ulong, PictureVector>(collectionName);
await collection.EnsureCollectionExistsAsync();
await collection.UpsertAsync(pictureVector);
}
public async Task RemovePictureFromUserCollectionAsync(int userId, int pictureId)
{
var collectionName = $"picture_{userId}";
var collection = GetVectorStore().GetCollection<ulong, PictureVector>(collectionName);
await collection.EnsureCollectionExistsAsync();
await collection.DeleteAsync((ulong)pictureId);
}
public async Task ClearVectorsAsync()
{
var collections = GetVectorStore().ListCollectionNamesAsync();
await foreach (var name in collections)
{
var collection = GetVectorStore().GetCollection<ulong, PictureVector>(name);
await collection.EnsureCollectionDeletedAsync();
}
}
}