ব্লগে ফিরে যান
১৯ অক্টোবর, ২০২৬Sergei Solod19 মিনিট পড়া

Whisper ও WebAssembly দিয়ে ওয়েবসাইটে গোপনীয়তা-সুরক্ষিত স্পিচ-টু-টেক্সট সুবিধা যোগ করবেন যেভাবে

Whisper, Transformers.js, ONNX Runtime Web, AudioWorklet ও WebAssembly দিয়ে সম্পূর্ণ ক্লায়েন্ট-সাইড ভয়েস টাইপিং তৈরি করুন। মোবাইলে পারফরম্যান্স উন্নত করা এবং স্পিচ রিকগনিশন ব্যর্থ করে দেওয়া রানটাইম, ওয়ার্কার ও টোকেনাইজারের ত্রুটি দূর করার উপায় জানুন।

কথা থেকে লেখাWhisperWebAssemblyAudioWorkletJavaScript

ওয়েবসাইটে একটি মাইক্রোফোন বোতাম যোগ করা সহজ মনে হয়: ব্যবহারকারীর কণ্ঠ ধারণ করা, কথাগুলো শনাক্ত করা এবং সেগুলো একটি টেক্সট ফিল্ডে বসিয়ে দেওয়া। কিন্তু ডেস্কটপ ও মোবাইল ব্রাউজারে এটি নির্ভরযোগ্যভাবে চালানো অনেক বেশি জটিল, বিশেষ করে যখন মাইক্রোফোনের অডিও সার্ভারে আপলোড না করে সম্পূর্ণ স্পিচ রিকগনিশন স্থানীয়ভাবে করতে হয়।

সমস্যা শুধু একটি স্পিচ রিকগনিশন মডেল বেছে নেওয়ার নয়। কার্যকর সমাধানে মাইক্রোফোনের অনুমতি, অডিও ধারণ, পুনরায় স্যাম্পলিং, ব্রাউজার ওয়ার্কার, WebAssembly, ONNX মডেল চালু করা, টোকেনাইজেশন, ক্যাশিং এবং অ্যাপ্লিকেশনের টেক্সট ইনপুটের সঙ্গে সংযোগ—সবই ঠিকভাবে সামলাতে হয়।

এই নিবন্ধে OpenAI Whisper, Transformers.js, ONNX Runtime Web, AudioWorklet এবং একটি নির্দিষ্ট Web Worker ব্যবহার করে বাস্তবে কাজে লাগে এমন, গোপনীয়তা রক্ষাকারী স্পিচ-টু-টেক্সট সুবিধা তৈরির পদ্ধতি দেখানো হয়েছে। মডেলের ফাইল সফলভাবে ডাউনলোড হওয়ার পরও যেসব বাস্তব ইন্টিগ্রেশন ত্রুটিতে মাইক্রোফোন বোতাম লোডিং অবস্থায় আটকে যেতে পারে, সেগুলোও আলোচনা করা হয়েছে।

লক্ষ্য সহজ: দর্শক মাইক্রোফোন বোতামে ক্লিক করবেন, স্বাভাবিকভাবে কথা বলবেন এবং শনাক্ত করা লেখা বিদ্যমান ইনপুট ফিল্ডে দেখতে পাবেন। জমা দেওয়ার আগে তিনি লেখাটি যাচাই বা সম্পাদনা করতে পারবেন। মাইক্রোফোনের রেকর্ডিং ব্রাউজারের বাইরে পাঠানোর দরকার নেই।

সম্পূর্ণ ক্লায়েন্ট-সাইড স্পিচ রিকগনিশন বলতে কী বোঝায়

ওয়েবসাইটে ভয়েস ইনপুট যোগ করার দুটি মৌলিকভাবে আলাদা পদ্ধতি আছে।

প্রথম পদ্ধতিতে স্পিচ রিকগনিশন পরিষেবা ব্যবহার করা হয়। ব্রাউজার অডিও ধারণ করে দূরবর্তী পরিষেবায় পাঠায় এবং শনাক্ত করা লেখা ফেরত পায়। এতে বাস্তবায়ন সহজ হতে পারে, তবে নেটওয়ার্কের ওপর নির্ভরতা, গোপনীয়তার বিষয়, পরিষেবাদাতার প্রাপ্যতা এবং ব্যবহারভিত্তিক খরচের সম্ভাবনা তৈরি হয়।

দ্বিতীয় পদ্ধতিতে অনুমান বা ইনফারেন্স সরাসরি ব্রাউজারের ভেতরেই চলে। ওয়েবসাইট স্পিচ রিকগনিশন মডেল ও তা চালানোর রানটাইম ডাউনলোড করে। ব্রাউজার মাইক্রোফোনের অডিও নিয়ে সংখ্যাগত স্যাম্পলে রূপান্তর করে, স্থানীয়ভাবে মডেল চালায় এবং স্পিচ রিকগনিশন সার্ভার ছাড়াই প্রতিলিপি তৈরি করে।

এই নিবন্ধে শুধু দ্বিতীয় পদ্ধতিটি নিয়ে আলোচনা করা হয়েছে।

সাধারণ ব্রাউজারভিত্তিক স্পিচ রিকগনিশনকে নিশ্চিতভাবে স্থানীয় স্পিচ রিকগনিশন মনে করা ঠিক নয়। Web Speech API সার্ভারনির্ভর রিকগনিশন ইঞ্জিন ব্যবহার করতে পারে। কিছু নতুন বাস্তবায়নে processLocally বিকল্প আছে, কিন্তু ব্রাউজার ও অপারেটিং সিস্টেমভেদে সমর্থন আলাদা। কঠোরভাবে স্থানীয় প্রক্রিয়াকরণ দরকার হলে সাধারণ SpeechRecognition স্বয়ংক্রিয় বিকল্প হিসেবে ব্যবহার করা যাবে না।

