Преминете към основното съдържание

WebSocket API

ASR сървърът предоставя WebSocket-базирано API за транскрипция на реч. Протоколът е прост 3-стъпков request-response цикъл през краткоживяща WebSocket връзка.

Endpoint

ws://<host>:8765/ws/transcribe

При production deployment (чрез Cloudflare Tunnel):

wss://asr.dictaro.ai/ws/transcribe

Протокол

Стъпка 1: Metadata (Client -> Server)

Клиентът изпраща JSON text frame с параметри на заявката:

{
"type": "transcribe",
"language": "bg",
"task": "transcribe",
"api_key": "your-api-key",
"machine_id": "a1b2c3d4e5f6...",
"postprocess": true
}

Полета

ПолеТипЗадължителноПо подразбиранеОписание
typestringда--"transcribe" за транскрипция или "ping" за health check
languagestring | nullнеnullISO 639-1 код на езика на речта. Ако е null, по подразбиране е "en"
taskstringне"transcribe""transcribe" -- текст на оригиналния език; "translate" -- превод на английски
api_keystringусловно--Задължителен, ако сървърът има конфигуриран SERVER_API_KEY
machine_idstringне"unknown"SHA256 хардуерен отпечатък за telemetry/billing
postprocessboolнеserver defaultOverride на LLM корекция per-request

Поддържани езици (25)

bg, hr, cs, da, nl, en, et, fi, fr, de, el, hu, it, lv, lt, mt, pl, pt, ro, sk, sl, es, sv, ru, uk

Task стойности

TaskОписаниеПример
transcribeТекст на оригиналния езикБългарска реч -> Български текст
translateПревод на английскиБългарска реч -> Английски текст

Machine ID (хардуерен отпечатък)

machine_id е SHA256 хеш, изчислен от хардуерни компоненти на клиентската машина:

КомпонентИзточник (Windows WMI)
BIOS serialWin32_BIOS.SerialNumber
Motherboard serialWin32_BaseBoard.SerialNumber
Motherboard manufacturerWin32_BaseBoard.Manufacturer
Motherboard productWin32_BaseBoard.Product
CPU IDWin32_Processor.ProcessorId
Disk serialWin32_DiskDrive.SerialNumber (само фиксирани дискове)
machine_id = SHA256(bios_serial + board_serial + board_manufacturer + board_product + cpu_id + disk_serial)

OS серийният номер умишлено не е включен -- преинсталиране на OS не трябва да променя ID-то.

Стъпка 2: Аудио данни (Client -> Server)

Клиентът изпраща WAV файл като binary WebSocket frame.

Изисквания към аудиото

СвойствоСтойност
ФорматWAV (RIFF)
Sample rateПроизволен (сървърът resample-ва до 16kHz при нужда; 16kHz е препоръчителен)
КаналиMono
Bit depthFloat32 или Int16

Валидации

Сървърът извършва следните проверки:

  1. Размер на файла -- максимум 50 MB (преди декодиране)
  2. WAV magic bytes -- проверка за RIFF и WAVE хедъри
  3. Продължителност -- максимум 300 секунди (5 минути) след декодиране

Стъпка 3: Резултат (Server -> Client)

Сървърът изпраща JSON text frame с резултата:

{
"text": "Здравейте, как сте?",
"segments": [
{
"text": "Здравейте, как сте?",
"start": 0.0,
"end": 2.5
}
],
"language": "bg",
"postprocessed_text": "Здравейте, как сте?",
"postprocess_ms": 150,
"postprocess_error": null
}

Полета на резултата

ПолеТипОписание
textstringСуров (raw) текст от ASR транскрипцията
segmentsarrayСегменти с text, start (секунди) и end (секунди)
languagestringДетектиран/използван език (ISO 639-1 код)
postprocessed_textstring | nullLLM-коригиран текст (ако post-processing е включен и успешен), иначе null
postprocess_msnumberЛатентност на post-processing в милисекунди (0, ако е изключен)
postprocess_errorstring | nullСъобщение за грешка, ако post-processing е неуспешен

Грешки

При грешка сървърът изпраща JSON с поле error:

{
"error": "описание на грешката"
}

Често срещани грешки

ГрешкаОписание
"unauthorized"Невалиден или липсващ API ключ
"File too large: X.XMB (max 50MB)"Файлът надвишава 50 MB лимита
"Invalid audio format: not a valid WAV file"Не е валиден WAV файл
"Audio too long: X.Xs (max 300s)"Аудиото е по-дълго от 5 минути
"GPU busy: server is processing another request..."GPU lock timeout (120s)

Ping / Health Check

За проверка на свързаността без изпращане на аудио:

Заявка:

{
"type": "ping"
}

Отговор:

{
"type": "pong",
"status": "ok"
}

HTTP Health Endpoint

GET /health

Отговор:

{
"status": "ok",
"model": "canary-1b-v2",
"postprocess_enabled": false
}

Примери

Python (websockets)

import json
import io
import soundfile as sf
from websockets.sync.client import connect

audio, sr = sf.read("recording.wav", dtype="float32")

with connect("ws://localhost:8765/ws/transcribe") as ws:
# 1. Изпращане на metadata
ws.send(json.dumps({
"type": "transcribe",
"language": "bg",
"task": "transcribe",
"api_key": "your-key",
"machine_id": "a1b2c3...",
"postprocess": True,
}))

# 2. Изпращане на аудио
buf = io.BytesIO()
sf.write(buf, audio, sr, format="WAV")
ws.send(buf.getvalue())

# 3. Получаване на резултат
result = json.loads(ws.recv())
if "error" in result:
print(f"Грешка: {result['error']}")
else:
text = result.get("postprocessed_text") or result["text"]
print(text)

JavaScript (browser)

const ws = new WebSocket("ws://localhost:8765/ws/transcribe");

ws.onopen = () => {
// 1. Изпращане на metadata
ws.send(JSON.stringify({
type: "transcribe",
language: "bg",
task: "transcribe",
api_key: "your-key",
machine_id: "a1b2c3...",
}));

// 2. Изпращане на аудио като ArrayBuffer (WAV формат)
ws.send(wavArrayBuffer);
};

ws.onmessage = (event) => {
const result = JSON.parse(event.data);
if (result.error) {
console.error(result.error);
} else {
// Използване на postprocessed_text ако е наличен
const text = result.postprocessed_text || result.text;
console.log(text);
}
};

Telemetry (Prometheus метрики)

Сървърът записва per-request метрики с label machine_id за usage tracking:

МетрикаТипLabelsОписание
asr_requests_totalCountermachine_id, task, status, languageОбщ брой заявки
asr_audio_seconds_totalCountermachine_id, task, languageОбработени аудио секунди
asr_processing_secondsHistogrammachine_id, task, languageОбща латентност на обработка
asr_postprocess_secondsHistogrammachine_id, task, languageЛатентност на LLM post-processing

PromQL примери

# Общо заявки по машина
sum by (machine_id) (asr_requests_total)

# Общо аудио минути по машина
sum by (machine_id) (asr_audio_seconds_total) / 60

# Request rate за последния час
rate(asr_requests_total[1h])

# Средно време за обработка по машина
rate(asr_processing_seconds_sum[5m]) / rate(asr_processing_seconds_count[5m])