From b6829ce7536fc0f0d6c924c8bf97412ea42fb416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BE=D0=B7=D0=BE=D1=80=D0=BE=D0=B2=D0=B0=20=D0=90?= =?UTF-8?q?=D0=BB=D1=91=D0=BD=D0=B0?= Date: Wed, 22 Jul 2026 22:36:12 +0400 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B5=D1=85=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=BD=D0=B0=20=D0=B2=D0=B5=D0=BA=D1=82=D1=83?= =?UTF-8?q?=D1=80=D0=BD=D1=83=D1=8E=20=D0=B1=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CodeBase/CodeBase.csproj | 1 + CodeBase/Program.cs | 27 +++++++ CodeBase/Repositories/QdrantRepository.cs | 89 +++++++++++++++++++++++ CodeBase/Services/CodeService.cs | 30 ++------ PythonProject/.idea/vcs.xml | 6 ++ 5 files changed, 130 insertions(+), 23 deletions(-) create mode 100644 CodeBase/Repositories/QdrantRepository.cs create mode 100644 PythonProject/.idea/vcs.xml diff --git a/CodeBase/CodeBase.csproj b/CodeBase/CodeBase.csproj index 8718518..cd5424c 100644 --- a/CodeBase/CodeBase.csproj +++ b/CodeBase/CodeBase.csproj @@ -10,6 +10,7 @@ + diff --git a/CodeBase/Program.cs b/CodeBase/Program.cs index cb2d15a..c583cda 100644 --- a/CodeBase/Program.cs +++ b/CodeBase/Program.cs @@ -1,9 +1,12 @@ using CodeBase.Services; using CodeBase.Warehouse; +using Qdrant.Client; +using Qdrant.Client.Grpc; var builder = WebApplication.CreateBuilder(args); // Add services to the container. +builder.Services.AddSingleton(new QdrantClient("localhost", 6334)); builder.Services.AddSingleton(); builder.Services.AddTransient(); @@ -11,6 +14,7 @@ builder.Services.AddTransient(); builder.Services.AddScoped(); builder.Services.AddTransient(); builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.AddControllers(); builder.Services.AddSwaggerGen(); @@ -30,4 +34,27 @@ app.UseAuthorization(); app.MapControllers(); + +using (var scope = app.Services.CreateScope()) +{ + var qdrantClient = scope.ServiceProvider.GetRequiredService(); + + // Получаем список существующих коллекций + var collections = await qdrantClient.ListCollectionsAsync(); + + if (!collections.Contains("CodeBaseCollection")) + { + Console.WriteLine("Создаем новую коллекцию в Qdrant..."); + await qdrantClient.CreateCollectionAsync( + collectionName: "CodeBaseCollection", + vectorsConfig: new VectorParams + { + Size = 768, // Размер вектора GraphCodeBERT + Distance = Distance.Cosine // Сразу задаем алгоритм поиска (косинусное сходство) + } + ); + } +} + + app.Run(); diff --git a/CodeBase/Repositories/QdrantRepository.cs b/CodeBase/Repositories/QdrantRepository.cs new file mode 100644 index 0000000..7db4408 --- /dev/null +++ b/CodeBase/Repositories/QdrantRepository.cs @@ -0,0 +1,89 @@ +using CodeBase.Models; +using Qdrant.Client; +using Qdrant.Client.Grpc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +public class QdrantRepository +{ + private readonly QdrantClient _client; + private const string CollectionName = "CodeBaseCollection"; + + public QdrantRepository(QdrantClient client) + { + _client = client; + } + + // ========================================== + // 1. СОХРАНЕНИЕ ВЕКТОРОВ С ПРИВЯЗКОЙ К ПРОЕКТУ + // ========================================== + public async Task SaveChunksAsync(string projectName, List chunks) + { + var points = new List(); + + foreach (var chunk in chunks) + { + if (chunk.Vector == null) continue; + + // Формируем точку для БД + var point = new PointStruct + { + Id = Guid.NewGuid(), // Уникальный ID чанка + Vectors = chunk.Vector, // Тот самый массив float[] + + // Вот здесь мы навешиваем все ярлыки! + Payload = + { + ["ProjectName"] = projectName, + ["FilePath"] = chunk.FilePath, + ["MethodName"] = chunk.MethodName, + ["Content"] = chunk.Content // Сам текст кода тоже храним прямо в БД + } + }; + points.Add(point); + } + + // Отправляем пачку векторов в базу + await _client.UpsertAsync(CollectionName, points); + } + + // ========================================== + // 2. ПОИСК ТОЛЬКО В РАМКАХ ОДНОГО ПРОЕКТА + // ========================================== + public async Task> SearchAsync(string projectName, float[] queryVector, int topK = 15) + { + // Создаем фильтр: искать только там, где ProjectName совпадает с запрошенным + var projectFilter = new Filter + { + Must = { + new Condition + { + Field = new FieldCondition + { + Key = "ProjectName", + Match = new Match { Keyword = projectName } + } + } + } + }; + + // База делает всю тяжелую математику за нас! + var searchResults = await _client.SearchAsync( + collectionName: CollectionName, + vector: queryVector, + limit: (ulong)topK, + filter: projectFilter, // Передаем наш фильтр + payloadSelector: true // Просим БД вернуть Payload вместе с результатами + ); + + // Превращаем ответы базы обратно в наши C#-объекты CodeChunk + return searchResults.Select(hit => new CodeChunk + { + FilePath = hit.Payload["FilePath"].StringValue, + MethodName = hit.Payload["MethodName"].StringValue, + Content = hit.Payload["Content"].StringValue + }).ToList(); + } +} \ No newline at end of file diff --git a/CodeBase/Services/CodeService.cs b/CodeBase/Services/CodeService.cs index c381a59..415d34e 100644 --- a/CodeBase/Services/CodeService.cs +++ b/CodeBase/Services/CodeService.cs @@ -4,7 +4,7 @@ using CodeBase.Warehouse; namespace CodeBase.Services { public class CodeService(ChunkService service, - ChunkWarehouse warehouse, + QdrantRepository repository, VectorizationService vectorizationService, LlmService llmService) { @@ -32,7 +32,7 @@ namespace CodeBase.Services var chunks = await vectorizationService.EnrichChunksWithVectorsAsync(allChunks); - warehouse.UpsertDictionary(name, allChunks); + await repository.SaveChunksAsync(name, chunks); return chunks; } @@ -41,38 +41,22 @@ namespace CodeBase.Services { var query = await vectorizationService.GetVectorAsync(question); - var answerVectors = Search(query, name, 15); + var answerVectors = await SearchAsync(query, name, 15); - var answer = await llmService.AskQuestionAsync(question, answerVectors.Select(s => s.Chunk).ToList()); + var answer = await llmService.AskQuestionAsync(question, answerVectors); return answer; } // Главный метод поиска - public List<(CodeChunk Chunk, float Score)> Search( + public async Task> SearchAsync( float[] queryVector, string name, int topK = 3) // Возвращаем топ-3 результата { - var memoryBase = warehouse.GetChunks(name); + var results = await repository.SearchAsync(name, queryVector, topK); - var results = new List<(CodeChunk, float)>(); - - foreach (var chunk in memoryBase) - { - if (chunk.Vector == null || chunk.Vector.Length == 0) - continue; - - // Считаем близость вектора вопроса к вектору кода - float similarity = CalculateCosineSimilarity(queryVector, chunk.Vector); - results.Add((chunk, similarity)); - } - - // Сортируем по убыванию сходства (чем ближе к 1, тем лучше) - return results - .OrderByDescending(x => x.Item2) - .Take(topK) - .ToList(); + return results; } // Математика косинусного сходства diff --git a/PythonProject/.idea/vcs.xml b/PythonProject/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/PythonProject/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file