From b2bacc54a9df9a314f6c1cf0ddf3414265b03d9e Mon Sep 17 00:00:00 2001 From: ShiYu Date: Sat, 31 May 2025 00:35:55 +0800 Subject: [PATCH] feat(services): implement VectorDbService for user-specific picture collections --- Services/VectorDb/VectorDbService.cs | 79 ++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Services/VectorDb/VectorDbService.cs diff --git a/Services/VectorDb/VectorDbService.cs b/Services/VectorDb/VectorDbService.cs new file mode 100644 index 0000000..e897ca5 --- /dev/null +++ b/Services/VectorDb/VectorDbService.cs @@ -0,0 +1,79 @@ +using Foxel.Models.Vector; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.VectorData; +using Microsoft.SemanticKernel.Connectors.InMemory; + +namespace Foxel.Services.VectorDB; + +public class VectorDbService +{ + private readonly VectorStore _vectorStore; + private readonly IDbContextFactory _contextFactory; + + public VectorDbService(IDbContextFactory contextFactory) + { + _vectorStore = new InMemoryVectorStore(); + _contextFactory = contextFactory; + _ = InitData(); + } + + private async Task InitData() + { + 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 = _vectorStore.GetCollection(collectionName); + await collection.EnsureCollectionExistsAsync(); + + var picVectors = group.Select(p => new PictureVector + { + Id = 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 = _vectorStore.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 = _vectorStore.GetCollection(collectionName); + await collection.EnsureCollectionExistsAsync(); + await collection.UpsertAsync(pictureVector); + } + + public async Task RemovePictureFromUserCollectionAsync(int userId, int pictureId) + { + var collectionName = $"picture_{userId}"; + var collection = _vectorStore.GetCollection(collectionName); + await collection.EnsureCollectionExistsAsync(); + await collection.DeleteAsync(pictureId); + } +} \ No newline at end of file