UNPKG

scai

Version:

> AI-powered CLI tool for commit messages **and** pull request reviews — using local models.

72 lines (71 loc) 2.72 kB
import { stringSimilarity } from 'string-similarity-js'; export function scoreFiles(query, embedding, candidates) { const terms = query.toLowerCase().split(/\s+/); const bm25Min = Math.min(...candidates.map(r => r.bm25Score)); const bm25Max = Math.max(...candidates.map(r => r.bm25Score)); return candidates.map(result => { let finalScore = 0; let sim = 0; const path = result.path.toLowerCase(); const filename = result.filename.toLowerCase(); const summary = (result.summary || '').toLowerCase(); // 🎯 Normalize BM25 const normalizedBm25 = 1 - ((result.bm25Score - bm25Min) / (bm25Max - bm25Min + 1e-5)); // 🧠 Embedding similarity if (result.embedding) { try { const vector = JSON.parse(result.embedding); sim = cosineSimilarity(embedding, vector); } catch { sim = 0; } } // 🧩 Match ratio let matchRatio = 0; let matchedTerms = 0; for (const term of terms) { if (path.includes(term) || summary.includes(term)) matchedTerms++; } matchRatio = matchedTerms / terms.length; const termBoost = matchRatio >= 1 ? 1.0 : matchRatio >= 0.5 ? 0.5 : 0; // 🪜 Path heuristics const isHtml = path.endsWith('.html'); const isSrc = path.includes('/src/') || path.includes('/controls/'); const isDoc = path.includes('/docs/') || path.includes('/mvndist/'); const isExactMatch = filename === `${terms[0]}.js`; let weight = 1; if (isHtml) weight *= 0.85; if (isDoc) weight *= 0.8; if (isSrc) weight *= 1.2; if (isExactMatch) weight *= 1.5; // 🧪 Fuzzy score const fuzzyScore = stringSimilarity(query, `${path} ${summary}`); // 🧮 Final composite score finalScore = (0.4 * normalizedBm25) + (0.4 * sim) + (0.2 * termBoost) + (fuzzyScore * 0.5); // scale fuzzy match moderately finalScore *= weight; return { id: result.id, path: result.path, summary: result.summary, score: finalScore, sim, bm25: result.bm25Score, }; }).sort((a, b) => b.score - a.score); } function cosineSimilarity(a, b) { const dot = a.reduce((sum, ai, i) => sum + ai * b[i], 0); const magA = Math.sqrt(a.reduce((sum, ai) => sum + ai * ai, 0)); const magB = Math.sqrt(b.reduce((sum, bi) => sum + bi * bi, 0)); return dot / (magA * magB); }