Kembali ke blog
19 Oktober 2026Sergei Solod20 mnt baca

Cara Menambahkan Fitur Ucapan ke Teks yang Menjaga Privasi ke Situs Web dengan Whisper dan WebAssembly

Bangun fitur pengetikan suara sepenuhnya di sisi klien menggunakan Whisper, Transformers.js, ONNX Runtime Web, AudioWorklet, dan WebAssembly. Pelajari cara mengoptimalkan performa seluler dan memperbaiki kesalahan runtime, worker, serta tokenizer yang membuat pengenalan ucapan tidak berfungsi.

Ucapan ke TeksWhisperWebAssemblyAudioWorkletJavaScript

Menambahkan tombol mikrofon ke situs web terlihat sederhana: menangkap suara pengguna, mengenali kata-katanya, lalu memasukkannya ke kolom teks. Namun, membuatnya bekerja secara andal di peramban desktop maupun seluler jauh lebih sulit, terutama jika seluruh pengenalan ucapan harus berlangsung secara lokal tanpa mengunggah audio mikrofon ke server.

Tantangannya bukan sekadar memilih model pengenalan ucapan. Implementasi yang berfungsi harus menangani izin mikrofon, perekaman audio, pengambilan sampel ulang, worker peramban, WebAssembly, inisialisasi model ONNX, tokenisasi, penyimpanan cache, dan integrasi dengan kolom input aplikasi secara benar.

Artikel ini menjelaskan cara membangun fitur pengubahan ucapan menjadi teks yang praktis dan menjaga privasi menggunakan OpenAI Whisper, Transformers.js, ONNX Runtime Web, AudioWorklet, dan Web Worker khusus. Artikel ini juga membahas sejumlah kegagalan integrasi nyata yang dapat membuat tombol mikrofon terus menampilkan indikator pemuatan meskipun berkas model sudah berhasil diunduh.

Tujuannya sederhana: pengunjung menekan tombol mikrofon, berbicara secara alami, lalu melihat hasil transkripsi muncul di kolom input yang sudah ada. Pengunjung dapat memeriksa atau mengedit hasilnya sebelum mengirimkannya. Rekaman mikrofon itu sendiri tidak perlu meninggalkan peramban.

Apa arti pengenalan ucapan yang sepenuhnya berjalan di sisi klien

Ada dua pendekatan yang secara mendasar berbeda untuk menambahkan input suara ke situs web.

Pendekatan pertama menggunakan layanan pengenalan ucapan. Peramban merekam audio, mengirimkannya ke layanan jarak jauh, lalu menerima teks hasil pengenalan. Pendekatan ini dapat menyederhanakan implementasi, tetapi menimbulkan ketergantungan pada jaringan, pertimbangan privasi, ketergantungan pada ketersediaan penyedia layanan, dan kemungkinan biaya berdasarkan penggunaan.

Pendekatan kedua menjalankan inferensi langsung di dalam peramban. Situs web mengunduh model pengenalan ucapan beserta runtime yang diperlukan untuk menjalankannya. Peramban menangkap audio mikrofon, mengubahnya menjadi sampel numerik, menjalankan model secara lokal, dan menghasilkan transkripsi tanpa server pengenalan ucapan.

Artikel ini sepenuhnya berfokus pada pendekatan kedua.

Pengenalan ucapan biasa di peramban tidak boleh disamakan dengan pengenalan yang dijamin berlangsung secara lokal. Web Speech API dapat menggunakan mesin pengenalan berbasis server. Beberapa implementasi yang lebih baru menyediakan opsi processLocally, tetapi dukungannya berbeda antarperamban dan sistem operasi. Jika pemrosesan lokal merupakan persyaratan mutlak, SpeechRecognition generik tidak boleh digunakan sebagai solusi cadangan otomatis.

Sebaliknya, aplikasi mengendalikan seluruh alur inferensi.

Mikrofon
    |
    v
AudioWorklet
    |
    v
Audio PCM Float32
    |
    v
Web Worker khusus
    |
    v
Pengambilan sampel ulang 16 kHz
    |
    v
Whisper + ONNX Runtime Web
    |
    v
Tokenisasi dan pendekodean teks
    |
    v
State input React

Situs web tetap menyajikan JavaScript, WebAssembly, berkas konfigurasi, dan bobot model. Semuanya merupakan unduhan berkas statis biasa. Perbedaannya adalah audio mikrofon diproses secara lokal, bukan diunggah untuk dikenali. Jika pengguna kemudian mengirimkan teks hasilnya melalui formulir biasa, itu merupakan tindakan aplikasi yang terpisah.

