การเพิ่มปุ่มไมโครโฟนลงในเว็บไซต์ดูเหมือนเป็นเรื่องง่าย แค่รับเสียงพูดของผู้ใช้ แปลงเป็นข้อความ แล้วใส่ข้อความลงในช่องกรอกข้อมูล แต่การทำให้ฟีเจอร์นี้ทำงานได้อย่างเชื่อถือได้ทั้งบนเบราว์เซอร์เดสก์ท็อปและมือถือกลับยากกว่ามาก โดยเฉพาะเมื่อต้องประมวลผลการรู้จำเสียงทั้งหมดภายในเครื่อง โดยไม่อัปโหลดเสียงจากไมโครโฟนไปยังเซิร์ฟเวอร์
ความท้าทายไม่ได้มีแค่การเลือกโมเดลรู้จำเสียงพูด ระบบที่ใช้งานได้จริงต้องจัดการสิทธิ์เข้าถึงไมโครโฟน การรับเสียง การปรับอัตราสุ่มตัวอย่าง Worker ของเบราว์เซอร์ WebAssembly การเริ่มต้นโมเดล ONNX การแปลงข้อความเป็นโทเคน การแคช และการเชื่อมต่อกับช่องป้อนข้อความของแอปพลิเคชันให้ถูกต้องด้วย
บทความนี้อธิบายวิธีสร้างฟีเจอร์แปลงเสียงเป็นข้อความที่ใช้งานได้จริงและคุ้มครองความเป็นส่วนตัว โดยใช้ OpenAI Whisper, Transformers.js, ONNX Runtime Web, AudioWorklet และ Web Worker แยกต่างหาก รวมถึงปัญหาที่เกิดขึ้นจริงระหว่างการเชื่อมต่อระบบ ซึ่งทำให้ปุ่มไมโครโฟนค้างอยู่ในสถานะกำลังโหลดได้ แม้ดาวน์โหลดไฟล์โมเดลสำเร็จแล้วก็ตาม
เป้าหมายชัดเจนคือ ผู้เข้าชมคลิกปุ่มไมโครโฟน พูดตามปกติ แล้วเห็นข้อความที่รู้จำได้ปรากฏในช่องกรอกข้อความเดิม ผู้ใช้สามารถตรวจสอบหรือแก้ไขก่อนส่งข้อมูลได้ โดยไฟล์เสียงที่บันทึกจากไมโครโฟนไม่จำเป็นต้องออกจากเบราว์เซอร์เลย
การรู้จำเสียงพูดที่ทำงานฝั่งไคลเอนต์ทั้งหมดหมายถึงอะไร
การเพิ่มการป้อนข้อมูลด้วยเสียงให้เว็บไซต์มีแนวทางหลักสองแบบที่แตกต่างกัน
แบบแรกใช้บริการรู้จำเสียงพูด เบราว์เซอร์รับเสียง ส่งไปยังบริการระยะไกล แล้วรับข้อความที่รู้จำได้กลับมา วิธีนี้ช่วยให้พัฒนาได้ง่ายขึ้น แต่ต้องพึ่งพาเครือข่าย มีประเด็นด้านความเป็นส่วนตัวและความพร้อมให้บริการของผู้ให้บริการ รวมถึงอาจมีค่าใช้จ่ายตามปริมาณการใช้งาน
แบบที่สองคือการประมวลผลอนุมานภายในเบราว์เซอร์โดยตรง เว็บไซต์ดาวน์โหลดโมเดลรู้จำเสียงพูดและสภาพแวดล้อมรันไทม์ที่จำเป็น เบราว์เซอร์รับเสียงจากไมโครโฟน แปลงเป็นตัวอย่างสัญญาณเชิงตัวเลข เรียกใช้โมเดลภายในเครื่อง แล้วสร้างข้อความถอดเสียงโดยไม่ต้องใช้เซิร์ฟเวอร์รู้จำเสียงพูด
บทความนี้จะกล่าวถึงวิธีที่สองเท่านั้น
อย่าสับสนระหว่างระบบรู้จำเสียงของเบราว์เซอร์ทั่วไปกับระบบที่รับประกันว่าประมวลผลในเครื่อง Web Speech API อาจใช้เอนจินรู้จำเสียงที่ทำงานผ่านเซิร์ฟเวอร์ การใช้งานบางแบบที่ใหม่กว่ามีตัวเลือก processLocally แต่ระดับการรองรับแตกต่างกันไปตามเบราว์เซอร์และระบบปฏิบัติการ หากจำเป็นต้องประมวลผลในเครื่องอย่างเคร่งครัด ห้ามใช้ SpeechRecognition แบบทั่วไปเป็นทางเลือกสำรองโดยอัตโนมัติ
แอปพลิเคชันจึงต้องควบคุมกระบวนการอนุมานทั้งหมดด้วยตัวเอง
ไมโครโฟน
|
v
AudioWorklet
|
v
เสียง PCM แบบ Float32
|
v
Web Worker แยกต่างหาก
|
v
ปรับอัตราสุ่มตัวอย่างเป็น 16 kHz
|
v
Whisper + ONNX Runtime Web
|
v
การแบ่งโทเคนและถอดรหัสข้อความ
|
v
สถานะช่องกรอกข้อความของ Reactเว็บไซต์ยังคงต้องให้ดาวน์โหลด JavaScript, WebAssembly, ไฟล์กำหนดค่า และค่าน้ำหนักโมเดล ซึ่งเป็นการดาวน์โหลดไฟล์คงที่ตามปกติ ความแตกต่างที่สำคัญคือเสียงจากไมโครโฟนถูกประมวลผลในเครื่อง ไม่ได้ถูกอัปโหลดเพื่อให้บริการภายนอกรู้จำเสียง หากต่อมาผู้ใช้ส่งข้อความที่ได้ผ่านแบบฟอร์มทั่วไป นั่นเป็นการกระทำอีกขั้นตอนหนึ่งของแอปพลิเคชัน
เลือกโมเดลที่เหมาะกับการใช้งานจริง: Whisper Tiny หรือ Base
Whisper เป็นตระกูลโมเดลรู้จำเสียงพูดหลายภาษา ความสามารถในการรู้จำหลายภาษาด้วยโมเดลเดียวทำให้เหมาะอย่างยิ่งกับเว็บไซต์ที่รองรับหลายภาษา
สำหรับข้อความเสียงสั้น ๆ โมเดลสองตัวที่ให้ความสมดุลระหว่างคุณภาพการรู้จำและการใช้ทรัพยากรเบราว์เซอร์ได้ดีคือ Whisper Tiny และ Whisper Base
| โมเดล | ขนาดโดยประมาณของไฟล์น้ำหนัก ONNX แบบ Q8 ที่เลือกใช้ | การใช้งานที่แนะนำ |
|---|---|---|
| Whisper Tiny | 41 MB | ตัวเลือกที่รอบคอบสำหรับมือถือและอุปกรณ์ที่มีทรัพยากรจำกัด |
| Whisper Base | 77 MB | ตัวเลือกที่คุณภาพสูงกว่าสำหรับอุปกรณ์ที่มีประสิทธิภาพเพียงพอและผ่านการทดสอบแล้ว |
ขนาดเหล่านี้หมายถึงไฟล์ ONNX ของตัวเข้ารหัสและตัวถอดรหัสที่เลือกจากชุดส่งออกโมเดลที่ตรวจสอบ ไม่รวมไฟล์สนับสนุนทั้งหมด และไม่ควรนำไปเทียบกับปริมาณหน่วยความจำสูงสุดที่เบราว์เซอร์ใช้ระหว่างทำงาน
Whisper Tiny น่าสนใจเพราะดาวน์โหลดได้เร็วกว่า โดยทั่วไปใช้ทรัพยากรประมวลผลน้อยกว่า และเหมาะกว่าในสภาพแวดล้อมมือถือที่ไม่ทราบขีดความสามารถแน่ชัด ส่วน Whisper Base มักให้คุณภาพการรู้จำดีกว่า โดยเฉพาะบางภาษาที่โมเดลขนาดเล็กผิดพลาดบ่อยกว่า
ไม่ควรเลือกโมเดลจากขนาด RAM จริงของอุปกรณ์เพียงอย่างเดียว หน่วยความจำที่เบราว์เซอร์ใช้ได้อาจน้อยกว่าที่ระบุในสเปกมาก ต้องคำนึงถึงหน่วยความจำที่หน้าเว็บใช้อยู่แล้ว การจองหน่วยความจำของ WebAssembly เทนเซอร์ชั่วคราว และภาวะหน่วยความจำตึงตัวของระบบปฏิบัติการด้วย
แนวทางที่รอบคอบคือเริ่มด้วย Tiny บนอุปกรณ์มือถือที่ยังไม่ทราบความสามารถแน่ชัด ใช้ Base เฉพาะกับกลุ่มอุปกรณ์ที่ผ่านเกณฑ์ และเปลี่ยนจาก Base ไปเป็น Tiny หากเริ่มต้นโมเดลไม่สำเร็จ
ต้องปล่อยทรัพยากรของ Base ที่เริ่มต้นไม่สำเร็จให้หมดก่อนโหลด Tiny หากปล่อยให้ทั้งสองโมเดลค้างอยู่ในหน่วยความจำพร้อมกัน ก็เท่ากับทำให้การเปลี่ยนไปใช้โมเดลสำรองหมดประโยชน์
เหตุใด WebAssembly จึงเป็นค่าเริ่มต้นที่เหมาะกับระบบใช้งานจริง
ONNX Runtime Web รองรับการรันโครงข่ายประสาทเทียมในเบราว์เซอร์ สำหรับงานลักษณะนี้ WebAssembly เป็นวิธีประมวลผลอนุมานด้วย CPU ที่ใช้งานได้จริงบนเบราว์เซอร์เดสก์ท็อปและมือถือหลัก ๆ
WebGPU ช่วยเร่งโมเดลที่รองรับบนฮาร์ดแวร์ที่เหมาะสมได้ แต่การมี WebGPU ไม่ได้หมายความว่าระบบรู้จำเสียงพูดจะทำงานได้จริง แม้เบราว์เซอร์จะเปิดให้ใช้ navigator.gpu ก็ยังไม่รับประกันว่า ONNX Runtime รองรับแพลตฟอร์มนั้น กราฟของ Whisper ที่เลือกจะเริ่มต้นได้ถูกต้อง หรือการอนุมานซ้ำหลายครั้งจะไม่มีปัญหาทรัพยากร
ดังนั้นแนวทางที่รอบคอบคือใช้ WASM เป็นแบ็กเอนด์ในระบบใช้งานจริง แล้วประเมิน WebGPU แยกต่างหากหลังผ่านการทดสอบความเข้ากันได้ ความแม่นยำ หน่วยความจำ และการใช้งานหลายรอบ
สำหรับการพัฒนารุ่นแรก การใช้ WASM แบบเธรดเดียวยังช่วยหลีกเลี่ยงการทำให้ทั้งเว็บไซต์ต้องพึ่งพาการแยกต้นทางข้ามโดเมนและ SharedArrayBuffer
env.backends.onnx.wasm.numThreads = 1;
env.backends.onnx.wasm.proxy = false;การรันการอนุมานภายใน Worker แยกต่างหากช่วยย้ายงานคำนวณหนักออกจากเธรด JavaScript หลัก ระหว่างโมเดลประมวลผลเสียง ช่องกรอกข้อความ แป้นพิมพ์เสมือน การเลื่อนหน้า และส่วนติดต่อผู้ใช้จึงยังตอบสนองได้
อย่าโหลดระบบรู้จำเสียงพูดตั้งแต่ตอนเปิดหน้าเว็บ
ผู้เข้าชมที่ไม่ได้ใช้ไมโครโฟนไม่ควรต้องเสียปริมาณข้อมูลเครือข่ายและหน่วยความจำมากเพราะฟีเจอร์นี้
อย่านำเข้า Transformers.js ล่วงหน้าในชุดไฟล์เริ่มต้นของแอปพลิเคชัน อย่าเริ่มต้น ONNX Runtime ทันทีที่เปิดหน้า และอย่าดาวน์โหลดน้ำหนักโมเดลโดยอัตโนมัติระหว่างที่เบราว์เซอร์ว่าง
ให้โหลดชุดระบบรู้จำเสียงก็ต่อเมื่อผู้ใช้คลิกปุ่มไมโครโฟนอย่างชัดเจนแล้วเท่านั้น
ลำดับการใช้งานครั้งแรกที่เหมาะสมมีดังนี้:
- รับเหตุการณ์คลิกปุ่มไมโครโฟน
- ขอสิทธิ์เข้าถึงไมโครโฟนผ่าน
getUserMedia() - หากไม่ได้รับอนุญาต ให้แสดงข้อผิดพลาดโดยไม่ดาวน์โหลดโมเดล
- หากได้รับอนุญาต ให้ปล่อยสตรีมไมโครโฟนชั่วคราวระหว่างเตรียมโมเดล
- เริ่มต้น Worker แยกต่างหากแบบไดนามิกและโหลดโมเดลภายในเครื่องที่เลือกไว้
- รอให้ Worker ยืนยันว่ากระบวนการรู้จำเสียงพร้อมทำงาน
- เริ่มบันทึกเสียงโดยอัตโนมัติหากผู้ใช้ยังไม่ได้ยกเลิก
- แสดงสถานะกำลังรับฟังที่เข้าใจได้ชัดเจน
คำขอสิทธิ์ต้องเชื่อมโยงกับการกระทำของผู้ใช้ แอปพลิเคชันควรรองรับการยกเลิกและข้อจำกัดการรับเสียงของแต่ละเบราว์เซอร์ด้วย แทนที่จะสมมติว่าสามารถเริ่มบันทึกใหม่ได้เงียบ ๆ ทุกครั้ง
ระหว่างเตรียมโมเดล ควรมีสถานะที่มองเห็นได้ เช่น กำลังเตรียมการป้อนข้อมูลด้วยเสียง ไอคอนหมุนที่ไม่มีการเปลี่ยนสถานะชัดเจนอาจทำให้การดาวน์โหลดโมเดลที่สำเร็จดูเหมือนไมโครโฟนเสีย
เมื่อเริ่มต้นเสร็จแล้ว สามารถคง Worker ไว้ชั่วครู่เผื่อผู้ใช้จะพูดข้อความถัดไป การตั้งเวลาเลิกใช้งานเมื่อไม่มีการทำงานประมาณหนึ่งนาทีเป็นจุดเริ่มต้นที่สมเหตุสมผล จากนั้นจึงยุติ Worker และคืนหน่วยความจำของโมเดล ส่วนไฟล์โมเดลที่เบราว์เซอร์แคชไว้ยังใช้ได้ในการเข้าชมครั้งต่อไป
รับข้อมูลเสียงดิบด้วย AudioWorklet
Whisper ต้องใช้ตัวอย่างเสียงในรูปแบบตัวเลข แม้ MediaRecorder จะเหมาะมากสำหรับการบันทึกไฟล์เสียง แต่การนำมาใช้กับการรู้จำเสียงในเครื่องอาจทำให้ต้องเข้ารหัสและถอดรหัสเสียงไปกลับโดยไม่จำเป็น
เส้นทางการประมวลผลที่ง่ายกว่าคือ:
getUserMedia()
|
v
AudioContext
|
v
AudioWorklet
|
v
บัฟเฟอร์ PCM แบบ Float32
|
v
Worker แยกต่างหากAudioWorklet รันโค้ดประมวลผลเสียงนอกเธรด JavaScript หลักของแอปพลิเคชัน โดยสามารถเก็บตัวอย่าง PCM ผสมเสียงหลายช่องเป็นช่องเดียว คำนวณค่าระดับเสียงพื้นฐาน และส่งบัฟเฟอร์ที่รวบรวมไว้ไปยัง Worker
ตัวอย่างการเริ่มต้นไมโครโฟนอย่างย่อมีดังนี้:
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.ข้อกำหนดไมโครโฟนเป็นเพียงค่าที่ต้องการ ไม่ใช่สิ่งที่รับประกันได้ เบราว์เซอร์แต่ละตัวอาจใช้อัลกอริทึมตัดเสียงสะท้อน ลดเสียงรบกวน และปรับระดับเสียงอัตโนมัติที่ต่างกัน
รายละเอียดสำคัญคืออัตราการสุ่มตัวอย่างของไมโครโฟนไม่จำเป็นต้องเป็น 16 kHz เสมอไป หลายระบบเสียงใช้ 44.1 kHz หรือ 48 kHz แต่ Whisper ต้องการอินพุต 16 kHz จึงต้องปรับอัตราการสุ่มตัวอย่างของข้อมูลที่รับมาอย่างถูกต้อง
การทิ้งทุก ๆ ตัวอย่างที่สองหรือสามไม่ใช่วิธีที่ถูกต้องในทุกกรณี ตัวปรับอัตราการสุ่มตัวอย่างแบบผ่านต่ำที่เหมาะสม เช่น วิธี windowed-sinc จะช่วยลดการเกิด aliasing และรักษาย่านความถี่เสียงพูดที่สำคัญขณะลดอัตราการสุ่มตัวอย่าง
ควรทำงานปรับอัตราการสุ่มตัวอย่างใน Worker แยกต่างหาก ไม่ใช่ภายในคอลแบ็ก AudioWorklet ที่ทำงานแบบเวลาจริง
ส่งข้อมูลเสียงระหว่างเธรดของเบราว์เซอร์อย่างมีประสิทธิภาพ
AudioWorklet อาจสร้างข้อมูลเสียงชิ้นเล็กจำนวนมาก การส่งทุกช่วงการประมวลผลเสียงเป็นข้อความแยกกันอาจทำให้เกิดภาระงานที่ไม่จำเป็น
วิธีที่ใช้ได้จริงคือรวบรวมตัวอย่าง PCM เป็นชุดสั้น ๆ ก่อน แล้วค่อยส่งแต่ละชุดในรูป ArrayBuffer
worker.postMessage(
{
type: 'audio-chunk',
buffer,
},
[buffer]
);รายการบัฟเฟอร์ที่ส่งแบบโอนกรรมสิทธิ์มีความสำคัญ เพราะเป็นการย้ายความเป็นเจ้าของ ArrayBuffer แทนการคัดลอกบัฟเฟอร์ทั้งหมดเพิ่มอีกชุดโดยไม่จำเป็น
Worker สามารถต่อข้อมูลเหล่านี้ลงในบัฟเฟอร์สะสมเสียง แล้วรวมเข้าด้วยกันเมื่อหยุดบันทึก
ควรติดตามอัตราสุ่มตัวอย่างจริงขณะรับเสียง จำนวนตัวอย่างที่เก็บได้ และระยะเวลาบันทึกด้วย ข้อมูลเมตาเหล่านี้ช่วยวินิจฉัยการบันทึกที่ไม่มีเสียงโดยไม่ต้องเก็บข้อมูลเสียงที่ละเอียดอ่อน
ตรวจจับช่วงหยุดพูดโดยไม่ต้องเพิ่มโครงข่ายประสาทเทียมอีกชุด
การพูดเพื่อกรอกข้อความสั้น ๆ ไม่จำเป็นต้องใช้ตัวตรวจจับกิจกรรมเสียงพูดที่อาศัยโครงข่ายประสาทเทียมเสมอไป
ตัวตรวจจับ RMS แบบปรับตัวได้ช่วยประเมินกิจกรรมเสียงพูดอย่างคร่าว ๆ โดยใช้ทรัพยากรน้อย RMS วัดขนาดของสัญญาณ จึงช่วยให้แอปพลิเคชันประเมินได้ว่าผู้ที่กำลังพูดอยู่ก่อนหน้านี้เงียบลงเมื่อใด
ส่วนติดต่อผู้ใช้ควรอนุญาตให้หยุดบันทึกด้วยตนเองได้เสมอโดยคลิกไมโครโฟนอีกครั้ง การตรวจจับความเงียบอัตโนมัติเป็นเพียงฟีเจอร์อำนวยความสะดวก ไม่ใช่เงื่อนไขที่จำเป็นต่อการรู้จำเสียงให้สำเร็จ
ค่าตั้งต้นที่สมเหตุสมผลสำหรับการพูดข้อความสั้น ๆ ได้แก่:
| พารามิเตอร์ | ค่าเริ่มต้น |
|---|---|
| ช่วงเวลาวิเคราะห์ | 20 ms |
| การปรับเทียบเสียงรบกวน | 300 ms |
| เวลายืนยันว่ามีเสียงพูด | 140 ms |
| ระยะเงียบก่อนหยุดอัตโนมัติ | 1.4 วินาที |
| เวลาหมดกำหนดเมื่อไม่พบเสียงพูด | 8 วินาที |
| ระยะเวลาบันทึกสูงสุด | 30 วินาที |
ค่าเหล่านี้เป็นเพียงจุดเริ่มต้นสำหรับกำหนดค่า ไม่ใช่เกณฑ์ที่ดีที่สุดสำหรับทุกสถานการณ์ การพูดเบา ๆ เพลงพื้นหลัง และการประมวลผลลดเสียงรบกวนของไมโครโฟนอาจส่งผลต่อค่าที่วัดด้วย RMS
ควรให้ผู้ใช้หยุดบันทึกเองเป็นหลัก แทนการหยุดอัตโนมัติจนตัดคำท้ายประโยค
สำหรับการกรอกข้อความสั้นทั่วไป การถอดเสียงเพียงครั้งเดียวมักง่ายกว่าการเรียก Whisper ซ้ำเพื่อแสดงผลลัพธ์ระหว่างทาง ให้บันทึกเสียงพูดจนจบ หยุดบันทึก เรียกโมเดลหนึ่งครั้ง แล้วใส่ข้อความถอดเสียงสุดท้าย
กระบวนการ Whisper ที่สมบูรณ์ต้องมีมากกว่าโมเดล ONNX
นี่เป็นหนึ่งในรายละเอียดสำคัญที่สุดของการติดตั้งใช้งาน
การอนุมานของ Whisper ไม่ใช่เพียงเรียกตัวเข้ารหัส ONNX ตามด้วยตัวถอดรหัส ONNX กระบวนการรู้จำเสียงพูดอัตโนมัติที่ครบถ้วนยังต้องมีการสกัดคุณลักษณะเสียง การแปลงเป็นโทเคน การกำหนดค่าการสร้างผลลัพธ์ และการถอดรหัสโทเคนที่คาดการณ์ให้เป็นข้อความอ่านได้
ลำดับการประมวลผลทั้งหมดคือ:
เสียง PCM ดิบจากไมโครโฟน
|
v
ปรับอัตราสุ่มตัวอย่างเป็น 16 kHz
|
v
ตัวสกัดคุณลักษณะของ Whisper
|
v
ตัวเข้ารหัส ONNX
|
v
ตัวถอดรหัส ONNX และการสร้างโทเคน
|
v
ตัวแบ่งโทเคน Whisper
|
v
ข้อความที่รู้จำได้การเริ่มต้นเซสชัน ONNX สำเร็จพิสูจน์ได้เพียงว่าโหลดกราฟโมเดลได้ ไม่ได้พิสูจน์ว่ากระบวนการรู้จำเสียงทั้งหมดทำงานได้
ในการเชื่อมต่อ Transformers.js ชุดหนึ่งที่ผ่านการทดสอบ เซสชันโมเดลเริ่มต้นได้ แต่การถอดเสียงยังล้มเหลว เพราะกระบวนการที่สร้างขึ้นภายในเครื่องไม่ได้กำหนดค่าตัวประมวลผลและตัวแบ่งโทเคนที่จำเป็นอย่างถูกต้อง
วิธีที่เข้ากันได้ในกรณีนั้นคือเริ่มต้นส่วนประกอบเหล่านี้อย่างชัดเจน โดยใช้ข้อมูลเมตาของโมเดลที่เก็บไว้ภายในเครื่อง
ตัวอย่างต่อไปนี้แสดงแนวทางเฉพาะรุ่นดังกล่าวแบบย่อ ไม่ใช่โค้ด Worker ที่สมบูรณ์และทำงานเดี่ยวได้ทันที:
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;ต้องตรวจสอบรูปแบบพารามิเตอร์ของตัวสร้างออบเจ็กต์และวิธีเชื่อมต่อกับ Transformers.js รุ่นที่ติดตั้งจริง บางรุ่นและบางชุดส่งออกโมเดลสร้างส่วนประกอบเหล่านี้ได้เอง จึงไม่ควรมองว่าต้องสร้างด้วยตนเองในทุกกรณี
เมื่อเตรียมกระบวนการทั้งหมดครบแล้ว สามารถเรียกถอดเสียงข้อความสั้นโดยระบุภาษาและงานให้ชัดเจน:
const result = await recognizer(audio16k, {
language: 'en',
task: 'transcribe',
return_timestamps: false,
});หากแอปพลิเคชันทราบภาษาของผู้ใช้อยู่แล้ว การส่งค่าภาษาอย่างชัดเจนช่วยหลีกเลี่ยงการตรวจจับภาษาโดยไม่จำเป็น และอาจทำให้ผลลัพธ์ของเสียงสั้นมีความสม่ำเสมอมากขึ้น
ตรึงรุ่น Transformers.js และ ONNX Runtime ที่เข้ากันได้
ปัญหาสำคัญอีกแบบหนึ่งเกี่ยวข้องกับความสัมพันธ์ระหว่าง Transformers.js และ ONNX Runtime Web
Transformers.js รับผิดชอบกระบวนการรู้จำเสียงในระดับสูง ส่วน ONNX Runtime Web รันกราฟโครงข่ายประสาทเทียม แพ็กเกจทั้งสองต้องเข้ากันได้เอง และต้องเข้ากันได้กับชุดไฟล์ ONNX ของโมเดลที่นำมาใช้จริงด้วย
ในระบบที่ตรวจสอบ พบว่า ONNX Runtime Web รุ่นพัฒนาสามารถเริ่มต้นตัวเข้ารหัส Whisper ได้ แต่ล้มเหลวเมื่อสร้างเซสชันตัวถอดรหัสที่ผ่านการควอนไทซ์ ข้อผิดพลาดเกี่ยวข้องกับค่าสเกลสำหรับการควอนไทซ์ที่หายไปในคำสั่ง DequantizeLinear
ปัญหานี้ไม่ได้เกิดจากสิทธิ์ไมโครโฟน การดาวน์โหลด หรือรูปแบบเสียง เบราว์เซอร์รับไฟล์โมเดลได้ แต่รันไทม์ไม่สามารถเริ่มต้นกราฟโมเดลที่จำเป็นหนึ่งส่วนได้
การทดสอบทั้งตัวเข้ารหัสและตัวถอดรหัสโดยตรงด้วย ONNX Runtime Web รุ่นเสถียรที่ตรึงเวอร์ชันไว้ ช่วยแก้ปัญหาความไม่เข้ากันในกรณีนั้นได้
การตรวจสอบความเข้ากันได้มีประโยชน์เป็นพิเศษ เพราะแยกข้อเท็จจริงสองอย่างที่แตกต่างกันออกจากกัน:
- ดาวน์โหลดไฟล์โมเดลสำเร็จแล้ว
- รันไทม์สร้างเซสชันอนุมานที่ใช้งานได้จากไฟล์โมเดลสำเร็จแล้ว
สองอย่างนี้ไม่ใช่เรื่องเดียวกัน
สำหรับชุดส่งออกโมเดลที่ทดสอบ การจับคู่ Transformers.js 4.2.0 กับ ONNX Runtime Web 1.24.3 ทำงานร่วมกันได้ ส่วนรันไทม์รุ่นพัฒนาที่ใหม่กว่าล้มเหลวกับกราฟตัวถอดรหัสแบบควอนไทซ์ นี่เป็นผลสังเกตเฉพาะรุ่น ไม่ใช่หลักฐานว่ารันไทม์รุ่นเก่าดีกว่าในทุกกรณี
เมื่อบังคับเปลี่ยนเวอร์ชันของรันไทม์ที่เป็นการพึ่งพาทางอ้อม ควรตรึงเวอร์ชันให้แน่นอนในไฟล์ล็อกแพ็กเกจและบันทึกเหตุผลไว้ การอัปเกรดรันไทม์ต้องผ่านการทดสอบถดถอยของการอนุมานจริงในเบราว์เซอร์อย่างครบถ้วน ไม่ใช่แค่ติดตั้งแพ็กเกจสำเร็จ
ตรวจสอบรูปแบบไฟล์ Worker ที่บันเดิลก่อนเริ่มแก้ปัญหา Whisper
JavaScript Web Worker สามารถสร้างด้วยรูปแบบโมดูลที่แตกต่างกันได้
ปัญหาการเชื่อมต่อครั้งหนึ่งเกิดจากแอปพลิเคชันเปิด Worker เป็นโมดูล ES แต่ไฟล์ Worker ที่สร้างขึ้นกลับใช้กลไก importScripts() ของ Worker แบบคลาสสิก
รูปแบบการรันสองแบบนี้ใช้แทนกันไม่ได้ Worker แบบโมดูลไม่สามารถเรียกใช้โค้ดที่ใช้ได้เฉพาะกับ Worker แบบคลาสสิกโดยตรง
บทเรียนเชิงปฏิบัติคือต้องเลือกตัวสร้าง Worker ให้ตรงกับไฟล์ที่บันเดิลออกมาจริง แทนการคัดลอกตัวเลือกจากบทสอนทั่วไป
ตัวอย่างเช่น ตัวเลือกสองแบบต่อไปนี้ไม่ได้เทียบเท่ากันโดยอัตโนมัติ:
// Module worker: requires a compatible module bundle.
new Worker(workerUrl, { type: 'module' });
// Classic worker: requires a compatible classic bundle.
new Worker(workerUrl);ตัวเลือกที่ถูกต้องขึ้นอยู่กับเครื่องมือบันเดิลและ JavaScript ที่สร้างขึ้น
เมื่อวินิจฉัยข้อผิดพลาดการเริ่มต้น Worker ให้ตรวจสอบ Console ของเบราว์เซอร์ ไฟล์ Worker ที่สร้างขึ้น และแผง Network เพื่อดูว่าปัญหาเกิดก่อน ONNX Runtime จะเริ่มต้นเสียอีกหรือไม่
ไลบรารีบางตัวที่ถูกบันเดิลยังคำนวณ URL โดยอ้างอิงตำแหน่งโมดูลของตัวเอง เมื่อรวมไลบรารีเหล่านี้เข้าไปใน Worker ต้องทดสอบพาธของไฟล์รันไทม์ที่ได้จริง อย่าสมมติว่าพาธสัมพัทธ์เดิมของแพ็กเกจจะยังถูกต้อง
ให้บริการโมดูล WASM และ JavaScript ด้วยชนิด MIME ที่ถูกต้อง
แม้ไฟล์ JavaScript และโมเดล ONNX จะเข้ากันได้อย่างสมบูรณ์ ก็ยังอาจล้มเหลวหากเว็บเซิร์ฟเวอร์ส่งส่วนหัวตอบกลับไม่ถูกต้อง
ปัญหาที่เกิดขึ้นจริงคือโมดูล JavaScript นามสกุล .mjs ถูกส่งกลับด้วยชนิด application/octet-stream เบราว์เซอร์จึงปฏิเสธโมดูล เพราะชนิดข้อมูลในคำตอบไม่เหมาะสำหรับการเรียกใช้โมดูล JavaScript
โดยทั่วไปชนิดข้อมูลตอบกลับที่ควรใช้คือ:
| นามสกุลไฟล์ | Content-Type |
|---|---|
| .mjs | application/javascript |
| .wasm | application/wasm |
ตรวจสอบคำตอบจริงจากระบบใช้งานจริง ไม่ใช่ดูแค่ไฟล์กำหนดค่าเซิร์ฟเวอร์
curl -I https://example.com/runtime/speech/v2/runtime.mjs
curl -I https://example.com/runtime/speech/v2/runtime.wasmURL ข้างต้นเป็นเพียงตัวอย่าง ให้ใช้ชื่อไฟล์ทรัพยากรที่มีเวอร์ชันกำกับจากชุดรันไทม์ที่เลือกจริง
สถานะ HTTP ที่ถูกต้องอย่างเดียวยังไม่เพียงพอ เบราว์เซอร์อาจปฏิเสธไฟล์เพราะชนิด MIME, Content Security Policy, รูปแบบการรันโมดูล หรือ URL ของทรัพยากรที่ไม่ถูกต้อง
โปรดจำไว้ว่าคำขอเดียวกันอาจเปิดได้สำเร็จในแท็บเบราว์เซอร์โดยตรง แต่ล้มเหลวเมื่อโหลดเป็นโมดูลที่ต้องรันหรือเป็นไฟล์ที่ WebAssembly ต้องใช้
ใช้ URL ทรัพยากรแบบเปลี่ยนแปลงไม่ได้ โดยไม่ทำให้ผู้ใช้ติดอยู่กับไฟล์รันไทม์ที่เสีย
ไฟล์โมเดล Whisper มีขนาดใหญ่พอที่การแคชในเบราว์เซอร์มีความสำคัญ
พาธของทรัพยากรที่มีเวอร์ชันกำกับและกำหนดให้เนื้อหาเปลี่ยนแปลงไม่ได้ ช่วยให้เบราว์เซอร์นำไฟล์โมเดลและรันไทม์เดิมที่ไม่เปลี่ยนไปใช้ซ้ำ โดยไม่ต้องดาวน์โหลดใหม่ทุกครั้งที่ผู้ใช้พูด
นโยบายแคชทั่วไปมีดังนี้:
Cache-Control: public, max-age=31536000, immutableอย่างไรก็ตาม วิธีนี้มีข้อกำหนดด้านการนำขึ้นใช้งาน เมื่อประกาศว่าเนื้อหาของ URL เปลี่ยนแปลงไม่ได้แล้ว ก็ไม่ควรแอบแทนที่เนื้อหาโดยใช้ URL เดิม
หากต้องเปลี่ยนไฟล์ไบนารีของรันไทม์ ให้เผยแพร่ด้วย URL ใหม่ที่มีเวอร์ชันกำกับ
/models/speech/v1/
/runtime/speech/v1/
/runtime/speech/v2/การเปลี่ยนพาธของรันไทม์ไม่ใช่เรื่องตกแต่ง หากแอปพลิเคชันใช้ URL ที่ประกาศว่าเปลี่ยนแปลงไม่ได้ซ้ำหลังแก้ไขเนื้อหา เบราว์เซอร์อาจยังใช้ไบนารี WebAssembly รุ่นเก่าที่แคชไว้และไม่เข้ากันอยู่
ควรใช้โค้ด JavaScript ที่เชื่อมกับรันไทม์และไฟล์ WebAssembly จากชุดเผยแพร่รันไทม์รุ่นเดียวกันด้วย การผสมไฟล์รันไทม์คนละรุ่นอาจทำให้เกิดข้อผิดพลาดตอนเริ่มต้นที่วินิจฉัยได้ยาก
ไฟล์รายการที่สร้างระหว่างการบิลด์และบันทึกชื่อไฟล์ที่คาดหวัง ขนาด และค่าแฮชสำหรับตรวจสอบความถูกต้อง สามารถช่วยตรวจพบไฟล์ที่ขาดหรือไม่ตรงกันก่อนนำขึ้นใช้งาน
กำหนดให้ไลบรารีรู้จำเสียงใช้ทรัพยากรที่โฮสต์บนเว็บไซต์ของตนเอง และปิดการโหลดโมเดลจากแหล่งภายนอก วิธีนี้ทำให้การไม่มีโมเดลในเครื่องแสดงข้อผิดพลาดชัดเจน แทนที่จะเริ่มดาวน์โหลดจากผู้ให้บริการโฮสต์โมเดลภายนอกโดยไม่ตั้งใจ
ทำไมปุ่มไมโครโฟนจึงหมุนค้าง ทั้งที่ไม่มีอะไรทำงาน
อาการที่พบบ่อยระหว่างพัฒนาคือ ปุ่มไมโครโฟนขอสิทธิ์เข้าถึง แสดงภาพกำลังโหลด แล้วสุดท้ายกลับไปอยู่ในสถานะข้อผิดพลาด โดยไม่มีข้อความถูกใส่ในช่องกรอกข้อมูล
เบราว์เซอร์อาจแสดงด้วยซ้ำว่าไมโครโฟนกำลังถูกใช้งาน
สิ่งนี้ไม่ได้พิสูจน์ว่าตัวรู้จำเสียงทำงานได้ เพียงบอกว่ามีการอนุญาตหรือมีการรับเสียงจากไมโครโฟนในช่วงใดช่วงหนึ่งเท่านั้น
ความผิดพลาดหลายแบบที่เกิดแยกกันสามารถแสดงอาการแทบเหมือนกันได้:
- ชนิด MIME ของโมดูล JavaScript ไม่ถูกต้อง เบราว์เซอร์ดาวน์โหลดโมดูลรันไทม์แล้ว แต่ปฏิเสธการรัน
- รูปแบบการรัน Worker ไม่ตรงกัน Worker ที่คอมไพล์ใช้ API แบบคลาสสิก แต่ถูกเปิดเป็น Worker แบบโมดูล หรือสลับกัน
- ตัวถอดรหัส ONNX ไม่เข้ากัน รันไทม์สร้างเซสชันตัวเข้ารหัสได้ แต่ล้มเหลวกับกราฟตัวถอดรหัสแบบควอนไทซ์
- กระบวนการรู้จำเสียงไม่ครบถ้วน มีเซสชัน ONNX แล้ว แต่ยังเริ่มต้นตัวแบ่งโทเคนหรือตัวประมวลผลเสียงไม่ถูกต้อง
ต้องวินิจฉัยปัญหาเหล่านี้แยกกัน การแก้ปัญหาหนึ่งอาจทำให้มองเห็นอีกปัญหาที่ถูกซ่อนไว้
หลักสำคัญที่สุดในการแก้บั๊กคือ HTTP 200 ไม่ได้หมายความว่าเริ่มต้นโมเดลสำเร็จ และการเริ่มต้นโมเดลสำเร็จก็ไม่ได้หมายความว่าถอดเสียงสำเร็จ
แม้จะถอดเสียงได้สำเร็จ ก็ยังไม่พิสูจน์ว่าข้อความไปถึงช่องกรอกข้อมูลจริงของแอปพลิเคชัน
แต่ละจุดเชื่อมต่อในกระบวนการจึงต้องมีสัญญาณวินิจฉัยที่มีความหมาย
เพิ่มความสามารถในการสังเกตระบบโดยไม่เก็บเสียงส่วนตัว
บันทึกวินิจฉัยที่มีประโยชน์ไม่จำเป็นต้องเก็บสิ่งที่ผู้ใช้พูด
แอปพลิเคชันสามารถติดตามสถานะทางเทคนิค เช่น:
permission-granted
worker-created
runtime-loading
runtime-ready
encoder-ready
decoder-ready
recording-started
pcm-received
recording-stopped
inference-started
inference-completed
result-insertedเมื่อเกิดข้อผิดพลาด ให้ระบุขั้นตอนที่ล้มเหลว รหัสข้อผิดพลาดทางเทคนิคที่คงที่ และข้อมูลเมตาของข้อผิดพลาดที่ผ่านการลบข้อมูลอ่อนไหวแล้ว
ควรแยกให้ได้ว่าการเริ่มต้นโมเดลล้มเหลว การขอสิทธิ์ไมโครโฟนถูกปฏิเสธ หรือการบันทึกไม่มีเสียง เป็นคนละเหตุการณ์กัน ความผิดพลาดของ Worker ควรมองเห็นได้ระหว่างพัฒนา แทนที่จะถูกตัวจัดการข้อผิดพลาดแบบทั่วไปกลืนหายไป
อย่าบันทึกตัวอย่างเสียงจากไมโครโฟน ประโยคที่ถอดเสียงได้ ลำดับโทเคน หรือเนื้อหาเสียงอื่น ๆ ข้อมูลวัดประสิทธิภาพสามารถเก็บเป็นช่วงระยะเวลา ระดับโมเดลที่เลือก เวลาเริ่มต้นโมเดล เวลาอนุมาน และประเภทข้อผิดพลาดได้
วิธีนี้ทำให้วินิจฉัยปัญหาไมโครโฟนได้ง่ายขึ้น โดยไม่ลดมาตรฐานการคุ้มครองความเป็นส่วนตัว
ใส่ข้อความถอดเสียงผ่านสถานะของ React
การรู้จำเสียงจะมีประโยชน์ก็ต่อเมื่อข้อความสุดท้ายไปถึงช่องกรอกข้อมูลในแบบฟอร์มเดิม
ในแอปพลิเคชัน React ช่องนั้นมักถูกควบคุมด้วยสถานะของคอมโพเนนต์ การกำหนดค่าให้ input.value โดยตรงอาจขัดกับกลไกการเรนเดอร์ของเฟรมเวิร์ก
ดังนั้นข้อความที่รู้จำได้ควรผ่านเส้นทางอัปเดตสถานะเดียวกับการพิมพ์ตามปกติ
การเชื่อมต่อระบบต้องคำนึงถึงการทำงานแบบอะซิงโครนัสด้วย การรู้จำเสียงอาจเสร็จหลังจากผู้ใช้พิมพ์อักขระเพิ่มหรือเลื่อนเคอร์เซอร์ไปแล้ว
การใช้ค่าในช่องกรอกที่บันทึกไว้ตอนเริ่มอัดเสียงและล้าสมัยแล้ว อาจเขียนทับการแก้ไขล่าสุดของผู้ใช้โดยไม่ตั้งใจ
รูปแบบการเชื่อมต่ออย่างย่อมีดังนี้:
const insertion = insertTranscript({
currentValue: latestValue,
transcript: recognizedText,
selection: currentSelection,
maxLength: inputLimit,
});
setMessage(insertion.value);
restoreCaret(insertion.caret);ฟังก์ชันช่วยแทรกข้อความควรรักษาข้อความปัจจุบันไว้ อาจแทนที่ช่วงที่เลือกเมื่อเหมาะสม จัดการช่องว่างให้ถูกต้อง และเคารพความยาวสูงสุดของช่องกรอกข้อมูล
ต้องระวัง Unicode ด้วย เพราะความยาวสตริงใน JavaScript นับเป็นหน่วยรหัส UTF-16 การตัดสตริงที่ตำแหน่งใดก็ได้อาจผ่าคู่อักขระตัวแทนออกจากกัน
สิ่งสำคัญที่สุดคือการรู้จำเสียงต้องไม่ส่งแบบฟอร์มโดยอัตโนมัติ ผู้ใช้ต้องตรวจสอบและแก้ไขข้อความก่อนส่งได้
จัดการข้อผิดพลาดโดยไม่ทำให้การพิมพ์ข้อความปกติเสีย
ระบบเสียงควรเป็นฟีเจอร์เสริมที่ไม่จำเป็นต่อการใช้งานหลัก
ไม่ว่าจะถูกปฏิเสธสิทธิ์ไมโครโฟน เบราว์เซอร์จัดสรรหน่วยความจำให้โมเดลไม่ได้ Worker หยุดทำงาน หรือไม่มีเสียงพูดในการบันทึก ช่องพิมพ์ข้อความปกติก็ต้องทำงานต่อได้
ใช้สถานะที่ชัดเจนเพื่อแสดงวงจรการทำงานของไมโครโฟน เช่น:
idle
preparing
listening
recognizing
errorใช้ป้ายกำกับที่รองรับการเข้าถึงและแสดงสถานะให้เห็นชัด ไมโครโฟนที่เพียงเปลี่ยนเป็นสีแดงหรือชมพูหลังโหลด ไม่ได้บอกผู้ใช้มากนักว่าเกิดอะไรขึ้น
เมื่อยกเลิก ต้องล้างแทร็กเสียง ออบเจ็กต์บริบทเสียง บัฟเฟอร์ที่รอดำเนินการ และเซสชันบันทึกที่ใช้งานอยู่ ส่วนติดต่อผู้ใช้ยังต้องป้องกันไม่ให้ผลลัพธ์เก่าจากการบันทึกที่ยกเลิกแล้วกลับมาเขียนทับสถานะข้อความใหม่
หากโมเดลขนาดใหญ่ล้มเหลวเพราะข้อจำกัดด้านหน่วยความจำหรือการเริ่มต้น ต้องปล่อยทรัพยากรทั้งหมดก่อนลองโมเดลขนาดเล็ก และจำกัดจำนวนครั้งที่ลองใหม่ เพื่อไม่ให้เบราว์เซอร์ดาวน์โหลดหรือเริ่มต้นโมเดลที่รันไม่ได้ซ้ำแล้วซ้ำเล่า
อย่าเปลี่ยนไปใช้บริการรู้จำเสียงบนคลาวด์โดยไม่แจ้งเมื่อระบบภายในเครื่องล้มเหลว หากกำหนดให้ประมวลผลเฉพาะภายในเครื่องอย่างเคร่งครัด เมื่อการรู้จำในเครื่องล้มเหลวก็ต้องจบด้วยข้อผิดพลาดในเครื่อง
ทดสอบกระบวนการทั้งหมดในเบราว์เซอร์
การตรวจสอบ TypeScript ผ่านหรือบิลด์สำหรับใช้งานจริงสำเร็จ ไม่ใช่หลักฐานว่าการป้อนข้อมูลด้วยเสียงใช้งานได้
เช่นเดียวกัน การยืนยันว่าเบราว์เซอร์ดาวน์โหลดไฟล์ ONNX ได้ ยังไม่พิสูจน์ว่าเซสชันทั้งตัวเข้ารหัสและตัวถอดรหัสเริ่มต้นได้สำเร็จ
การทดสอบถดถอยที่มีประโยชน์ที่สุดควรใช้ Worker ไฟล์รันไทม์ โมเดล ตัวประมวลผล และตัวแบ่งโทเคนชุดเดียวกับที่ใช้จริงในระบบใช้งานจริง
ป้อนข้อมูล PCM ที่บันทึกไว้เป็นเสียงพูดสั้น ๆ ซึ่งทราบเนื้อหาเข้าสู่กระบวนการอนุมานจริงในเบราว์เซอร์ และตรวจสอบว่าได้ข้อความถอดเสียงที่ไม่ว่างเปล่ากลับมา
จากนั้นทดสอบการทำงานกับไมโครโฟนทั้งหมดในเบราว์เซอร์จริง
- การโหลดหน้าเว็บครั้งแรก: ตรวจสอบว่าไม่มีการดาวน์โหลดโมเดลเสียงหรือทรัพยากรรันไทม์ก่อนใช้ไมโครโฟน
- การเริ่มต้นแบบโหลดใหม่ทั้งหมด: ตรวจสอบสิทธิ์ไมโครโฟน คำขอโมเดล ชนิด MIME ของ JavaScript และ WASM รวมถึงการตอบกลับที่ยืนยันว่า Worker พร้อมจริง
- การเริ่มต้น ONNX: ตรวจสอบว่าทั้งเซสชันตัวเข้ารหัสและตัวถอดรหัสสร้างได้
- การรับเสียง: ยืนยันว่า AudioWorklet สร้างบัฟเฟอร์ PCM ที่ไม่ว่างเปล่า
- การปรับอัตราสุ่มตัวอย่าง: ยืนยันว่า Worker ได้รับอัตราที่ใช้จริงและสร้างเสียง 16 kHz ที่ถูกต้อง
- การหยุดด้วยตนเอง: ยืนยันว่าการคลิกไมโครโฟนครั้งที่สองหยุดบันทึกได้อย่างเชื่อถือได้
- การหยุดอัตโนมัติ: ยืนยันว่าช่วงหยุดพูดตามธรรมชาติทำให้หยุดบันทึกได้โดยไม่ตัดเสียงพูดเบา ๆ
- การถอดเสียง: ตรวจสอบว่าตัวประมวลผล โมเดล และตัวแบ่งโทเคนที่ครบถ้วนส่งข้อความที่อ่านเข้าใจได้กลับมา
- การเชื่อมต่อช่องกรอกข้อมูล: ยืนยันว่าข้อความที่รู้จำได้ปรากฏในช่องจริงที่ควบคุมด้วยสถานะ โดยไม่เขียนทับข้อความที่ผู้ใช้แก้ไข
- การกู้คืนจากข้อผิดพลาด: ทดสอบสิทธิ์ถูกปฏิเสธ ไฟล์หาย ข้อผิดพลาด Worker การเริ่มต้นโมเดลล้มเหลว การยกเลิก และการเปลี่ยนไปใช้โมเดลขนาดเล็ก
- ความเป็นส่วนตัว: ตรวจสอบคำขอเครือข่ายและยืนยันว่าไม่อัปโหลดเสียงจากไมโครโฟนไปยังเซิร์ฟเวอร์หรือบริการวิเคราะห์ข้อมูล
- ความเข้ากันได้กับมือถือ: ทดสอบซ้ำบนโทรศัพท์จริง ทั้งการเริ่มต้นจากศูนย์ การเริ่มต้นเมื่อมีข้อมูลพร้อมแล้ว และการพูดต่อเนื่องหลายรอบ
การทดสอบด้วย PCM ที่บันทึกไว้เหมาะมากสำหรับตรวจสอบชุดประมวลผลอนุมาน แต่ไม่ได้พิสูจน์ว่าการรับเสียงจากไมโครโฟนทำงานได้ การทดสอบยอมรับขั้นสุดท้ายต้องใช้ไมโครโฟนจริงและส่วนติดต่อผู้ใช้จริง
สถาปัตยกรรมที่ใช้งานได้จริงสำหรับการพิมพ์ด้วยเสียงในเบราว์เซอร์
สำหรับเว็บไซต์ที่ต้องการการป้อนเสียงแบบสั้น รองรับหลายภาษา และคุ้มครองความเป็นส่วนตัว สถาปัตยกรรมที่ใช้งานได้จริงที่สุดควรตั้งใจให้ง่าย:
ปุ่มไมโครโฟนของ React
|
v
ขอสิทธิ์เข้าถึง
|
v
เริ่มต้นโมเดลเมื่อจำเป็น
|
v
รับเสียง PCM ด้วย AudioWorklet
|
v
RMS แบบปรับตัว / หยุดด้วยตนเอง
|
v
Worker แยกต่างหาก
|
v
ปรับอัตราสุ่มเสียงเป็น 16 kHz
|
v
Whisper Tiny หรือ Base Q8
|
v
ONNX Runtime WASM ที่เข้ากันได้
|
v
ตัวประมวลผล + ตัวแบ่งโทเคน Whisper
|
v
ข้อความถอดเสียงสุดท้าย
|
v
ช่องกรอกที่ควบคุมด้วยสถานะ Reactแอปพลิเคชันควรโฮสต์ไฟล์โมเดลและรันไทม์ที่มีเวอร์ชันกำกับเอง รันการอนุมานนอกเธรดหลัก หลีกเลี่ยงการดาวน์โหลดโมเดลโดยไม่จำเป็น คืนทรัพยากรหลังใช้งาน และไม่อัปโหลดเสียงจากไมโครโฟนเพื่อการรู้จำเสียงเด็ดขาด
ตัวเลือกที่ซับซ้อนกว่า เช่น การเร่งความเร็วด้วย WebGPU การตรวจจับกิจกรรมเสียงพูดด้วยโครงข่ายประสาทเทียม การถอดเสียงบางส่วนอย่างต่อเนื่อง หรือการเพิ่มระดับโมเดล สามารถพิจารณาภายหลังเมื่อผลการวัดแสดงว่าความซับซ้อนนั้นคุ้มค่า
บทเรียนที่สำคัญที่สุดไม่ใช่ไลบรารีรุ่นใดรุ่นหนึ่งหรือขนาดโมเดลใดขนาดหนึ่ง แต่คือการตรวจสอบทุกจุดเชื่อมต่อในกระบวนการรู้จำเสียงพูดของเบราว์เซอร์
การแสดงคำขอสิทธิ์ไมโครโฟนได้ ไม่ได้หมายความว่ามีการถอดเสียง การดาวน์โหลดโมเดลสำเร็จไม่ได้หมายความว่าตัวถอดรหัสเริ่มต้นแล้ว เซสชัน ONNX ที่สร้างสำเร็จไม่ได้หมายความว่ามีตัวแบ่งโทเคนพร้อมใช้ และแม้ถอดเสียงสำเร็จก็ไม่ได้หมายความว่าแอปพลิเคชันใส่ข้อความลงในช่องกรอกข้อมูลอย่างถูกต้อง
ฟีเจอร์นี้จะถือว่าเสร็จสมบูรณ์ก็ต่อเมื่อผู้เข้าชมสามารถกดไมโครโฟน พูดตามธรรมชาติ หยุดบันทึก แล้วเห็นข้อความที่รู้จำได้ในช่องกรอกที่แก้ไขได้ โดยไม่ต้องส่งไฟล์เสียงที่บันทึกไปยังเซิร์ฟเวอร์รู้จำเสียงพูด