Bumalik sa blog

API at SDKGabay

I-stream ang mga chat response sa Node.js gamit ang OpenAI SDK

I-stream ang isang chat completion token sa token sa Node.js: for await loop, paghinto kapag kailangan, paghawak ng error at token usage gamit ang OpenAI SDK.

Ni CheapTokens TeamNai-publish noong Na-update noong 5 min na pagbabasa

Terminal window na nagpi-print ng streamed na sagot token sa token mula sa isang Node.js script
Sa pahinang ito
  1. Ano ang kailangan mo
  2. Hakbang 1. I-stream ang sagot gamit ang for await
  3. Hakbang 2. Ihinto ang stream kapag kailangan
  4. Hakbang 3. Pangasiwaan ang mga error
  5. Hakbang 4. Basahin ang usage at tantiyahin ang gastos
  6. Buong script
  7. Mga susunod na hakbang

Binibigyang-daan ng streaming ang iyong app na ipakita ang sagot habang ito ay nililikha sa halip na hintayin ang buong tugon. Sa gabay na ito, gagawa ka ng maliit na Node.js script na nag-stream ng chat completion mula sa CheapTokens API token sa token, hinihinto ito kapag kailangan at hinahawakan ang mga error. Ang bersyon ng Python ng paksang ito ay nasa Streaming responses in Python.

Ano ang kailangan mo#

  • Node.js 22 o mas bago (ang minimum na bersyon na nakasaad sa openai package README, sinuri noong 22 Oktubre 2026).
  • Isang CheapTokens API key. Kung wala ka pa, sundin ang Your first API request with CheapTokens.
  • Ang opisyal na SDK: npm install openai.

Nagbibigay ang CheapTokens ng OpenAI-compatible API sa https://api.cheaptokens.dev/v1, kaya gumagana ang opisyal na openai package sa pamamagitan ng pagpapalit lamang ng base URL at ang key. Itago ang key sa isang environment variable, hindi sa code:

bash
export CHEAPTOKENS_API_KEY="your-key"

Hakbang 1. I-stream ang sagot gamit ang for await#

Gumawa ng stream.mjs (ang .mjs extension ay nagbibigay-daan sa iyo na gumamit ng import at top-level await):

javascript
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.CHEAPTOKENS_API_KEY,
  baseURL: 'https://api.cheaptokens.dev/v1',
});

const stream = await client.chat.completions.create({
  model: 'deepseek-ai/DeepSeek-V4-Flash-0731', // take the id from the CheapTokens docs
  messages: [{ role: 'user', content: 'Explain streaming in two sentences.' }],
  stream: true,
  stream_options: { include_usage: true },
});

let usage = null;
for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta?.content;
  if (delta) process.stdout.write(delta);
  if (chunk.usage) usage = chunk.usage;
}

console.log('\n\nusage:', usage);

Patakbuhin ito gamit ang node stream.mjs. Binabasa ng SDK ang Server-Sent Events mula sa API at binibigyan ka ng isang chunk bawat pag-ulit ng for await. Tatlong detalye ang mahalaga:

  • Dumarating ang teksto sa chunk.choices[0].delta.content. May mga chunk na walang teksto (ang una ay madalas naglalaman lamang ng role), kaya tiyakin na ang delta ay hindi walang laman.
  • Ang process.stdout.write ay nagpi-print nang walang line break, kaya lumalabas ang mga salita nang sunod-sunod.
  • Sa stream_options: { include_usage: true }, ang huling chunk ay nagdadala ng usage object na may bilang ng prompt at completion token, at ang choices array nito ay walang laman. Iyon ang dahilan kung bakit ginagamit ng code ang chunk.choices[0]?. na may optional chaining.

Ang model id ay nagmumula sa dokumentasyon ng CheapTokens: iba't ibang pangalan ang ibinibigay ng mga provider sa parehong modelo, kaya kopyahin ang id mula doon.

Hakbang 2. Ihinto ang stream kapag kailangan#

Pinipindot ng mga user ang Stop, nagsasara ng tab o nagpapalit ng chat. Kanselahin ang request para hindi ka maghintay ng mga token na walang babasa. Magpasa ng AbortSignal sa mga opsyon ng request:

javascript
const controller = new AbortController();

process.on('SIGINT', () => controller.abort()); // Ctrl+C stops the stream

const stream = await client.chat.completions.create(
  {
    model: 'deepseek-ai/DeepSeek-V4-Flash-0731',
    messages: [{ role: 'user', content: 'Write a long story about a lighthouse.' }],
    stream: true,
  },
  { signal: controller.signal },
);

Ang stream object ay mayroon ding sariling stream.controller.abort(), at ang pag-alis sa for await loop gamit ang break ay nagsasara rin ng koneksyon. Gamitin ang mas malapit sa iyong code: isang signal kapag ang cancel button ay nasa ibang lugar, break kapag ang desisyon ay ginawa sa loob ng loop (halimbawa, nakakita ka ng stop word).

