DokumentacjaTranskrypcja na żywo
Transkrypcja na żywo
Przesyłaj dźwięk z mikrofonu lub karty przez WebSocket do transcript1 i odbieraj linie napisów w trakcie mówienia, opcjonalnie z tłumaczeniem w czasie rzeczywistym.
Transkrypcja na żywo zamienia strumień audio w linie napisów, kiedy ludzie jeszcze mówią. Twój klient wysyła surowe audio PCM przez WebSocket, a transcript1 odsyła linie, które najpierw są wstępnym rozpoznaniem, a potem stają się ostateczne. Dodaj translate_to, a każda linia dostanie też tłumaczenie. Po zakończeniu sesji wynik zapisuje się jako zwykła transkrypcja.
Nie ma osobnych planów dla transkrypcji na żywo: korzysta ona z tego samego salda minut co wszystko inne. Jak liczy się czas połączenia, opisuje sekcja Rozliczenia.
Kiedy używać transkrypcji na żywo
| Użyj transkrypcji na żywo, gdy | Użyj zwykłej transkrypcji, gdy |
|---|---|
| Dźwięk dopiero powstaje: rozmowa, wykład, transmisja, film, który właśnie oglądasz. | Masz link albo gotowy plik. |
| Potrzebujesz napisów w ciągu sekundy lub dwóch od wypowiedzi. | Zależy ci na najwyższej dokładności i możesz poczekać na wynik. |
| Chcesz mieć tłumaczenie w czasie rzeczywistym obok każdej linii. | Chcesz przetłumaczyć gotową transkrypcję albo na kilka języków. |
Transkrypcja na żywo przyjmuje wyłącznie dźwięk, jako surowe PCM. Nie przyjmuje linków do wideo, plików przesłanych, WebM, Opus ani MP3. Nagraj dźwięk po stronie klienta i najpierw zamień go na PCM. Jak to zrobić, pokazuje sekcja Przechwytywanie dźwięku w przeglądarce.
Szybki start z SDK
Zainstaluj SDK w wersji 1.5.0 lub nowszej: npm i @transcript1/sdk@latest. t1.live.start tworzy sesję, łączy się i kończy się, gdy sesja wystartuje, więc od razu możesz wysyłać dźwięk.
import { createReadStream } from 'node:fs';
import { setTimeout as sleep } from 'node:timers/promises';
import { Transcript1 } from '@transcript1/sdk';
const t1 = new Transcript1(); // reads TRANSCRIPT1_API_KEY
const live = await t1.live.start({ language: 'en', translateTo: 'es', sampleRate: 16000 });
live.on('line', line => {
const mark = line.final ? 'final ' : 'partial';
console.log(mark, line.text, '→', line.translation?.text ?? '');
});
live.on('warning', warning => console.warn(warning.code));
// speech.pcm: 16 kHz, mono, signed 16-bit little-endian, no header
for await (const chunk of createReadStream('./speech.pcm', { highWaterMark: 3200 })) {
live.send(chunk);
await sleep(100); // 3,200 bytes are 100 ms of audio: send at real-time speed
}
const result = await live.end();
console.log(result.reason, result.transcriptionId, result.minutesCharged);Linie aktualizują się w miejscu. Gdy przyjdzie linia z tym samym id, zastąp tę, którą już masz, albo odczytaj wszystkie z live.lines. end() kończy sesję, czeka na ostatnie linie i zapisuje transkrypcję. Wszystkie metody i zdarzenia opisuje SDK dla Node.js.
Szybki start z czystym WebSocketem
Bez SDK są dwa kroki: utwórz sesję przez HTTPS, a potem otwórz WebSocket z jednorazowym tokenem, który dostaniesz w odpowiedzi.
Utwórz sesję
curl -X POST https://api.transcript1.com/v1/live/sessions \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
-H "Content-Type: application/json" \
-d '{"language": "en", "translate_to": "es", "sample_rate": 16000}'API odpowiada kodem 201:
{
"id": "lv_8fK2Lm0PqRsTuVwXyZaBcD",
"status": "waiting",
"transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
"websocket_url": "wss://api.transcript1.com/v1/live/sessions/lv_8fK2Lm0PqRsTuVwXyZaBcD/stream",
"token": "Zk3x...",
"token_expires_at": "2026-11-02T12:01:00Z",
"rate": 1
}Gdy save ma wartość false, transcription_id to null. Token jest jednorazowy i wygasa po 60 sekundach, więc połącz się od razu. rate to liczba minut salda pobieranych za każdą rozpoczętą minutę tej sesji; zobacz Rozliczenia.
Ciało żądania przyjmuje te pola. Wszystkie są opcjonalne, a wymagany zakres to transcriptions:write:
| Pole | Domyślnie | Zasada |
|---|---|---|
language | auto | auto albo dwuliterowy kod języka obsługiwany przez transkrypcję na żywo. |
translate_to | brak | Dwuliterowy kod języka. Jeden język docelowy na sesję. Zobacz Tłumaczenie na żywo. |
diarize | false | Oznacza rozmówców. Niektóre ustawienia nie pozwalają rozpoznawać rozmówców, na przykład razem z language: "auto", i kończą się błędem 422. Sprawdź możliwości. |
audio_format | pcm_s16le | Jedyna wartość. Pole istnieje, żeby można było później dodać kolejne formaty. |
sample_rate | 16000 | Liczba całkowita od 8000 do 48000. Tylko mono. |
save | true | false nie zachowuje niczego po zakończeniu sesji. Zobacz Zapisane transkrypcje. |
Połącz się i przesyłaj dźwięk
Otwórz WebSocket z tokenem jako drugim podprotokołem. Działa to w przeglądarkach i w Node 22+ bez własnych nagłówków. Zanim wyślesz dźwięk, poczekaj na session.started: ramki binarne wysłane wcześniej są odrzucane i dostajesz ostrzeżenie audio_dropped.
import { createReadStream } from 'node:fs';
import { setTimeout as sleep } from 'node:timers/promises';
const session = await fetch('https://api.transcript1.com/v1/live/sessions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TRANSCRIPT1_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ language: 'en', translate_to: 'es', sample_rate: 16000 }),
}).then(response => response.json());
const ws = new WebSocket(session.websocket_url, ['t1-live', session.token]);
const lines = new Map();
ws.addEventListener('message', async message => {
const event = JSON.parse(message.data);
if (event.type === 'session.started') {
for await (const chunk of createReadStream('./speech.pcm', { highWaterMark: 3200 })) {
ws.send(chunk);
await sleep(100);
}
ws.send(JSON.stringify({ type: 'end' }));
} else if (event.type === 'line') {
lines.set(event.line.id, event.line); // the full current state: replace by id
console.log(event.line.final, event.line.text, event.line.translation?.text);
} else if (event.type === 'session.ended') {
console.log('ended:', event.reason, event.minutes_charged);
}
});
ws.addEventListener('close', event => console.log('closed', event.code));W Node 20 nie ma wbudowanego WebSocket: użyj pakietu ws, który ma tę samą formę new WebSocket(url, protocols).
Na poprawny token serwer odpowiada podprotokołem t1-live i niczym więcej. Zły token nigdy nie psuje handshake'u: gniazdo się otwiera, dostajesz zdarzenie error, a gniazdo zamyka się kodem 4xxx, więc przeglądarka pokazuje prawdziwy powód zamiast ogólnego 1006. Zobacz Kody zamknięcia.
Przechwytywanie dźwięku w przeglądarce
Dźwięk na żywo musi być monofonicznym PCM 16-bit signed little-endian z częstotliwością sample_rate sesji. Przeglądarki dają próbki zmiennoprzecinkowe, więc zamień je w AudioWorklet. Ten fragment przechwytuje mikrofon jako PCM 16 kHz w porcjach po 100 ms i wysyła go przez wejście SDK dla przeglądarek. getAccessToken zwraca token dostępu OAuth; nigdy nie umieszczaj klucza API w przeglądarce. Zobacz Bezpieczeństwo.
import { createLiveClient } from '@transcript1/sdk/live';
const workletSource = `
class Pcm16Processor extends AudioWorkletProcessor {
constructor() {
super();
this.buffer = new Int16Array(1600); // 100 ms at 16 kHz
this.filled = 0;
}
process(inputs) {
const channel = inputs[0][0];
if (!channel) return true;
for (let i = 0; i < channel.length; i++) {
const sample = Math.max(-1, Math.min(1, channel[i]));
this.buffer[this.filled++] = sample < 0 ? sample * 0x8000 : sample * 0x7fff;
if (this.filled === this.buffer.length) {
this.port.postMessage(this.buffer.slice());
this.filled = 0;
}
}
return true;
}
}
registerProcessor('pcm16', Pcm16Processor);
`;
const client = createLiveClient({ getAccessToken: () => myApp.getOAuthAccessToken() });
const stream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: 1 } });
const context = new AudioContext({ sampleRate: 16000 });
const moduleUrl = URL.createObjectURL(new Blob([workletSource], { type: 'text/javascript' }));
await context.audioWorklet.addModule(moduleUrl);
// the context's real rate: a browser that cannot do 16 kHz picks its own
const live = await client.start({ language: 'auto', sampleRate: context.sampleRate });
live.on('line', renderLine);
const microphone = context.createMediaStreamSource(stream);
const capture = new AudioWorkletNode(context, 'pcm16');
capture.port.onmessage = event => live.send(event.data); // an Int16Array
const mute = context.createGain();
mute.gain.value = 0;
microphone.connect(capture).connect(mute).connect(context.destination);
async function stop() {
stream.getTracks().forEach(track => track.stop());
await context.close();
return live.end();
}Worklet jest napisany pod 16 kHz. Jeśli kontekst działa z inną częstotliwością, porcja nie ma już 100 ms, ale PCM pozostaje poprawne, bo sampleRate zgadza się z kontekstem. Żeby przechwycić dźwięk karty lub filmu zamiast mikrofonu, utwórz MediaStream przez getDisplayMedia albo z captureStream() elementu multimedialnego i podłącz go tak samo.
Tłumaczenie na żywo
Dodaj translate_to do sesji, a transcript1 będzie tłumaczyć każdą linię w trakcie mówienia.
- Jeden język docelowy na sesję. Kolejne języki dodasz później do zapisanej transkrypcji endpointem tłumaczeń.
- Każda
linema oryginał (text,final) i obiekttranslation(language,text,final).translationtonull, gdytranslate_tonie jest ustawione. - Oryginał i tłumaczenie stają się ostateczne niezależnie od siebie: linia może mieć ostateczny oryginał, a jej tłumaczenie wciąż się zmienia. Pokaż linię jako ostateczną dopiero, gdy oba są ostateczne.
- Linia, która jest już w języku docelowym, używa własnego tekstu jako tłumaczenia i jest ostateczna, gdy się zamknie.
- Linia zamyka się, gdy mówca zrobi pauzę, zmieni się mówca, przerwa między słowami przekroczy 0,9 sekundy, linia osiągnie dwa wiersze napisów (84 znaki) albo 15 sekund, albo wyślesz
finalize. Przy włączonym tłumaczeniu zamknięcie linii może potrwać o około 3 sekundy dłużej, bo czeka na tłumaczenie. Wtedy tłumaczenie może pozostać otwarte (final: false) i dalej rosnąć, gdy oryginał jest już ostateczny. - Tłumaczenie jest darmowe. Nie zużywa minut.
To, jakie języki docelowe i pary językowe są dostępne, zależy od dostawcy rozpoznawania mowy na żywo. Zamiast wpisywać reguły na sztywno, czytaj możliwości. Nieobsługiwany język docelowy kończy się błędem 422 unsupported_translation. Dostawca może na przykład wymagać jawnego language zamiast auto albo dopuszczać tylko pary zawierające angielski.
Protokół WebSocket
Łączenie
new WebSocket(websocket_url, ['t1-live', token]);Token podróżuje jako podprotokół WebSocket. Nigdy nie trafia do URL-a ani do logów dostępu. Nie wysyłaj nagłówka Authorization: poświadczeniem jest token. Serwer wysyła ping co 30 sekund; przeglądarki i pakiet ws odpowiadają automatycznie. Gniazdo, które przez 60 sekund nie wyśle pong, zostaje rozłączone.
Poprawne połączenie z sesją, która ma już gniazdo, zastępuje stare. Zobacz Wznawianie i przejęcie.
Komunikaty klienta
| Komunikat | Znaczenie |
|---|---|
| Ramka binarna | Dźwięk: PCM s16le mono z sample_rate sesji. Każda ramka ma parzystą długość i najwyżej 256 KB. Dobry rozmiar to około 100 ms na ramkę. |
{"type":"finalize"} | Zamknij bieżącą linię teraz, na przykład gdy film jest wstrzymany. |
{"type":"end"} | Zakończ sesję i zapisz ją. Serwer odpowiada session.ended i zamyka gniazdo. |
| Cokolwiek innego | Niekrytyczne zdarzenie error z kodem invalid_message. |
Ramka o nieparzystej długości albo zbyt duża to naruszenie protokołu i zamyka gniazdo kodem 4008.
Zacznij wysyłać dźwięk po session.started. Klient, który wysyła dźwięk szybciej niż w czasie rzeczywistym, jest rozliczany za czas dźwięku zamiast czasu połączenia (zobacz Rozliczenia), więc wysyłaj w tempie, w jakim dźwięk powstaje.
Zdarzenia serwera
Każde zdarzenie to tekstowa ramka JSON z polem type.
| Zdarzenie | Kiedy jest wysyłane |
|---|---|
session.started | Połączenie zostało przyjęte. Od teraz wysyłaj dźwięk. |
line | Linia napisów powstała albo się zmieniła. |
usage | Po każdym pobraniu opłaty. |
warning | Coś wymaga uwagi, ale sesja trwa dalej. |
error | Niekrytyczny problem albo powód natychmiastowego zamknięcia. |
reconnect | Serwer zaraz się zrestartuje. Wznów sesję. |
session.ended | Sesja się skończyła i została zapisana. Ostatnie zdarzenie przed normalnym zamknięciem. |
session.started mówi, czy to wznowienie, i ile dźwięku sesja już przetworzyła:
{
"type": "session.started",
"session_id": "lv_8fK2Lm0PqRsTuVwXyZaBcD",
"transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
"resumed": false,
"offset_ms": 0
}line zawiera pełny aktualny stan jednej linii, więc zastąp nim linię z tym samym id. Zobacz Obiekt line.
{
"type": "line",
"line": {
"id": 12,
"start_ms": 53120,
"end_ms": 56040,
"speaker": null,
"language": "en",
"text": "Welcome back to the stream",
"final": true,
"translation": { "language": "es", "text": "Bienvenidos de nuevo", "final": false }
}
}usage jest wysyłane po każdym pobraniu opłaty, z czasem połączenia, czasem dźwięku, liczbą minut salda pobranych do tej pory i minutami, które ci zostały:
{
"type": "usage",
"connected_ms": 61240,
"audio_ms": 60100,
"minutes_charged": 2,
"minutes_remaining": 898
}warning ma pole code:
code | Znaczenie |
|---|---|
balance_low | Następne pobranie opłaty się nie powiedzie. Gdy nadejdzie jego termin, sesja kończy się z balance_exhausted. Nie jest wysyłane, gdy włączone jest automatyczne doładowanie. |
audio_dropped | Dźwięk przyszedł, zanim sesja była gotowa, albo przyszło go za dużo, gdy łączył się dostawca rozpoznawania mowy. Najstarszy dźwięk został odrzucony. |
idle_timeout_soon | Brak dźwięku od 4 minut. Sesja kończy się po 5 minutach bez dźwięku. Wyślij dźwięk, żeby ją utrzymać. |
{ "type": "warning", "code": "idle_timeout_soon" }error ma code i message. Na gnieździe live mogą pojawić się te kody:
code | Krytyczny | Znaczenie |
|---|---|---|
invalid_message | Nie | Ramka tekstowa, która nie jest finalize ani end. |
invalid_token | Tak | Token jest nieprawidłowy, wygasł albo został już użyty. Gniazdo zamyka się kodem 4001. |
not_found | Tak | Sesja nie istnieje. Gniazdo zamyka się kodem 4004. |
session_ended | Tak | Sesja już się zakończyła. Gniazdo zamyka się kodem 4004. |
{ "type": "error", "code": "invalid_message", "message": "Expected {\"type\":\"finalize\"} or {\"type\":\"end\"}" }reconnect przychodzi, zanim serwer zamknie gniazdo kodem 1012, na przykład podczas wdrożenia. Pobierz nowy token i wznów sesję.
{ "type": "reconnect", "reason": "server_restart" }session.ended to ostatnie zdarzenie każdej sesji. Liczby to końcowe sumy:
{
"type": "session.ended",
"reason": "client_ended",
"transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
"minutes_charged": 3,
"connected_ms": 142500,
"audio_ms": 141900
}Obiekt line
| Pole | Znaczenie |
|---|---|
id | Numer liczony od 0, rosnący o jeden z każdą linią. To indeks segmentu w zapisanej transkrypcji. |
start_ms, end_ms | Początek i koniec w czasie dźwięku sesji. Ten czas biegnie dalej po ponownych połączeniach. |
speaker | Etykieta rozmówcy, gdy diarize jest włączone, w przeciwnym razie null. Etykiety są takie same jak w zwykłych transkrypcjach. |
language | Wykryty lub podany język linii albo null, gdy nie jest jeszcze znany. |
text | Dotychczasowy tekst oryginału. |
final | true, gdy tekst oryginału już się nie zmieni. |
translation | null bez translate_to, w przeciwnym razie language, text i final. |
Linie z final: false pokazuj jaśniejszym stylem: ich tekst może się jeszcze zmienić. Tekst linii z final: true nigdy się już nie zmienia, a ostateczna linia nigdy nie jest usuwana.
SDK używa camelCase dla pól linii: startMs, endMs.
Powody zakończenia
session.ended i GET /v1/live/sessions/:id podają end_reason:
| Powód | Znaczenie |
|---|---|
client_ended | Wysłano end. |
balance_exhausted | Następne pobranie opłaty się nie powiodło. Sesja kończy się na granicy minuty i jest zapisywana. |
idle_timeout | 5 minut bez dźwięku. |
max_duration | Sesja była połączona przez 300 minut. Rozpocznij nową. |
disconnected | Klient był nieobecny dłużej niż 2 minuty i nie wznowił sesji. |
upstream_error | Dostawca rozpoznawania mowy zawiódł. |
internal_error | Coś poszło nie tak po naszej stronie. |
not_connected | Sesja nie połączyła się w ciągu 5 minut. Nigdy nie jest rozliczana i widać ją tylko przez GET. |
Kody zamknięcia
| Kod | Znaczenie |
|---|---|
1000 | Normalne zamknięcie. Zawsze po session.ended. |
1011 | Nieoczekiwany błąd serwera. Serwer odzyskuje sesję: wznów ją z nowym tokenem. |
1012 | Restart serwera. Po reconnect: wznów sesję z nowym tokenem. |
4001 | Token jest nieprawidłowy, wygasł albo został już użyty. |
4004 | Nie znaleziono sesji albo już się zakończyła. |
4008 | Naruszenie protokołu: ramka binarna o nieparzystej długości albo zbyt duża. |
4010 | Zastąpione nowszym połączeniem z tą samą sesją. |
Podczas restartu API nowe żądanie WebSocket może dostać odpowiedź HTTP 503. Spróbuj ponownie za chwilę.
Wznawianie i przejęcie
Sesja przetrwa zerwaną sieć, wdrożenie API i awarię. Po zerwaniu połączenia czeka na ciebie 2 minuty; potem kończy się jako disconnected i jest zapisywana.
- Wywołaj
POST /v1/live/sessions/:id/token. Odpowiedź zawieratoken,token_expires_atiwebsocket_url, czyli te same pola co przy tworzeniu sesji. Gdy sesja już się zakończyła, kończy się to błędem409 session_ended. - Otwórz nowy WebSocket z tym tokenem.
- Przychodzi
session.startedzresumed: true.offset_msto ilość dźwięku, którą sesja już przetworzyła: kontynuuj od tego miejsca. Identyfikatory linii liczą się dalej.
Linie, które były już ostateczne, zostają. Niedokończony koniec z chwili zerwania przepada, więc jeśli buforujesz dźwięk, odtwórz ponownie kilka sekund od offset_ms. Przerwy na ponowne łączenie nie są rozliczane.
Przejęcie to to samo wywołanie. Jeśli serwer nadal uważa, że gniazdo jest otwarte, nowe poprawne połączenie je zastępuje, a stare gniazdo zamyka się kodem 4010 po zapisaniu jego linii. Limit równoczesnych sesji nigdy nie blokuje wznowienia.
SDK robi to wszystko za ciebie: po zerwaniu połączenia albo zdarzeniu reconnect pobiera token i łączy się ponownie z opóźnieniem rosnącym od 0,5 do 8 sekund, przez maksymalnie 2 minuty, a ostatnie 10 sekund dźwięku wysłanego w czasie przerwy odtwarza ponownie.
Rozliczenia
Transkrypcja na żywo korzysta z tego samego salda minut co transkrypcje wsadowe.
- Rozliczany jest czas połączenia, od przyjęcia gniazda do jego zamknięcia. Cisza i wstrzymany film się liczą. Czas między zerwaniem a wznowieniem już nie.
- Za każdą rozpoczętą minutę, minimum 1. Pierwsza minuta jest pobierana, gdy pierwsze połączenie zostanie przyjęte, a każda następna, gdy się zaczyna.
- Szybciej niż w czasie rzeczywistym rozlicza się jako czas dźwięku. Jeśli wysłany dźwięk jest dłuższy niż czas połączenia, rozliczany jest czas dźwięku.
- Stawkę odczytujesz z API. Jedna rozpoczęta minuta kosztuje
rateminut salda, zaokrąglone w górę. Stawka to zwykle 1 i może mieć części dziesiętne. Stawkę live odczytasz zrates.livewGET /v1/account, zratewGET /v1/live/capabilitiesoraz zratew tworzonej sesji. Stawka sesji jest stała od jej utworzenia. - Tłumaczenie jest darmowe.
- Brak połączenia oznacza brak opłaty. Sesja, która nie połączy się w ciągu 5 minut, kończy się jako
not_connected. - Błędy są zwracane. Jeśli sesja kończy się z
upstream_errorlubinternal_error, zanim wytworzy choć jedną linię, wszystkie opłaty wracają na konto. Pusta sesja z powodu ciszy jest rozliczana i zapisywana jako pusta. - Gdy saldo się skończy i włączone jest automatyczne doładowanie, transcript1 obciąża zapisaną kartę, nie przerywając strumienia, i sesja trwa dalej. Jeśli automatyczne doładowanie jest wyłączone lub wstrzymane albo obciążenie się nie powiedzie, sesja jest finalizowana, zapisywana i kończy się z
balance_exhaustedna granicy minuty. Ostrzeżeniebalance_lowpojawia się wcześniej, chyba że automatyczne doładowanie jest włączone.
Utworzenie sesji zwraca 402 insufficient_minutes, gdy twoje dostępne saldo jest niższe niż jedna rozpoczęta minuta przy bieżącej stawce. Jeśli włączone jest automatyczne doładowanie, transcript1 najpierw próbuje doładować konto. Zobacz Rozliczenia i limity.
Limity
| Free | Monthly | Annual | |
|---|---|---|---|
| Równoczesne sesje na żywo | 1 | 2 | 3 |
- Sesja liczy się, dopóki jest w stanie
waiting,connectedlubdisconnected(w ramach 2-minutowego okna). Po przekroczeniu limituPOST /v1/live/sessionszwraca429 too_many_live_sessionsz nagłówkiemRetry-After: 30. - Sesje na żywo nie liczą się do limitu aktywnych zadań.
- Sesja trwa najwyżej 300 minut czasu połączenia. Potem kończy się z
max_duration. - Sesja bez dźwięku przez 5 minut kończy się z
idle_timeout; po 4 minutach dostajeszidle_timeout_soon. Wstrzymany strumień nadal nalicza czas połączenia i liczy się jako bezczynny, więc przy długiej przerwie zakończ sesję. - transcript1 ogranicza też łączną liczbę wszystkich sesji na żywo. Gdy wszystkie miejsca są zajęte,
POST /v1/live/sessionszwraca503 live_capacity, co można ponowić. Poczekaj naRetry-After(30 sekund) i spróbuj jeszcze raz. Sprawdzamy to tylko przy tworzeniu sesji, nigdy w jej trakcie. - Tworzenie sesji i pobieranie tokenów liczą się do limitu żądań na minutę.
- Dźwięk to wyłącznie surowe PCM:
pcm_s16le, mono, od 8000 do 48000 Hz.
Możliwości
GET /v1/live/capabilities opisuje, co transkrypcja na żywo obsługuje w tej chwili, żeby klienci nie musieli wpisywać reguł dostawcy na sztywno. Wymagany zakres to transcriptions:read.
{
"available": true,
"auto_language": true,
"languages": ["en", "es"],
"translation": {
"targets": ["es", "de"],
"pairs": "any",
"requires_language": false
},
"diarize": true,
"audio_formats": ["pcm_s16le"],
"sample_rate": { "min": 8000, "max": 48000 },
"max_session_minutes": 300,
"rate": 1
}Listy są tu skrócone. Odczytaj je z API.
translation.pairsto"any"(dowolny wykryty język na dowolny język docelowy) albo lista obiektów z polamifromito.translation.requires_languagema wartośćtrue, gdy tłumaczenie wymaga jawnegolanguagezamiastauto.- Gdy transkrypcja na żywo nie jest skonfigurowana, odpowiedź to
available: falsetylko z polemrate, a utworzenie sesji zwraca503 live_unavailable.
W SDK: await t1.live.capabilities().
Odczyt sesji
GET /v1/live/sessions/:id zwraca stan sesji. Wymagany zakres to transcriptions:read.
curl https://api.transcript1.com/v1/live/sessions/lv_8fK2Lm0PqRsTuVwXyZaBcD \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"id": "lv_8fK2Lm0PqRsTuVwXyZaBcD",
"status": "ended",
"end_reason": "client_ended",
"transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
"options": {
"language": "en",
"translate_to": "es",
"diarize": false,
"audio_format": "pcm_s16le",
"sample_rate": 16000,
"save": true
},
"connected_ms": 142500,
"audio_ms": 141900,
"minutes_charged": 3,
"rate": 1,
"created_at": "2026-11-02T11:58:12Z",
"ended_at": "2026-11-02T12:00:35Z"
}status to waiting, connected, disconnected albo ended. end_reason to null, dopóki sesja się nie zakończy. W SDK: await t1.live.get(id).
Błędy
Błędy żądań używają zwykłej koperty błędu. Oto te, które zwracają POST /v1/live/sessions i pokrewne endpointy:
| Status HTTP | code | Można ponowić | Kiedy |
|---|---|---|---|
| 422 | invalid_request | Nie | Brakuje pola albo jest nieprawidłowe, na przykład sample_rate spoza zakresu 8000–48000. |
| 422 | unsupported_language | Nie | language nie jest obsługiwany w transkrypcji na żywo. |
| 422 | unsupported_translation | Nie | Język docelowy albo para językowa nie jest obsługiwana. |
| 402 | insufficient_minutes | Nie | Twoje dostępne saldo jest niższe niż jedna rozpoczęta minuta przy bieżącej stawce. |
| 403 | email_not_verified | Nie | Najpierw potwierdź adres e-mail. |
| 429 | too_many_live_sessions | Tak | Wszystkie równoczesne sesje na żywo z twojego planu są w użyciu. Poczekaj na Retry-After. |
| 503 | live_capacity | Tak | Cała pojemność transkrypcji na żywo jest zajęta. Poczekaj na Retry-After (30 sekund). |
| 503 | live_unavailable | Nie | Transkrypcja na żywo jest teraz niedostępna. |
| 409 | session_ended | Nie | POST /v1/live/sessions/:id/token dla sesji, która już się zakończyła. |
Problemy na gnieździe docierają jako zdarzenia error i kody zamknięcia.
Zapisane transkrypcje
Przy save: true (domyślnie) sesja po zakończeniu zapisuje się jako zwykła transkrypcja. Dźwięk nigdy nie jest przechowywany.
transcription_iddostajesz przy tworzeniu sesji. Jego status tolive, gdy sesja trwa, icompletedpo jej zakończeniu. Sesja, która nigdy się nie połączyła, zostawia transkrypcję ze statusemcanceled.- Transkrypcja ma
source: { "platform": "live", "session_id": "lv_…" }. Nie ma linku ani pliku. Panel wyświetla ją jako sesję na żywo. - Każda linia staje się jednym segmentem o tym samym indeksie co
idlinii. Transkrypcję odczytasz jako JSON, tekst, SRT lub VTT, tak jak każdą inną: zobacz dokumentację API. - Tłumaczenie na żywo zapisuje się razem z nią. Odczytasz je parametrem
translation, jak opisano w sekcji Tłumaczenie. - Kolejne języki tłumaczenia dodasz później przez
POST /v1/transcriptions/:id/translations, gdy transkrypcja ma statuscompleted. Zobacz Tłumaczenie.
Przy save: false po zakończeniu sesji nic nie zostaje: nie powstaje transkrypcja, a transcription_id to null. Nadal dostajesz każdą linię przez gniazdo i obowiązuje zwykła opłata.
Bezpieczeństwo
- Token, który dostajesz przy tworzeniu sesji, jest jednorazowy i wygasa po 60 sekundach. Jest przesyłany jako podprotokół WebSocket, a nie w URL-u, więc nie trafia do logów dostępu. Wyciekły token jest bezużyteczny, gdy został użyty albo wygasł.
- Klucza API używaj tylko na serwerze, który kontrolujesz. Nigdy nie umieszczaj klucza API na stronie internetowej ani w rozszerzeniu.
- W przeglądarce lub rozszerzeniu loguj użytkowników przez OAuth i przekaż token dostępu OAuth do
getAccessTokenwcreateLiveClient. Do rozpoczynania sesji token potrzebuje zakresutranscriptions:write. Tokeny dostępu OAuth wygasają po 1 godzinie, a przy każdym wznowieniu SDK prosigetAccessTokeno świeży token. - Twój serwer może też utworzyć sesję kluczem API i przekazać przeglądarce tylko
websocket_urloraztoken. Klient łączy się wtedy bezpośrednio. Bez nowego tokena od ciebie nie może wznowić sesji.
Ostatnia aktualizacja 3 listopada 2026