Memilih model yang praktis: Whisper Tiny atau Base

Whisper merupakan keluarga model pengenalan ucapan multibahasa. Kemampuannya mengenali banyak bahasa menggunakan satu model membuatnya sangat berguna bagi situs web multibahasa.

Untuk pesan suara singkat, dua model menawarkan keseimbangan yang baik antara kualitas pengenalan dan penggunaan sumber daya peramban: Whisper Tiny dan Whisper Base.

ModelPerkiraan bobot ONNX Q8 yang dipilihPenggunaan yang disarankan
Whisper Tiny41 MBPilihan konservatif untuk perangkat seluler dan perangkat dengan sumber daya terbatas
Whisper Base77 MBPilihan dengan kualitas lebih tinggi untuk perangkat mumpuni yang telah diuji

Ukuran tersebut mengacu pada berkas ONNX encoder dan decoder terpilih dari hasil ekspor yang diperiksa. Ukuran ini tidak mencakup seluruh berkas pendukung dan tidak boleh disamakan dengan penggunaan memori puncak di peramban.

Whisper Tiny menarik karena lebih cepat diunduh, umumnya membutuhkan lebih sedikit sumber daya komputasi, dan lebih cocok untuk lingkungan seluler dengan kemampuan yang belum diketahui. Whisper Base biasanya memberikan kualitas pengenalan yang lebih baik, terutama untuk bahasa tertentu yang lebih sering salah dikenali oleh model kecil.

Pemilihan model tidak boleh hanya berdasarkan RAM fisik. Memori yang tersedia bagi peramban mungkin jauh lebih kecil daripada kapasitas yang tercantum dalam spesifikasi perangkat. Penggunaan memori halaman yang sudah berjalan, alokasi WebAssembly, tensor sementara, dan tekanan memori sistem operasi semuanya berpengaruh.

Pendekatan konservatif adalah memulai dengan Tiny pada perangkat seluler yang kemampuannya belum diketahui, menggunakan Base hanya untuk kelas perangkat yang telah memenuhi kriteria, serta beralih dari Base ke Tiny jika inisialisasi model gagal.

Instans Base yang gagal harus dilepaskan sebelum Tiny dimuat. Membiarkan kedua model tetap berada di memori akan menggagalkan tujuan mekanisme cadangan tersebut.

Mengapa WebAssembly merupakan pilihan bawaan yang masuk akal untuk produksi

ONNX Runtime Web mendukung eksekusi jaringan saraf di dalam peramban. Untuk beban kerja ini, WebAssembly menyediakan jalur inferensi CPU yang praktis di berbagai peramban desktop dan seluler utama.

WebGPU dapat mempercepat model yang didukung pada perangkat keras yang sesuai, tetapi ketersediaannya tidak berarti seluruh alur pengenalan ucapan akan berfungsi. Peramban yang menyediakan navigator.gpu tidak menjamin bahwa ONNX Runtime mendukung platform tersebut, bahwa grafik Whisper tertentu dapat diinisialisasi dengan benar, ataupun bahwa inferensi berulang bebas dari masalah sumber daya.

Karena itu, implementasi konservatif dapat menggunakan WASM sebagai backend produksi dan mengevaluasi WebGPU secara terpisah setelah pengujian kompatibilitas, akurasi, memori, dan sesi berulang.

Untuk implementasi awal, WASM berutas tunggal juga menghindarkan seluruh situs web dari ketergantungan pada isolasi lintas-origin dan SharedArrayBuffer.

env.backends.onnx.wasm.numThreads = 1;
env.backends.onnx.wasm.proxy = false;

Menjalankan inferensi di worker khusus menjauhkan komputasi berat dari utas JavaScript utama. Kolom input, papan ketik virtual, pengguliran, dan antarmuka aplikasi tetap responsif saat model memproses audio.

Jangan membebani pemuatan awal halaman dengan pengenalan ucapan

Fitur mikrofon tidak seharusnya menimbulkan biaya jaringan dan memori yang besar bagi pengunjung yang tidak pernah menggunakannya.

Jangan mengimpor Transformers.js lebih awal ke bundel awal aplikasi. Jangan menginisialisasi ONNX Runtime saat halaman dibuka, dan jangan mengunduh bobot model secara otomatis ketika aplikasi sedang tidak digunakan.

Sebaliknya, muat seluruh komponen pengenalan hanya setelah pengguna secara jelas menekan tombol mikrofon.

