Mae trawsgrifiad amser real yn cyrraedd ddwywaith: yn gyntaf fel drafft sy'n dal i newid, yna fel llinell derfynol nad yw'n newid. Dangoswch y drafft fel cynffon y gellir ei disodli a'r llinell derfynol fel hanes, a gweddill golwg capsiynau byw yw'r pibellwaith.
Y peth lleiaf y mae API VocalStack yn ei wneud yw sesiwn amser real. Mae eich gweinydd yn gwneud un galwad HTTP ac yn cael yn ôl streamUrl wedi'i llofnodi. Mae eich cleient yn agor WebSocket i'r URL hwnnw, yn anfon sain amrwd wrth iddi gael ei chipio, ac yn darllen y trawsgrifiad yn ôl fel fframiau testun JSON ychydig eiliadau y tu ôl i'r siaradwr. Pan ddaw'r sain i ben, rydych yn anfon eof; mae'r gweinydd yn fflysio'r hyn sydd ganddo, yn adrodd yr hyn a fesurodd y sesiwn, ac yn cau.
Nid oes dim yn cael ei storio. Mae'r trawsgrifiad yn bodoli ar y wifren yn unig, sef yr hyn sydd ei angen ar olwg capsiynau, troshaen cyfarfod neu nodwedd llais yn eich ap eich hun. Os ydych eisiau cadw'r geiriau, eu rhannu a'u hallforio wedyn, mae arnoch angen trawsgrifiad byw a darllediad yn lle hynny; mae'r adran olaf yn eich cyfeirio yno.
Mae'r siâp yr un fath â'r rhan fwyaf o APIs lleferydd ffrydio: cyfnewid manylion mewngofnodi dros HTTP, soced hir-oes gyda sain yn mynd i mewn a JSON yn dod allan, a rhyw ffordd o wahaniaethu rhwng testun dros dro a thestun terfynol. Mae'r enwau'n wahanol o un API i'r llall; prin y mae'r rhannau symudol yn newid. Dyma nhw, yn eu trefn:
POST /v1/realtime/sessions gyda'ch allwedd API, ar eich gweinydd. Yr ateb yw { sessionId, streamUrl, expiresAt }.streamUrl.session.loading nes session.ready.transcript.draft (disodli'r gynffon) a transcript.committed (atodi llinell derfynol).{"type":"eof"}; darllenwch session.done.Dim ond cam 1 sydd angen eich allwedd, felly mae'n digwydd ar eich gweinydd.
Crëwch allwedd o dan Developers, API keys gyda'r caniatâd Write. Mae allwedd ar gyfer gweinyddion a sgriptiau: mae'r API yn gwrthod un a anfonir o dudalen we neu mewn URL, felly rydych yn creu'r sesiwn y tu ôl i lwybr eich hun, a'r unig beth y mae'r dudalen yn ei weld yw'r streamUrl.
Mae'r URL yn cario ei docyn ei hun oherwydd cyfyngiad porwr sy'n werth ei wybod yn gyffredinol. Ni all cysylltydd WebSocket y porwr osod penawdau cais, felly nid oes penawd Authorization i roi allwedd ynddo; mae pob API lleferydd sy'n wynebu porwr yn dilysu ei soced gyda thocyn byrhoedlog yn yr URL (neu wedi'i guddio mewn enw is-brotocol). Byrhoedlog yw'r pwynt: mae URL yn cyrraedd logiau a hanes, felly rhaid i'r hyn y mae'n ei gario ddod i ben. Cysylltwch cyn expiresAt.
Mae'r SDKs yn cael eu lawrlwytho o'r ardal Developers, nid o gofrestr becynnau; mae'r adran Install yn y dechrau cyflym yn dangos gorchmynion yr amgylchedd hwn ei hun. Gyda'r SDK TypeScript, mae llwybr gweinydd yn edrych fel hyn:
// On your server, behind a route of yours (POST /api/transcribe, say):
import { VocalStack } from '@vocalstack/sdk';
const vs = new VocalStack({ baseUrl: '{{api}}', apiKey: process.env.VOCALSTACK_API_KEY });
export async function createStream(): Promise<{ sessionId: string; streamUrl: string }> {
const { sessionId, streamUrl } = await vs.realtime.createSession({ spokenLanguage: 'en' });
return { sessionId, streamUrl };
}
Heb SDK, un fetch yw hi. Mae'r un hwn hefyd yn gofyn am Sbaeneg ac yn diffodd cydosod brawddegau, gan gydweddu â'r enghraifft wifren isod:
const res = await fetch('{{api}}/v1/realtime/sessions', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.VOCALSTACK_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ spokenLanguage: 'en', translate: ['es'], sentences: { enabled: false } }),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`); // the error envelope: { code, message, … }
const { streamUrl } = (await res.json()) as { sessionId: string; streamUrl: string; expiresAt: string };
Mae gan bob opsiwn ddiofyn. Y rhai sy'n werth eu gwybod ar y dechrau yw spokenLanguage (gadewch ef allan a chanfyddir yr iaith), translate (rhestr o ieithoedd targed), speakerLabels a latencyMode; daw'r gweddill i'r amlwg pan fydd eu hangen isod.
Rhowch y streamUrl i'r hyn bynnag sy'n cipio'r sain; o hyn ymlaen, nid oes allwedd yn rhan o'r broses.
Cysylltwch â streamUrl fel y mae, heb unrhyw bennyn. Tra bod y sesiwn yn cychwyn, mae'r gweinydd yn anfon curiadau calon session.loading. Yna daw session.ready. Peidiwch ag anfon unrhyw sain cyn hynny. Nid yw sain a anfonir yn gynnar yn cael ei chadw i'w defnyddio wedyn; mae'r gweinydd yn ei thrin fel gwall, yn anfon ffrâm error ac yn cau'r soced.
Unwaith y bydd y soced ar agor, mae pob methiant yn cymryd siâp y ffrâm honno: {"type":"error","code":"…","message":"…","retryable":true|false}. Mae'r code yn rhestr gaeedig (invalid_audio, invalid_options, invalid_token, capacity_exceeded, session_expired, slow_consumer, engine_unavailable, internal), mae message ar gyfer eich logiau, ac mae retryable yn dweud a yw'n werth rhoi cynnig ar sesiwn newydd. Trinwch ef o'r ffrâm gyntaf:
const ws = new WebSocket(streamUrl); // the token is in the URL: no header
ws.binaryType = 'arraybuffer';
ws.addEventListener('message', (m: MessageEvent) => {
if (typeof m.data !== 'string') return;
const f = JSON.parse(m.data);
switch (f.type) {
case 'session.loading':
console.error('starting…');
break;
case 'session.ready':
startMicrophone(); // send audio only after session.ready
break;
case 'error':
console.error(`${f.code}: ${f.message}`);
if (f.retryable) scheduleReconnect(); // a new session, with backoff; see "Stop"
break;
}
});
Mae angen i gleient amrwd drin dau beth arall eto; mae'r SDKs eisoes yn gwneud hynny. Yn gyntaf, mae uwchraddio wedi'i wrthod yn cario amlen wall HTTP arferol yr API: 401 invalid_token, 410 session_expired, neu 503 unavailable gyda phennyn Retry-After i'w anrhydeddu.
Yn ail, mae dirlawnder yn edrych fel tawelwch, nid gwall. Os na chyrhaeddodd unrhyw ffrâm o gwbl o fewn 30 eiliad, trinwch hynny fel capacity_exceeded a chysylltwch eto; fel arfer mae sesiwn newydd yn mynd drwodd. Os yw fframiau llwytho'n dal i gyrraedd ond nad yw session.ready byth yn dod, trinwch hynny fel engine_unavailable, sydd hefyd yn ailgynnig. Yn yr SDKs, mae RealtimeSession.connect yn dychwelyd ar session.ready ac yn methu ar ôl readyDeadlineMs gyda'r cod cywir.
Unwaith y mae session.ready wedi cyrraedd, mae'r gweinydd yn disgwyl sain ar y cyflymder y caiff ei siarad.
Mae sain yn mynd i mewn fel fframiau deuaidd o PCM amrwd: pwynt arnofiol 32-did, little-endian, 16 kHz, mono (pcm_f32le, fformat audio diofyn y sesiwn). Anfonwch hi wrth iddi gael ei chipio, mewn darnau o tua 100 i 250 ms, heb aros am y trawsgrifiad rhwng darnau.
Mae'n werth gwneud y mathemateg beitiau unwaith. 16,000 sampl yr eiliad ar 4 beit yr un yw 64,000 beit yr eiliad, felly mae 100 ms yn 6,400 beit a 250 ms yn 16,000. Mae modelau lleferydd yn cael eu hyfforddi'n gyffredin ar 16 kHz mono, a dyna pam mae cymaint o APIs amser real yn gofyn amdano, tra bod meicroffonau a phorwyr yn cipio ar 44.1 neu 48 kHz ac yn aml mewn stereo. Mae angen i rywbeth ailsamplu'r sain a chyfuno'r sianeli'n un cyn i'r beitiau fynd allan: yma ffmpeg yw hynny, ac yn y porwr mae'n gynorthwyydd meicroffon yr SDK. Nid yw anfon sain 48 kHz a datgan 16 kHz yn methu; mae'n trawsgrifio lleferydd mewn cyflymder araf, yn wael.
Yn Node, ffmpeg yw'r ddyfais gipio symlaf:
import { spawn } from 'node:child_process';
function startMicrophone(): void {
// Raw PCM: f32le, 16 kHz, mono, as binary frames. macOS: -f avfoundation -i :0, Linux: -f pulse -i default.
const mic = spawn('ffmpeg', ['-loglevel', 'error', '-f', 'avfoundation', '-i', ':0', '-f', 'f32le', '-ac', '1', '-ar', '16000', '-']);
mic.stdout.on('data', (chunk: Buffer) => {
// Backpressure: bytes the socket has accepted but not yet put on the wire.
// Two seconds of audio (128,000 bytes) queued means the link, not the server, is behind.
if (ws.bufferedAmount > 128_000) console.error(`link behind by ${ws.bufferedAmount} bytes`);
ws.send(new Uint8Array(chunk));
});
mic.on('close', () => ws.send(JSON.stringify({ type: 'eof' })));
process.once('SIGINT', () => mic.kill());
}
ws.send byth yn blocio; mae'n ciwio. bufferedAmount yw maint y ciw hwnnw, ac ar gyswllt iach mae'n aros yn agos at sero. Nid oes modd oedi sain fyw, felly'r ymateb defnyddiol i giw sy'n tyfu yw sylwi arno, nid gollwng fframiau. Mae'r gweinydd hefyd yn cymhwyso pwysedd nôl. Mae'n derbyn sain ychydig eiliadau o flaen amser real (limits.audioBufferS), yna'n stopio darllen nes ei fod wedi dal i fyny. Ar y ffordd yn ôl, mae cadarnhadau'n cael eu ciwio heb eu colli tra bod drafftiau'n cael eu cyfuno, felly mae darllenydd araf yn gweld llai o ddrafftiau, a rhai mwy ffres. Os na all cleient ddal i fyny hyd yn oed gyda'r cadarnhadau, mae'n derbyn ffrâm error gyda slow_consumer a retryable: false, ac mae'n cael ei ddatgysylltu; os gwelwch hynny, mae eich trinwr negeseuon yn gwneud gormod o waith.
Mewn porwr, mae streamMicrophone o @vocalstack/sdk/mic yn gofyn am y meicroffon, yn ailsamplu i 16 kHz, ac yn anfon y darnau ynghyd â fframiau clock, sy'n gadael i'r gweinydd nodi bylchau pan fydd y porwr yn arafu'r tab. Mae'r dudalen yn cael y sesiwn o'ch llwybr ac nid yw byth yn gweld yr allwedd:
import { RealtimeSession } from '@vocalstack/sdk';
import { streamMicrophone } from '@vocalstack/sdk/mic';
export async function transcribeMicrophone(
stream: { sessionId: string; streamUrl: string },
render: (committed: string, tail: string) => void,
): Promise<void> {
const session = await RealtimeSession.connect(stream);
const mic = await streamMicrophone(session); // asks for the microphone, sends 16 kHz PCM
document.querySelector('#stop')?.addEventListener('click', () => {
void mic.stop();
session.eof();
});
let committed = '';
for await (const ev of session) {
if (ev.type === 'transcript.draft') render(committed, ev.segments.map((s) => s.text).join(' '));
if (ev.type === 'transcript.committed') {
committed += `${ev.segment.text} `;
render(committed, '');
}
}
}
Dyna'r llofnod render(committed, tail) yw'r patrwm UI cyfan; mae'r adran nesaf yn esbonio pam.
Mae dau fath o ffrâm yn adeiladu'r trawsgrifiad, ac mae eu drysu yw'r camgymeriad mwyaf cyffredin.
Yn gyntaf, pam mae dau ohonynt o gwbl. Mae model lleferydd yn penderfynu beth oedd gair yn rhannol o'r geiriau sy'n dilyn: mae "I scream" a "ice cream" yn swnio'r un fath nes bod y frawddeg yn mynd ymlaen. Felly mae cydnabyddydd amser real yn allyrru dyfaliad cynnar, yna'n ei ddiwygio wrth i fwy o sain gyrraedd, a dim ond yn setlo unwaith y mae wedi clywed digon. Mae pob API lleferydd ffrydio yn datgelu hyn rywsut. Mae rhai yn galw'r dyfaliadau'n ganlyniadau "interim" neu "partial" ac yn marcio'r rhai sydd wedi setlo gydag is_final; mae'r eirfa'n amrywio, nid y ddisgyblaeth. Yma y dyfalu yw'r drafft, a'r testun sydd wedi setlo yw'r cadarnhad.
transcript.draft yw'r gynffon fyw: y geiriau a glywyd ers y cadarnhad diwethaf, sy'n dal i newid. Mae pob drafft yn ddisodliad llawn o'r un blaenorol. Ail-luniwch y gynffon gyda'i segments; peidiwch byth â'i hatodi. Nid oes gan ddrafftiau seq yn fwriadol, felly peidiwch â cheisio'u paru â'r cadarnhadau y maent yn troi'n rhai.
transcript.committed yw'r terfynol: un segment gyda seq (0, 1, 2, heb fylchau), start, end, text, speaker a words gydag amseriadau ar gyfer pob gair. Atodwch ef a gollyngwch y drafft y mae'n ei gwmpasu; mae'r drafft nesaf yn dechrau lle daeth y cadarnhad hwn i ben.
committed: [seq 0] [seq 1]
draft: "how are" ← frame 1
draft: "how are you do" ← frame 2 REPLACES frame 1
committed: [seq 0] [seq 1] [seq 2 "How are you doing?"]
← the commit consumes the tail; drop the draft
Mae UI sy'n atodi drafftiau yn dangos testun dyblyg, fflachlyd. Mae eich golwg capsiynau yn datblygu baglu nad oedd gan y siaradwr erioed. Rendrwch bob segment wedi'i gadarnhau, yna'r drafft diweddaraf ar eu hôl, a chliriwch y drafft pan ddaw cadarnhad. Gall cadarnhad gynnwys geiriau na ymddangosodd mewn unrhyw ddrafft.
Dyma ychydig eiliadau o leferydd ar y wifren, o'r enghraifft fetch uchod (translate: ["es"], cydosod brawddegau i ffwrdd):
{"type":"session.loading"}
{"type":"session.ready"}
{"type":"transcript.draft","segments":[{"start":0.0,"text":"Good","speaker":0,"tentative":true}]}
{"type":"transcript.draft","segments":[{"start":0.0,"text":"Good morning every","speaker":0,"tentative":true}]}
{"type":"transcript.committed","segment":{"seq":0,"start":0.0,"end":1.4,"text":"Good morning, everyone.","speaker":0,"words":[{"start":0.0,"end":0.3,"text":"Good"},{"start":0.3,"end":0.8,"text":"morning,"},{"start":0.8,"end":1.4,"text":"everyone."}]}}
{"type":"transcript.translated","seq":0,"translations":{"es":"Buenos días a todos."}}
{"type":"transcript.draft","segments":[{"start":1.6,"text":"Thanks for","speaker":0,"tentative":true}]}
Mae dau ffrâm arall o gwmpas y rhain. Mae transcript.amended yn cywiro segment wedi'i chadarnhau yn ei lle (yr un seq, text neu speaker newydd) pan fydd gair ynddi wedi'i gywiro; cymhwyswch ef i'r llinell rydych eisoes wedi'i thynnu. Mae transcript.words yn ffrydio amseriadau geiriau ar gyfer y gynffon ychydig cyn iddi gael ei chadarnhau. Mae angen events.words, sydd ymlaen yn ddiofyn; mae cadarnhad bob amser yn cynnwys ei words, beth bynnag y mae'r opsiynau digwyddiad yn ei ddweud. Yn olaf, anwybyddwch fathau o fframiau nad ydych yn eu hadnabod: mae rhai newydd yn cael eu hychwanegu heb rybudd.
Dyma ddolen ddarllen SDK Python, gyda'r derfynell fel golwg capsiynau. Mae cydosod brawddegau wedi'i ddiffodd yma hefyd, felly mae cyfieithiadau'n cyrraedd fel transcript.translated, ac mae'r ffrâm error yn codi fel VocalStackError allan o'r ddolen:
import asyncio
import os
from vocalstack import RealtimeSession, VocalStack, VocalStackError
MIC = ["ffmpeg", "-loglevel", "error", "-f", "avfoundation", "-i", ":0",
"-f", "f32le", "-ac", "1", "-ar", "16000", "-"]
async def main() -> None:
async with VocalStack("{{api}}", api_key=os.environ["VOCALSTACK_API_KEY"]) as vs:
created = await vs.realtime.create_session(
spoken_language="en", translate=["es"], sentences={"enabled": False}
)
session = await RealtimeSession.connect(created.session_id, created.stream_url)
mic = await asyncio.create_subprocess_exec(*MIC, stdout=asyncio.subprocess.PIPE)
async def feed() -> None:
assert mic.stdout is not None
while chunk := await mic.stdout.read(8000): # 125 ms of audio
await session.send_audio(chunk)
await session.eof() # the server flushes, then sends session.done
feeder = asyncio.create_task(feed())
try:
async with session:
async for event in session:
if event.type == "transcript.draft":
# The live tail: replace it, never append it.
tail = " ".join(s.text for s in event.segments)
print(f"\r\x1b[K\x1b[2m{tail}\x1b[0m", end="", flush=True)
elif event.type == "transcript.committed":
# Final: append it (seq 0, 1, 2...), and the tail it covers is gone.
print(f"\r\x1b[K{event.segment.text}", flush=True)
elif event.type == "transcript.translated":
print(f" es: {event.translations.get('es')}")
await feeder
print(f"done ({session.done_reason})", session.stats)
except VocalStackError as e:
# An `error` frame mid-stream, or a refused connect.
print(f"\nerror {e.code}: {e.message} (retryable: {e.retryable})")
finally:
if mic.returncode is None:
mic.kill()
asyncio.run(main())
Cyfieithu fesul segment, fel uchod, yw'r ffurf syml. Mae'r ffurf y mae darllenwyr yn ei ffafrio yn cael adran ei hun.
translate: ["es", "fr"] yn gofyn am gyfieithiadau wrth i'r sesiwn fynd yn ei blaen. Mae'r ffordd y maent yn cyrraedd yn dibynnu ar gydosod brawddegau (sentences: { enabled: true }), sydd ymlaen yn ddiofyn.
Gyda brawddegau i ffwrdd, mae pob cadarnhad yn cael ei ddilyn ychydig yn ddiweddarach gan ffrâm transcript.translated sy'n enwi ei seq ac yn cario translations wedi'u hallweddu fesul iaith; rydych yn eu rhoi ynghlwm wrth y segment hwnnw. Dyna mae'r enghreifftiau hyd yn hyn wedi'i ddefnyddio. Mae'n syml ac mae'n darllen fel log cadarnhadau: un segment, un cyfieithiad, y ffin brawddeg lle bynnag y mae'r siaradwr yn cymryd anadl.
Gyda brawddegau ymlaen, mae'r gweinydd yn cydosod cadarnhadau'n frawddegau cyfan ac yn eu cyfieithu, sy'n darllen yn llawer gwell. Mae pob ffrâm transcript.sentence yn ddisodliad llawn o un frawddeg, wedi'i hallweddu gan sentenceId. Mae ei status yn mynd o open i closed (neu dropped, sy'n golygu ei thaflu), ac mae ei translations dros dro tra bo'n agored ac yn derfynol unwaith y mae'n cau. Diweddarwch (neu mewnosodwch) yn ôl sentenceId, peidiwch byth ag atodi. Mae SDK TypeScript yn cynnwys applySentence ar gyfer yr union bwrpas hwn:
import { applySentence, type SentenceSegment } from '@vocalstack/sdk';
let sentences: SentenceSegment[] = [];
for await (const ev of session) {
if (ev.type !== 'transcript.sentence') continue;
sentences = applySentence(sentences, ev.sentence); // upsert by sentenceId
if (ev.sentence.status === 'closed') console.log(`${ev.sentence.text}\n es: ${ev.sentence.translations?.es}`);
}
Mae cyfieithiadau'n dilyn y trawsgrifiad o ryw eiliad neu ddwy. Os ydych eisiau iddynt gael eu llefaru hefyd, ychwanegwch voice: ["es"] (mae angen brawddegau). Yna mae'r Sbaeneg ar gyfer pob brawddeg gaeedig yn cyrraedd fel ffrâm transcript.voice, gan gario'r clip fel Ogg/Opus base64 ar 24 kHz mono. Daw brawddeg hir mewn darnau (part o parts) i'w chwarae yn olynol. Ni chaiff testun dros dro ei lefaru byth. Mae'r canllaw cyfieithu byw yn trafod lleisiau'n fanwl, ac mae ble mae'r eiliadau'n mynd yn esbonio'r gadwyn oedi.
Nid yw ieithoedd targed yn sefydlog ar adeg creu.
Mae ffrâm destun session.update yn newid spokenLanguage, translate, speakerLabels, latencyMode, voice neu voiceByLang o'r pwynt hwnnw ymlaen; mae meysydd nad ydych yn eu cynnwys yn aros yr un fath.
{"type":"session.update","translate":["es","fr"],"latencyMode":"fast"}
Mae'r SDKs yn ei ddangos fel session.update(…). Mae translate yn disodli'r rhestr gyfan, ac mae [] yn diffodd cyfieithu. Nid yw segmentau sydd eisoes wedi'u cyflwyno'n cael eu hail-drawsgrifio na'u hail-gyfieithu, ac os trowch labeli siaradwyr ymlaen, mae siaradwyr yn cael eu labelu o'r pwynt hwnnw ymlaen yn unig. Yr hyn a ddywedwyd sy'n aros wedi'i ddweud; dim ond beth sy'n dod nesaf y mae'r gosodiadau'n ei lywodraethu.
Pan ddaw'r sain i ben, anfonwch {"type":"eof"} (session.eof() yn yr SDKs). Mae'r gweinydd yn trawsgrifio'r hyn sydd ganddo o hyd, yn anfon y cadarnhadau olaf, yna session.done ac yn cau. Os anfonwch cancel yn lle hynny, mae'n stopio ar unwaith ac yn gollwng y gweddill.
{"type":"session.done","reason":"eof","stats":{"audioS":30.0,"processingS":30.6,"realtimeFactor":0.98}}
Mae reason yn eof, max_duration (cyrhaeddodd y sesiwn hyd mwyaf y cynllun a rhedeg yr un fflysio) neu cancelled. Mae stats yn cael ei fesur gan y gweinydd: audioS yw'r sain a anfonoch, processingS yw'r amser wal-cloc y rhedodd y sesiwn, a realtimeFactor yw eu cymhareb. Mae sesiwn fyw yn glanio ychydig o dan 1, oherwydd mae'r amser wal-cloc yn cynnwys y fflysio olaf ar ôl eich eof. Mae rhif sylweddol is na hynny'n golygu bod y sesiwn wedi cymryd yn hirach yn amlwg na hyd y sain; y lle cyntaf i edrych yw pa mor gyflym y cyrhaeddodd y sain. Ar gyfer ffeil, mae'r un rhif yn dweud sawl gwaith yn gyflymach na chwarae y daeth y trawsgrifiad yn ôl.
Mae sesiwn yn para uchafswm o limits.maxDurationS o GET /v1/realtime/capabilities, ac mae ei sain yn gwario eich credyd fesul eiliad ar gyfradd fyw eich cynllun, gyda'r un isafswm 5 munud â phob trawsgrifiad: mae pob sesiwn sy'n derbyn sain yn cael ei bilio am o leiaf 5 munud (prisiau). Gall yr un soced hefyd dderbyn ffeil gyfan: crëwch y sesiwn gyda input: { kind: "file" }, anfonwch beitiau'r ffeil ei hun (mp3, wav, flac, ogg, m4a) a eof, a daw'r trawsgrifiad yn ôl sawl gwaith yn gyflymach na chwarae'r sain, gyda fframiau transcript.progress ar hyd y ffordd.
Nid oes ailddechrau. Mae cysylltiad a gollir yn dod â'r sesiwn i ben; mae ailgysylltu'n golygu creu un newydd, a fydd yn cael ei bilio ar ei isafswm ei hun, ac ail-ffrydio o'ch ffynhonnell fyw, gyda seq yn ôl i 0. Mae'r ailgysylltu ei hun yn batrwm safonol ar gyfer unrhyw API soced, ac mae'n werth ei gael yn gywir unwaith:
retryable: true ar ffrâm error, 503 gyda'i Retry-After, neu 30 eiliad heb ffrâm, sy'n golygu capacity_exceeded. Mae invalid_token a session_expired yn golygu streamUrl newydd gan eich gweinydd, nid ymgais arall gyda'r hen un.Cadwch y llwybr sy'n creu'r sesiwn yn rhad i'w alw, a thrinwch gau fel dechrau o'r newydd. Nid oes ailddechrau yw'r pris am beidio â storio dim; os oes rhaid i'r trawsgrifiad oroesi'r soced, cadwch ef.
Pan ydych eisiau i'r un ffrwd gael ei storio fel recordiad, ei gywiro wedyn, ei hallforio, a'i darllen gan gynulleidfa yn eu hieithoedd eu hunain, cyhoeddwch hi i drawsgrifiad byw yn lle hynny. Mae'r canllaw mynd yn fyw yn dangos yr un soced PCM drwy drawsgrifiad a dolen darllediad, ac mae'r canllaw gwrando yn dangos ochr y tanysgrifiwr, lle mae pob gwrandäwr yn dewis iaith a bod rhywun sy'n ymuno'n hwyr yn dal i fyny o gyrchwr lastSeq. Sut mae hynny'n edrych mewn ystafell yw testun un ddolen, pob iaith.
Ar gyfer ffeil rydych eisiau ei chadw, y llwybr wedi'i storio yw trawsgrifio ffeil gyda'r API. Mae'r cyfeirnod ffrâm llawn, pob maes wedi'i gynnwys, yn y canllaw Ffrydio meicroffon yn y cyfeirnod API.