উক্তি ভেতরে কীভাবে কাজ করে

যারা জানতে চান উক্তিকে বিশ্বাস করা যায় কিনা, আর কীভাবে বানানো, তাদের জন্য। সব কোড GitHub এ খোলা।

অংশগুলো

উক্তি একটা Manifest V3 Chrome এক্সটেনশন। এর অংশ:

  • কন্টেন্ট স্ক্রিপ্ট: প্রতিটা পেজে চলে। ভাসমান কন্ট্রোলটা দেখায়, আর লেখা বক্সে বসায়। কন্ট্রোলটা একটা shadow root এর ভেতরে থাকে, তাই কোনো সাইটের CSS এটাকে ছুঁতে পারে না, আর এটাও সাইটের কিছু ছোঁয় না।
  • অফস্ক্রিন পেজ: একটা লুকানো পেজ যেখানে মাইক্রোফোন খোলে, Web Speech API দিয়ে কথা চেনা হয় (ভাষা bn-BD বা bn-IN), আর Chrome এর Translator API দিয়ে অনুবাদ হয়।
  • সার্ভিস ওয়ার্কার: এই দুইয়ের মাঝে বার্তা আদান-প্রদান করে।
  • বাংলিশ ইঞ্জিন: উচ্চারণের নিয়ম, একটা অভিধান, আর সাড়ে চার লাখ বাংলা শব্দের তালিকা, যা ৭০৪ KB এর একটা Bloom filter হিসেবে এক্সটেনশনের ভেতরেই থাকে।

অনুমতি

মাত্র দুইটা: storage (সেটিং আর শব্দের তালিকা রাখার জন্য) আর offscreen (লুকানো পেজটার জন্য)। কোনো host_permissions নেই।

তবু Chrome ইনস্টলের সময় বলে “Read and change all your data on all websites”। এটা আসে কন্টেন্ট স্ক্রিপ্টের matches থেকে, যা সব http আর https পেজ ধরে, কোনো অনুমতি থেকে না। Chrome এর নিজের getPermissionWarningsByManifest দিয়ে মাপা। activeTab দিয়ে এটা এড়ানো যেত, কিন্তু তখন বক্সে ক্লিক করলে কন্ট্রোল নিজে থেকে আসত না, প্রতি ট্যাবে আগে টুলবারের আইকন চাপতে হতো। উক্তির মূল কাজটাই তাতে হারিয়ে যেত।

নেটওয়ার্ক

উক্তির নিজের কোড কোনো নেটওয়ার্ক অনুরোধ পাঠায় না। দুইভাবে এটা নিশ্চিত:

  • উক্তির নিজের পেজগুলোতে (পপআপ, সেটআপ, শব্দের পেজ, অফস্ক্রিন পেজ) manifest এর content security policy তে connect-src 'none', তাই কোনো অনুরোধ Chrome নিজেই আটকে দেয়। একটা টেস্ট ইচ্ছা করে অনুরোধ পাঠিয়ে দেখে যে সেটা আটকায়।
  • কন্টেন্ট স্ক্রিপ্ট চলে প্রতিটা সাইটের নিজস্ব নিয়মে, তাই সেখানে নিশ্চয়তা কোড নিজেই: একটা টেস্ট প্রতিটা কোড ফাইলে fetch, XMLHttpRequest, WebSocket, EventSource, sendBeacon, importScripts আর বাইরের src খোঁজে।

যা নেটওয়ার্কে যায় তা Chrome এর কাজ: Web Speech এর অডিও Google এর কাছে, আর ভাষা প্যাক নামানো।

কঠিন অংশ: লেখা বক্সে বসানো

ব্যবহারকারী এটা দেখেন না, কিন্তু উক্তির সবচেয়ে বেশি কাজ এখানেই।

প্রতিটা আধুনিক এডিটর লেখা নেয় নিজের মতো করে। Gemini এর বক্স Quill দিয়ে বানানো: বাইরে থেকে paste করলে সেটা পেজে বসতে দেয়, তারপর এক মুহূর্ত পরে নিজের ভেতরের হিসাব থেকে পেজটা আবার লিখে ফেলে, বসানো লেখা মুছে যায়। WhatsApp এর বক্স Lexical দিয়ে, যা ঠিক উল্টো: শুধু paste মানে, আর কিছু না। তাই “একভাবে বসিয়ে সাথে সাথে দেখে নেওয়া” দুই জায়গাতেই ভুল ফল দেয়।

উক্তি তিনটা উপায় একটার পর একটা চেষ্টা করে: paste, execCommand, আর সরাসরি Range। প্রতিটার পর এডিটরকে তার কাজ শেষ করার সময় দেয়, তারপর দেখে বক্সে আসলে কী আছে। আর লেখার আগে নিশ্চিত হয় যে পুরো বক্সটা সত্যিই সিলেক্ট হয়েছে, নইলে কার্সরের জায়গায় paste হয়ে বাক্যটা দুইবার বসে যেত। কোনো উপায়েই না হলে আগের লেখা হুবহু ফিরিয়ে রাখে, আর বলে দেয় যে পারেনি।

তাই উক্তি এমন অনেক জায়গায় কাজ করে যেখানে অন্য টুল আটকে যায়। আর যেখানে পারে না, সেখানে আপনার লেখা নষ্ট করে না।

পাসওয়ার্ড আর পেমেন্টের ঘর

type="password", autocomplete এর one-time-code আর cc-* মান, CSS দিয়ে ডট করা ঘর, আর contenteditable দিয়ে বানানো পিন বা কার্ডের ঘর বাদ দেওয়া হয়। বাদ দেওয়া হয় ব্যবহারের মুহূর্তেও আবার যাচাই করে। কোনো চিহ্ন ছাড়া সাধারণ ঘর হিসেবে বানানো পাসওয়ার্ডের ঘর চেনা যায় না, এটা একটা সীমা।

নিরাপত্তা

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

যা যাচাই করা হয়নি

ক্লাউডে চলা টেস্টগুলো gemini.google.com বা web.whatsapp.com এ পৌঁছাতে পারে না। তাই এই এডিটরগুলোর মতো আচরণ করা নকল পেজ বানিয়ে টেস্ট করা হয়। আসল সাইটে পরীক্ষা হয় নির্মাতার নিজের কম্পিউটারে। Gemini তে ডিক্টেশন এখনো খোলা সমস্যা।