Urutan penggunaan pertama yang baik adalah:

  1. Terima klik pada tombol mikrofon.
  2. Minta izin mikrofon melalui getUserMedia().
  3. Jika izin ditolak, tampilkan kesalahan tanpa mengunduh model.
  4. Jika izin diberikan, lepaskan aliran mikrofon sementara selama model disiapkan.
  5. Inisialisasi worker khusus secara dinamis dan muat model lokal yang dipilih.
  6. Tunggu hingga worker memastikan bahwa alur pengenalan siap digunakan.
  7. Mulai perekaman secara otomatis jika pengguna belum membatalkan operasi.
  8. Tampilkan status yang jelas bahwa aplikasi sedang mendengarkan.

Permintaan izin harus terkait dengan interaksi pengguna. Aplikasi juga harus menangani operasi yang dibatalkan dan pembatasan perekaman khusus peramban, alih-alih mengasumsikan bahwa perekaman selalu dapat dimulai kembali tanpa interaksi pengguna.

Persiapan model perlu memiliki status yang terlihat, misalnya Menyiapkan input suara. Indikator berputar tanpa perubahan status yang bermakna dapat membuat pengunduhan model yang sebenarnya berhasil terlihat seperti mikrofon yang rusak.

Setelah diinisialisasi, worker dapat tetap tersedia sebentar untuk dikte berikutnya. Batas waktu tidak aktif sekitar satu menit merupakan titik awal yang masuk akal. Setelah itu, hentikan worker dan lepaskan model dari memorinya. Berkas model yang tersimpan di cache peramban dapat tetap tersedia untuk kunjungan berikutnya.

Menangkap audio mentah dengan AudioWorklet

Whisper membutuhkan sampel audio numerik. Walaupun MediaRecorder sangat baik untuk merekam berkas audio, penggunaannya untuk pengenalan ucapan lokal dapat menambahkan proses pengodean dan pendekodean bolak-balik yang tidak diperlukan.

Alur pemrosesan yang lebih sederhana adalah:

getUserMedia()
    |
    v
AudioContext
    |
    v
AudioWorklet
    |
    v
Buffer PCM Float32
    |
    v
Worker khusus

AudioWorklet menjalankan kode pemrosesan audio di luar utas JavaScript utama aplikasi. Komponen ini dapat menangkap sampel PCM, mengubah input multikanal menjadi mono, menghitung pengukuran volume sederhana, dan mentransfer buffer yang telah dikumpulkan ke worker.

Contoh sederhana inisialisasi mikrofon adalah sebagai berikut:

const stream = await navigator.mediaDevices.getUserMedia({
  audio: {
    channelCount: { ideal: 1 },
    echoCancellation: true,
    noiseSuppression: true,
    autoGainControl: true,
  },
});

const context = new AudioContext();

await context.audioWorklet.addModule(
  '/assets/speech/pcm-worklet.js'
);

const source = context.createMediaStreamSource(stream);
const processor = new AudioWorkletNode(
  context,
  'pcm-capture'
);

source.connect(processor);

// Connect the worklet through an inaudible output path
// if required to keep the audio processing graph active.

Batasan mikrofon tersebut merupakan preferensi, bukan jaminan. Peramban dapat menerapkan algoritma pembatalan gema, peredaman kebisingan, dan pengaturan penguatan otomatis yang berbeda.

Hal penting lainnya adalah laju sampel mikrofon belum tentu 16 kHz. Banyak konteks audio menggunakan 44.1 kHz atau 48 kHz. Whisper mengharapkan input 16 kHz, sehingga sampel yang direkam harus melalui pengambilan sampel ulang yang tepat.

Membuang begitu saja setiap sampel kedua atau ketiga umumnya bukan solusi yang benar. Pengambil sampel ulang dengan filter lolos-rendah yang sesuai, misalnya implementasi windowed-sinc, mengurangi aliasing dan mempertahankan frekuensi ucapan yang berguna saat laju sampel diturunkan.

Tempatkan pekerjaan pengambilan sampel ulang di worker khusus, bukan di callback AudioWorklet yang berjalan secara waktu nyata.

Mentransfer audio secara efisien antarutas peramban

AudioWorklet dapat menghasilkan banyak potongan audio kecil. Mengirim setiap kuantum pemrosesan audio sebagai pesan tersendiri dapat menimbulkan beban tambahan yang tidak perlu.

Strategi yang praktis adalah mengumpulkan potongan PCM menjadi kelompok singkat, lalu mentransfer setiap kelompok sebagai ArrayBuffer.

worker.postMessage(
  {
    type: 'audio-chunk',
    buffer,
  },
  [buffer]
);

Daftar transfer itu penting: daftar tersebut memindahkan kepemilikan ArrayBuffer alih-alih membuat salinan penuh yang tidak diperlukan.

