رفتن به محتوا

اتصال Node.js به API هوش مصنوعی با کتابخانهٔ openai

راهنمای قدم‌به‌قدم استفاده از کتابخانهٔ رسمی openai در Node.js با API هیبانا؛ نصب، متغیر محیطی، چت، استریم و مدیریت خطا با کد آزموده‌شده.

تیم هیبانا۵ دقیقه مطالعه
رباتی کوچک کنار یک لپ‌تاپ که با سیمی به یک ابر روشن وصل است، شش‌ضلعی‌های سبز درخشان را مثل قطعه‌های پازل کنار هم می‌چیند

اگر بک‌اند شما با Node.js نوشته شده، ساده‌ترین راه برای اضافه کردن هوش مصنوعی به آن، کتابخانهٔ رسمی openai است. API هیبانا سازگار با OpenAI است؛ یعنی همین کتابخانه بدون هیچ تغییری کار می‌کند و فقط کلید و آدرس پایه عوض می‌شود. در این مطلب از نصب شروع می‌کنیم و تا پاسخ استریم و مدیریت خطا پیش می‌رویم. همهٔ نمونه‌ها را با Node.js 22 و نسخهٔ 7.39 کتابخانهٔ openai روی API واقعی هیبانا اجرا کرده‌ایم و خروجی‌هایی که می‌بینید واقعی‌اند.

پیش‌نیازها و نصب

دو چیز لازم دارید: Node.js و یک کلید API. طبق README کتابخانه، نسخه‌های فعلی openai روی Node.js 22 و 24 پشتیبانی می‌شوند و حداقل نسخهٔ Node.js 22 است. نسخهٔ خود را با node -v ببینید.

کلید را از داشبورد هیبانا بسازید؛ مراحل تصویری در دریافت کلید API آمده است. بعد یک پوشهٔ تازه بسازید و کتابخانه را نصب کنید:

mkdir hibana-node && cd hibana-nodenpm init -ynpm pkg set type=modulenpm install openai

خط npm pkg set type=module پروژه را ES Module می‌کند تا بتوانید از import و await در سطح بالای فایل استفاده کنید. همهٔ نمونه‌های این مطلب با پسوند .mjs نوشته شده‌اند که بدون این تنظیم هم ES Module حساب می‌شوند.

کلید را در کد ننویسید

کلید API مثل رمز عبور است و نباید در کد یا مخزن Git قرار بگیرد. آن را در متغیر محیطی نگه دارید. Node.js خودش می‌تواند فایل .env را بخواند و به بستهٔ اضافه‌ای نیاز نیست. یک فایل .env بسازید:

HIBANA_API_KEY=YOUR_API_KEY

و برنامه را با پرچم --env-file اجرا کنید:

node --env-file=.env chat.mjs

طبق مستندات Node.js، این پرچم از نسخهٔ ۲۰.۶ اضافه شده و از نسخه‌های ۲۲.۲۱ و ۲۴.۱۰ دیگر آزمایشی نیست. اگر همان متغیر هم در محیط سیستم و هم در فایل تعریف شده باشد، مقدار محیط سیستم برنده است. فراموش نکنید .env را به .gitignore اضافه کنید.

اولین درخواست چت

کد زیر یک کلاینت می‌سازد که به‌جای سرور OpenAI به هیبانا وصل می‌شود و یک پیام می‌فرستد:

// chat.mjsimport OpenAI from "openai"; const client = new OpenAI({  apiKey: process.env.HIBANA_API_KEY,  baseURL: "https://api-ai.hibanacloud.ir/v1",}); const completion = await client.chat.completions.create({  model: "gpt-5-nano",  reasoning_effort: "low",  messages: [    { role: "system", content: "پاسخ را کوتاه و به فارسی بده." },    { role: "user", content: "Node.js در یک جمله چیست؟" },  ],}); console.log(completion.choices[0].message.content);console.log(completion.usage);

خروجی واقعی:

Node.js یک محیط اجرای جاوااسکریپت است که جاوااسکریپت را خارج از مرورگر و روی سرور، به‌صورت غیرهم‌زمان و رویداد-محور اجرا می‌کند.{  prompt_tokens: 28,  completion_tokens: 184,  total_tokens: 212,  cost_rial: 343}

چند نکته در همین چند خط هست:

  • baseURL تنها تفاوت با کد OpenAI است. هر نمونه‌کدی که برای OpenAI نوشته شده، با عوض کردن همین خط و کلید روی هیبانا اجرا می‌شود.
  • model نام مدل است و باید دقیقاً همان رشته‌ای باشد که در لیست مدل‌ها آمده است. اینجا از GPT-5 nano، کوچک‌ترین و سریع‌ترین عضو خانوادهٔ GPT-5، استفاده کرده‌ایم؛ قیمت آن در زمان نگارش این مطلب را در صفحهٔ همان مدل ببینید.
  • usage.cost_rial هزینهٔ همین درخواست به ریال است. هیبانا این فیلد را به پاسخ اضافه می‌کند و می‌توانید آن را برای گزارش مصرف ذخیره کنید.
  • completion_tokens از طول ظاهری پاسخ بیشتر است، چون GPT-5 nano پیش از نوشتن پاسخ استدلال می‌کند و توکن‌های استدلال هم حساب می‌شوند. همین درخواست را بدون reasoning_effort: "low" هم اجرا کردیم و ۵۲۱ توکن خروجی مصرف شد؛ برای کارهای ساده، سطح پایین استدلال هزینه را به‌طور محسوسی کم می‌کند. دربارهٔ نحوهٔ محاسبهٔ هزینه، توکن چیست و هزینهٔ API چطور حساب می‌شود را بخوانید.

