Steven
Steven6 min lugemist

Vaikus oli kandev

Kaks viimast GeekBye v1 väljalaset räägivad samast ebamugavast tõest: reaalajas transkriptsioon üle päris võrgu ei ole kadudeta, ja aus samm on lõpetada teesklemine, et see on. v1.8.20 hoidis igast helitükist koopia kettal, enne kui selle taasühenduse ajal maha viskas, ja hakkas transkriptsiooni tühikuid valjult märkima. v1.9.0 lõpetas vaikuse saatmise ribalaiuse säästmiseks — ja avastas, et vaikus oli täpselt see signaal, mida transkribeerija kasutas, et teada, millal lause oli lõppenud. Kaks väljalaset asjade äraviskamise hinnast.

Arendus
Audio
Töökindlus
GeekBye väljalasked
Vaikus oli kandev

Kaks viimast GeekBye v1 väljalaset — v1.8.20 ja v1.9.0, need vahetult enne teise versiooni verstaposti — jagavad teemat, mis muutub ilmseks alles siis, kui neid koos loed. Mõlemad räägivad asjadest, mida rakendus vaikselt ära viskas, ja mõlemad jõuavad sama järelduseni: asi, mille sa tõhususe nimel maha viskad, tegi rohkem tööd, kui arvasid. Üks väljalase viskas heli võrgu taasühenduste ajal. Teine viskas vaikust ribalaiuse säästmiseks. Mõlemal juhul osutus mahavisatud asi kandvaks.

Reaalajas transkriptsioon ei ole kadudeta, ja v1.8.20 tunnistab seda

Siin on üks fakt kõne-tekstiks voogedastuse kohta üle WebSocketi, millest on lihtne kõrvale vaadata: kui ühendus katkeb ja taastub — või kui rakendus lülitub ühelt transkriptsioonipakkujalt teisele, Deepgramilt ElevenLabsile — viskab klient tahtlikult maha selle vahemiku ajal püütud helitükid. Ta peab. Värskelt ühendatud pakkuja, kes saab järsku vananenud heli järjekorra, lämbub või, mis veelgi hullem, haakib oma hääleaktiivsuse detektori vale asja külge. Nii et klient viskab need tükid ära.

Probleem ei ole mahaviskamises. Probleem on selles, mida mahaviskamine varem tähendas: need sõnad lihtsalt ei ilmunud kunagi transkriptsiooni, ja miski ei öelnud sulle, et need puuduvad. Salvestus nägi välja täielik. Ei olnud.

v1.8.20 ründab seda kahel rindel, ja kumbki neist ei ole "tee nii, et taasühendused ei kaotaks kunagi heli" — sest sa ei saa, mitte reaalajas. Selle asemel teeb see kaotuse taastatavaks ja ausaks.

Taastatav pool on püsiv PCM-kopeerimine. Peaprotsessi püüdmiskäitlejas kirjutatakse iga püütud tükk nüüd kettafaili enne seda, kui see jõuab taasühenduse ja armuaja mahaviskamise väravateni:

every captured chunk is written to <userData>/sessions/session-<ts>.wav before realtime drop gates so reconnect-lost audio is preserved for a future batch-STT reconciliation pass

Mehhanism on meeldivalt lihttehniline: teeChunkToDisk avab WriteStream-i, reserveerib ette 44-baidise WAV-päise, lisab toored 16-bitised monoproovid nende saabudes, ja peatamisel paigab päise lõplike suurustega (fs.openSync(..., 'r+'), kirjutab 44 baiti nihkel 0). Tulemus on esitatav WAV täielikust helist — kaasa arvatud osad, mida reaalajas transkriptsioon kunagi ei näinud. Kui salvestus lõpeb, väljastab see session-audio-saved sündmuse koos failitee ja baitide arvuga.

Siin loevad kaks aususemärkust, sest seda on lihtne üle väita. Esiteks: kopeerimine ei täida tühikut nendes väljalasetes. See säilitab toorheli tarvis hilisemat lepitusläbimist — pakktöötluslikku ümbertranskribeerimist, mis lepitab faili otsetranskriptsiooniga — mis on konks, mille need väljalasked maha panevad, mitte funktsioon, mille nad tarnivad. Järgnev commit isegi annoteerib session-audio-saved TODO-ga, mis osutab lepitusprobleemidele, et keegi ei peaks seda surnud koodiks. Teiseks: see maksab ketast. Meeskond hindas umbes 86 MB 30-minutilise salvestuse kohta, nii et sama väljalase lisab StartupCleanupService, mis kärbib salvestatud sessioone, mis on vanemad kui 7 päeva. Turvavõrk, mis kasvab piirideta, on leke; koristus on see, mis teeb kopeerimise tarnitavaks.

