We have three vectors from the last lesson. Two are similar (both about a fox). One is unrelated (Python). The comparison is one short function: multiply matching positions, then sum them up.
For two 1024-dimension vectors a and b, the similarity is the dot product Σᵢ aᵢ × bᵢ, the sum of the element-wise products. That's all there is to it. Strictly speaking, "cosine similarity" divides by the magnitudes too, but for normalized embeddings like these the dot product alone ranks similarity correctly.
Same batch embed() call, but destructured into three named variables. Different destructuring pattern than the previous lesson, since we want three separate handles rather than one batch. You would destructure like so:
const { embedding: [emb1, emb2, emb3] } = await embed({ modelId, text: texts });The cosineSimilarity helper is one-line math: a loop that multiplies matching positions and sums. Output range is -1 to 1, but GTE_LARGE_FP16 typically produces 0 to 1. Note that the ?? 0 is defensive against sparse arrays. The function looks as follows:
function cosineSimilarity(vecA: number[], vecB: number[]) {
let dotProduct = 0;
for (let i = 0; i < vecA.length; i++) {
dotProduct += (vecA[i] ?? 0) * (vecB[i] ?? 0);
}
return dotProduct;
}With cosineSimilarity defined, the side-by-side compare is two calls and two logs. The similar pair (text 1 vs text 2) should land high (around 0.87), the unrelated one (text 1 vs text 3) should land low (around 0.11). .toFixed(4) rounds each to four decimal places so the numbers stay readable on one line:
const similarity1 = cosineSimilarity(emb1, emb2);
const similarity2 = cosineSimilarity(emb1, emb3);
console.log(`Similarity between texts 1 and 2 (similar meaning): ${similarity1.toFixed(4)}`);
console.log(`Similarity between texts 1 and 3 (different topics): ${similarity2.toFixed(4)}`);Note:
vecA[i] ?? 0defends againstundefinedif the array is ever sparse, which doesn't happen for our case. Drop the?? 0and usevecA[i]!if you want the leaner read.
embed({ modelId, text: texts }) and destructure the batch as emb1, emb2, emb3.cosineSimilarity(vecA: number[], vecB: number[]) that returns the dot product.cosineSimilarity(emb1, emb2) and cosineSimilarity(emb1, emb3), then console.log both with .toFixed(4).$ Run your code to see results
$