Worker dapat menambahkan potongan-potongan ini ke penampung audio dan menggabungkannya ketika perekaman berhenti.

Pencatatan laju sampel perekaman yang sebenarnya, jumlah sampel yang terkumpul, dan durasi perekaman juga berguna. Metadata ini membantu mendiagnosis rekaman tanpa suara tanpa mencatat data audio yang sensitif.

Mendeteksi jeda tanpa menambahkan jaringan saraf lain

Dikte untuk pesan teks singkat tidak selalu memerlukan pendeteksi aktivitas suara berbasis jaringan saraf.

Pendeteksi RMS adaptif dapat memberikan perkiraan ringan atas aktivitas ucapan. RMS mengukur amplitudo sinyal sehingga aplikasi dapat memperkirakan kapan seseorang yang sebelumnya berbicara mulai diam.

Antarmuka harus selalu mendukung penghentian manual melalui klik kedua pada tombol mikrofon. Deteksi hening otomatis hanyalah fitur kenyamanan, bukan syarat agar pengenalan berhasil.

Nilai awal yang masuk akal untuk dikte singkat meliputi:

ParameterNilai awal
Interval analisis20 ms
Kalibrasi kebisingan300 ms
Konfirmasi ucapan140 ms
Durasi hening sebelum berhenti otomatis1.4 detik
Batas waktu tanpa ucapan8 detik
Durasi perekaman maksimum30 detik

Nilai tersebut hanyalah titik awal konfigurasi, bukan ambang batas optimal yang berlaku universal. Ucapan pelan, musik latar, dan pemrosesan kebisingan mikrofon dapat memengaruhi pengukuran RMS.

Lebih baik membiarkan pengguna menghentikan rekaman secara manual daripada menghentikannya otomatis hingga kata-kata terakhir dalam kalimat terpotong.

Untuk input teks singkat biasa, transkripsi sekali jalan biasanya lebih sederhana daripada menjalankan Whisper berulang kali untuk memperoleh hasil sementara. Rekam ucapan, hentikan, jalankan model satu kali, lalu masukkan transkripsi akhirnya.

Alur Whisper yang lengkap membutuhkan lebih dari sekadar model ONNX

Ini merupakan salah satu detail implementasi yang paling penting.

Inferensi Whisper bukan sekadar memanggil encoder ONNX lalu decoder ONNX. Alur pengenalan ucapan otomatis yang lengkap juga memerlukan ekstraksi fitur audio, tokenisasi, konfigurasi pembangkitan, dan pendekodean token prediksi menjadi teks yang dapat dibaca.

Rangkaian pemrosesan lengkapnya adalah:

PCM mentah dari mikrofon
        |
        v
Pengambilan sampel ulang ke 16 kHz
        |
        v
Ekstraktor fitur Whisper
        |
        v
Encoder ONNX
        |
        v
Decoder ONNX dan pembuatan token
        |
        v
Tokenizer Whisper
        |
        v
Teks yang dikenali

Inisialisasi sesi ONNX yang berhasil hanya membuktikan bahwa grafik model dapat dimuat. Hal itu tidak membuktikan bahwa seluruh alur pengenalan berfungsi.

Dalam salah satu integrasi Transformers.js yang diuji, sesi model berhasil diinisialisasi, tetapi transkripsi tetap gagal karena alur yang disusun secara lokal belum memiliki processor dan tokenizer yang dikonfigurasi dengan benar.

Implementasi yang kompatibel menginisialisasi komponen-komponen tersebut secara eksplisit menggunakan metadata model lokal.

Berikut ilustrasi ringkas pendekatan khusus versi tersebut, bukan worker mandiri yang lengkap:

import {
  WhisperTokenizer,
  WhisperFeatureExtractor,
  WhisperProcessor,
} from '@huggingface/transformers';

// These values come from local model configuration files.
const tokenizer = new WhisperTokenizer(
  tokenizerJson,
  tokenizerConfig
);

const featureExtractor = new WhisperFeatureExtractor(
  preprocessorConfig
);

const processor = new WhisperProcessor(
  {},
  {
    tokenizer,
    feature_extractor: featureExtractor,
  },
  ''
);

// In the affected version-specific integration:
recognizer.tokenizer = tokenizer;
recognizer.processor = processor;

Signature constructor dan metode integrasi yang tepat harus diperiksa terhadap versi Transformers.js yang terpasang. Beberapa versi dan hasil ekspor model dapat menyusun komponen tersebut secara otomatis; pembuatan manual tidak boleh dianggap sebagai persyaratan universal.