Aus pool on veelgi lihtsam. Esimesel taasühenduse katsel kirjutab klient päris, nähtava kirje transkriptsiooni:

[reconnecting — audio may be missing]

See üksik rida on kogu väljalaske filosoofia miniatuuris. Rakendus ei saa garanteerida, et kuulis kõike, nii et ta lõpetab vihjamise, et kuulis. Tühik, mida sa näed, on tühik, millest saad mööda; tühik, mida sa ei näe, on veateade, mis ootab juhtumist.

v1.9.0: vaikus, mille sa tõhususe nimel ära optimeerisid, oli signaal

v1.9.0 on viimane v1 väljalase, ja see on koht, kus backend andis rea otsetranskriptsiooni kohustusi kliendile üle — vaikuse mahaviskamine, iga transkriptsioonirea omistamine mikrofonile või süsteemihelile kohalikult hääleaktiivsuse ajajoonelt, taasühenduse silmuse omamine, salvestuspiiride jõustamine. Suurem osa sellest on aluspõhi teise versiooni arhitektuurile ja on räägitud mujal. Aga üks lõng selles on parim väike lugu kummaski väljalaskes, sest see on parandus, mis pidi heastama kahju, mille tekitas optimeerimine, mis eraldiseisvana oli täiesti õige.

See algab ilmselgelt hea muudatusega: lõpeta vaikuse saatmine. Klient hakkas välja filtreerima tükke, mille domineeriv allikas oli vaikus, enne kui need üle pistiku saatis — vähem ribalaiust, vähem kasutut heli backendile töötlemiseks, ja see austas selget backendi kliendilepingut, mis ütles "ära saada vaikust". Iga põhjus seda teha oli mõistlik.

Ja see rikkus lause lõpetamise täielikult. Commit, mis selle parandab, laotab põhjusliku ahela lahti ebatavalise avameelsusega:

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.

See on lekkiva abstraktsiooni platooniline vorm, mis tagasi hammustab. Transkribeerija hääleaktiivsuse detektoril ei ole eraldi "kõneleja on lõpetanud" sisendit — see järeldab lause lõpu, kuuldes umbes sekundit vaikust helis. Vaikus ei olnud müra juhtmel; see oli sõnum. Filtreerides selle ribalaiuse säästmiseks välja, lõpetas klient kogemata selle ainsa signaali saatmise, mis ütles transkribeerijale, et lause oli lõppenud. Nii et iga osaline transkriptsioon lihtsalt kasvas edasi, saba hajudes ...-ks, mis kunagi ei lahenenud.

Sa võiksid selle parandada, pannes vaikuse tagasi — aga siis oled optimeerimise tühistanud. Tegelik parandus on parem: saada vaikuse tähendus vaikust saatmata. Klient jälgib nüüd kohalikult, kui kaua heli on vaikne olnud, ja kui see ületab SILENCE_COMMIT_THRESHOLD_MS = 1000 — tahtlikult sobitatud backendi enda VAD vaikuseläveks — saadab see selge commit signaali ribaväliselt: sendMixedChunk märkab püsivat vaikust, saadab realtime-audio:commit üle IPC, peaprotsess edastab { type: 'commit' } pistikul, ja backend käseb ElevenLabsil osalise tulemuse lõpetada. Kaks väikest olekutükki, silenceStartedAt ja silenceCommitFired, hoiavad seda korduvalt käivitumast. Ribalaiuse võit jääb alles; lõpetamine töötab jälle; lõpp ... laheneb.

Sellel väljalaskel on ka väike, aus allmärkus: piiramatu taasühenduse loogika, mille v1.9.0 tutvustas, ehitati esmalt renderdajasse WsReconnectController-ina, seejärel kustutati sama väljalaske sees, kui päris teostus maandus peaprotsessi käitlejasse, kuhu ta kuulus. Taasühenduse lugu ise — piiramatu tagasitaandumine, pakkujaid vaheldumisi iga viie ebaõnnestumise järel — on räägitud omaenda peatükis; mida v1.9.0 lisab, on see, et siin see arhitektuur sündis ja kus klient selle esimest korda omaks võttis.