এর পরিবর্তে অ্যাপ্লিকেশন পুরো ইনফারেন্স পাইপলাইন নিজেই নিয়ন্ত্রণ করে।

Microphone
    |
    v
AudioWorklet
    |
    v
Float32 PCM audio
    |
    v
Dedicated Web Worker
    |
    v
16 kHz resampling
    |
    v
Whisper + ONNX Runtime Web
    |
    v
Tokenizer and text decoding
    |
    v
React input state

ওয়েবসাইট তখনও JavaScript, WebAssembly, কনফিগারেশন ফাইল ও মডেলের ওয়েট সরবরাহ করে। এগুলো সাধারণ স্ট্যাটিক ডাউনলোড। পার্থক্য হলো, শনাক্তকরণের জন্য মাইক্রোফোনের অডিও আপলোড না করে স্থানীয়ভাবেই প্রক্রিয়াকরণ করা হয়। ব্যবহারকারী পরে সাধারণ ফর্মে শনাক্ত করা লেখা জমা দিলে সেটি অ্যাপ্লিকেশনের আলাদা একটি কাজ।

ব্যবহারিক মডেল নির্বাচন: Whisper Tiny নাকি Base

Whisper বহু ভাষার স্পিচ রিকগনিশন মডেলের একটি পরিবার। একটি মডেল দিয়েই অনেক ভাষার কথা শনাক্ত করতে পারায় এটি বহুভাষিক ওয়েবসাইটের জন্য বিশেষভাবে উপযোগী।

ছোট ভয়েস মেসেজের ক্ষেত্রে Whisper Tiny ও Whisper Base—এই দুটি মডেল শনাক্তকরণের মান এবং ব্রাউজারের রিসোর্স ব্যবহারের মধ্যে কার্যকর ভারসাম্য দেয়।

মডেলনির্বাচিত Q8 ONNX ওয়েটের আনুমানিক আকারপ্রস্তাবিত ব্যবহার
Whisper Tiny41 MBমোবাইল ও সীমিত রিসোর্সের জন্য সতর্কতামূলক বিকল্প
Whisper Base77 MBপরীক্ষিত ও সক্ষম ডিভাইসে উন্নত মানের বিকল্প

এই আকারগুলো পরীক্ষা করা মডেল এক্সপোর্টে নির্বাচিত এনকোডার ও ডিকোডারের ONNX ফাইলের জন্য। এর মধ্যে সব সহায়ক ফাইল নেই; এগুলোকে ব্রাউজারের সর্বোচ্চ মেমরি ব্যবহারের পরিমাণও ভাবা উচিত নয়।

Whisper Tiny দ্রুত ডাউনলোড হয়, সাধারণত কম কম্পিউটিং রিসোর্স চায় এবং সক্ষমতা অনিশ্চিত এমন মোবাইল পরিবেশের জন্য বেশি উপযোগী। Whisper Base সাধারণত আরও ভালো শনাক্তকরণ দেয়, বিশেষ করে কিছু ভাষায়, যেখানে ছোট মডেল বেশি ভুল করে।

শুধু ডিভাইসের প্রকৃত RAM দেখে মডেল নির্বাচন করা উচিত নয়। ডিভাইসের স্পেসিফিকেশনে দেখানো মেমরির তুলনায় ব্রাউজারের জন্য উপলব্ধ মেমরি অনেক কম হতে পারে। আগে থেকেই পেজের ব্যবহৃত মেমরি, WebAssembly-এর বরাদ্দ, সাময়িক টেনসর ও অপারেটিং সিস্টেমের মেমরি চাপ—সবই গুরুত্বপূর্ণ।

সতর্ক পন্থা হলো, সক্ষমতা অজানা মোবাইল ডিভাইসে Tiny দিয়ে শুরু করা, যাচাই করা সক্ষম ডিভাইসের জন্য Base রাখা এবং Base চালু করতে ব্যর্থ হলে Tiny-তে ফিরে যাওয়া।

Tiny লোড করার আগে ব্যর্থ Base ইনস্ট্যান্স সম্পূর্ণ ছেড়ে দিতে হবে। দুটি মডেলই মেমরিতে রেখে দিলে বিকল্পে যাওয়ার উদ্দেশ্যই ব্যর্থ হয়।

প্রোডাকশনের জন্য WebAssembly কেন যুক্তিসংগত ডিফল্ট

ONNX Runtime Web ব্রাউজারে নিউরাল নেটওয়ার্ক চালাতে পারে। এই কাজের জন্য WebAssembly প্রধান ডেস্কটপ ও মোবাইল ব্রাউজারগুলোতে CPU-ভিত্তিক ইনফারেন্সের ব্যবহারিক পথ দেয়।

উপযুক্ত হার্ডওয়্যারে WebGPU সমর্থিত মডেলের গতি বাড়াতে পারে। কিন্তু WebGPU উপলব্ধ থাকলেই কার্যকর স্পিচ রিকগনিশন পাইপলাইন পাওয়া যায় না। কোনো ব্রাউজারে navigator.gpu থাকলেও ONNX Runtime সেই প্ল্যাটফর্ম সমর্থন করে কি না, নির্দিষ্ট Whisper গ্রাফ ঠিকভাবে চালু হয় কি না বা বারবার ইনফারেন্স চালালে রিসোর্সের সমস্যা এড়ানো যায় কি না—কোনোটিই নিশ্চিত হয় না।

তাই সতর্ক বাস্তবায়নে প্রোডাকশনের ব্যাকএন্ড হিসেবে WASM ব্যবহার করা যায় এবং সামঞ্জস্য, নির্ভুলতা, মেমরি ও পুনরাবৃত্ত সেশন পরীক্ষার পরে WebGPU আলাদাভাবে মূল্যায়ন করা যায়।

প্রাথমিক বাস্তবায়নে এক থ্রেডের WASM ব্যবহার করলে পুরো ওয়েবসাইটকে cross-origin isolation ও SharedArrayBuffer-এর ওপর নির্ভরশীল করতে হয় না।

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