Setelah alur lengkap tersedia, transkripsi ucapan singkat dapat dipanggil dengan bahasa dan tugas yang ditentukan secara eksplisit:

const result = await recognizer(audio16k, {
  language: 'en',
  task: 'transcribe',
  return_timestamps: false,
});

Jika aplikasi sudah mengetahui bahasa pengguna, memberikannya secara eksplisit menghindari deteksi bahasa yang tidak diperlukan dan dapat meningkatkan konsistensi perilaku untuk rekaman singkat.

Tetapkan versi Transformers.js dan ONNX Runtime yang kompatibel

Jenis kegagalan penting lainnya berkaitan dengan hubungan antara Transformers.js dan ONNX Runtime Web.

Transformers.js menyediakan alur pengenalan pada tingkat yang lebih tinggi, sedangkan ONNX Runtime Web mengeksekusi grafik jaringan saraf. Kedua paket harus saling kompatibel dan sesuai dengan berkas ekspor model ONNX yang benar-benar digunakan.

Dalam implementasi yang diteliti, build pengembangan ONNX Runtime Web berhasil menginisialisasi encoder Whisper tetapi gagal saat membuat sesi decoder terkuantisasi. Kesalahan tersebut berkaitan dengan skala kuantisasi yang hilang dalam operasi DequantizeLinear.

Ini bukan masalah izin mikrofon, masalah pengunduhan, ataupun masalah format audio. Peramban dapat menerima berkas model, tetapi runtime tidak dapat menginisialisasi salah satu grafik model yang diperlukan.

Pengujian langsung pada encoder dan decoder menggunakan rilis stabil ONNX Runtime Web dengan versi yang ditetapkan menyelesaikan ketidakcocokan khusus tersebut.

Pemeriksaan kompatibilitas sangat berguna karena membedakan dua pernyataan berikut:

  • Berkas model berhasil diunduh.
  • Runtime berhasil membuat sesi inferensi yang dapat digunakan dari berkas model tersebut.

Keduanya bukan hal yang sama.

Untuk hasil ekspor model yang diuji, pasangan yang kompatibel adalah Transformers.js 4.2.0 dan ONNX Runtime Web 1.24.3. Runtime pengembangan yang lebih baru gagal pada grafik decoder terkuantisasi. Ini merupakan pengamatan khusus versi, bukan bukti bahwa runtime lama selalu lebih baik.

Saat menimpa versi dependensi runtime transitif, tetapkan versi persisnya dalam berkas pengunci dependensi paket dan dokumentasikan alasan penggantian tersebut. Peningkatan versi runtime harus melalui pengujian regresi inferensi penuh di peramban, bukan sekadar pemasangan paket yang berhasil.

Periksa format bundel worker sebelum men-debug Whisper

JavaScript Web Worker dapat dibuat menggunakan berbagai format modul.

Salah satu kegagalan integrasi terjadi karena aplikasi membuat worker sebagai modul ES, sedangkan bundel worker yang dihasilkan menggunakan mekanisme worker klasik importScripts().

Kedua model eksekusi ini tidak dapat saling dipertukarkan. Worker modul tidak bisa begitu saja menjalankan kode yang hanya mendukung API worker klasik.

Pelajaran praktisnya adalah menyesuaikan constructor Worker dengan keluaran bundel yang sebenarnya, bukan menyalin opsi constructor dari tutorial umum.

Sebagai contoh, kedua opsi berikut tidak otomatis setara:

// Module worker: requires a compatible module bundle.
new Worker(workerUrl, { type: 'module' });

// Classic worker: requires a compatible classic bundle.
new Worker(workerUrl);

Pilihan yang benar bergantung pada bundler dan JavaScript yang dihasilkannya.

Saat mendiagnosis kesalahan inisialisasi worker, periksa Console peramban, berkas worker yang dihasilkan, dan panel Network. Tentukan apakah kegagalan terjadi bahkan sebelum ONNX Runtime mulai diinisialisasi.

Beberapa pustaka peramban yang telah dibundel juga menghitung URL relatif terhadap lokasi modulnya sendiri. Ketika mengemas pustaka itu di dalam worker, uji jalur aset runtime yang dihasilkan alih-alih berasumsi bahwa URL relatif paket aslinya tetap dapat ditemukan.

Sajikan modul WASM dan JavaScript dengan tipe MIME yang benar

Bahkan berkas JavaScript dan model ONNX yang sepenuhnya kompatibel dapat gagal jika server web mengembalikan header respons yang salah.

Kegagalan nyata terjadi ketika modul JavaScript berekstensi .mjs disajikan sebagai application/octet-stream. Peramban menolak modul tersebut karena tipe responsnya tidak sesuai untuk eksekusi modul JavaScript.

