переехали на вектурную бд
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.6" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.6.0" />
|
||||
<PackageReference Include="OpenAI" Version="2.12.0" />
|
||||
<PackageReference Include="Qdrant.Client" Version="1.18.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -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<ChunkWarehouse>();
|
||||
builder.Services.AddTransient<VectorizationService>();
|
||||
@@ -11,6 +14,7 @@ builder.Services.AddTransient<LlmService>();
|
||||
builder.Services.AddScoped<LlmPromptBuilder>();
|
||||
builder.Services.AddTransient<ChunkService>();
|
||||
builder.Services.AddTransient<CodeService>();
|
||||
builder.Services.AddTransient<QdrantRepository>();
|
||||
|
||||
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<QdrantClient>();
|
||||
|
||||
// Получаем список существующих коллекций
|
||||
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();
|
||||
|
||||
89
CodeBase/Repositories/QdrantRepository.cs
Normal file
89
CodeBase/Repositories/QdrantRepository.cs
Normal file
@@ -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<CodeChunk> chunks)
|
||||
{
|
||||
var points = new List<PointStruct>();
|
||||
|
||||
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<List<CodeChunk>> 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();
|
||||
}
|
||||
}
|
||||
@@ -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<List<CodeChunk>> 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;
|
||||
}
|
||||
|
||||
// Математика косинусного сходства
|
||||
|
||||
6
PythonProject/.idea/vcs.xml
generated
Normal file
6
PythonProject/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
Reference in New Issue
Block a user