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});constvector=awaitembed("openai/text-embedding-3-small","hello world");constvectors=awaitembed("openai/text-embedding-3-small",["hello","world"]);Keys resolve from setKeys() first, then environment variables (OPENAI_API_KEY, GEMINI_API_KEY). Use isConfigured(model) to check whether a hosted provider has credentials or a local model has its optional dependency without making a request.
Request billed token usage with withUsage. Providers that do not report usage return null rather than an estimate.
const{ vectors, usage }=awaitembed("openai/text-embedding-3-small",docs,{withUsage: true,});console.log(usage);// { totalTokens: 42, provider: "openai", model: "text-embedding-3-small" }Provider failures are EmbedError instances with provider, status, and retryable properties. Rate limits, server failures, and network errors are retryable.
try{awaitembed("openai/text-embedding-3-small",docs);}catch(error){if(error.retryable)queue.retry(error);}OpenAI batches are split at 2,048 inputs by default. Set batchSize to a lower provider limit, or use baseUrl for an OpenAI-compatible endpoint:
awaitembed("openai/custom-model",docs,{baseUrl: "http://127.0.0.1:8199/v1",batchSize: 512,});cosineSimilarity scores two vectors from -1 to 1. A small semantic search looks like this:
import{embed,cosineSimilarity}from"@prsm/embed";constdocs=["how to reset my password","store hours and locations","track my order"];const[docVectors,queryVector]=awaitPromise.all([embed("openai/text-embedding-3-small",docs),embed("openai/text-embedding-3-small","I forgot my login"),]);constranked=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:
constvector=awaitembed("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):
constvector=awaitembed("openai/text-embedding-3-small","hello",{dimensions: 256});See docs/embeddings.md for providers, batching, dimensions, local models, and semantic search.
ISC