Tipe respons yang umumnya diharapkan adalah:

Ekstensi berkasContent-Type
.mjsapplication/javascript
.wasmapplication/wasm

Periksa respons produksi yang sebenarnya, bukan hanya berkas konfigurasi server.

curl -I https://example.com/runtime/speech/v2/runtime.mjs
curl -I https://example.com/runtime/speech/v2/runtime.wasm

URL di atas hanya ilustrasi. Gunakan nama berkas aset berversi yang sebenarnya dari build runtime yang dipilih.

Status HTTP yang benar saja tidak cukup. Peramban masih dapat menolak berkas karena tipe MIME, Content Security Policy, mode eksekusi modul, atau URL aset yang salah.

Ingat bahwa permintaan yang sama dapat berhasil ketika dibuka langsung dalam tab peramban, tetapi gagal saat dimuat sebagai modul yang dapat dijalankan atau dependensi WebAssembly.

Gunakan URL aset yang tidak berubah tanpa mengunci pengguna pada berkas runtime yang rusak

Berkas model Whisper cukup besar sehingga penyimpanan cache peramban menjadi penting.

Jalur aset berversi yang tidak berubah memungkinkan peramban menggunakan kembali berkas model dan runtime yang sama tanpa mengunduhnya setiap kali pengguna berbicara.

Kebijakan cache yang umum adalah:

Cache-Control: public, max-age=31536000, immutable

Namun, hal ini menimbulkan persyaratan penerapan: setelah URL dinyatakan tidak berubah, isinya tidak boleh diganti diam-diam.

Jika berkas biner runtime harus berubah, terbitkan di URL baru yang memiliki versi berbeda.

/models/speech/v1/
/runtime/speech/v1/
/runtime/speech/v2/

Mengubah jalur runtime bukan sekadar urusan penamaan. Peramban mungkin terus menggunakan berkas WebAssembly tidak kompatibel yang sebelumnya tersimpan di cache jika aplikasi memakai lagi URL yang ditetapkan tidak berubah setelah mengganti isinya.

Sebaiknya berkas penghubung JavaScript dan WebAssembly juga berasal dari distribusi runtime yang sama. Mencampur berkas runtime dari berbagai versi dapat menyebabkan kegagalan inisialisasi yang sulit didiagnosis.

Manifes pada tahap build yang berisi berkas, ukuran, dan checksum kriptografis yang diharapkan dapat mendeteksi aset yang hilang atau tidak cocok sebelum penerapan.

Konfigurasikan pustaka pengenalan agar menggunakan aset yang dihosting sendiri dan nonaktifkan pemuatan model jarak jauh. Dengan begitu, model lokal yang hilang menimbulkan kesalahan yang jelas, bukan memicu pengunduhan tidak terencana dari penyedia model eksternal.

Mengapa mikrofon terus memuat meskipun tidak berfungsi

Gejala umum saat pengembangan adalah tombol mikrofon yang meminta izin, menampilkan animasi pemuatan, lalu akhirnya kembali ke status kesalahan tanpa memasukkan teks.

Peramban bahkan mungkin menunjukkan bahwa mikrofon sedang digunakan.

Hal itu tidak membuktikan bahwa pengenal ucapan berfungsi. Itu hanya membuktikan bahwa perekaman mikrofon pernah diizinkan atau aktif.

Beberapa kegagalan independen dapat menimbulkan gejala yang hampir sama:

  1. Tipe MIME modul JavaScript salah. Peramban mengunduh modul runtime tetapi menolak mengeksekusinya.
  2. Format eksekusi worker tidak cocok. Worker hasil kompilasi menggunakan API worker klasik tetapi dijalankan sebagai worker modul, atau sebaliknya.
  3. Decoder ONNX tidak kompatibel. Runtime berhasil membuat sesi encoder tetapi gagal pada grafik decoder terkuantisasi.
  4. Alur pengenalan tidak lengkap. Sesi ONNX tersedia, tetapi tokenizer atau pemroses audio belum diinisialisasi dengan benar.

Masalah-masalah tersebut harus didiagnosis secara terpisah. Memperbaiki satu masalah mungkin akan memperlihatkan masalah berikutnya.

Prinsip debugging terpenting adalah bahwa HTTP 200 bukan berarti inisialisasi model berhasil, dan inisialisasi model yang berhasil bukan berarti transkripsi berhasil.

Transkripsi yang berhasil pun belum membuktikan bahwa hasilnya sampai ke kolom teks aplikasi yang sebenarnya.

Setiap batas antarkomponen membutuhkan sinyal diagnostik yang bermakna.