নির্দিষ্ট ওয়ার্কারে ইনফারেন্স চালালে ভারী গণনার কাজ মূল JavaScript থ্রেডের বাইরে থাকে। মডেল অডিও প্রক্রিয়াকরণের সময়ও ইনপুট ফিল্ড, ভার্চুয়াল কিবোর্ড, স্ক্রলিং ও অ্যাপ্লিকেশনের ইন্টারফেস সাড়া দিতে পারে।

পেজ প্রথম লোড হওয়ার সময় স্পিচ রিকগনিশন সম্পূর্ণ বাদ রাখুন

যারা কখনো মাইক্রোফোন ব্যবহার করবেন না, তাঁদের ওপর এই সুবিধার কারণে উল্লেখযোগ্য নেটওয়ার্ক বা মেমরির খরচ চাপানো উচিত নয়।

প্রাথমিক অ্যাপ্লিকেশন বান্ডেলে আগেভাগে Transformers.js ইমপোর্ট করবেন না। পেজ খুলতেই ONNX Runtime চালু করবেন না, আর অব্যবহৃত অবস্থায় মডেলের ওয়েট স্বয়ংক্রিয়ভাবে ডাউনলোড করবেন না।

ব্যবহারকারী স্পষ্টভাবে মাইক্রোফোন বোতামে ক্লিক করার পরই রিকগনিশন স্ট্যাক লোড করুন।

প্রথমবার ব্যবহারের কার্যকর ধাপগুলো হলো:

  1. মাইক্রোফোন বোতামে ক্লিকের ইভেন্ট গ্রহণ করুন।
  2. getUserMedia() দিয়ে মাইক্রোফোন ব্যবহারের অনুমতি চান।
  3. অনুমতি না পেলে মডেল ডাউনলোড না করে ত্রুটি দেখান।
  4. অনুমতি পেলে মডেল প্রস্তুত হওয়ার সময় অস্থায়ী মাইক্রোফোন স্ট্রিমটি ছেড়ে দিন।
  5. প্রয়োজনমতো নির্দিষ্ট ওয়ার্কার চালু করে নির্বাচিত স্থানীয় মডেল লোড করুন।
  6. রিকগনিশন পাইপলাইন প্রস্তুত বলে ওয়ার্কারের নিশ্চিতকরণ আসা পর্যন্ত অপেক্ষা করুন।
  7. ব্যবহারকারী বাতিল না করলে স্বয়ংক্রিয়ভাবে রেকর্ডিং শুরু করুন।
  8. কথা শোনা হচ্ছে—এমন অবস্থা স্পষ্টভাবে দেখান।

অনুমতি চাওয়ার কাজটি ব্যবহারকারীর ইন্টারঅ্যাকশনের সঙ্গে যুক্ত থাকতে হবে। রেকর্ডিং সবসময় নিঃশব্দে আবার শুরু করা যাবে ধরে না নিয়ে বাতিল করা অপারেশন এবং ব্রাউজারভেদে অডিও ধারণের বিধিনিষেধও সামলাতে হবে।

মডেল প্রস্তুতির সময় ভয়েস ইনপুট প্রস্তুত হচ্ছে—এমন দৃশ্যমান অবস্থা দেখানো উচিত। অবস্থার অর্থপূর্ণ পরিবর্তন না দেখিয়ে শুধু ঘূর্ণায়মান চিহ্ন রাখলে মডেল সফলভাবে ডাউনলোড হলেও ব্যবহারকারীর মনে হতে পারে মাইক্রোফোন নষ্ট।

একবার চালু হলে পরবর্তী ডিকটেশনের জন্য ওয়ার্কারকে অল্প সময় সক্রিয় রাখা যায়। প্রায় এক মিনিট নিষ্ক্রিয় থাকার পর বন্ধ করার নিয়ম একটি যুক্তিসংগত প্রাথমিক সিদ্ধান্ত। এরপর ওয়ার্কার বন্ধ করে মেমরিতে থাকা মডেল ছেড়ে দিন। ব্রাউজারের ক্যাশে থাকা মডেল ফাইল পরবর্তী ভিজিটের জন্য রেখে দেওয়া যায়।

AudioWorklet দিয়ে কাঁচা অডিও ধারণ

Whisper-এর সংখ্যাগত অডিও স্যাম্পল দরকার। MediaRecorder অডিও ফাইল রেকর্ড করার জন্য খুব ভালো হলেও স্থানীয় স্পিচ রিকগনিশনে এটি ব্যবহার করলে অপ্রয়োজনীয় এনকোডিং ও ডিকোডিংয়ের ধাপ যোগ হতে পারে।

সহজতর প্রক্রিয়াকরণ পথটি হলো:

getUserMedia()
    |
    v
AudioContext
    |
    v
AudioWorklet
    |
    v
Float32 PCM buffers
    |
    v
Dedicated Worker

AudioWorklet অ্যাপ্লিকেশনের মূল JavaScript থ্রেডের বাইরে অডিও প্রক্রিয়াকরণের কোড চালায়। এটি PCM স্যাম্পল ধারণ করতে, বহু চ্যানেলের ইনপুটকে মনোতে নামিয়ে আনতে, শব্দের মাত্রার সহজ পরিমাপ করতে এবং জমা হওয়া বাফার ওয়ার্কারে পাঠাতে পারে।

মাইক্রোফোন চালুর একটি সরলীকৃত উদাহরণ:

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.

মাইক্রোফোনের কনস্ট্রেইন্টগুলো পছন্দের নির্দেশনা, নিশ্চয়তা নয়। ব্রাউজারভেদে echo cancellation, noise suppression ও automatic gain control-এর অ্যালগরিদম আলাদা হতে পারে।

