NexaraNexara

TypeScript SDK

Официальная TypeScript/JavaScript-библиотека Nexara: транскрибация, диаризация, роли и LLM-анализ в несколько строк кода.

nexara-sdk — официальная TypeScript/JavaScript-библиотека для Nexara API. Она берёт на себя сборку запросов, разбор ответов в типизированные объекты, обработку ошибок и повторные попытки, а асинхронные задачи превращает в один вызов job.wait(). Библиотека полностью типизирована и поставляет собственные .d.ts, тип результата сужается автоматически по task и response_format. Требуется Node.js 20+.

npm install nexara-sdk

Сохраните API-ключ в переменной окружения NEXARA_API_KEY. SDK читает её автоматически при создании клиента, поэтому ключ не нужно указывать в коде — и он не попадёт в репозиторий:

export NEXARA_API_KEY=nx-...

Команда export задаёт переменную только для текущей сессии терминала. Чтобы ключ сохранялся между сессиями, добавьте эту строку в файл конфигурации вашей оболочки (например, ~/.zshrc или ~/.bashrc). На сервере переменную удобнее задавать через настройки окружения или менеджер секретов.

Быстрый старт

import { Nexara } from "nexara-sdk";

const client = new Nexara(); // ключ из переменной окружения NEXARA_API_KEY

const { text } = await client.transcriptions.create({ file: "audio.mp3" });
console.log(text);

Клиент берёт ключ из NEXARA_API_KEY — той самой переменной, что вы задали выше, — поэтому в коде его указывать не нужно. Передать ключ явным полем apiKey тоже можно, но не храните его в коде и не коммитьте в репозиторий.

Клиент

const client = new Nexara({
  // apiKey по умолчанию берётся из переменной окружения NEXARA_API_KEY,
  // либо можете передать ключ сами: apiKey: "nx-..."
  timeoutMs: 600_000, // таймаут запроса в миллисекундах
  maxRetries: 2, // повторы при 429 и сетевых сбоях
});

Клиент асинхронный целиком — отдельного синхронного варианта нет (в отличие от Nexara/AsyncNexara в Python SDK). Все методы возвращают промисы.

Транскрибация

Передайте ровно один из параметров: file (путь, Uint8Array или Blob) или url (прямая ссылка). Файл, переданный путём, стримится с диска и не загружается в память целиком.

// Локальный файл
const local = await client.transcriptions.create({ file: "audio.mp3" });
console.log(local.text);

// Файл по ссылке
const remote = await client.transcriptions.create({
  url: "https://example.com/audio.mp3",
});
console.log(remote.text);

Параметры те же, что и у API: model, language, response_format, timestamp_granularities, profanity_filter и другие. Тип результата сужается автоматически: text, srt и vtt возвращаются строкой, json и verbose_json — типизированными объектами:

import { writeFile } from "node:fs/promises";

const srt = await client.transcriptions.create({
  file: "video.mp4",
  response_format: "srt",
});
await writeFile("video.srt", srt);

const verbose = await client.transcriptions.create({
  file: "audio.mp3",
  response_format: "verbose_json",
  timestamp_granularities: ["word"],
});
for (const word of verbose.words ?? []) {
  console.log(`${word.start.toFixed(2)}–${word.end.toFixed(2)}: ${word.word}`);
}

Диаризация и роли

Разделение по говорящим включается так же, как в API, — task: "diarize". Роли передаются обычным массивом или объектом: SDK сам сериализует их в JSON.

const call = await client.transcriptions.create({
  file: "call.mp3",
  task: "diarize",
  num_speakers: 2,
  roles: ["Оператор", "Клиент"], // или "auto", или { "Роль": "описание" }
});

for (const segment of call.segments) {
  console.log(`${segment.speaker}: ${segment.text}`);
}

Подробнее о режимах — на странице спикеры и роли.

Асинхронные задачи

Для длинных записей используйте асинхронный режим: createJob() ставит задачу и сразу возвращает объект Job, а job.wait() опрашивает статус и возвращает готовый результат.

const job = await client.transcriptions.createJob({
  file: "long_recording.mp3",
});
console.log(job.job_id, job.status); // in_progress

const result = await job.wait(); // опрашивает статус; таймаут по умолчанию — 1_800_000 мс
console.log((result as { text: string }).text);

Задачу можно забрать позже — в том числе из другого процесса:

const job = await client.transcriptions.retrieveJob(jobId);
if (job.status === "complete") {
  console.log(job.result);
}

Что важно знать:

  • Результат хранится 12 часов с момента создания задачи, затем удаляется — после этого retrieveJob() бросит NotFoundError.
  • Одновременно на один ключ может выполняться до 200 задач.
  • Если задача завершилась ошибкой, wait() бросает JobFailedError. Неудавшаяся задача не тарифицируется — повторная отправка бесплатна.
  • Если задача не успела за таймаут, wait() бросает JobTimeoutError; сама задача при этом не отменяется, её можно забрать позже через retrieveJob().

LLM-анализ

Передайте prompt, чтобы прогнать расшифровку через языковую модель, и json_schema — чтобы получить структурированный ответ. Схема передаётся обычным объектом, а llm_output возвращается уже разобранным — никакого ручного JSON.parse.

const result = await client.transcriptions.create({
  file: "meeting.mp3",
  prompt: "Составь протокол встречи: резюме, решения и задачи.",
  json_schema: {
    type: "object",
    properties: {
      summary: { type: "string" },
      decisions: { type: "array", items: { type: "string" } },
      action_items: { type: "array", items: { type: "string" } },
    },
    required: ["summary", "decisions", "action_items"],
  },
});

console.log(result.llm_output); // объект по вашей схеме
console.log(result.transcription.text); // расшифровка, из которой он получен

Без json_schema поле llm_output — строка со свободным ответом модели.

Параллельные запросы

Клиент асинхронный целиком — «async» здесь означает промисы. Отдельного синхронного клиента нет, поэтому несколько запросов запускаются обычным Promise.all:

const urls = [
  "https://example.com/a.mp3",
  "https://example.com/b.mp3",
  "https://example.com/c.mp3",
];

const results = await Promise.all(
  urls.map((url) => client.transcriptions.create({ url })),
);

for (const result of results) {
  console.log(result.text);
}

Ошибки

Некорректные запросы (например, file и url одновременно, слишком много ролей) отклоняются на стороне клиента с NexaraValidationError — ещё до обращения к серверу. Ошибки сервера превращаются в типизированные классы по коду статуса:

КлассКодКогда возникает
BadRequestError400Некорректные параметры запроса
InsufficientBalanceError402Недостаточно средств на балансе
AuthenticationError403Ключ не передан или недействителен
NotFoundError404Задача, модель или ключ не найдены
RateLimitError429Превышен лимит частоты или число одновременных задач
InternalServerError500Внутренняя ошибка сервера
APIConnectionErrorЗапрос не дошёл до сервера (сеть, таймаут)

Все они наследуются от NexaraError, а у ошибок API есть поля status_code и detail с сообщением сервера. Тип ошибки проверяется через instanceof. Полный список кодов — на странице ошибок.

import { Nexara, InsufficientBalanceError, RateLimitError } from "nexara-sdk";

const client = new Nexara();

try {
  await client.transcriptions.create({ file: "audio.mp3" });
} catch (e) {
  if (e instanceof InsufficientBalanceError) {
    console.log("Пополните баланс:", e.detail); // 402
  } else if (e instanceof RateLimitError) {
    console.log("Слишком много запросов, попробуйте позже.");
  } else {
    throw e;
  }
}

Ссылки

On this page