برای گفت‌وگوی چندمرحله‌ای، API چیزی از پیام‌های قبلی به خاطر نمی‌سپارد. پاسخ مدل را با نقش assistant به آرایهٔ messages اضافه کنید و پیام بعدی کاربر را پشت آن بفرستید.

کلید در مرورگر نه

کتابخانهٔ openai به‌طور پیش‌فرض در مرورگر اجرا نمی‌شود تا کلید شما در کد سمت کاربر لو نرود. راه درست این است که درخواست را از سرور Node.js خودتان بفرستید و فقط پاسخ را به مرورگر برگردانید.

راه کوتاه‌تر با متغیرهای OPENAI

اگر نمی‌خواهید apiKey و baseURL را در کد بنویسید، کتابخانه به‌طور پیش‌فرض آن‌ها را از متغیرهای OPENAI_API_KEY و OPENAI_BASE_URL می‌خواند. فایل .env را این‌طور بنویسید:

OPENAI_API_KEY=YOUR_API_KEYOPENAI_BASE_URL=https://api-ai.hibanacloud.ir/v1

و کلاینت را بدون هیچ تنظیمی بسازید:

// env.mjsimport OpenAI from "openai"; // کلید و آدرس از OPENAI_API_KEY و OPENAI_BASE_URL خوانده می‌شوندconst client = new OpenAI(); const r = await client.chat.completions.create({  model: "gpt-5-nano",  reasoning_effort: "low",  messages: [{ role: "user", content: "فقط بنویس: اتصال برقرار است" }],});console.log(client.baseURL);console.log(r.choices[0].message.content);

خروجی واقعی:

https://api-ai.hibanacloud.ir/v1اتصال برقرار است

این روش برای ابزارها و کتابخانه‌هایی که خودشان کلاینت OpenAI می‌سازند هم مفید است، چون همان متغیرها را می‌خوانند. فقط دقت کنید اگر روی یک سیستم با OpenAI هم کار می‌کنید، این دو متغیر بر همهٔ برنامه‌هایی که آن‌ها را می‌خوانند اثر می‌گذارند.

پاسخ استریم؛ نمایش کلمه‌به‌کلمه

در یک چت‌بات، کاربر نباید چند ثانیه منتظر کل پاسخ بماند. با stream: true پاسخ تکه‌تکه می‌رسد و کتابخانه آن را به یک حلقهٔ for await تبدیل می‌کند:

// stream.mjsimport OpenAI from "openai"; const client = new OpenAI({  apiKey: process.env.HIBANA_API_KEY,  baseURL: "https://api-ai.hibanacloud.ir/v1",}); const stream = await client.chat.completions.create({  model: "gpt-5-nano",  reasoning_effort: "low",  messages: [{ role: "user", content: "در دو جملهٔ کوتاه بگو چرا پاسخ استریم تجربهٔ کاربر را بهتر می‌کند." }],  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\nusage:", chunk.usage);}

خروجی واقعی:

- استریم با ارسال سریع‌ترین قطعات پاسخ، کاربر را در همان لحظه درگیر می‌کند و حس سرعت و پویایی را افزایش می‌دهد.- کاربر می‌تواند به مرور مطلب را دنبال کرده، بازخورد سریع بگیرد و از تأخیرهای طولانی جلوگیری شود. usage: {  prompt_tokens: 27,  completion_tokens: 264,  total_tokens: 291,  cost_rial: 489}

هر تکه فقط بخش تازهٔ متن را در delta.content دارد و ممکن است خالی باشد؛ برای همین از ?. استفاده کرده‌ایم. در آزمون ما، بدون stream_options: { include_usage: true } هیچ تکه‌ای usage نداشت؛ اگر هزینهٔ هر درخواست استریم را لازم دارید، این گزینه را بفرستید. کتابخانه خودش خطوط : keep-alive را که سرور هنگام فکر کردن مدل می‌فرستد، نادیده می‌گیرد. جزئیات قالب تکه‌ها در مستندات استریم آمده است.

مدیریت خطا، تلاش مجدد و timeout

وقتی سرور کد خطا برمی‌گرداند، کتابخانه یک زیرکلاس از OpenAI.APIError پرتاب می‌کند. طبق README کتابخانه، ۴۰۰ به BadRequestError، ۴۰۱ به AuthenticationError، ۴۲۹ به RateLimitError و ۵۰۰ به بالا به InternalServerError تبدیل می‌شود و خطاهای شبکه APIConnectionError هستند. ۴۰۲ کلاس جداگانه‌ای ندارد و باید آن را از status تشخیص داد.

