Spaces:
Running
Running
| /** | |
| * 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'; | |
| } | |