গুরুত্বপূর্ণ একটি বিষয় হলো, মাইক্রোফোনের স্যাম্পল রেট সবসময় 16 kHz নয়। অনেক অডিও কনটেক্সট 44.1 kHz বা 48 kHz ব্যবহার করে। Whisper-এর 16 kHz ইনপুট দরকার, তাই ধারণ করা স্যাম্পল যথাযথভাবে পুনরায় স্যাম্পল করতে হবে।

প্রতি দ্বিতীয় বা তৃতীয় স্যাম্পল বাদ দেওয়া সাধারণভাবে সঠিক সমাধান নয়। windowed-sinc-এর মতো উপযুক্ত low-pass resampler স্যাম্পল রেট কমানোর সময় অ্যালিয়াসিং কমায় এবং কথার গুরুত্বপূর্ণ ফ্রিকোয়েন্সি সংরক্ষণ করে।

রিয়েল-টাইম AudioWorklet কলব্যাকের বদলে নির্দিষ্ট ওয়ার্কারের ভেতরে রিস্যাম্পলিং চালান।

ব্রাউজারের থ্রেডগুলোর মধ্যে দক্ষভাবে অডিও স্থানান্তর

AudioWorklet অনেক ছোট ছোট অডিও অংশ তৈরি করতে পারে। প্রতিটি অডিও রেন্ডারিং কোয়ান্টাম আলাদা বার্তায় পাঠালে অপ্রয়োজনীয় ওভারহেড তৈরি হতে পারে।

ব্যবহারিক উপায় হলো অল্প সময়ের PCM স্যাম্পল একত্র করে প্রতিটি ব্যাচ ArrayBuffer হিসেবে পাঠানো।

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

ট্রান্সফার তালিকাটি গুরুত্বপূর্ণ: এটি সম্পূর্ণ বাফারের অপ্রয়োজনীয় কপি তৈরির বদলে ArrayBuffer-এর মালিকানা হস্তান্তর করে।

ওয়ার্কার এসব অংশ একটি অডিও অ্যাকিউমুলেটরে যোগ করতে পারে এবং রেকর্ডিং থামলে একত্র করতে পারে।

প্রকৃত ধারণকৃত স্যাম্পল রেট, সংগৃহীত স্যাম্পলের সংখ্যা ও রেকর্ডিংয়ের দৈর্ঘ্যও নজরে রাখা উপকারী। এই মেটাডেটা সংবেদনশীল অডিও লগ না করেই নীরব রেকর্ডিংয়ের সমস্যা শনাক্ত করতে সাহায্য করে।

আরেকটি নিউরাল নেটওয়ার্ক ছাড়াই বিরতি শনাক্ত করুন

ছোট টেক্সট মেসেজ ডিকটেশনের জন্য নিউরাল ভয়েস অ্যাক্টিভিটি ডিটেক্টর অপরিহার্য নয়।

অভিযোজিত RMS ডিটেক্টর কম খরচে কথার উপস্থিতির আনুমানিক ধারণা দিতে পারে। RMS সংকেতের অ্যামপ্লিটিউড মাপে, ফলে আগে কথা বলা ব্যক্তি কখন নীরব হয়েছেন তা অ্যাপ্লিকেশন অনুমান করতে পারে।

ইন্টারফেসে দ্বিতীয়বার মাইক্রোফোনে ক্লিক করে হাতে রেকর্ডিং থামানোর সুবিধা সবসময় থাকা উচিত। স্বয়ংক্রিয় নীরবতা শনাক্তকরণ একটি বাড়তি সুবিধা, সফল রিকগনিশনের শর্ত নয়।

ছোট ডিকটেশনের জন্য যুক্তিসংগত প্রাথমিক মানগুলো হলো:

প্যারামিটারপ্রাথমিক মান
বিশ্লেষণের ব্যবধান20 ms
শব্দদূষণ ক্যালিব্রেশন300 ms
কথা বলার নিশ্চয়তা140 ms
স্বয়ংক্রিয়ভাবে থামার আগে নীরবতা1.4 সেকেন্ড
কথা না বললে সময়সীমা8 সেকেন্ড
রেকর্ডিংয়ের সর্বোচ্চ দৈর্ঘ্য30 সেকেন্ড

এগুলো কনফিগারেশন শুরু করার মান, সবার জন্য সর্বোত্তম সীমা নয়। আস্তে কথা বলা, পটভূমির সংগীত এবং মাইক্রোফোনের শব্দদূষণ প্রক্রিয়াকরণ RMS পরিমাপে প্রভাব ফেলতে পারে।

বাক্যের শেষের নিচু স্বরের শব্দ কেটে দেওয়ার চেয়ে ব্যবহারকারীকে নিজে রেকর্ডিং থামাতে দেওয়াই ভালো।

সাধারণ ছোট টেক্সট ইনপুটে মধ্যবর্তী ফলের জন্য বারবার Whisper চালানোর তুলনায় একবারে প্রতিলিপি তৈরি করা সাধারণত সহজ। কথা রেকর্ড করুন, থামান, একবার মডেল চালান এবং চূড়ান্ত লেখা বসিয়ে দিন।

সম্পূর্ণ Whisper পাইপলাইনে শুধু ONNX মডেল যথেষ্ট নয়

এটি বাস্তবায়নের সবচেয়ে গুরুত্বপূর্ণ দিকগুলোর একটি।

Whisper ইনফারেন্স মানে শুধু ONNX এনকোডার ও তার পরে ONNX ডিকোডার চালানো নয়। সম্পূর্ণ স্বয়ংক্রিয় স্পিচ রিকগনিশন পাইপলাইনে অডিও ফিচার এক্সট্র্যাকশন, টোকেনাইজেশন, জেনারেশন কনফিগারেশন এবং পূর্বানুমিত টোকেনকে পাঠযোগ্য লেখায় ডিকোড করাও দরকার।

সম্পূর্ণ প্রক্রিয়ার ধাপগুলো হলো:

Raw microphone PCM
        |
        v
Resampling to 16 kHz
        |
        v
Whisper feature extractor
        |
        v