همین README می‌گوید خطاهای اتصال، ۴۰۸، ۴۰۹، ۴۲۹ و ۵۰۰ به بالا به‌طور پیش‌فرض دو بار با فاصلهٔ فزاینده دوباره امتحان می‌شوند و timeout پیش‌فرض هر درخواست ۱۰ دقیقه است. هر دو را می‌توانید هنگام ساختن کلاینت تغییر دهید:

// errors.mjsimport OpenAI from "openai"; const client = new OpenAI({  apiKey: process.env.HIBANA_API_KEY,  baseURL: "https://api-ai.hibanacloud.ir/v1",  maxRetries: 3, // برای 429 و 5xx و خطای اتصال، خودِ SDK دوباره تلاش می‌کند  timeout: 60 * 1000, // پیش‌فرض ۱۰ دقیقه است}); async function ask(model, text) {  try {    const r = await client.chat.completions.create({      model,      messages: [{ role: "user", content: text }],    });    return r.choices[0].message.content;  } catch (err) {    if (err instanceof OpenAI.AuthenticationError) {      console.log("401:", err.code, "→ کلید یا هدر Authorization را بررسی کنید");    } else if (err instanceof OpenAI.RateLimitError) {      console.log("429:", err.headers?.get("retry-after"), "ثانیه صبر کنید");    } else if (err instanceof OpenAI.BadRequestError) {      console.log("400:", err.code, "→", err.error?.message);    } else if (err instanceof OpenAI.APIError && err.status === 402) {      console.log("402:", err.code, "→ موجودی یا سقف بودجهٔ کلید");    } else if (err instanceof OpenAI.APIConnectionError) {      console.log("اتصال برقرار نشد یا زمان تمام شد");    } else {      throw err;    }    return null;  }} const model = process.argv[2] ?? "gpt-5-nano";const answer = await ask(model, "فقط بنویس: سلام");if (answer) console.log("پاسخ:", answer);

این اسکریپت را سه بار اجرا کردیم: یک بار عادی، یک بار با نام مدلی که وجود ندارد (node errors.mjs gpt-unknown) و یک بار با کلید غلط در HIBANA_API_KEY. خروجی واقعی به همان ترتیب:

پاسخ: سلام400: model_not_found → The requested model 'gpt-unknown' was not found or is disabled.401: invalid_api_key → کلید یا هدر Authorization را بررسی کنید

دو نکته: err.code همان شناسهٔ پایدار خطاست و برنامه باید روی آن تصمیم بگیرد، نه روی متن پیام. و چون تلاش مجدد ممکن است یک درخواست را دو بار پردازش کند، برای کارهای حساس هدر Idempotency-Key را بفرستید؛ در Node.js کافی است گزینهٔ headers: { "Idempotency-Key": key } را به آرگومان دوم create بدهید. ما همین کار را دو بار با یک کلید امتحان کردیم و پاسخ دوم هدر Idempotent-Replayed: true داشت، یعنی مدل دوباره صدا زده نشد. توضیح کامل در کلید یکتاسازی آمده و معنی هر کد خطا را در خطاهای API هوش مصنوعی مفصل نوشته‌ایم.

Responses API هم کار می‌کند

نمونه‌های README کتابخانهٔ openai این روزها بیشتر با client.responses.create نوشته شده‌اند. هیبانا مسیر /v1/responses را هم دارد، پس این شکل هم با همان کلاینت کار می‌کند:

// responses.mjsimport OpenAI from "openai"; const client = new OpenAI({  apiKey: process.env.HIBANA_API_KEY,  baseURL: "https://api-ai.hibanacloud.ir/v1",}); const response = await client.responses.create({  model: "gpt-5-nano",  reasoning: { effort: "low" },  input: "فقط بنویس: سلام از Responses API",}); console.log(response.output_text);

خروجی واقعی:

سلام از Responses API

مستندات هیبانا بیشتر بر پایهٔ Chat Completions نوشته شده‌اند و نمونه‌های این مطلب هم همین‌طور. اگر کد موجودتان با Responses API است، لازم نیست آن را بازنویسی کنید.

جمع‌بندی

برای اتصال Node.js به هیبانا کافی است کتابخانهٔ openai را نصب کنید، کلید را در متغیر محیطی بگذارید و baseURL را روی https://api-ai.hibanacloud.ir/v1 تنظیم کنید. از آنجا به بعد همه‌چیز همان کتابخانهٔ آشناست: chat.completions.create برای چت، stream: true برای پاسخ زنده و کلاس‌های خطای SDK برای مدیریت خطا. برای شروع سریع با زبان‌های دیگر شروع سریع و نمونه‌کدها را ببینید و اگر می‌خواهید همین کد را به یک ربات یا سایت وصل کنید، ساخت چت‌بات برای سایت و بازوی بله قدم بعدی است.

مطالب مرتبط

با یک کلید به همه مدل‌ها وصل شوید

GPT، Claude، Gemini و ده‌ها مدل دیگر، با پرداخت ریالی و یک API سازگار با OpenAI.