Tambahkan kemampuan observasi tanpa mengumpulkan percakapan pribadi

Pencatatan diagnostik yang berguna tidak memerlukan rekaman atas apa yang dikatakan pengguna.

Aplikasi dapat melacak status teknis seperti:

permission-granted
worker-created
runtime-loading
runtime-ready
encoder-ready
decoder-ready
recording-started
pcm-received
recording-stopped
inference-started
inference-completed
result-inserted

Ketika terjadi kegagalan, sertakan tahap, kode kesalahan teknis yang stabil, dan metadata kesalahan yang telah disanitasi.

Kegagalan inisialisasi model harus dapat dibedakan dari penolakan izin mikrofon atau rekaman kosong. Kegagalan worker harus terlihat selama pengembangan, bukan ditelan oleh penangan kesalahan generik.

Jangan catat sampel mikrofon, kalimat yang dikenali, rangkaian token, atau isi ucapan lainnya. Telemetri performa dapat menggunakan kelompok rentang durasi, tingkat model yang dipilih, waktu inisialisasi, waktu inferensi, dan kategori kesalahan.

Dengan cara ini, mikrofon yang gagal jauh lebih mudah didiagnosis tanpa melemahkan persyaratan privasi.

Masukkan transkripsi melalui state React

Pengenalan ucapan hanya berguna jika transkripsi akhirnya masuk ke kolom formulir yang sudah ada.

Pada aplikasi React, kolom tersebut sering dikendalikan oleh state komponen. Mengisi input.value secara langsung dapat bertentangan dengan cara framework merender antarmuka.

Sebaliknya, teks yang dikenali harus melalui jalur pembaruan state yang sama dengan pengetikan biasa.

Integrasi juga harus mempertimbangkan perilaku asinkron. Pengenalan mungkin selesai setelah pengguna mengetik karakter tambahan atau memindahkan kursor.

Penggunaan nilai input lama yang disimpan saat perekaman dimulai dapat tanpa sengaja menimpa perubahan terbaru.

Pola integrasi yang disederhanakan adalah:

const insertion = insertTranscript({
  currentValue: latestValue,
  transcript: recognizedText,
  selection: currentSelection,
  maxLength: inputLimit,
});

setMessage(insertion.value);
restoreCaret(insertion.caret);

Fungsi pembantu penyisipan harus mempertahankan teks saat ini, dapat mengganti rentang yang dipilih, menerapkan spasi yang sesuai, dan mematuhi batas panjang kolom.

Unicode perlu diperhatikan karena panjang string JavaScript dihitung dalam unit kode UTF-16. Memotong string pada posisi sembarang dapat membelah pasangan surrogate.

Yang paling penting, pengenalan ucapan tidak boleh secara otomatis mengirim formulir. Pengguna harus dapat memeriksa dan memperbaiki teks sebelum mengirimnya.

Tangani kegagalan tanpa merusak input teks biasa

Subsistem ucapan seharusnya bersifat opsional.

Jika izin mikrofon ditolak, peramban tidak mampu mengalokasikan model, worker mengalami crash, atau rekaman tidak berisi ucapan, kolom input biasa harus tetap berfungsi.

Nyatakan siklus hidup mikrofon dengan status eksplisit seperti:

idle
preparing
listening
recognizing
error

Gunakan label yang dapat diakses dan umpan balik status yang terlihat. Mikrofon yang hanya berubah merah atau merah muda setelah pemuatan hampir tidak memberi informasi apa pun kepada pengguna.

Pembatalan harus membersihkan jalur audio, konteks audio, buffer yang tertunda, dan sesi perekaman aktif. Antarmuka juga harus mencegah hasil lama dari rekaman yang telah dibatalkan menimpa state input yang lebih baru.

Jika model besar gagal akibat keterbatasan memori atau inisialisasi, lepaskan sepenuhnya sebelum mencoba model yang lebih kecil. Batasi percobaan ulang agar peramban tidak terus-menerus mengunduh atau menginisialisasi model yang tidak dapat dijalankan.

Jangan diam-diam beralih ke layanan pengenalan ucapan cloud ketika pengenalan lokal gagal. Jika pemrosesan lokal saja merupakan persyaratan mutlak, kegagalan pengenal lokal harus tetap ditangani secara lokal.

Uji seluruh alur di peramban

Pemeriksaan TypeScript atau build produksi yang berhasil belum cukup untuk membuktikan bahwa input suara bekerja.

Demikian pula, memastikan peramban dapat mengunduh berkas ONNX tidak membuktikan bahwa kedua sesi model berhasil diinisialisasi.