ONNX encoder
        |
        v
ONNX decoder and token generation
        |
        v
Whisper tokenizer
        |
        v
Recognized text

ONNX সেশন সফলভাবে চালু হওয়া শুধু প্রমাণ করে যে মডেলের গ্রাফ লোড করা গেছে। পুরো রিকগনিশন পাইপলাইন কাজ করছে—এটি প্রমাণ করে না।

পরীক্ষা করা একটি Transformers.js ইন্টিগ্রেশনে মডেলের সেশনগুলো চালু হলেও ট্রান্সক্রিপশন ব্যর্থ হয়েছিল, কারণ স্থানীয়ভাবে তৈরি পাইপলাইনে প্রয়োজনীয় প্রসেসর ও টোকেনাইজার সঠিকভাবে কনফিগার করা ছিল না।

সামঞ্জস্যপূর্ণ বাস্তবায়নে স্থানীয় মডেল মেটাডেটা ব্যবহার করে এই উপাদানগুলো স্পষ্টভাবে চালু করা হয়েছিল।

নিচে সেই নির্দিষ্ট সংস্করণভিত্তিক পদ্ধতির সংক্ষিপ্ত উদাহরণ দেওয়া হলো; এটি পূর্ণ স্বতন্ত্র ওয়ার্কার নয়:

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 অপারেশনে প্রয়োজনীয় quantization scale না থাকার সঙ্গে ত্রুটিটি সম্পর্কিত ছিল।

এটি মাইক্রোফোনের অনুমতি, ডাউনলোড বা অডিও ফরম্যাটের সমস্যা ছিল না। ব্রাউজার মডেলের ফাইল পেয়েছিল, কিন্তু রানটাইম প্রয়োজনীয় একটি মডেল গ্রাফ চালু করতে পারেনি।

স্থিতিশীল, নির্দিষ্ট সংস্করণে স্থির রাখা ONNX Runtime Web রিলিজ দিয়ে এনকোডার ও ডিকোডার সরাসরি পরীক্ষা করে ওই নির্দিষ্ট অসামঞ্জস্য দূর হয়েছিল।

সামঞ্জস্য পরীক্ষাটি বিশেষভাবে মূল্যবান ছিল, কারণ এটি দুটি আলাদা দাবি পৃথক করেছিল:

  • মডেলের ফাইল সফলভাবে ডাউনলোড হয়েছে।
  • রানটাইম ওই ফাইল থেকে ব্যবহারযোগ্য ইনফারেন্স সেশন সফলভাবে তৈরি করেছে।

দুটি বিষয় এক নয়।

পরীক্ষা করা মডেল এক্সপোর্টে Transformers.js 4.2.0 ও ONNX Runtime Web 1.24.3 একসঙ্গে কাজ করেছিল। অপেক্ষাকৃত নতুন ডেভেলপমেন্ট রানটাইম কোয়ান্টাইজড ডিকোডার গ্রাফে ব্যর্থ হয়েছিল। এটি নির্দিষ্ট সংস্করণসংক্রান্ত পর্যবেক্ষণ; পুরোনো রানটাইম সবসময় ভালো—তার প্রমাণ নয়।

পরোক্ষভাবে আসা রানটাইম ডিপেন্ডেন্সির সংস্করণ বদলালে প্যাকেজের লকফাইলে সঠিক সংস্করণ স্থির করুন এবং কেন পরিবর্তনটি দরকার লিখে রাখুন। রানটাইম আপগ্রেডের জন্য শুধু প্যাকেজ ইনস্টল সফল হওয়া নয়, ব্রাউজারে সম্পূর্ণ ইনফারেন্স রিগ্রেশন টেস্ট আবশ্যক হওয়া উচিত।

Whisper ডিবাগ করার আগে ওয়ার্কার বান্ডেলের ফরম্যাট পরীক্ষা করুন

JavaScript Web Worker বিভিন্ন মডিউল ফরম্যাটে তৈরি করা যায়।

একটি ইন্টিগ্রেশনে সমস্যা হয়েছিল, কারণ অ্যাপ্লিকেশন ওয়ার্কারকে ES module হিসেবে চালাচ্ছিল, অথচ তৈরি হওয়া ওয়ার্কার বান্ডেল classic-worker পদ্ধতির importScripts() ব্যবহার করছিল।

এই এক্সিকিউশন মডেল দুটি পরস্পরের বদলি নয়। মডিউল ওয়ার্কার সরাসরি শুধু classic-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-এর ওপর।

ওয়ার্কার চালুর ত্রুটি খুঁজতে ব্রাউজারের Console, তৈরি হওয়া ওয়ার্কার ফাইল এবং Network প্যানেল দেখুন। ONNX Runtime চালু হওয়ার আগেই সমস্যা হচ্ছে কি না নির্ধারণ করুন।

কিছু বান্ডল করা ব্রাউজার লাইব্রেরি নিজেদের মডিউলের অবস্থানের ভিত্তিতে URL তৈরি করে। ওয়ার্কারের মধ্যে এগুলো প্যাকেজ করলে মূল প্যাকেজ-আপেক্ষিক URL ঠিকই কাজ করবে ধরে না নিয়ে বাস্তবে তৈরি রানটাইম অ্যাসেটের পথ পরীক্ষা করুন।

সঠিক MIME টাইপ দিয়ে WASM ও JavaScript মডিউল পরিবেশন করুন

ওয়েব সার্ভার ভুল রেসপন্স হেডার দিলে পুরোপুরি সামঞ্জস্যপূর্ণ JavaScript ও ONNX মডেল ফাইলও ব্যর্থ হতে পারে।

একটি বাস্তব ত্রুটিতে .mjs এক্সটেনশনের JavaScript মডিউল application/octet-stream হিসেবে পরিবেশন করা হচ্ছিল। মডিউল চালানোর জন্য রেসপন্সের টাইপ উপযুক্ত না হওয়ায় ব্রাউজার সেটি প্রত্যাখ্যান করেছিল।

