Text Similarity
Compare text similarity with Workers AI embeddings at the edge - cosine similarity for duplicate and related-content detection
Compare two text strings for semantic similarity using Workers AI embeddings and cosine similarity. Returns a score between 0 and 1.
Features
- Compare two text strings for semantic similarity (score 0–1)
- Workers AI embeddings via
@cf/baai/bge-base-en-v1.5 - Cosine similarity computed at the edge
- Stateless GET API with
text1andtext2query parameters
API Reference
GET /similarity
Computes the cosine similarity between embeddings of two text inputs.
Prop
Type
Example Request
curl "https://your-worker.workers.dev/similarity?text1=hello%20world&text2=hello%20there"Success Response
text1 string
The first input text
text2 string
The second input text
similarity number
Cosine similarity score between 0 and 1 (higher means more similar)
{
"text1": "hello world",
"text2": "hello there",
"similarity": 0.82
}Error Response
{
"error": "Missing or invalid query parameter: text1",
"code": "INVALID_TEXT1"
}Error Codes
400- Missing or invalidtext1(INVALID_TEXT1)400- Missing or invalidtext2(INVALID_TEXT2)502- Workers AI model run failed (AI_ERROR)
Use Cases
- Detect duplicate or near-duplicate content at the edge
- Rank search results or FAQ matches by semantic relevance
- Learn Workers AI embedding models and vector similarity
- Build lightweight deduplication or matching APIs without a vector database
Limitations
- Workers AI is subject to usage limits by plan
- Each input string length is capped
- Compares two strings only; no corpus or vector database search
Use in your project
Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/text-similarity.
import type { Env } from "../types/env";import { AI_MODEL } from "../constants/defaults";type EmbeddingResult = { data?: number[][];};export function cosineSimilarity(a: number[], b: number[]): number { if (a.length !== b.length || a.length === 0) return 0; let dot = 0; let normA = 0; let normB = 0; for (let i = 0; i < a.length; i++) { dot += a[i] * b[i]; normA += a[i] * a[i]; normB += b[i] * b[i]; } const denom = Math.sqrt(normA) * Math.sqrt(normB); if (denom === 0) return 0; const raw = dot / denom; return Math.max(0, Math.min(1, raw));}export async function computeSimilarity(env: Env, text1: string, text2: string): Promise<number> { const out = (await env.AI.run(AI_MODEL, { text: [text1, text2] })) as EmbeddingResult; const vectors = out.data; if (!vectors || vectors.length < 2) { throw new Error("Embedding model returned insufficient vectors"); } return cosineSimilarity(vectors[0], vectors[1]);}Deployment
Deploy
Enable the Workers AI binding (AI) in your Worker settings. The deploy button configures this automatically via wrangler.json. Requires a Cloudflare account with Workers AI enabled.
Test your deployment
curl "https://your-worker.workers.dev/similarity?text1=hello&text2=hi"Local Development
cd apps/experiments/text-similarity
npm install
npm run devTest locally:
curl "http://localhost:8787/similarity?text1=hello&text2=hi"Cloudflare Features Used
- Workers - Edge compute runtime
- Workers AI -
@cf/baai/bge-base-en-v1.5text embedding model