NexaraNexara

Асинхронное распознавание

Узнайте, как поставить задачу транскрибации в фон.

Асинхронный режим подходит для длинных записей и пакетной обработки: запрос не держит HTTP-соединение открытым всё время обработки. Вместо этого он сразу возвращает job_id, а готовый результат вы забираете отдельным запросом. Подробнее о разнице режимов — на странице синхронная и асинхронная обработка.

Шаг 1. Поставить задачу

Отправьте аудио на POST /v1/audio/transcriptions/async. Запрос принимает те же параметры, что и синхронный (можно передать локальный file или ссылку url), но возвращается сразу, не дожидаясь обработки.

curl https://api.nexara.ru/v1/audio/transcriptions/async \
  -H "Authorization: Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX" \
  -F "file=@long-audio.mp3" \
  -F "model=whisper-1"
import requests

with open("long-audio.mp3", "rb") as audio_file:
    response = requests.post(
        "https://api.nexara.ru/v1/audio/transcriptions/async",
        headers={"Authorization": "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"},
        files={"file": audio_file},
        data={"model": "whisper-1"},
    )

job_id = response.json()["job_id"]
print(job_id)

Node.js 18+:

import fs from "fs";

const form = new FormData();
form.append("file", new Blob([fs.readFileSync("long-audio.mp3")]), "long-audio.mp3");
form.append("model", "whisper-1");

const response = await fetch(
  "https://api.nexara.ru/v1/audio/transcriptions/async",
  {
    method: "POST",
    headers: { Authorization: "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX" },
    body: form,
  },
);

const { job_id } = await response.json();
console.log(job_id);
package main

import (
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	file, _ := os.Open("long-audio.mp3")
	defer file.Close()

	var buf bytes.Buffer
	writer := multipart.NewWriter(&buf)
	part, _ := writer.CreateFormFile("file", "long-audio.mp3")
	io.Copy(part, file)
	writer.WriteField("model", "whisper-1")
	writer.Close()

	req, _ := http.NewRequest("POST", "https://api.nexara.ru/v1/audio/transcriptions/async", &buf)
	req.Header.Set("Authorization", "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX")
	req.Header.Set("Content-Type", writer.FormDataContentType())

	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
require "net/http"
require "uri"
require "json"

uri = URI("https://api.nexara.ru/v1/audio/transcriptions/async")

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"
request.set_form(
  [
    ["file", File.open("long-audio.mp3")],
    ["model", "whisper-1"],
  ],
  "multipart/form-data",
)

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

puts JSON.parse(response.body)["job_id"]

В ответ приходит идентификатор задачи и её статус:

{
  "job_id": "5f1c2e3a-...",
  "status": "in_progress",
  "created_at": "2026-07-13T10:00:00+00:00"
}

Сохраните job_id — по нему вы будете забирать результат.

Шаг 2. Опросить статус

Периодически запрашивайте GET /v1/audio/transcriptions/async/{job_id}, пока задача не завершится.

curl https://api.nexara.ru/v1/audio/transcriptions/async/5f1c2e3a-... \
  -H "Authorization: Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"
import requests

job_id = "5f1c2e3a-..."

response = requests.get(
    f"https://api.nexara.ru/v1/audio/transcriptions/async/{job_id}",
    headers={"Authorization": "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"},
)

print(response.json())
const jobId = "5f1c2e3a-...";

const response = await fetch(
  `https://api.nexara.ru/v1/audio/transcriptions/async/${jobId}`,
  { headers: { Authorization: "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX" } },
);

console.log(await response.json());
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	jobID := "5f1c2e3a-..."

	req, _ := http.NewRequest("GET", "https://api.nexara.ru/v1/audio/transcriptions/async/"+jobID, nil)
	req.Header.Set("Authorization", "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX")

	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
require "net/http"
require "uri"
require "json"

job_id = "5f1c2e3a-..."
uri = URI("https://api.nexara.ru/v1/audio/transcriptions/async/#{job_id}")

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

puts response.body

Пока задача выполняется, поле result пустое:

{
  "job_id": "5f1c2e3a-...",
  "status": "in_progress",
  "created_at": "2026-07-13T10:00:00+00:00",
  "completed_at": null,
  "result": null,
  "error": null
}

После завершения в поле result появляется готовая расшифровка:

{
  "job_id": "5f1c2e3a-...",
  "status": "complete",
  "created_at": "2026-07-13T10:00:00+00:00",
  "completed_at": "2026-07-13T10:01:12+00:00",
  "result": {
    "text": "Привет! Это пример транскрибации."
  },
  "error": null
}

Поле result может содержать любой из форматов ответа — в зависимости от параметра response_format, переданного при постановке задачи.

Статусы задачи

  • in_progress: задача поставлена в очередь или обрабатывается. Поле result пустое;
  • complete: обработка завершена успешно. Результат находится в поле result, а время завершения — в completed_at;
  • error: обработка завершилась ошибкой. Описание причины находится в поле error.

Полный пример

Постановка задачи и опрос до готового результата в одном скрипте:

import time
import requests

headers = {"Authorization": "Bearer nx-XXXXXXXXXXXXXXXXXXXXXXXX"}

# 1. Поставить задачу
with open("long-audio.mp3", "rb") as audio_file:
    job = requests.post(
        "https://api.nexara.ru/v1/audio/transcriptions/async",
        headers=headers,
        files={"file": audio_file},
        data={"model": "whisper-1"},
    ).json()

job_id = job["job_id"]

# 2. Опрашивать статус, пока задача не завершится
while True:
    status = requests.get(
        f"https://api.nexara.ru/v1/audio/transcriptions/async/{job_id}",
        headers=headers,
    ).json()

    if status["status"] == "complete":
        print(status["result"]["text"])
        break
    if status["status"] == "error":
        raise RuntimeError(status["error"])

    time.sleep(3)

Что учитывать

  • Хранение результата. После завершения результат хранится на сервере 12 часов, а затем удаляется безвозвратно.
  • Интервал опроса. Опрашивайте статус с разумным интервалом (например, раз в несколько секунд), чтобы так вы не упереться в лимит частоты запросов.
  • Одновременные задачи. На один API-ключ может выполняться не более 200 задач одновременно. Дождитесь завершения текущих, прежде чем ставить новые. Подробнее — на странице лимитов.
  • Частота запросов. Постановка задач и опрос статуса ограничены 10 запросами в секунду. Подробнее — на странице лимитов.
  • Форматы и размер. Как и в синхронном режиме, принимается большинство аудио- и видеоформатов, а максимальный размер файла — 3 ГБ.
  • Хранение ключа. Не вставляйте API-ключ прямо в код. Храните его в переменной окружения (например, export NEXARA_API_KEY="nx-...") и ссылайтесь на неё. Подробнее — на странице аутентификации.

On this page