Hoppa till innehåll

Möten och transkription

Control Center kan spela in ett samtal och ge dig en prydlig sammanställning – en sammanfattning, åtgärdspunkter och beslut – med taligenkänning och talarseparation som körs på din egen hårdvara. Tänk Granola, men självhostat och kopplat till samma arbetsyta som dina agenter lever i.

Ett möte är en inspelad och transkriberad session. Det är inte samma sak som en kalenderhändelse: en händelse är ett planerat åtagande som synkas från Google, medan ett möte är något du faktiskt har spelat in. De två kan länkas, eftersom du kan starta en inspelning från en händelse, men de förblir separata poster.

Varje möte är knutet till en arbetsyta, precis som allt annat i Control Center. Möten som spelats in i en arbetsyta dyker aldrig upp i en annan.

”På enheten” är rätt instinkt men fel ord. Klienten fångar ljudet och strömmar PCM16-ramar i 16 kHz till maskinen som kör cc_server. Värdmaskinen sköter allt övrigt: den skriver WAV-filerna per kanal under <dataDir>/meetings/<meetingId>/, transkriberar i ett worker-isolat, filtrerar bort eko och diariserar i efterhand. På en fristående skrivbordsdator är värden samma maskin. Riktad mot en fjärrserver är den inte det – så ”inget lämnar min laptop” stämmer bara när servern är din laptop.

Det finns ett undantag till, och det är det viktiga.

Allt före sammanfattningen – ljudfångst, transkribering, ekodämpning, diarisering och matchning av röstavtryck – körs på servern utan några nätverksanrop.

Modellerna för embedding, diarisering och tal (ASR) installeras med tvång vid första uppstarten (hoppas över i en demo), så talarseparation och inspelning finns utan att du behöver besöka inställningarna. ASR är fortfarande valbar – den är flera hundra megabyte, och fyra varianter följer med i väljaren. Taligenkänningen kräver ändå en omstart efter den första nedladdningen, eftersom transkriberaren löser sin modell innan hämtningen hinner bli klar.

De fyra posterna i väljaren, som skiljer sig i storlek, språktäckning och träffsäkerhet:

  • Parakeet TDT 0.6B v3 — flerspråkig, den rekommenderade standarden (~600 MB)
  • Parakeet TDT 0.6B v2 — engelska (~480 MB)
  • Whisper large-v3-turbo — flerspråkig (~626 MB)
  • Whisper base.en — endast engelska, den lilla historiska standarden (~198 MB)

Modellerna är de enda artefakter som servern hämtar vid körning; alla inbyggda bibliotek följer med i paketet.

Ett möte spelar in två ljudkanaler samtidigt:

  • Du (”jag”): din mikrofon.
  • De andra (”dem”): mötets ljudutgång, fångad av en drivrutinsfri loopback — Core Audio-tappar för processer och enheter på macOS, WASAPI-loopback på Windows, en PipeWire-/PulseAudio-monitor på Linux.

Eftersom de två kanalerna fångas separat är transkriptet tillskrivet talare från början: dina ord märks med me, och alla andra i samtalet märks med them.

Din egen röst läcker från systemutgången tillbaka in i mikrofonen och skulle annars transkriberas två gånger. Två filter stoppar det. På signalnivå körs AEC3 vid varje inspelning i fjärrläge och är obligatoriskt – om det inbyggda AEC-biblioteket inte kan läsas in vägrar inspelningen att starta i stället för att tyst strömma en mikrofon förorenad av eko. (I närvaroläge finns ingen referens från andra änden att dämpa mot, så AEC är en identitetsgenomgång där.) Ovanpå det körs ett textbaserat ekofilter på värdsidan på alla plattformar.

All mikrofonbehandling på operativsystemnivå är medvetet avstängd. Om du aktiverar plattformens egen ekodämpning eller automatiska förstärkning på macOS växlar mikrofonen till Voice Processing I/O, vilket i den här versionen dödade både mikrofonen och tappen för systemljudet.

Medan du spelar in avkodas ljudet i rullande fönster – som klipps vid en kort avslutande tystnad eller vid en maximal fönsterlängd – utanför gränssnittstråden. Varje fönster blir ett talarmärkt transkriptsegment med millisekundsoffset.

Fönster som aldrig nådde över en RMS-tröskel hoppas över utan att avkodas alls, eftersom en talmodell återger tystnad som hallucinerade icke-taltoken och avkodningen slösar CPU. Den praktiska konsekvensen: en genomgående mycket tyst talare ger inget transkript. Om någon kommer tillbaka tom kontrollerar du ingångsnivån innan du skyller på modellen.

