Chunks to vectors
Now turn chunks into vectors so you can compare them by meaning. Embed each chunk's text into a fixed-dimension unit vector; cosine similarity is then just the dot product. You embed every chunk once and store chunkId → vector as the index.
Real RAG uses a model like MiniLM (384-dim, mean-pool + L2-norm). To stay zero-setup and bit-deterministic on every CPU, this course ships a model-free embedder: lowercase the text, slide a character 3-gram window, hash each gram into a fixed 256-dim signed bucket, then L2-normalize. Shared wording → shared n-grams → high cosine — a real similarity space, no download.
export function embedText(text: string): number[] // 256-dim L2-normalized vector
export interface Index { ids: string[]; vectors: number[][] } // vectors[i] for ids[i]
In a production build you'd swap embedText for an ONNX MiniLM call and ship frozen reference embeddings (because ONNX float ops aren't bit-identical across CPUs). With the n-gram embedder there's nothing to freeze — the same input always yields the same vector. See NOTES.md.