সাধারণত প্রত্যাশিত রেসপন্স টাইপগুলো হলো:

ফাইল এক্সটেনশনContent-Type
.mjsapplication/javascript
.wasmapplication/wasm

শুধু সার্ভার কনফিগারেশন ফাইল নয়, প্রোডাকশনের প্রকৃত রেসপন্স পরীক্ষা করুন।

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

ওপরের URL-গুলো কেবল উদাহরণ। নির্বাচিত রানটাইম বিল্ডের প্রকৃত সংস্করণযুক্ত অ্যাসেট ফাইলের নাম ব্যবহার করুন।

সঠিক HTTP স্ট্যাটাস পেলেই যথেষ্ট নয়। MIME টাইপ, Content Security Policy, মডিউল চালানোর ধরন বা ভুল অ্যাসেট URL-এর কারণে ব্রাউজার ফাইল প্রত্যাখ্যান করতে পারে।

মনে রাখুন, একই অনুরোধ সরাসরি ব্রাউজার ট্যাবে সফল হতে পারে, কিন্তু এক্সিকিউটেবল মডিউল বা WebAssembly ডিপেন্ডেন্সি হিসেবে লোড করলে ব্যর্থ হতে পারে।

অপরিবর্তনীয় অ্যাসেট URL ব্যবহার করুন, তবে নষ্ট রানটাইমে ব্যবহারকারীকে আটকে রাখবেন না

Whisper মডেলের ফাইলগুলো যথেষ্ট বড়, তাই ব্রাউজার ক্যাশিং গুরুত্বপূর্ণ।

সংস্করণযুক্ত অপরিবর্তনীয় অ্যাসেট পাথ থাকলে প্রতিবার কথা বলার সময় নতুন করে ডাউনলোড না করে ব্রাউজার একই মডেল ও রানটাইম ফাইল ব্যবহার করতে পারে।

সাধারণ ক্যাশ নীতি হলো:

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

তবে এর ফলে ডেপ্লয়মেন্টে একটি শর্ত আসে: কোনো URL-কে অপরিবর্তনীয় ঘোষণা করার পর তার কনটেন্ট গোপনে বদলানো উচিত নয়।

রানটাইম বাইনারি বদলাতে হলে নতুন সংস্করণযুক্ত URL-এ তা প্রকাশ করুন।

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

রানটাইমের পথ বদলানোর কারণ শুধু নামসজ্জা নয়। অপরিবর্তনীয় URL-এর কনটেন্ট পাল্টেও একই URL ব্যবহার করলে ব্রাউজার আগে ক্যাশ করা অসামঞ্জস্যপূর্ণ WebAssembly বাইনারি চালিয়ে যেতে পারে।

JavaScript-এর সহায়ক কোড এবং WebAssembly ফাইল একই রানটাইম ডিস্ট্রিবিউশন থেকে নেওয়াও জরুরি। বিভিন্ন সংস্করণের রানটাইম ফাইল মেশালে এমন ইনিশিয়ালাইজেশন ত্রুটি হতে পারে যার কারণ খুঁজে পাওয়া কঠিন।

বিল্ডের সময় তৈরি একটি ম্যানিফেস্টে প্রত্যাশিত ফাইল, আকার ও ক্রিপ্টোগ্রাফিক চেকসাম রাখলে ডেপ্লয়ের আগেই অনুপস্থিত বা অমিল অ্যাসেট ধরা যায়।

রিকগনিশন লাইব্রেরিকে নিজের সার্ভারে রাখা অ্যাসেট ব্যবহার করতে কনফিগার করুন এবং দূরবর্তী মডেল লোডিং বন্ধ রাখুন। তাতে স্থানীয় মডেল না থাকলে বাইরের মডেল হোস্ট থেকে অনিচ্ছাকৃত ডাউনলোড শুরু না হয়ে স্পষ্ট ত্রুটি দেখাবে।

কিছুই কাজ না করলেও মাইক্রোফোনে লোডিং কেন চলতে পারে

ডেভেলপমেন্টে একটি সাধারণ লক্ষণ হলো, মাইক্রোফোন বোতাম অনুমতি চায়, লোডিং অ্যানিমেশন দেখায় এবং শেষ পর্যন্ত কোনো লেখা না বসিয়েই ত্রুটির অবস্থায় ফিরে যায়।

ব্রাউজার এমনও দেখাতে পারে যে মাইক্রোফোন ব্যবহৃত হচ্ছে।

তাতে স্পিচ রিকগনাইজার কাজ করছে প্রমাণ হয় না। শুধু বোঝা যায়, কোনো এক সময় মাইক্রোফোন থেকে অডিও ধারণ অনুমোদিত ছিল বা সক্রিয় ছিল।

স্বতন্ত্র কয়েকটি ত্রুটি প্রায় একই রকম লক্ষণ তৈরি করতে পারে:

  1. JavaScript মডিউলের ভুল MIME টাইপ। ব্রাউজার রানটাইম মডিউল ডাউনলোড করলেও সেটি চালাতে অস্বীকার করে।
  2. ওয়ার্কার এক্সিকিউশন ফরম্যাটের অমিল। কম্পাইল করা ওয়ার্কার classic-worker API ব্যবহার করে অথচ মডিউল ওয়ার্কার হিসেবে চালু হয়, অথবা উল্টোটা।
  3. ONNX ডিকোডারের অসামঞ্জস্য। রানটাইম এনকোডার সেশন তৈরি করলেও কোয়ান্টাইজড ডিকোডার গ্রাফে ব্যর্থ হয়।
  4. অসম্পূর্ণ রিকগনিশন পাইপলাইন। 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

ব্যর্থ হলে কোন ধাপে সমস্যা হয়েছে, স্থিতিশীল প্রযুক্তিগত ত্রুটি কোড এবং সংবেদনশীল তথ্য বাদ দেওয়া ত্রুটি মেটাডেটা অন্তর্ভুক্ত করুন।

