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 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(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> SearchAsync(ReadOnlyMemory query, int? userId, int topK = 10) { var collectionName = $"picture_{userId}"; var collection = GetVectorStore().GetCollection(collectionName); var results = collection.SearchAsync(query, topK); var res = new List(); 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(collectionName); await collection.EnsureCollectionExistsAsync(); await collection.UpsertAsync(pictureVector); } public async Task RemovePictureFromUserCollectionAsync(int userId, int pictureId) { var collectionName = $"picture_{userId}"; var collection = GetVectorStore().GetCollection(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(name); await collection.EnsureCollectionDeletedAsync(); } } }