Text embeddings with multi-provider support, batching, and cosine similarity.
npm install @prsm/embedNode 24 or newer. Local models need @huggingface/transformers (an optional peer); hosted models don't.
Pick a model with a provider/model prefix. Pass a string for one vector, or an array for a batch.
import { embed, setKeys } from "@prsm/embed";
setKeys({ openai: process.env.OPENAI_API_KEY });
const vector = await embed("openai/text-embedding-3-small", "hello world");
const vectors = await embed("openai/text-embedding-3-small", ["hello", "world"]);Keys resolve from setKeys() first, then environment variables (OPENAI_API_KEY, GEMINI_API_KEY).
cosineSimilarity scores two vectors from -1 to 1. A small semantic search looks like this:
import { embed, cosineSimilarity } from "@prsm/embed";
const docs = ["how to reset my password", "store hours and locations", "track my order"];
const [docVectors, queryVector] = await Promise.all([
embed("openai/text-embedding-3-small", docs),
embed("openai/text-embedding-3-small", "I forgot my login"),
]);
const ranked = docs
.map((doc, i) => ({ doc, score: cosineSimilarity(queryVector, docVectors[i]) }))
.sort((a, b) => b.score - a.score);
console.log(ranked[0].doc); // "how to reset my password"| Provider | Prefix | Example model |
|---|---|---|
| OpenAI | openai/ |
openai/text-embedding-3-small |
google/ |
google/text-embedding-004 |
|
| Local (HuggingFace) | none | Xenova/all-MiniLM-L6-v2 |
A bare model name with no slash runs locally through @huggingface/transformers, so you can embed without any API key:
const vector = await embed("Xenova/all-MiniLM-L6-v2", "runs locally, no key needed");Models that support shortened embeddings accept a dimensions config (mapped to each provider's native parameter):
const vector = await embed("openai/text-embedding-3-small", "hello", { dimensions: 256 });See docs/embeddings.md for providers, batching, dimensions, local models, and semantic search.
ISC