using CodeBase.Models; using CodeBase.Warehouse; namespace CodeBase.Services { public class CodeService(ChunkService service, ChunkWarehouse warehouse, VectorizationService vectorizationService, LlmService llmService) { public async Task> GetCodeChunksAsync(string path, string name) { if (!Path.Exists(path)) { throw new Exception("Путь не найден"); } var allChunks = new List(); // Находим все .cs файлы во всех вложенных папках var csFiles = Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories); foreach (var filePath in csFiles) { var content = File.ReadAllText(filePath); // Парсим каждый файл отдельно, сохраняя его оригинальный путь var fileChunks = service.ChunkCSharpFile(filePath, content); allChunks.AddRange(fileChunks); } var chunks = await vectorizationService.EnrichChunksWithVectorsAsync(allChunks); warehouse.UpsertDictionary(name, allChunks); return chunks; } public async Task GetAnswerAsync(string name, string question) { var query = await vectorizationService.GetVectorAsync(question); var answerVectors = Search(query, name, 15); var answer = await llmService.AskQuestionAsync(question, answerVectors.Select(s => s.Chunk).ToList()); return answer; } // Главный метод поиска public List<(CodeChunk Chunk, float Score)> Search( float[] queryVector, string name, int topK = 3) // Возвращаем топ-3 результата { var memoryBase = warehouse.GetChunks(name); 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(); } // Математика косинусного сходства private float CalculateCosineSimilarity(float[] vectorA, float[] vectorB) { if (vectorA.Length != vectorB.Length) throw new ArgumentException("Векторы должны быть одинаковой длины (например, 768)."); float dotProduct = 0; float magnitudeA = 0; float magnitudeB = 0; for (int i = 0; i < vectorA.Length; i++) { dotProduct += vectorA[i] * vectorB[i]; magnitudeA += vectorA[i] * vectorA[i]; magnitudeB += vectorB[i] * vectorB[i]; } // Защита от деления на ноль if (magnitudeA == 0 || magnitudeB == 0) return 0; return (float)(dotProduct / (Math.Sqrt(magnitudeA) * Math.Sqrt(magnitudeB))); } } }