মডেল চালুর ত্রুটিকে মাইক্রোফোনের অনুমতি না পাওয়া বা খালি রেকর্ডিং থেকে আলাদা করে বোঝা যেতে হবে। সাধারণ ত্রুটি হ্যান্ডলারের আড়ালে চাপা না পড়ে ডেভেলপমেন্টের সময় ওয়ার্কারের ব্যর্থতা দৃশ্যমান থাকা উচিত।

মাইক্রোফোনের স্যাম্পল, শনাক্ত করা বাক্য, টোকেনের ক্রম বা কথাবার্তার অন্য কোনো কনটেন্ট লগ করবেন না। পারফরম্যান্স টেলিমেট্রিতে সময়ের শ্রেণি, নির্বাচিত মডেল স্তর, চালু হতে লাগা সময়, ইনফারেন্সের সময় ও ত্রুটির ধরন রাখা যায়।

এতে গোপনীয়তার শর্ত দুর্বল না করেই অকেজো মাইক্রোফোনের সমস্যা খুঁজে পাওয়া অনেক সহজ হয়।

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 কোড ইউনিটে গণনা করা হয়। নির্বিচারে অবস্থানে স্ট্রিং কেটে দিলে একটি surrogate pair ভেঙে যেতে পারে।

সবচেয়ে গুরুত্বপূর্ণ হলো, কথা শনাক্ত হলেই ফর্ম স্বয়ংক্রিয়ভাবে জমা দেওয়া যাবে না। পাঠানোর আগে ব্যবহারকারীকে লেখা পড়ে দেখা ও সংশোধনের সুযোগ দিতে হবে।

সাধারণ টেক্সট ইনপুট অক্ষত রেখে ব্যর্থতা সামলান

স্পিচ সাবসিস্টেম ঐচ্ছিক হওয়া উচিত।

মাইক্রোফোনের অনুমতি না পাওয়া, ব্রাউজার মডেলের জন্য মেমরি বরাদ্দ করতে না পারা, ওয়ার্কার ক্র্যাশ করা বা রেকর্ডিংয়ে কথা না থাকার পরও সাধারণ ইনপুট ফিল্ড কাজ করতে হবে।

মাইক্রোফোনের জীবনচক্র নিচের মতো স্পষ্ট স্টেট দিয়ে প্রকাশ করুন:

idle
preparing
listening
recognizing
error

সহজে বোঝা যায় এমন লেবেল ও দৃশ্যমান স্ট্যাটাস দেখান। লোডিংয়ের পরে মাইক্রোফোন শুধু লাল বা গোলাপি হয়ে গেলে ব্যবহারকারী প্রায় কিছুই বুঝতে পারেন না।

বাতিল করার সময় অডিও ট্র্যাক, অডিও কনটেক্সট, অপেক্ষমাণ বাফার ও সক্রিয় রেকর্ডিং সেশন পরিষ্কার করতে হবে। আগে বাতিল করা রেকর্ডিংয়ের দেরিতে আসা ফল যেন নতুন ইনপুট স্টেটের ওপর না লেখে, সেটিও নিশ্চিত করতে হবে।

মেমরি বা ইনিশিয়ালাইজেশনের সীমাবদ্ধতায় বড় মডেল ব্যর্থ হলে ছোট মডেল চেষ্টা করার আগে বড়টি সম্পূর্ণ ছেড়ে দিন। পুনরায় চেষ্টার সংখ্যা সীমিত রাখুন, যাতে ব্রাউজার চলতে অক্ষম মডেল বারবার ডাউনলোড বা চালু না করে।

স্থানীয় রিকগনিশন ব্যর্থ হলে গোপনে ক্লাউড স্পিচ পরিষেবায় চলে যাবেন না। শুধু স্থানীয় প্রক্রিয়াকরণ বাধ্যতামূলক হলে স্থানীয় রিকগনাইজার ব্যর্থতার ফলও স্থানীয় ব্যর্থতাই থাকতে হবে।

ব্রাউজারের সম্পূর্ণ পাইপলাইন পরীক্ষা করুন

TypeScript যাচাই বা প্রোডাকশন বিল্ড সফল হলেই ভয়েস ইনপুট কাজ করে—এটি প্রমাণ হয় না।

একইভাবে ব্রাউজার ONNX ফাইল ডাউনলোড করতে পারছে মানেই এনকোডার ও ডিকোডার—উভয় মডেল সেশন সফলভাবে চালু হবে, তা নয়।

সবচেয়ে উপকারী রিগ্রেশন টেস্টে প্রোডাকশনে ব্যবহৃত একই ওয়ার্কার, রানটাইম ফাইল, মডেল, প্রসেসর ও টোকেনাইজার চালানো উচিত।

পরিচিত ছোট একটি PCM রেকর্ডিং প্রকৃত ব্রাউজার ইনফারেন্স পথে দিন এবং নিশ্চিত করুন যে খালি নয় এমন প্রতিলিপি ফেরত আসে।

