
Klusums bija nesošs
Pēdējie divi GeekBye v1 laidieni ir par vienu un to pašu neērto patiesību: reāllaika transkripcija pār īstu tīklu nav bezzudumu, un godīgais solis ir pārstāt izlikties, ka tā ir. v1.8.20 saglabāja katra audio gabala kopiju diskā, pirms to nomest atkārtotas savienošanās laikā, un sāka skaļi iezīmēt transkripta robus. v1.9.0 pārstāja sūtīt klusumu, lai taupītu joslas platumu — un atklāja, ka klusums bija tieši tas signāls, ko transkribētājs izmantoja, lai zinātu, ka teikums ir beidzies. Divi laidieni par cenu, ko maksā izmešana.
Pēdējie divi GeekBye v1 laidieni — v1.8.20 un v1.9.0, tie tieši pirms otrās versijas atskaites punkta — dala tēmu, kas kļūst acīmredzama tikai tad, kad tos lasi kopā. Abi ir par lietām, ko lietotne klusi izmeta, un abi nonāk pie viena secinājuma: lieta, ko tu nomet efektivitātes labad, darīja vairāk darba, nekā tu domāji. Viens laidiens meta audio tīkla atkārtoto savienojumu laikā. Otrs meta klusumu, lai taupītu joslas platumu. Abos gadījumos izmestā lieta izrādījās nesoša.
Reāllaika transkripcija nav bezzudumu, un v1.8.20 to atzīst
Lūk fakts par runas-uz-tekstu straumēšanu pār WebSocket, no kura ir viegli novērsties: kad savienojums pārtrūkst un atjaunojas — vai kad lietotne pārslēdzas no viena transkripcijas sniedzēja uz citu, no Deepgram uz ElevenLabs — klients apzināti nomet audio gabalus, kas uztverti šajā spraugā. Tam tā jādara. Svaigi pieslēgts sniedzējs, kas pēkšņi saņem novecojuša audio uzkrājumu, aizrīsies vai, vēl ļaunāk, pieķers savu balss aktivitātes detektoru pie nepareizās lietas. Tāpēc klients šos gabalus izmet.
Problēma nav nomešanā. Problēma ir tajā, ko nomešana agrāk nozīmēja: šie vārdi vienkārši nekad neparādījās transkriptā, un nekas tev nepateica, ka tie trūkst. Ieraksts izskatījās pilnīgs. Tāds tas nebija.
v1.8.20 uzbrūk tam divās frontēs, un neviena no tām nav "padarīt tā, lai atkārtotie savienojumi nekad nezaudē audio" — jo tu nevari, ne reāllaikā. Tā vietā tas padara zudumu atgūstamu un godīgu.
Atgūstamā puse ir noturīga PCM kopēšana. Galvenā procesa uztveršanas apstrādātājā katrs uztvertais gabals tagad tiek ierakstīts failā diskā pirms tas sasniedz atkārtotās savienošanās un labvēlības perioda nomešanas vārtus:
every captured chunk is written to
<userData>/sessions/session-<ts>.wavbefore realtime drop gates so reconnect-lost audio is preserved for a future batch-STT reconciliation pass
Mehānisms ir patīkami vienkāršs: teeChunkToDisk atver WriteStream, iepriekš rezervē 44 baitu WAV galveni, pievieno neapstrādātos 16 bitu mono paraugus, tiklīdz tie pienāk, un apturot ielāpo galveni ar galīgajiem izmēriem (fs.openSync(..., 'r+'), ieraksta 44 baitus nobīdē 0). Rezultāts ir atskaņojams WAV ar pilnīgo audio — ieskaitot daļas, ko reāllaika transkripts nekad neredzēja. Kad ieraksts beidzas, tas raida session-audio-saved notikumu ar faila ceļu un baitu skaitu.
Šeit svarīgas divas godīguma piezīmes, jo šo ir viegli pārspīlēt. Pirmkārt: kopēšana šajos laidienos robu neaizpilda. Tā saglabā neapstrādāto audio priekš vēlāka saskaņošanas piegājiena — pakešveida atkārtotas transkribēšanas, kas saskaņo failu ar dzīvo transkriptu — kas ir āķis, ko šie laidieni noliek, nevis funkcija, ko tie piegādā. Turpinājuma komits pat anotē session-audio-saved ar TODO, kas norāda uz saskaņošanas problēmām, lai neviens to nesajauc ar mirušu kodu. Otrkārt: tas maksā disku. Komanda novērtēja aptuveni 86 MB uz 30 minūšu ierakstu, tāpēc tas pats laidiens pievieno StartupCleanupService, kas iztīra saglabātās sesijas, kas vecākas par 7 dienām. Drošības tīkls, kas aug bez robežām, ir noplūde; sakopšana ir tas, kas padara kopēšanu piegādājamu.
Godīgā puse ir vēl vienkāršāka. Pirmajā atkārtotās savienošanās mēģinājumā klients ieraksta īstu, redzamu ierakstu transkriptā:
[reconnecting — audio may be missing]
Šī viena rinda ir visa laidiena filozofija miniatūrā. Lietotne nevar garantēt, ka dzirdēja visu, tāpēc tā pārstāj netieši apgalvot, ka dzirdēja. Robs, ko tu redzi, ir robs, ko tu vari apiet; robs, ko tu neredzi, ir kļūdas ziņojums, kas tikai gaida notikt.
v1.9.0: klusums, ko optimizēji prom, bija signāls
v1.9.0 ir pēdējais v1 laidiens, un tas ir vieta, kur aizmugure nodeva klientam virkni dzīvā transkripta pienākumu — klusuma nomešanu, katras transkripta rindas piedēvēšanu mikrofonam vai sistēmas audio no lokālas balss aktivitātes laika līnijas, atkārtotās savienošanās cilpas īpašumtiesības, ieraksta ierobežojumu ieviešanu. Lielākā daļa no tā ir pamatdarbs otrās versijas arhitektūrai un ir stāstīts citur. Bet viens pavediens tajā ir labākais mazais stāsts jebkurā no abiem laidieniem, jo tas ir labojums, kam nācās atsaukt kaitējumu, ko nodarīja optimizācija, kas atsevišķi bija pilnīgi pareiza.
Tas sākas ar acīmredzami labu izmaiņu: pārstāt sūtīt klusumu. Klients sāka izfiltrēt gabalus, kuru dominējošais avots bija klusums, pirms to nosūtīšanas pār ligzdu — mazāk joslas platuma, mazāk bezjēdzīga audio, ko aizmugurei apstrādāt, un tas ievēroja skaidru aizmugures klienta līgumu, kas teica "nesūti klusumu". Katrs iemesls to darīt bija pamatots.
Un tas pilnīgi sabojāja izteikumu pabeigšanu. Komits, kas to izlabo, izklāsta cēloņsakarību ķēdi ar neparastu atklātību:
After the client began filtering silence chunks … ElevenLabs Scribe's VAD-based commit strategy no longer fires — EL needs ~1s of silence in the audio stream to commit a partial, and that silence never reaches it. Result: partials accumulate forever, UI shows trailing "...", utterances never finalize.
Šī ir platoniskā forma noplūstošai abstrakcijai, kas iekož atpakaļ. Transkribētāja balss aktivitātes detektoram nav atsevišķas "runātājs ir pabeidzis" ievades — tas secina teikuma beigas, dzirdot aptuveni sekundi klusuma audio. Klusums nebija troksnis vadā; tas bija ziņa. Izfiltrējot to, lai taupītu joslas platumu, klients nejauši pārstāja sūtīt vienīgo signālu, kas transkribētājam pateica, ka teikums ir beidzies. Tāpēc katrs daļējais transkripts vienkārši turpināja augt, astei aizplūstot ..., kas nekad neizšķīrās.
Tu to varētu izlabot, ieliekot klusumu atpakaļ — bet tad tu esi atcēlis optimizāciju. Īstais labojums ir labāks: sūti klusuma nozīmi, nesūtot klusumu. Klients tagad seko, cik ilgi audio ir bijis kluss lokāli, un, kad tas šķērso SILENCE_COMMIT_THRESHOLD_MS = 1000 — apzināti pieskaņots aizmugures paša VAD klusuma slieksnim — tas raida skaidru commit signālu ārpus joslas: sendMixedChunk pamana ilgstošo klusumu, nosūta realtime-audio:commit caur IPC, galvenais process pārsūta { type: 'commit' } pa ligzdu, un aizmugure liek ElevenLabs pabeigt daļējo rezultātu. Divi mazi stāvokļa gabaliņi, silenceStartedAt un silenceCommitFired, neļauj tam raidīt atkārtoti. Joslas platuma ieguvums izdzīvo; pabeigšana atkal darbojas; beigu ... izšķīrās.
Šim laidienam ir arī maza, godīga zemsvītras piezīme: neierobežotā atkārtotās savienošanās loģika, ko v1.9.0 ieviesa, vispirms tika uzbūvēta renderētājā kā WsReconnectController, tad izdzēsta tā paša laidiena ietvaros, tiklīdz īstā implementācija nolaidās galvenā procesa apstrādātājā, kur tā piederēja. Pats atkārtotās savienošanās stāsts — neierobežota atkāpšanās, mainot sniedzējus ik pēc piecām neveiksmēm — ir stāstīts savā nodaļā; ko v1.9.0 pievieno, ir tas, ka tā ir vieta, kur šī arhitektūra piedzima, un kur klients pirmoreiz pārņēma tās īpašumtiesības.
Trīs lietas, ko šie laidieni iemācīja
- Kad tu nevari novērst zudumu, padari to atgūstamu un padari to redzamu. v1.8.20 neliedz atkārtotajiem savienojumiem nomest audio — tas reāllaikā nav fiziski iespējams. Tas saglabā neapstrādātā audio kopiju vēlākam laikam, un tas iezīmē robu transkriptā. Neviens no tiem nav grezns; kopā tie klusu datu zudumu pārvērš par zināmu, ierobežotu, atgūstamu stāvokli.
- Drošības tīklam vajag savas robežas. Noturīgā kopēšana klusi piepildītu disku, ja atstātu vienu — labojums, kas kļūst par lēnas darbības kļūdu. 7 dienu sakopšana, kas piegādāta tajā pašā laidienā, nav pēcdoma; tā ir lieta, kas kopēšanu vispār padara drošu piegādei. Ja tu pievieno mehānismu, kas uzkrāj, pievieno mehānismu, kas to iztīra, tajā pašā elpas vilcienā.
- Lieta, ko tu nomet efektivitātes labad, var būt signāls. Asākā mācība jebkurā no abiem laidieniem: klusuma izfiltrēšana bija pareiza katrā asī, ko tu parasti pārbaudītu — joslas platums, slodze, līguma ievērošana — un tā tomēr sabojāja produktu, jo pakārtota sistēma klusumā ielasīja nozīmi. Kad tu noņem datus efektivitātes labad, jautā, kas kaut ko secināja no šiem datiem. Dažreiz tev nākas sūtīt nozīmi skaidri tieši tāpēc, ka tu pārstāji sūtīt lietu, no kuras tā agrāk tika secināta.
Un tas ir versijas 1 stāsta gals — pēdējā nostiprināšana pirms pārrakstīšanas. Iepriekšējai nodaļai — trīs darbības vārdi, kas uztur Web Audio dzīvu (v1.8.16 + v2.0.2); tam, uz kurieni tas viss virzījās — ko patiesībā prasa otrā versija: 206 komiti (v2.0.0); un visai lokai — programmatūras piegādes līdz pilnībai anatomiju.