
Cara Menstrim Laporan Langsung Tanpa Kelipan
Apabila mesyuarat anda tamat, ringkasan GeekBye kini terisi secara langsung dan bukannya membuat anda merenung pemutar menunggu. Menjadikan UI penstriman terasa tenang dan bukannya bergegar memerlukan penyelesaian kelipan dua kali — sekali untuk medan berstruktur, sekali untuk markdown — dan pembetulan kedua ialah sebuah renderer yang sudah kami miliki.
Sebelum keluaran ini, menamatkan mesyuarat GeekBye bermakna menonton pemutar menunggu. Aplikasi akan menghantar keseluruhan transkrip anda untuk dianalisis, menunggu ringkasan penuh — skor, perkara penting, item tindakan, semuanya — kemudian menjatuhkannya ke skrin serentak. Berfungsi, tetapi ia terasa perlahan, kerana anda merenung kekosongan sementara ia bekerja.
GeekBye v1.6.13–v1.6.15 mengubahnya menjadi laporan yang mengalir masuk secara langsung, medan demi medan, sambil ia dijana. Bahagian yang menarik bukanlah penstrimannya — tetapi segala yang perlu kami lakukan supaya penstriman tidak kelihatan bergegar. Penstriman yang tenang dan penstriman yang tersekat-sekat ialah ciri yang sama dengan pelaksanaan yang sangat berbeza.
Kelipan, bahagian satu: jangan biarkan setiap ketulan menggegarkan React
Ringkasan bukanlah satu gumpalan — ia ialah medan berstruktur (skor keseluruhan, perkara penting, item tindakan, dan sebagainya) yang dipancarkan backend satu demi satu melalui server-sent events. Cara naif untuk memaparkannya adalah mengemas kini keadaan React pada setiap peristiwa sebaik ia tiba.
Buat begitu, dan anda akan mendapat kelipan. Setiap medan yang tiba mencetuskan pemaparan semulanya sendiri; komponen yang memaparkan "kosong" akan mount, kemudian unmount, kemudian remount sebagai "dimuatkan"; susun atur bergegar pada setiap paket. Laporan memasang dirinya sendiri di depan anda dengan cara yang paling teruk — jelas kelihatan, gugup.
Pembetulannya ialah disiplin dua bahagian. Pertama, kumpulkan medan yang masuk dalam sebuah ref — bekas boleh ubah yang tidak mencetuskan pemaparan — dan terbitkan ke keadaan React sekali setiap ketulan dengan salinan baharu, supaya pepohon dikemas kini secara sengaja dan bukannya pada setiap mikro-peristiwa. Kedua, paparkan satu pepohon komponen yang stabil sepanjang masa, sama ada sedang distrim mahupun selesai, dengan pemegang tempat sebaris untuk medan yang belum tiba:
// accumulate in a ref, publish once per chunk
partialRef.current = { ...partialRef.current, [field]: value }
setPartial({ ...partialRef.current })
// one tree, never swapped; missing fields show a placeholder in place
const report = isStreaming ? partial : saved
<Score>{report.overallScore ?? '…'}</Score>
Komponen yang memaparkan skor tidak pernah unmount — ia hanya memaparkan … sehingga nombornya tiba, kemudian nombornya. Tiada apa-apa bergegar. Dan objek yang dipasang sepenuhnya tetap dicache ke pangkalan data setempat pada akhirnya, supaya UI penstriman dan storan tahan lama wujud bersama tanpa bergaduh.
Kelipan, bahagian dua: renderer yang sudah kami miliki
Kelipan kedua lebih halus dan hidup dalam markdown itu sendiri. Laporan memaparkan markdown kaya — tajuk, tebal, senarai, blok kod. Tetapi markdown yang tiba di tengah strim, pada bila-bila masa, separuh siap. Satu senarai dengan satu butir setakat ini. Satu pagar kod yang telah dibuka tetapi belum ditutup. Satu penanda tebal yang belum ada pasangan.
Sebuah renderer markdown konvensional menghurai semula keseluruhan rentetan pada setiap token, dan keadaan separuh siap itu terhurai menjadi sesuatu yang berbeza setiap kali — jadi senarai berkelip, blok kod berkelip buka-tutup, susun atur melompat sambil token selesai. Ia ialah pemasangan gugup yang sama seperti sebelumnya, satu lapisan lebih dalam.
Pembetulannya hampir memalukan kerana begitu mudah didapati: kami sudah menggunakan renderer markdown yang sedar-penstriman untuk sembang AI langsung. Sebuah renderer yang dibina untuk bertolak ansur dengan token tidak lengkap — untuk memaparkan markdown separuh siap secara stabil dan hanya menetapkannya apabila token selesai — dan bukannya menghurai semula dari kosong setiap kali. Laporan hanya perlu menggunakan yang sama. Kami telah menyelesaikan masalah yang tepat ini untuk sembang berbulan-bulan sebelumnya; "pembetulan" untuk laporan adalah menyedari bahawa kami sudah ada alatnya dan mengarahkannya ke permukaan kedua. Guna semula mengalahkan bina semula.
Bonusnya: salin kaya ialah masalah format papan keratan
Sebaik laporan kelihatan bagus, orang mahu menampalnya — ke dokumen, e-mel — dan mengekalkan formatnya serta tangkapan skrinnya. Naluri adalah menyirikan laporan menjadi rentetan markdown dan berharap destinasi memaparkannya. Biasanya tidak.
Jawapan sebenar ialah papan keratan menyimpan berbilang perwakilan serentak. Jadi kami menulis dua: sebuah versi HTML dengan format utuh dan tangkapan skrin terbenam sebagai imej sebaris, dan sebuah sandaran teks biasa untuk destinasi yang tidak menerima HTML. Tampal ke editor kaya dan anda mendapat laporan berformat dengan gambar; tampal ke kotak teks biasa dan anda mendapat teks bersih. "Salin kaya" tidak pernah menjadi masalah penyirian — ia ialah masalah pilih-format-papan-keratan-yang-betul.
Keluaran yang sama juga memberikan laporan label gaya-sembang Me / Them dengan kedua-dua penutur dijajarkan ke sisi bertentangan, supaya sebuah transkrip terbaca seperti perbualan yang sebenarnya, dan memindahkan tangkapan skrin anda sendiri ke sisinya sendiri agar sepadan. (Satu keluaran dalam tetingkap ini, v1.6.14, ialah pembinaan semula tulen — tiada cerita di situ, dan jujur untuk mengatakannya.)
Tiga perkara yang diajar UI penstriman kepada kami
- Timbunkan medan yang distrim, terbitkan sekali setiap ketulan. Membiarkan setiap server-sent event memacu kemas kini keadaannya sendiri ialah puncak kelipan. Sebuah pengumpul ref serta satu penerbitan setiap ketulan, ke dalam pepohon yang tidak pernah unmount, mengubah pemasangan gugup menjadi pengisian yang tenang.
- Apa-apa sahaja yang distrim memerlukan renderer yang sedar-penstriman. Renderer yang menghurai semula keseluruhan rentetan setiap token akan berkelip pada markdown separuh siap. Gunakan yang dibina untuk input tidak lengkap — dan jika anda sudah ada satu untuk permukaan lain, guna semula sebelum membina yang kedua.
- Salin kaya adalah tentang format papan keratan, bukan penyirian. Tulis
text/htmldengan imej terbenam dan sandarantext/plain. Papan keratan direka untuk membawa kedua-duanya; gunakannya.
Ini ialah bab kelima daripada kisah kebolehpercayaan-dan-penggilapan yang menjadi GeekBye v2. Untuk bab sebelumnya, lihat pepijat fon telinga (v1.6.12); untuk tempat di mana idea server-sent events yang sama kemudiannya menjadi keseluruhan pengangkutan sandaran, transkripsi langsung apabila tembok api menyekat WebSockets (v2.0.8); dan untuk keseluruhan lengkoknya, anatomi menghantar perisian hingga ke kesempurnaan.