এরপর প্রকৃত ব্রাউজারে মাইক্রোফোনের সম্পূর্ণ ইন্টারঅ্যাকশন পরীক্ষা করুন।

  • প্রাথমিক পেজ লোড: মাইক্রোফোন ব্যবহার না করা পর্যন্ত কোনো স্পিচ মডেল বা রানটাইম অ্যাসেট ডাউনলোড হচ্ছে না নিশ্চিত করুন।
  • প্রথমবার চালু করা: মাইক্রোফোনের অনুমতি, মডেলের অনুরোধ, JavaScript ও WASM-এর MIME টাইপ এবং প্রকৃত ওয়ার্কার প্রস্তুত হওয়ার প্রতিক্রিয়া পরীক্ষা করুন।
  • ONNX চালু করা: এনকোডার ও ডিকোডার—দুটির সেশন তৈরি হচ্ছে নিশ্চিত করুন।
  • অডিও ধারণ: AudioWorklet খালি নয় এমন PCM বাফার তৈরি করছে নিশ্চিত করুন।
  • রিস্যাম্পলিং: ওয়ার্কার প্রকৃত স্যাম্পল রেট পাচ্ছে এবং বৈধ 16 kHz অডিও তৈরি করছে নিশ্চিত করুন।
  • হাতে থামানো: দ্বিতীয়বার মাইক্রোফোনে ক্লিক করলে নির্ভরযোগ্যভাবে রেকর্ডিং থামে কি না পরীক্ষা করুন।
  • স্বয়ংক্রিয়ভাবে থামানো: স্বাভাবিক বিরতিতে আস্তে বলা শব্দ কেটে না দিয়েই রেকর্ডিং শেষ হচ্ছে কি না পরীক্ষা করুন।
  • ট্রান্সক্রিপশন: সম্পূর্ণ প্রসেসর, মডেল ও টোকেনাইজার বোধগম্য লেখা দিচ্ছে নিশ্চিত করুন।
  • ইনপুটের সঙ্গে সংযোগ: ব্যবহারকারীর সম্পাদনা মুছে না দিয়ে শনাক্ত করা লেখা প্রকৃত নিয়ন্ত্রিত ফিল্ডে আসছে নিশ্চিত করুন।
  • ব্যর্থতা থেকে পুনরুদ্ধার: অনুমতি প্রত্যাখ্যান, ফাইল না থাকা, ওয়ার্কার ত্রুটি, মডেল চালু করতে ব্যর্থতা, বাতিল করা এবং ছোট মডেলে ফিরে যাওয়া পরীক্ষা করুন।
  • গোপনীয়তা: নেটওয়ার্ক অনুরোধ দেখে নিশ্চিত করুন যে মাইক্রোফোনের অডিও সার্ভার বা অ্যানালিটিকস পরিষেবায় আপলোড হচ্ছে না।
  • মোবাইলে সামঞ্জস্য: প্রকৃত ফোনে প্রথমবার, পরে আবার চালু করা এবং বারবার ডিকটেশনের পরীক্ষা করুন।

রেকর্ড করা PCM দিয়ে পরীক্ষা ইনফারেন্স স্ট্যাক যাচাইয়ের জন্য চমৎকার, কিন্তু এতে মাইক্রোফোন থেকে অডিও ধারণ কাজ করে কি না প্রমাণ হয় না। চূড়ান্ত গ্রহণযোগ্যতা পরীক্ষায় প্রকৃত মাইক্রোফোন ও আসল ইউজার ইন্টারফেস থাকতে হবে।

নির্ভরযোগ্য ব্রাউজার ভয়েস টাইপিংয়ের ব্যবহারিক স্থাপত্য

যে ওয়েবসাইটে ছোট, বহুভাষিক এবং গোপনীয়তা রক্ষাকারী ভয়েস ইনপুট দরকার, তার জন্য সবচেয়ে ব্যবহারিক স্থাপত্যটি ইচ্ছাকৃতভাবেই সহজ:

React microphone button
        |
        v
Permission request
        |
        v
Lazy model initialization
        |
        v
AudioWorklet PCM capture
        |
        v
Adaptive RMS / manual stop
        |
        v
Dedicated Worker
        |
        v
16 kHz audio resampling
        |
        v
Whisper Tiny or Base Q8
        |
        v
Compatible ONNX Runtime WASM
        |
        v
Whisper processor + tokenizer
        |
        v
Final transcript
        |
        v
Controlled React input

অ্যাপ্লিকেশনের নিজস্ব সার্ভার থেকে সংস্করণযুক্ত মডেল ও রানটাইম ফাইল পরিবেশন করা, মূল থ্রেডের বাইরে ইনফারেন্স চালানো, অপ্রয়োজনীয় মডেল ডাউনলোড এড়ানো, কাজ শেষে রিসোর্স ছেড়ে দেওয়া এবং স্পিচ রিকগনিশনের জন্য মাইক্রোফোনের অডিও কখনো আপলোড না করা উচিত।

WebGPU অ্যাক্সেলারেশন, নিউরাল ভয়েস অ্যাক্টিভিটি ডিটেকশন, চলমান আংশিক ট্রান্সক্রিপশন বা আরও মডেল স্তরের মতো জটিল বিকল্পগুলো পরবর্তী সময়ে বিবেচনা করা যায়, যখন পরিমাপ দিয়ে সেগুলোর বাড়তি জটিলতার যৌক্তিকতা বোঝা যাবে।

সবচেয়ে মূল্যবান শিক্ষা কোনো নির্দিষ্ট লাইব্রেরি সংস্করণ বা মডেলের আকার নয়। তা হলো ব্রাউজারের স্পিচ রিকগনিশন পাইপলাইনের প্রতিটি সংযোগস্থল যাচাই করার গুরুত্ব।

মাইক্রোফোনের অনুমতি চাওয়ার প্রম্পট কাজ করলেই অডিও ট্রান্সক্রাইব হচ্ছে না। মডেল ডাউনলোড হলেই তার ডিকোডার চালু হয়েছে—এমন নয়। ONNX সেশন সফল হলেই টোকেনাইজার উপলব্ধ—এমনও নয়। আবার ট্রান্সক্রিপশন সফল হলেই অ্যাপ্লিকেশন লেখাটি ঠিকভাবে বসিয়েছে, তা-ও নিশ্চিত নয়।

এই সুবিধাটি তখনই সম্পূর্ণ, যখন দর্শক মাইক্রোফোন চাপতে, স্বাভাবিকভাবে কথা বলতে, রেকর্ডিং থামাতে এবং শনাক্ত করা কথাগুলো সম্পাদনাযোগ্য ফিল্ডে দেখতে পারেন—স্পিচ রিকগনিশন সার্ভারে রেকর্ডিং না পাঠিয়েই।