När du stoppar körs diariseringen offline över inspelningen och delar upp fjärrkanalen i enskilda talare (Person 1, Person 2, …) som du kan byta namn på. Antalet talare härleds från en klustringströskel, inte från ett antal du anger – så det är en tröskelartefakt, och en tyst eller överlappande talare kan slås samman med en granne. Transkriptet visas som rader i formen [mm:ss] SPEAKER: text.

Att byta namn på en talare gör mer än att märka ett transkript. Control Center kan spara talarens röstavtryck som en röstprofil och känner då igen personen automatiskt i framtida möten. När du namnger en diariserad talare får du frågan om du vill spara röstavtrycket; gör du det vävs det in i en löpande centroid för namnet och matchas mot nya talare med cosinuslikhet, så samma person dyker upp med sitt namn nästa gång utan att du märker om den.

Röstprofiler är knutna till arbetsytan och korsar aldrig gränsen. Hantera dem under Inställningar → Arbetsyta → Möten. Om du byter namn på en talare som tidigare sparats avregistreras det gamla namnet och du erbjuds registrera det nya; om du tar bort en profil försvinner det sparade röstavtrycket, men namn som redan tillämpats på tidigare möten ligger kvar.

När en inspelning stoppas publicerar servern en MeetingRecordingStopped domänhändelse. Den inbyggda pipelinemallen meeting_summary utlöses av händelsen. Inspelaren väntar inte på den; mötet går helt enkelt igenom sin statuslivscykel:

recording → processing → done

Sammanfattningsagenten tar emot titeln, dina grova anteckningar från inspelningen och transkriptet och returnerar strukturerad JSON. Vilka avsnitt den skriver formas av arbetsytans aktiva mall för mötesanteckningar (Inställningar → Arbetsyta → Möten); den aktiva mallen gäller nya och omkörda sammanfattningar. Pipelinens persistenssteg skriver sedan den JSON:en till separata rader:

  • enhancedNotes och summary → mötets anteckningar
  • varje åtgärdspunkt → en rad av typen MeetingActionItem (innehåll, ägare, valfri ärendelänk)
  • varje beslut → en rad av typen MeetingDecision

Åtgärdspunkter och beslut tolkas aldrig ut ur fritt markdown, bara ur agentens strukturerade arrayer. Om en körning inte ger någon strukturerad utdata hoppas persistensstegen över och det råa transkriptet behålls som reserv, så du förlorar aldrig posten. Inget i pipelinen markerar mötet som done – det gör en enda avstämningsprocess utifrån körningens avslutande händelse, så ett systersteg som misslyckas kan inte lämna ett halvskrivet möte som redan ser färdigt ut.

Yta Vad den visar
/meetings Listan över möten, med antal åtgärdspunkter och beslut
/meetings/record Live-HUD:en för inspelning: dina anteckningar på ena sidan, det strömmande transkriptet på den andra
/meetings/:meetingId En mötesdetalj: flikarna Anteckningar, Utskrift, Åtgärdspunkter och Beslut
Inställningar → Arbetsyta → Möten Anteckningsmallar och sparade röstprofiler för den här arbetsytan

Ljudfångsten är drivrutinsfri på alla tre skrivbordsplattformar (Core Audio-tappar på macOS, WASAPI på Windows, PipeWire på Linux).

Även webbklienten spelar in, vilket resten av den här sidans skrivbordsinriktning kan dölja: webbläsaren tar din mikrofon via getUserMedia och mötesljudet via getDisplayMedia (skärmdelning), samplingreducerar till 16 kHz PCM16 och strömmar till samma värd. Tre förbehåll gäller där:

  • Den delade ytan måste innehålla ett ljudspår. Safaris, Firefox och macOS delning av helskärm ger inget, och inspelningen vägrar starta.
  • Det finns ingen inbyggd AEC3. Webbläsarens egen ekodämpning begärs på mikrofonen; det textbaserade ekofiltret på värdsidan körs fortfarande. HUD:en visar en ingångsnivåmätare som drivs av mikrofonens PCM.
  • Kör om sammanfattning och avbryt bearbetning finns bara på skrivbordet.

Kalenderns åtgärd Starta inspelning och länka finns bara på skrivbordet och säger det rakt ut på webben, även om mötesskärmens eget inspelningsflöde fungerar där.