Hakbang 3. Pangasiwaan ang mga error#

Maaaring mabigo ang isang stream bago ang unang token (maling key, walang laman na balanse) o sa gitna (pagkawala ng network). Balutin ang parehong request at loop sa isang try:

javascript
try {
  for await (const chunk of stream) {
    const delta = chunk.choices[0]?.delta?.content;
    if (delta) process.stdout.write(delta);
  }
} catch (err) {
  if (err instanceof OpenAI.APIUserAbortError) {
    console.log('\n[stopped by user]');
  } else if (err instanceof OpenAI.APIError) {
    console.error(`\nAPI error ${err.status}: ${err.message}`);
  } else {
    throw err;
  }
}
  • Ang APIUserAbortError ay ang makukuha mo pagkatapos ng iyong sariling abort(). Hindi ito pagkabigo, kaya huwag ipakita ito bilang isa.
  • Ang APIError ay may HTTP status: 401 ay nangangahulugang mali o nawawalang key, 429 ay nangangahulugang masyadong maraming request, at ang mensahe tungkol sa mga token ay nangangahulugang kailangan ng top-up ang balanse. Higit pang mga sanhi at solusyon ay nasa Common connection errors and how to fix them at "Not enough tokens" error.
  • Ang tekstong na-print na ay nananatiling wasto pagkatapos ng error. Panatilihin ito kung gusto mong ipakita ang bahagyang sagot.

Hakbang 4. Basahin ang usage at tantiyahin ang gastos#

Ang usage object ay naglalaman ng prompt_tokens at completion_tokens. Kasama ang presyo ng modelo kada 1M token, binibigyan ka nito ng eksaktong gastos ng isang request. Para sa magaspang na tantiya bago ka magpatakbo ng anuman, gamitin ang live na talahanayan sa ibaba: ipinapakita nito ang gastos ng 1,000 request na may 2,000 input at 800 output token bawat isa.

Modelo Bawat kahilingan 1,000 mga kahilingan OpenRouter, 1,000 mga kahilingan
GLM-5.3-Flash $0.000072 $0.072 $0.143
DeepSeek-V4-Flash $0.00011 $0.11 $0.22
MiniMax-M2.7 $0.00022 $0.22 $1.56

2,000 input at 800 output na token bawat kahilingan. Ang mga presyo kada 1M token ay kasalukuyan at nagbabago kasabay ng aming mga taripa; ang column ng OpenRouter ay nagpapakita ng reference na presyo para sa parehong workload.

Para sa mga streamed na chat reply, ang MiniMax-M2.7 ay may presyong $0.05 kada 1M input at $0.15 kada 1M output token, na may 180K context at hanggang 8,192 output token bawat sagot. Ang presyo ay fixed kada modelo sa anumang oras ng araw, at isang balanse ang sumasaklaw sa lahat ng modelo, kaya sapat na ang pagpapalit ng model string upang ihambing ang mga ito sa iyong sariling mga prompt.

Buong script#

javascript
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.CHEAPTOKENS_API_KEY,
  baseURL: 'https://api.cheaptokens.dev/v1',
});

const controller = new AbortController();
process.on('SIGINT', () => controller.abort());

try {
  const stream = await client.chat.completions.create(
    {
      model: 'deepseek-ai/DeepSeek-V4-Flash-0731',
      messages: [{ role: 'user', content: 'Explain streaming in two sentences.' }],
      stream: true,
      stream_options: { include_usage: true },
    },
    { signal: controller.signal },
  );

  let usage = null;
  for await (const chunk of stream) {
    const delta = chunk.choices[0]?.delta?.content;
    if (delta) process.stdout.write(delta);
    if (chunk.usage) usage = chunk.usage;
  }
  console.log('\n\nusage:', usage);
} catch (err) {
  if (err instanceof OpenAI.APIUserAbortError) {
    console.log('\n[stopped by user]');
  } else if (err instanceof OpenAI.APIError) {
    console.error(`\nAPI error ${err.status}: ${err.message}`);
  } else {
    throw err;
  }
}

Mga susunod na hakbang#

  • Ipadala ang mga chunk sa isang browser gamit ang Server-Sent Events mula sa iyong sariling endpoint, para hindi kailanman umalis ang key sa server.
  • Subukan ang iba pang mga modelo sa pamamagitan ng pagpapalit lamang ng model string: ang MiniMax-M2.7 ay available sa parehong balanse at parehong base URL.
  • Kumuha ng key at patakbuhin ang script: create a CheapTokens API key at mag-top up ng balanse.

Ang mga endpoint, model id at limitasyon para sa bawat modelo ay nasa CheapTokens docs.