Skip to content

Node.js ও TypeScript (OpenAI SDK)

Node.js ও TypeScript থেকে Tokens-এর সাথে official openai npm package ব্যবহার করুন: client setup, streaming, APIError দিয়ে error handling, আর key server-এ রাখার জন্য Next.js route handler।

যেসব tool-এ কাজ করেOpenAI Node SDKNext.js

সর্বশেষ আপডেট 11 অক্টোবর 2026

Markdown-এ দেখুন
এই পাতায়

Official openai npm package Tokens-এর সাথে চালাতে দুটো setting বদলালেই হয়: baseURL আর apiKey। এই পেজে আছে TypeScript setup, streaming, APIError থেকে Tokens-এর error code পড়া, আর একটা Next.js route handler, যাতে আপনার key কখনো browser-এ না পৌঁছায়।

OpenAI Node.js SDK install করুন#

bash
npm install openai
export TOKENS_API_KEY="tok_live_your_key"

উদাহরণগুলোতে ES module আর top-level await আছে, তাই .mjs বা .ts file হিসেবে চালান (যেমন npx tsx hello.ts)। ধরে নেওয়া হয়েছে আপনি openai-এর সাম্প্রতিক major version (v5 বা তার পরের) ব্যবহার করছেন।

lib/tokens.ts
import OpenAI from "openai";

export const tokens = new OpenAI({
  baseURL: "https://tokens.bd/v1",
  apiKey: process.env.TOKENS_API_KEY,
  timeout: 120_000, // ms; SDK default is 10 minutes
  maxRetries: 2, // SDK default; retries connection errors, 408, 409, 429, 5xx
});
hello.ts
import { tokens } from "./lib/tokens";

const completion = await tokens.chat.completions.create({
  model: "deepseek/deepseek-v4.1-flash",
  messages: [
    { role: "system", content: "Reply in one short paragraph." },
    { role: "user", content: "What's the difference between interface and type in TypeScript?" },
  ],
  max_tokens: 400,
});

console.log(completion.choices[0]?.message.content);
console.log(completion.usage);

Code না ছুঁয়েই কাজ সারতে চাইলে SDK environment থেকে OPENAI_BASE_URL আর OPENAI_API_KEY-ও পড়ে নেয়। তবে খেয়াল রাখবেন, ওই environment-এ যত OpenAI-based tool আছে, এই variable সবগুলোর ওপরই প্রভাব ফেলবে।

Model ID copy করুন /models থেকে বা await tokens.models.list() থেকে। আন্দাজে লিখবেন না।

Chat completion stream করুন#

ts
const stream = await tokens.chat.completions.create({
  model: "deepseek/deepseek-v4.1-flash",
  messages: [{ role: "user", content: "List five git commands I should know, one per line." }],
  stream: true,
  stream_options: { include_usage: true },
});

for await (const chunk of stream) {
  const text = chunk.choices[0]?.delta?.content;
  if (text) process.stdout.write(text);
  if (chunk.usage) {
    console.log(`\n${chunk.usage.prompt_tokens} in, ${chunk.usage.completion_tokens} out`);
  }
}

include_usage চালু থাকলে শেষ chunk-এর choices array ফাঁকা থাকে, সেজন্যই code-এ optional chaining আছে। মাঝপথে থামাতে চাইলে loop থেকে break করুন অথবা stream.controller.abort() call করুন। আরও দেখুন Streaming।

APIError দিয়ে error সামলান#

2xx ছাড়া যেকোনো response OpenAI.APIError-এর একটা subclass throw করে। Tokens প্রতিটি error-এ একটা নির্দিষ্ট code বসিয়ে দেয়, আর HTTP status-এর চেয়ে সেটা থেকে অনেক বেশি জানা যায়।

ts
import OpenAI from "openai";
import { tokens } from "./lib/tokens";

try {
  await tokens.chat.completions.create({
    model: "deepseek/deepseek-v4.1-flash",
    messages: [{ role: "user", content: "hi" }],
  });
} catch (err) {
  if (err instanceof OpenAI.APIConnectionError) {
    console.error("Network problem:", err.message);
  } else if (err instanceof OpenAI.APIError) {
    const requestId = err.headers?.get("x-tokens-request-id");
    console.error(err.status, err.code, err.message, requestId);

    switch (err.code) {
      case "insufficient_credits":
        // 402: top up at /dashboard/billing
        break;
      case "window_exhausted":
        // 429: plan window used up; Retry-After header = seconds until reset
        console.error("Resets in", err.headers?.get("retry-after"), "s");
        break;
      case "model_not_allowed_on_key":
      case "tier_permission_denied":
        // 403: key allow-list or plan doesn't cover this model
        break;
    }
  } else {
    throw err;
  }
}

