POST https://tokens.bd/v1/embeddings হলো OpenAI-compatible embeddings endpoint। আপনি text পাঠান, প্রতিটা input-এর জন্য একটা করে vector ফেরত পান। এই vector জমিয়ে রেখে semantic search, RAG-এর retrieval, duplicate খোঁজা বা clustering-এ ব্যবহার করা যায়। gateway আগে আপনার key, plan আর সীমা যাচাই করে, তারপর body-টা যে model-এর নাম দিয়েছেন তার upstream provider-এর কাছে পাঠিয়ে দেয়।
এই endpoint শুধু embedding model-এর সাথে চলে। deepseek/deepseek-v4.1-flash-এর মতো chat model এখানে কাজ করে না, পাঠালে fail করবে। তাই আগে পরের section-টা পড়ে নিন।
Embedding model খুঁজে নেওয়া#
Tokens GET /v1/models-এ কোনো capability flag যোগ করে না, তাই ওই list-এ শুধু id-ই থাকে। embedding model খুঁজতে এভাবে এগোন:
- model catalog খুলে
embedলিখে search করুন। search মেলে model-এর নাম, id আর provider ধরে। - model-এর পেজ খুলে context window আর প্রতি million token-এর input price দেখে নিন।
- আপনার key দিয়ে model-টা call করা যায় কি না দেখুন: ওই key-র জন্য
GET /v1/models-এ id-টা থাকতে হবে (কোনো model কেন বাদ পড়ে)।
catalog-এ একটাও embedding model না থাকলে বুঝবেন আপনার অ্যাকাউন্টে এখনো কোনোটা চালু নেই, আর /v1/embeddings-এর দেওয়ার মতো কিছু নেই। তালিকায় না আসা পর্যন্ত এখনকার embedding provider-ই ব্যবহার করতে থাকুন। catalog বদলায় বলে এই পেজে কোনো model-এর নাম দেওয়া হয়নি। নিচের উদাহরণগুলো id-টা environment variable থেকে পড়ে নেয়:
export EMBEDDING_MODEL="the-id-from-the-catalog"Embeddings তৈরি করা#
curl https://tokens.bd/v1/embeddings \
-H "Authorization: Bearer $TOKENS_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{
"model": "$EMBEDDING_MODEL",
"input": ["How do I reset my password?", "Where can I change my billing email?"],
"encoding_format": "float"
}
EOFimport os
from openai import OpenAI
client = OpenAI(base_url="https://tokens.bd/v1", api_key=os.environ["TOKENS_API_KEY"])
resp = client.embeddings.create(
model=os.environ["EMBEDDING_MODEL"],
input=["How do I reset my password?", "Where can I change my billing email?"],
encoding_format="float",
)
vectors = [item.embedding for item in resp.data]
print(len(vectors), "vectors of", len(vectors[0]), "numbers")
print(resp.usage)import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://tokens.bd/v1", apiKey: process.env.TOKENS_API_KEY });
const resp = await client.embeddings.create({
model: process.env.EMBEDDING_MODEL!,
input: ["How do I reset my password?", "Where can I change my billing email?"],
encoding_format: "float",
});
const vectors = resp.data.map((item) => item.embedding);
console.log(vectors.length, "vectors of", vectors[0].length, "numbers");
console.log(resp.usage);Content-Type: application/json header-টা ভুলবেন না। এটা না থাকলে gateway body পড়তে পারে না, আর model field দেওয়া থাকলেও 400 invalid_request দিয়ে বলে যে request-এ model field নেই।
Request-এর field#
body চলে OpenAI-র embeddings format মেনে। OpenAI-র API reference-এর সাথে 2026 সালের অক্টোবরে মিলিয়ে দেখা হয়েছে।
| Field | Type | নোট |
|---|---|---|
model | string | বাধ্যতামূলক। embedding model-এর id, catalog-এ যেভাবে লেখা আছে ঠিক সেভাবে। |
input | string or array | বাধ্যতামূলক। একটা string, অথবা এক request-এ embed করার জন্য string-এর array। OpenAI-র format-এ token id-ও দেওয়া যায়। |
encoding_format | string | "float" (raw API-তে default) বা "base64"। সমর্থন আছে কি না, সেটা model-এর provider-এর ওপর নির্ভর করে। |
dimensions | integer | ছোট output vector। OpenAI-র নিজের API-তে সব model এটা নেয় না। আপনার model নেবে কি না, ঠিক করে তার provider। |
user | string | end-user-এর একটা identifier, যা provider-এর কাছে পাঠানো হয়। |
Parameter নির্ভর করে upstream model-এর ওপর
gateway এই body থেকে শুধু model পড়ে, আর কিছু না। বাকি field-গুলো provider-এর কাছে যেমন আছে তেমনই যায়। তাই যে সীমাগুলো আসলে কাজে লাগে (প্রতি input-এ সর্বোচ্চ token, এক request-এ কয়টা input, dimensions চলে কি না, vector কত বড়), সেগুলো provider-এর, আর model ভেদে আলাদা। OpenAI-র নিজের embedding model-এর জন্য OpenAI-র docs বলে প্রতি input-এ 8,192 token, input array-তে সর্বোচ্চ 2,048টা item, আর পুরো এক request-এ 300,000 token। অন্য model-এর বেলায় এই সংখ্যা ধরে নেবেন না।
request body সব মিলিয়ে 10 MB পর্যন্ত হতে পারে। এর চেয়ে বড় হলে 413 request_entity_too_large আসে।
Python SDK default-এ base64 চায়#
encoding_format না দিলে OpenAI-র Python SDK নিজে থেকে "base64" পাঠায় আর result নিজেই decode করে (SDK-র source দেখে মিলিয়েছি, অক্টোবর 2026)। এটা তখনই চলে, যখন model-এর provider base64 সমর্থন করে। call fail করলে বা vector অদ্ভুত এলে উপরের উদাহরণের মতো encoding_format="float" দিয়ে দিন। Node.js SDK-তেও স্পষ্ট করে দিয়ে দিলে কোনো ক্ষতি নেই।
Response-এর উদাহরণ#
এখানে vector ছোট করে দেখানো হয়েছে। আসল vector-এ শ'য়ে শ'য়ে বা হাজার হাজার সংখ্যা থাকে, তাই request-এর তুলনায় response body অনেক বড় হয়।
{
"object": "list",
"data": [
{ "object": "embedding", "index": 0, "embedding": [0.0123, -0.0456, 0.0789] },
{ "object": "embedding", "index": 1, "embedding": [0.0311, -0.0127, 0.0644] }
],
"model": "the-id-from-the-catalog",
"usage": { "prompt_tokens": 14, "total_tokens": 14 }
}data-তে প্রতিটা input-এর জন্য একটা করে entry থাকে, একই ক্রমে। index হলো input-টার অবস্থান। body আসে provider থেকে, তাই বাড়তি field আসতে পারে, আর vector কত বড় হবে সেটা model ঠিক করে। completion_tokens নেই, কারণ embedding request কোনো text তৈরি করে না।
দুটো vector তুলনা করা#
একই model-এর vector-গুলো cosine similarity দিয়ে তুলনা করা যায়। Python-এ ছোট একটা উদাহরণ:
import math
def cosine(a, b):
dot = sum(x * y for x, y in zip(a, b))
return dot / (math.sqrt(sum(x * x for x in a)) * math.sqrt(sum(y * y for y in b)))
print(cosine(vectors[0], vectors[1]))আলাদা model-এর vector, বা একই model-এর আলাদা dimensions-এর vector, কখনো একসাথে তুলনা বা index করবেন না। প্রতিটা vector-এর পাশে model-এর id আর dimensions রেখে দিন, তাহলে কখন আবার embed করতে হবে সেটা বোঝা যাবে।
Billing আর সীমা#
- হিসাব। embeddings-এর বিল হয় provider-এর জানানো
usage.prompt_tokensধরে, model-এর প্রতি million token-এর input price-এ। output-এর দিক নেই। প্রতিটা model-এর দাম model catalog আর pricing-এ আছে। provider usage না পাঠালে gateway request আর response-এর size দেখে আন্দাজ করে নেয়। max_tokensনেই। chat-এর মতো এখানে output-এর জন্য কিছু আটকে রাখা হয় না। admission শুধু request-এর size থেকে সবচেয়ে খারাপ ক্ষেত্রের খরচ ধরে রাখে, তাই আপনার ব্যালান্স ওই আন্দাজ মেটাতে না পারলে তবেই টাকার অভাবে request ফিরিয়ে দেওয়া হয়। দাম দিতে হয় আসল usage-এর।- Rate limit। প্রতিটা embeddings request আপনার per-minute limit-এ একটা request হিসেবে গোনা হয় আর চলার সময় একটা concurrency slot ধরে রাখে, request ছোট হোক বা বড়। তাই প্রতি text-এর জন্য আলাদা request না পাঠিয়ে, model-এর provider-এর সীমার ভেতরে অনেকগুলো input এক
inputarray-তে দিন। rate limits পেজ দেখুন। - Fail করা request-এর বিল হয় না। provider 400 বা তার ওপরের status দিলে সেটা কোনো চার্জ ছাড়াই আপনার কাছে ফেরত আসে।
- Stream হয় না। embeddings-এ
streammode নেই।
Embeddings endpoint-এ chat model দিলে#
এখানে chat model পাঠানোই সবচেয়ে চেনা ভুল। কী দেখবেন, সেটা model-এর provider-এর ওপর নির্ভর করে, Tokens-এর কোনো বাঁধা নিয়ম নেই:
| Response | কারণ |
|---|---|
400 invalid_request, "rejected by the upstream provider" | provider request নিয়েছে, কিন্তু ফিরিয়ে দিয়েছে, কারণ model-টা embeddings বানাতে পারে না। |
404 model_not_found | ওই model-এর জন্য provider-এর কাছে embeddings route নেই। catalog-এ নেই এমন id দিলেও এটাই আসে। |
400 endpoint_not_supported_for_model | model-টা শুধু এমন provider-এর মাধ্যমে চলে যে Anthropic Messages protocol বোঝে, আর সেখানে embeddings নেই। কিছুই পাঠানো হয়নি। |
502 upstream_unreachable | model-এর কয়েকটা provider আছে, আর প্রতিটাই fail করেছে বা request ফিরিয়ে দিয়েছে। |
সব ক্ষেত্রেই catalog থেকে একটা embedding model বেছে নিন। upstream-এর message বদলে একটা সাধারণ message বসানো হয়, তাই Support-এর সাথে যোগাযোগ করার সময় x-tokens-request-id header-টা দিন। পুরো তালিকা errors পেজে।
Error#
gateway-র error OpenAI-র error shape-এ আসে, সাথে থাকে একটা code, যা ধরে আপনি branch করতে পারেন। প্রতিটা response-এ x-tokens-request-id header থাকে। এখানে সবচেয়ে বেশি যেগুলো পাবেন:
| Status | Code | কী করবেন |
|---|---|---|
| 400 | invalid_request | model আর input দেখুন, আর Content-Type: application/json পাঠিয়েছেন কি না। |
| 402 | insufficient_credits, no_funding | billing থেকে টাকা যোগ করুন বা renew করুন। |
| 403 | model_not_allowed_on_key | key-র allow-list-এ এই model নেই। অন্য key ব্যবহার করুন। |
| 404 | model_not_found | GET /v1/models দিয়ে id মিলিয়ে নিন, নয়তো model-টা embedding model নয়। |
| 413 | request_entity_too_large | এক request-এ কম input পাঠান। |
| 429 | rate_limited, concurrency_limit | Retry-After পর্যন্ত অপেক্ষা করুন, আর input-গুলো কম request-এ ভাগ করে নিন। |
বড় আকারে bulk indexing চালালে rate limits পেজের মতো backoff সহ retry যোগ করুন, আর একসাথে চলা request-এর সংখ্যা plan-এর concurrency limit-এর নিচে রাখুন।
আরও পড়ুন#
- Chat completions: text তৈরির জন্য।
- Token counting: অনেক বড় corpus embed করার আগে input-এর size আন্দাজ করতে।
- Models and usage:
GET /v1/modelsআরGET /v1/tokens/usage-এর জন্য।