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
}
Полета
| Поле | Тип | Задължително | По подразбиране | Описание |
|---|---|---|---|---|
type | string | да | -- | "transcribe" за транскрипция или "ping" за health check |
language | string | null | не | null | ISO 639-1 код на езика на речта. Ако е null, по подразбиране е "en" |
task | string | не | "transcribe" | "transcribe" -- текст на оригиналния език; "translate" -- превод на английски |
api_key | string | условно | -- | Задължителен, ако сървърът има конфигуриран SERVER_API_KEY |
machine_id | string | не | "unknown" | SHA256 хардуерен отпечатък за telemetry/billing |
postprocess | bool | не | server default | Override на 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 serial | Win32_BIOS.SerialNumber |
| Motherboard serial | Win32_BaseBoard.SerialNumber |
| Motherboard manufacturer | Win32_BaseBoard.Manufacturer |
| Motherboard product | Win32_BaseBoard.Product |
| CPU ID | Win32_Processor.ProcessorId |
| Disk serial | Win32_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 depth | Float32 или Int16 |
Валидации
Сървърът извършва следните проверки:
- Размер на файла -- максимум 50 MB (преди декодиране)
- WAV magic bytes -- проверка за
RIFFиWAVEхедъри - Продължителност -- максимум 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
}
Полета на резултата
| Поле | Тип | Описание |
|---|---|---|
text | string | Суров (raw) текст от ASR транскрипцията |
segments | array | Сегменти с text, start (секунди) и end (секунди) |
language | string | Детектиран/използван език (ISO 639-1 код) |
postprocessed_text | string | null | LLM-коригиран текст (ако post-processing е включен и успешен), иначе null |
postprocess_ms | number | Латентност на post-processing в милисекунди (0, ако е изключен) |
postprocess_error | string | 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_total | Counter | machine_id, task, status, language | Общ брой заявки |
asr_audio_seconds_total | Counter | machine_id, task, language | Обработени аудио секунди |
asr_processing_seconds | Histogram | machine_id, task, language | Обща латентност на обработка |
asr_postprocess_seconds | Histogram | machine_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])