দুটো কথা জেনে রাখুন:

  • SDK-র সাম্প্রতিক version-এ err.headers একটা সাধারণ Headers object, তাই .get() দিয়ে পড়ুন। x-tokens-request-id সবসময় log করুন। আপনার request খুঁজে পেতে Support-এর এটা লাগে।
  • SDK নিজে থেকেই 429 আর 5xx-এ retry করে। আর 502, 503 বা 504 ফেরত দেওয়ার আগেই gateway অন্য upstream source-এ চেষ্টা করে দেখে নিয়েছে। window_exhausted-এ Retry-After পার না হওয়া পর্যন্ত retry করে লাভ নেই, আর সেটা কয়েক ঘণ্টাও হতে পারে। তাই তাড়াতাড়ি fail করাতে চাইলে maxRetries কম রাখুন।

সব code-এর তালিকা Errors পেজে, আর প্রতিটার সমাধান Troubleshooting পেজে।

Key server-এ রাখুন: Next.js route handler#

Tokens CORS header পাঠায় না, তাই browser-এর JavaScript থেকে সরাসরি call করলে সেটা fail করবে। আর করলেও আপনার key ফাঁস হয়ে যেত। Call-টা একটা route handler-এর ভেতরে রাখুন, আর frontend থেকে সেই route-কে call করুন।

app/api/chat/route.ts
import OpenAI from "openai";

export const runtime = "nodejs";

const tokens = new OpenAI({
  baseURL: "https://tokens.bd/v1",
  apiKey: process.env.TOKENS_API_KEY, // server-only: no NEXT_PUBLIC_ prefix
});

type ChatMessage = { role: "user" | "assistant"; content: string };

export async function POST(req: Request) {
  const body = (await req.json()) as { messages?: ChatMessage[] };
  if (!Array.isArray(body.messages) || body.messages.length === 0) {
    return Response.json({ error: "messages required" }, { status: 400 });
  }

  try {
    const stream = await tokens.chat.completions.create(
      {
        model: "deepseek/deepseek-v4.1-flash", // pick on the server, not from the client
        messages: body.messages.slice(-20),
        max_tokens: 1024,
        stream: true,
      },
      { signal: req.signal } // stop paying for tokens if the user navigates away
    );

    const encoder = new TextEncoder();
    const text = new ReadableStream<Uint8Array>({
      async start(controller) {
        try {
          for await (const chunk of stream) {
            const delta = chunk.choices[0]?.delta?.content;
            if (delta) controller.enqueue(encoder.encode(delta));
          }
          controller.close();
        } catch (e) {
          controller.error(e);
        }
      },
    });

    return new Response(text, {
      headers: { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "no-store" },
    });
  } catch (err) {
    if (err instanceof OpenAI.APIError) {
      return Response.json(
        { error: err.code ?? "upstream_error", requestId: err.headers?.get("x-tokens-request-id") },
        { status: err.status ?? 502 }
      );
    }
    throw err;
  }
}

Client-এর দিকে লাগে শুধু সাধারণ একটা fetch, যা response body-কে stream হিসেবে পড়ে:

ts
const res = await fetch("/api/chat", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ messages: [{ role: "user", content: "Hello" }] }),
});
const reader = res.body!.pipeThrough(new TextDecoderStream()).getReader();
for (;;) {
  const { value, done } = await reader.read();
  if (done) break;
  console.log(value);
}

Handler-এর কিছু সিদ্ধান্ত ইচ্ছে করেই নেওয়া। Model আর max_tokens server-এ ঠিক করা হয়েছে, যাতে কোনো visitor আপনার app-কে দামি model-এ নিয়ে যেতে না পারে। Message history ছেঁটে রাখা হয়েছে। এই route-এর সামনে নিজের authentication আর প্রতি user-এর rate limiting বসানোও উচিত, কারণ যে-ই route-টায় পৌঁছাতে পারবে, সে-ই আপনার ব্যালান্স খরচ করবে। মাসিক spend cap দেওয়া key (API keys) ক্ষতির একটা শক্ত ঊর্ধ্বসীমা বেঁধে দেয়।

Vercel AI SDK ব্যবহার করলে streamText দিয়ে একই pattern Vercel AI SDK পেজে দেখানো আছে।

এই পাতাটা কি কাজে লেগেছে?

এখনো আটকে আছেন? Support ticket খুলুন

আপনার agent set up করতে সাহায্য লাগবে?

Connection tester দিয়ে সংযোগ পরীক্ষা করে নিন, অথবা একটা API key তৈরি করুন।