/** * Compute cosine similarity between two vectors * Assumes vectors are already normalized */ export function cosineSimilarity( a, b ) { let dot = 0; for ( let i = 0; i < a.length; i++ ) { dot += a[ i ] * b[ i ]; } return dot; } /** * Search chunks by embedding similarity */ export function search( queryEmbedding, chunks, topK = 3, threshold = 0.4 ) { const scored = chunks.map( ( chunk ) => ( { ...chunk, score: cosineSimilarity( queryEmbedding, chunk.embedding ) } ) ); scored.sort( ( a, b ) => b.score - a.score ); const results = scored.slice( 0, topK ).map( ( r ) => ( { chunkId: r.id, text: r.text, score: r.score, confidence: scoreToConfidence( r.score ), sectionId: r.sectionId, sectionTitle: r.sectionTitle, selector: r.selector, paragraphIndex: r.paragraphIndex } ) ); const belowThreshold = results.length === 0 || results[ 0 ].score < threshold; return { results, belowThreshold }; } function scoreToConfidence( score ) { if ( score >= 0.6 ) { return 'high'; } if ( score >= 0.45 ) { return 'medium'; } return 'low'; }