Установка SDK, base_url и ключ, пример для Node.js и Next.js, streaming-ответ, rate limits, логи и стоимость. Совместимо с пакетом openai.
Используется официальный пакет openai. Ключ держите только на сервере — никогда не светите его в браузерном бандле.
npm install openai
Создаёте клиент с baseURL и ключом из окружения — дальше стандартный вызов chat.completions.create.
import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.growmi.ru/v1", apiKey: process.env.GROWMI_KEY, }); const r = await client.chat.completions.create({ model: "gpt", messages: [{ role: "user", content: "Что такое base_url?" }], }); console.log(r.choices[0].message.content);
Запрос выполняется на сервере, ключ не попадает в клиент. Пример route handler в App Router:
// app/api/chat/route.ts import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.growmi.ru/v1", apiKey: process.env.GROWMI_KEY, }); export async function POST(req: Request) { const { prompt } = await req.json(); const r = await client.chat.completions.create({ model: "gpt", messages: [{ role: "user", content: prompt }], }); return Response.json({ text: r.choices[0].message.content }); }
Для печати «по мере генерации» возвращайте поток. SDK отдаёт async-итератор чанков.
export async function POST(req: Request) { const { prompt } = await req.json(); const completion = await client.chat.completions.create({ model: "gpt", stream: true, messages: [{ role: "user", content: prompt }], }); const stream = new ReadableStream({ async start(controller) { for await (const chunk of completion) { controller.enqueue(new TextEncoder().encode( chunk.choices[0].delta.content ?? "")); } controller.close(); }, }); return new Response(stream); }
На 429 читайте retry-after и повторяйте с бэкоффом. SDK бросает RateLimitError — удобно перехватывать.
import { RateLimitError, APIError } from "openai"; async function ask(messages, retries = 3) { for (let i = 0; i < retries; i++) { try { return await client.chat.completions.create({ model: "gpt", messages }); } catch (e) { const retriable = e instanceof RateLimitError || (e instanceof APIError && e.status >= 500); if (!retriable) throw e; await new Promise(r => setTimeout(r, 2 ** i * 1000)); } } throw new Error("AI API недоступен после ретраев"); }
Поле usage в ответе содержит число токенов. Логируйте его рядом с requestId, чтобы видеть себестоимость каждого запроса; полная история — в кабинете.
const u = r.usage; console.log({ in: u.prompt_tokens, out: u.completion_tokens, rub: ((u.prompt_tokens / 1000) * PRICE_IN + (u.completion_tokens / 1000) * PRICE_OUT).toFixed(2), });
PRICE_IN / PRICE_OUT за 1K токенов берутся из тарифа модели — точные значения в кабинете.
Пакет openai (npm i openai). API совместим с OpenAI, поэтому в конструкторе указываете baseURL и apiKey GROWMI — остальной код стандартный.
В route handler или server action создайте запрос со stream: true и верните ReadableStream. Токены отдаются клиенту по мере генерации.
На ответ 429 читайте заголовок retry-after и повторяйте запрос с экспоненциальным бэкоффом. SDK openai также бросает RateLimitError, который удобно перехватывать.
Нет. Ключ всегда на сервере (route handler, server action, бэкенд). Клиент обращается к вашему эндпоинту, а тот — к AI API.
Оставьте email — пришлём API-ключ, тестовый баланс и шаблон для Next.js.