Kolm asja, mida need väljalasked õpetasid

  1. Kui sa ei saa kaotust vältida, tee see taastatavaks ja tee see nähtavaks. v1.8.20 ei takista taasühendustel heli maha viskamast — see ei ole reaalajas füüsiliselt võimalik. See hoiab toorhelist koopia hilisemaks, ja see märgistab tühiku transkriptsioonis. Kumbki ei ole glamuurne; koos muudavad nad vaikse andmekao teadaolevaks, piiritletud, taastatavaks olukorraks.
  2. Turvavõrk vajab omaenda piire. Püsiv kopeerimine täidaks vaikselt ketta, kui see üksi jätta — parandus, millest saab aegluubis viga. 7-päevane koristus, mis samas väljalaskes tarniti, ei ole tagantjärele mõte; see on asi, mis teeb kopeerimise üldse tarnimiseks ohutuks. Kui lisad mehhanismi, mis koguneb, lisa mehhanism, mis seda kärbib, samas hingetõmbes.
  3. Asi, mille sa tõhususe nimel maha viskad, võib olla signaal. Kummagi väljalaske teravaim õppetund: vaikuse väljafiltreerimine oli õige igal teljel, mida sa tavaliselt kontrolliksid — ribalaius, koormus, lepingu järgimine — ja see rikkus ikkagi toote, sest allavoolu süsteem luges vaikusesse tähendust. Kui eemaldad andmeid tõhususe nimel, küsi, mis nendest andmetest midagi järeldas. Mõnikord pead saatma tähenduse otsesõnu just seetõttu, et lõpetasid selle asja saatmise, millest see varem järeldati.

Ja see on versiooni 1 loo lõpp — viimane karastamine enne ümberkirjutust. Eelmise peatüki jaoks — kolm tegusõna, mis hoiavad Web Audio elus (v1.8.16 + v2.0.2); selle jaoks, kuhu see kõik suundus — mida versioon 2 tegelikult nõuab: 206 kommitit (v2.0.0); ja kogu kaare jaoks — tarkvara täiuslikkuseni tarnimise anatoomia.

Seotud artiklid

Kolm tegusõna, mis hoiavad Web Audio elus
Steven
Steven7 min lugemist

Kolm tegusõna, mis hoiavad Web Audio elus

Kaks GeekBye väljalaset, kahe kuu vahega ja kahes eri failis, õpetasid meie helikoodile sama õppetunni vastasotstest: lõpeta brauseri AudioContexti kohtlemine ühekordselt kasutatavana. Üks väljalase õppis kutsuma `resume()` kontekstile, mille macOS oli salaja peatanud keset salvestust; teine õppis kutsuma `suspend()` mitte `close()`, et järjestikused sessioonid lakkaksid põrkumast vastu Chromiumi umbes-kuue-konteksti lage. Resume, suspend, close — see ongi kogu süžee.

Arendus
Audio
Desktop
Kõne eristamine avatud rakendusest
Steven
Steven7 min lugemist

Kõne eristamine avatud rakendusest

GeekBye võib märgata, et oled videokoosolekuga liitunud, ja pakkuda selle salvestamist. Tuvastus osutub lihtsamaks pooleks — Swift-binaar, mis loeb aknapealkirju iga kümne sekundi tagant. Raske pool on täpsus: mitte vallanduda, kui Zoom on lihtsalt avatud, mitte pakkuda koosolekut, mida sa juba salvestad, ja mitte vaigistada mikrofoni kõnes, milles sa tegelikult oled. Kolm väljalaset, ja igaüks neist on valvur, kes pidi õppima ennast mitte lööma.

Arendus
macOS
Desktop
Backend-i eemaldamine üleslaadimise teelt
Steven
Steven7 min lugemist

Backend-i eemaldamine üleslaadimise teelt

GeekBye salvestab su ekraani ja hoiab video su Google Drive-i. Esimene versioon saatis iga salvestuse teel sinna läbi GeekBye enda serverite; üks väljalase hiljem läks fail otse su masinast Drive-i, ja backend alandati ühe kursori hoidmiseni. Huvitav osa on see, kui vähe koodi 'otsene, jätkatav' versioon tegelikult sisaldab — sest jätkatavus tuli proksi kustutamisest, mitte selle kirjutamisest.

Arendus
Arhitektuur
Desktop