AiYURAS API страница проверки

шлюз распознавание перевод
Ключ хранится только в этом браузере. Выдать ключ — СОЗДАТЬ_КЛЮЧ.bat в папке D:\AiYURAS_API.

Живая стенограмма с микрофона

Звук идёт на сервер по ходу речи, текст возвращается сразу: серым — пока человек говорит, чёрным — когда фраза закончилась, уже со знаками препинания.

Перевод текста

Русский, узбекский (латиница) и английский. Кусок на нужном языке оставляется как есть.

Субтитры в видеоконференции

Так это будет у коллеги в его конференции: звук каждого участника — отдельный поток, поэтому кто говорит, известно без распознавания голосов. Здесь роль участника играет ваша камера и микрофон.

Стенограмма готовой записи

WAV, 16 бит, до 30 минут. Длиннее — частями: Cloudflare обрывает ответ, который готовится дольше 100 секунд.

Команды API

Адрес: {HTTP}. Ключ — в заголовке Authorization: Bearer <ключ>.

КомандаЧто делает
WS /v1/streamживая стенограмма: звук по ходу речи → текст, по желанию перевод
POST /v1/translateперевод текста
POST /v1/transcribeстенограмма готового WAV (до 30 минут)
GET /v1/whoamiпроверка ключа
GET /v1/healthработают ли службы (без ключа)

1. Живая стенограмма — WebSocket

Подключиться к {WS}. Первое сообщение — start (JSON), дальше звук: двоичные сообщения, PCM 16 бит, моно, little-endian, по 20–200 мс. Частота любая от 8000 до 48000 Гц — укажите её в sample_rate, сервер пересчитает сам.

{"type": "start",
 "key": "aiy…",            // если не передан заголовком Authorization
 "sample_rate": 48000,
 "punctuation": true,        // знаки препинания и заглавные
 "partial": true,            // промежуточный текст, пока человек говорит
 "translate_to": "ru",       // ru | uz | en | null
 "latin": "uz"}              // латиница — узбекский (uz) или английский (en)

Ответы сервера (JSON):

{"type":"ready", "session":"…"}                        // можно слать звук
{"type":"partial", "start":3.2, "text":"…"}             // пока говорит
{"type":"final", "id":1, "start":3.2, "end":6.9,
 "text":"Фраза со знаками.", "raw":"фраза без знаков", "lang":"ru"}
{"type":"translation", "id":1, "to":"ru", "text":"…"}   // перевод фразы id
{"type":"error", "message":"…"}
{"type":"end", "audio_sec":123.4, "phrases":17}         // после {"type":"stop"}

Команды по ходу: {"type":"config","translate_to":"uz"} — сменить перевод, {"type":"stop"} — закончить (сервер дорасшифрует последнюю фразу, пришлёт end и закроет поток). Без звука дольше 2 минут поток закрывается сам.

Пример: браузер, звук участника конференции

// mediaStream — микрофон или звук участника: new MediaStream([remoteAudioTrack])
async function aiyurasStream(mediaStream, opts, onMsg) {
  const ws = new WebSocket("{WS}");
  ws.binaryType = "arraybuffer";
  const ctx = new AudioContext();
  const src = ctx.createMediaStreamSource(mediaStream);
  const code = "class Tap extends AudioWorkletProcessor{process(i){const c=i[0]&&i[0][0];" +
               "if(c)this.port.postMessage(c.slice(0));return true}}registerProcessor('tap',Tap)";
  await ctx.audioWorklet.addModule(URL.createObjectURL(new Blob([code], {type: "application/javascript"})));
  const tap = new AudioWorkletNode(ctx, "tap"), mute = ctx.createGain();
  mute.gain.value = 0; src.connect(tap); tap.connect(mute); mute.connect(ctx.destination);
  let parts = [], len = 0, ready = false;
  tap.port.onmessage = (e) => {
    if (!ready) return;
    parts.push(e.data); len += e.data.length;
    if (len < ctx.sampleRate / 10) return;              // шлём кусками по 100 мс
    const pcm = new Int16Array(len); let o = 0;
    for (const p of parts) for (const s of p) pcm[o++] = Math.max(-1, Math.min(1, s)) * 32767;
    parts = []; len = 0;
    if (ws.readyState === 1) ws.send(pcm.buffer);
  };
  ws.onopen = () => ws.send(JSON.stringify({type: "start", key: opts.key,
      sample_rate: ctx.sampleRate, translate_to: opts.translate_to || null}));
  ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.type === "ready") ready = true; onMsg(m); };
  ws.onclose = () => ctx.close();
  return { stop: () => ws.send(JSON.stringify({type: "stop"})) };
}

// в конференции — на каждого участника свой поток:
pc.ontrack = (e) => {
  if (e.track.kind !== "audio") return;
  aiyurasStream(new MediaStream([e.track]), {key: KEY, translate_to: "ru"}, (m) => {
    if (m.type === "partial") showCaption(e.streams[0].id, m.text, true);
    if (m.type === "final") showCaption(e.streams[0].id, m.text, false);
    if (m.type === "translation") showTranslation(e.streams[0].id, m.id, m.text);
  });
};
Ключ в коде браузера виден любому пользователю этой страницы. В рабочей системе лучше отправлять звук со своего сервера (пример ниже на Python) или выдавать отдельный ключ, который не жалко отозвать.

Пример: Python, с сервера

import asyncio, json, wave
import websockets                     # pip install websockets

KEY = "aiy…"
URL = "{WS}"

async def main(path):
    hdr = {"Authorization": "Bearer " + KEY}
    async with websockets.connect(URL, additional_headers=hdr) as ws:   # старые версии: extra_headers=
        w = wave.open(path)           # WAV, 16 бит, моно
        await ws.send(json.dumps({"type": "start", "sample_rate": w.getframerate(),
                                  "translate_to": "ru"}))
        print(await ws.recv())        # ready

        async def read():
            async for msg in ws:
                print(json.loads(msg))

        reader = asyncio.create_task(read())
        step = w.getframerate() // 10                 # 100 мс
        while chunk := w.readframes(step):
            await ws.send(chunk)
            await asyncio.sleep(0.1)                  # темп живой речи
        await ws.send(json.dumps({"type": "stop"}))
        await reader

asyncio.run(main("zapis.wav"))

2. Перевод

curl -X POST "{HTTP}/v1/translate" ^
  -H "Authorization: Bearer aiy…" -H "Content-Type: application/json" ^
  -d "{\"text\": \"Sud majlisi ochiq deb e'lon qilinadi.\", \"to\": \"ru\"}"

→ {"text": "Судебное заседание объявляется открытым.", "to": "ru"}

to: ru, uz, en. from: "en", если латиница — английский (по умолчанию узбекский). До 5000 знаков за раз, до 120 запросов в минуту.

3. Стенограмма файла

curl -X POST "{HTTP}/v1/transcribe?translate_to=ru" ^
  -H "Authorization: Bearer aiy…" -H "Content-Type: audio/wav" ^
  --data-binary @zapis.wav

→ {"duration": 95.2, "text": "…",
   "segments": [{"start": 0.4, "end": 5.1, "text": "…", "translation": "…"}, …]}

Можно и сырой PCM 16 бит: тогда частоту — в адресе, ?sample_rate=16000. Параметры: punctuation=0 — без знаков, translate_to, latin=en.

Ошибки и лимиты

401 / закрытие 4401неверный или отозванный ключ
429 / закрытие 4429слишком много одновременных потоков или переводов
400 / закрытие 4400неверный запрос (формат, частота, размер)
503модель загружается или недоступна — повторить через несколько секунд