Pengujian regresi yang paling berguna harus menjalankan worker, berkas runtime, model, processor, dan tokenizer yang sama dengan yang digunakan dalam produksi.

Masukkan rekaman PCM singkat yang telah diketahui ke jalur inferensi peramban yang sebenarnya dan pastikan transkripsi yang dihasilkan tidak kosong.

Kemudian uji seluruh interaksi mikrofon di peramban sungguhan.

  • Pemuatan awal halaman: pastikan tidak ada model ucapan atau aset runtime yang diunduh sebelum mikrofon digunakan.
  • Inisialisasi awal tanpa cache: periksa izin mikrofon, permintaan model, tipe MIME JavaScript dan WASM, serta respons nyata bahwa worker siap.
  • Inisialisasi ONNX: pastikan sesi encoder dan decoder dapat dibuat.
  • Penangkapan audio: pastikan AudioWorklet menghasilkan buffer PCM yang tidak kosong.
  • Pengambilan sampel ulang: pastikan worker menerima laju sampel sebenarnya dan menghasilkan audio 16 kHz yang valid.
  • Penghentian manual: pastikan klik kedua pada tombol mikrofon menghentikan perekaman secara andal.
  • Penghentian otomatis: pastikan jeda alami mengakhiri rekaman tanpa memotong ucapan pelan.
  • Transkripsi: pastikan processor, model, dan tokenizer lengkap menghasilkan teks yang dapat dikenali.
  • Integrasi input: pastikan teks yang dikenali muncul di kolom yang benar-benar dikendalikan state tanpa menimpa perubahan pengguna.
  • Pemulihan kegagalan: uji izin yang ditolak, berkas yang hilang, kesalahan worker, kegagalan inisialisasi model, pembatalan, dan mekanisme cadangan model lebih kecil.
  • Privasi: periksa permintaan jaringan dan pastikan audio mikrofon tidak diunggah ke server atau layanan analitik.
  • Kompatibilitas seluler: ulangi pengujian di ponsel fisik, termasuk inisialisasi pertama, penggunaan ulang, dan sesi dikte berulang.

Pengujian PCM yang telah direkam sangat baik untuk memvalidasi komponen inferensi, tetapi tidak membuktikan bahwa penangkapan suara dari mikrofon berfungsi. Pengujian penerimaan terakhir harus mencakup mikrofon nyata dan antarmuka pengguna yang sebenarnya.

Arsitektur praktis untuk pengetikan suara yang andal di peramban

Untuk situs web yang memerlukan input suara singkat, multibahasa, dan menjaga privasi, arsitektur yang paling praktis sengaja dibuat sederhana:

Tombol mikrofon React
        |
        v
Permintaan izin
        |
        v
Inisialisasi model sesuai kebutuhan
        |
        v
Perekaman PCM AudioWorklet
        |
        v
RMS adaptif / penghentian manual
        |
        v
Worker khusus
        |
        v
Pengambilan sampel ulang audio 16 kHz
        |
        v
Whisper Tiny atau Base Q8
        |
        v
ONNX Runtime WASM yang kompatibel
        |
        v
Processor + tokenizer Whisper
        |
        v
Transkripsi akhir
        |
        v
Input React terkendali

Aplikasi sebaiknya menghosting sendiri berkas model dan runtime berversi, menjalankan inferensi di luar utas utama, menghindari pengunduhan model yang tidak perlu, melepaskan sumber daya setelah dipakai, dan tidak pernah mengunggah audio mikrofon untuk pengenalan ucapan.

Pilihan yang lebih canggih seperti akselerasi WebGPU, deteksi aktivitas suara berbasis jaringan saraf, transkripsi parsial berkelanjutan, atau tingkat model tambahan dapat dipertimbangkan kemudian ketika hasil pengukuran membenarkan kompleksitasnya.

Pelajaran paling berharga bukanlah versi pustaka atau ukuran model tertentu, melainkan pentingnya memvalidasi setiap batas dalam alur pengenalan ucapan di peramban.

Permintaan izin mikrofon yang berfungsi bukan berarti audio berhasil ditranskripsi. Model yang diunduh bukan berarti decodernya berhasil diinisialisasi. Sesi ONNX yang berhasil bukan berarti tokenizer tersedia. Dan transkripsi yang berhasil bukan berarti aplikasi telah memasukkan teksnya dengan benar.

Fitur tersebut baru lengkap ketika pengunjung dapat menekan mikrofon, berbicara secara alami, menghentikan rekaman, dan melihat kata-kata yang dikenali muncul pada kolom yang dapat diedit—tanpa mengirim rekaman ke server pengenalan ucapan.