अपने उपयोगकर्ताओं की हैंडराइटिंग को पहचानें

हैंडराइटिंग की पहचान करने वाले एपीआई की मदद से, हाथ से लिखे गए इनपुट से टेक्स्ट की पहचान की जा सकती है.

Handwriting Recognition API क्या है?

हैंडराइटिंग की पहचान करने वाले एपीआई की मदद से, उपयोगकर्ताओं की हैंडराइटिंग (स्याही) को टेक्स्ट में बदला जा सकता है. कुछ ऑपरेटिंग सिस्टम में, ऐसे एपीआई लंबे समय से शामिल हैं. इस नई सुविधा की मदद से, आपके वेब ऐप्लिकेशन आखिरकार इस सुविधा का इस्तेमाल कर सकते हैं. कन्वर्ज़न सीधे उपयोगकर्ता के डिवाइस पर होता है. यह ऑफ़लाइन मोड में भी काम करता है. इसके लिए, तीसरे पक्ष की लाइब्रेरी या सेवाओं को जोड़ने की ज़रूरत नहीं होती.

यह एपीआई, "ऑन-लाइन" या करीब-करीब रीयल-टाइम में पहचान करने की सुविधा देता है. इसका मतलब है कि उपयोगकर्ता के लिखते ही, लिखाई को पहचान लिया जाता है. इसके लिए, एक-एक स्ट्रोक को कैप्चर करके उसका विश्लेषण किया जाता है. ऑप्टिकल कैरेक्टर रिकग्निशन (ओसीआर) जैसी "ऑफ़लाइन" प्रोसेस के मुकाबले, ऑन-लाइन एल्गोरिदम ज़्यादा सटीक नतीजे दे सकते हैं. ऐसा, अलग-अलग इंक स्ट्रोक के समय के क्रम और दबाव जैसे अतिरिक्त सिग्नल की वजह से होता है.

लिखावट की पहचान करने वाले एपीआई के इस्तेमाल के सुझाए गए उदाहरण

इसका इस्तेमाल इन कामों के लिए किया जा सकता है:

  • नोट लेने वाले ऐसे ऐप्लिकेशन जिनमें उपयोगकर्ता, हाथ से लिखे गए नोट कैप्चर करके उन्हें टेक्स्ट में बदलना चाहते हैं.
  • फ़ॉर्म ऐप्लिकेशन, जहां समय की कमी की वजह से उपयोगकर्ता, पेन या उंगली से इनपुट कर सकते हैं.
  • ऐसे गेम जिनमें अक्षर या संख्याएं भरनी होती हैं, जैसे कि क्रॉसवर्ड, हैंगमैन या सुडोकू.

मौजूदा स्थिति

लिखावट की पहचान करने वाला एपीआई, Chromium 99 से उपलब्ध है.

लिखावट की पहचान करने वाले एपीआई का इस्तेमाल करने का तरीका

फ़ीचर का पता लगाना

नेविगेटर ऑब्जेक्ट पर createHandwritingRecognizer() तरीके के मौजूद होने की जांच करके, ब्राउज़र के साथ काम करने की सुविधा का पता लगाएं:

if ('createHandwritingRecognizer' in navigator) {
  // 🎉 The Handwriting Recognition API is supported!
}

मुख्य कॉन्सेप्ट

हैंडराइटिंग की पहचान करने वाला एपीआई, लिखावट वाले इनपुट को टेक्स्ट में बदल देता है. इस बात से कोई फ़र्क़ नहीं पड़ता कि इनपुट का तरीका क्या है (माउस, टच, पेन). एपीआई में चार मुख्य इकाइयां होती हैं:

  1. पॉइंट से पता चलता है कि किसी खास समय पर पॉइंटर कहां था.
  2. स्ट्रोक में एक या उससे ज़्यादा पॉइंट होते हैं. स्ट्रोक की रिकॉर्डिंग तब शुरू होती है, जब उपयोगकर्ता कर्सर को नीचे रखता है.जैसे, माउस के प्राइमरी बटन पर क्लिक करना या स्क्रीन को अपने पैन या उंगली से छूना. यह रिकॉर्डिंग तब खत्म होती है, जब उपयोगकर्ता कर्सर को फिर से ऊपर ले जाता है.
  3. ड्रॉइंग में एक या उससे ज़्यादा स्ट्रोक होते हैं. असल पहचान इस लेवल पर होती है.
  4. आवाज़ पहचानने की सुविधा को, इनपुट भाषा के हिसाब से कॉन्फ़िगर किया गया है. इसका इस्तेमाल, पहचान करने वाले टूल के कॉन्फ़िगरेशन के साथ ड्रॉइंग का एक इंस्टेंस बनाने के लिए किया जाता है.

इन कॉन्सेप्ट को खास इंटरफ़ेस और डिक्शनरी के तौर पर लागू किया जाता है. इनके बारे में हम जल्द ही बताएंगे.

लिखावट की पहचान करने वाले एपीआई की मुख्य इकाइयां: एक या उससे ज़्यादा पॉइंट से एक स्ट्रोक बनता है. एक या उससे ज़्यादा स्ट्रोक से एक ड्रॉइंग बनती है, जिसे पहचानने वाला टूल बनाता है. असल पहचान, ड्रॉइंग के लेवल पर होती है.

पहचानने वाला टूल बनाना

हाथ से लिखे गए इनपुट से टेक्स्ट की पहचान करने के लिए, आपको navigator.createHandwritingRecognizer() को कॉल करके और उसमें पाबंदियां डालकर, HandwritingRecognizer का एक इंस्टेंस पाना होगा. पाबंदियों से यह तय होता है कि लिखावट की पहचान करने के लिए किस मॉडल का इस्तेमाल किया जाना चाहिए. फ़िलहाल, भाषाओं की सूची को प्राथमिकता के हिसाब से तय किया जा सकता है:

const recognizer = await navigator.createHandwritingRecognizer({
  languages: ['en'],
});

जब ब्राउज़र आपका अनुरोध पूरा कर सकता है, तब यह तरीका एक HandwritingRecognizer के इंस्टेंस के साथ रिज़ॉल्व होने वाला प्रॉमिस दिखाता है. ऐसा न करने पर, यह गड़बड़ी के साथ वादा अस्वीकार कर देगा और लिखावट की पहचान करने की सुविधा उपलब्ध नहीं होगी. इसलिए, हो सकता है कि आप पहले पहचान करने वाली सुविधाओं के लिए, पहचान करने वाले टूल की सहायता टीम से संपर्क करना चाहें.

बोली पहचानने की सुविधा से जुड़ी सहायता के लिए क्वेरी करना

navigator.queryHandwritingRecognizerSupport() को कॉल करके, यह देखा जा सकता है कि टारगेट प्लैटफ़ॉर्म पर, हैंडराइटिंग की पहचान करने की उन सुविधाओं का इस्तेमाल किया जा सकता है या नहीं जिनका आपको इस्तेमाल करना है. नीचे दिए गए उदाहरण में, डेवलपर:

  • को अंग्रेज़ी में टेक्स्ट का पता लगाना है
  • उपलब्ध होने पर, कम संभावना वाले अन्य अनुमान पाएं
  • सेगमेंटेशन के नतीजे का ऐक्सेस पाएं. जैसे, पहचाने गए वर्णों के साथ-साथ, उन वर्णों को बनाने वाले पॉइंट और स्ट्रोक
const { languages, alternatives, segmentationResults } =
  await navigator.queryHandwritingRecognizerSupport({
    languages: ['en'],
    alternatives: true,
    segmentationResult: true,
  });

console.log(languages); // true or false
console.log(alternatives); // true or false
console.log(segmentationResult); // true or false

यह तरीका, नतीजे के ऑब्जेक्ट के साथ रिज़ॉल्व होने वाला प्रॉमिस दिखाता है. अगर ब्राउज़र, डेवलपर की बताई गई सुविधा के साथ काम करता है, तो इसकी वैल्यू true पर सेट हो जाएगी. ऐसा न करने पर, यह false पर सेट हो जाएगा. इस जानकारी का इस्तेमाल करके, अपने ऐप्लिकेशन में कुछ सुविधाओं को चालू या बंद किया जा सकता है. इसके अलावा, अपनी क्वेरी में बदलाव करके नई क्वेरी भी भेजी जा सकती है.

ड्रॉइंग बनाना

आपको अपने ऐप्लिकेशन में एक इनपुट एरिया उपलब्ध कराना चाहिए, जहां उपयोगकर्ता अपनी लिखावट में जानकारी डाल सके. परफ़ॉर्मेंस की वजह से, हमारा सुझाव है कि इसे कैनवस ऑब्जेक्ट की मदद से लागू करें. इस लेख में, इस हिस्से को लागू करने का सटीक तरीका नहीं बताया गया है. हालांकि, इसे लागू करने का तरीका जानने के लिए, डेमो देखें.

नई ड्रॉइंग शुरू करने के लिए, पहचानने वाले टूल पर startDrawing() तरीका कॉल करें. इस तरीके में, ऑब्जेक्ट की पहचान करने वाले एल्गोरिदम को बेहतर बनाने के लिए, अलग-अलग तरह के संकेत देने वाले ऑब्जेक्ट का इस्तेमाल किया जाता है. सभी संकेत देने की ज़रूरत नहीं है:

  • डाला जा रहा टेक्स्ट किस तरह का है: टेक्स्ट, ईमेल पते, नंबर या कोई एक वर्ण (recognitionType)
  • इनपुट डिवाइस का टाइप: माउस, टच या पेन इनपुट (inputType)
  • पिछला टेक्स्ट (textContext)
  • कम संभावना वाले वैकल्पिक अनुमान की संख्या, जो दिखाए जाने चाहिए (alternatives)
  • उपयोगकर्ता की पहचान करने वाले उन वर्णों ("ग्राफ़िम") की सूची जिन्हें उपयोगकर्ता डाल सकता है (graphemeSet)

हस्तलेखन की पहचान करने वाला एपीआई, पॉइंटर इवेंट के साथ बेहतर तरीके से काम करता है. ये इवेंट, किसी भी पॉइंटर डिवाइस से इनपुट लेने के लिए, एक एब्स्ट्रैक्ट इंटरफ़ेस उपलब्ध कराते हैं. पॉइंटर इवेंट के आर्ग्युमेंट में, इस्तेमाल किए जा रहे पॉइंटर का टाइप शामिल होता है. इसका मतलब है कि इनपुट टाइप का पता अपने-आप लगाने के लिए, पॉइंटर इवेंट का इस्तेमाल किया जा सकता है. नीचे दिए गए उदाहरण में, लिखावट की पहचान करने के लिए ड्रॉइंग, लिखावट वाले एरिया में pointerdown इवेंट की पहली बार होने पर अपने-आप बन जाती है. pointerType खाली हो सकता है या मालिकाना हक वाली वैल्यू पर सेट हो सकता है. इसलिए, मैंने एक जांच की सुविधा जोड़ी है, ताकि यह पक्का किया जा सके कि ड्रॉइंग के इनपुट टाइप के लिए सिर्फ़ काम करने वाली वैल्यू सेट की गई हों.

let drawing;
let activeStroke;

canvas.addEventListener('pointerdown', (event) => {
  if (!drawing) {
    drawing = recognizer.startDrawing({
      recognitionType: 'text', // email, number, per-character
      inputType: ['mouse', 'touch', 'pen'].find((type) => type === event.pointerType),
      textContext: 'Hello, ',
      alternatives: 2,
      graphemeSet: ['f', 'i', 'z', 'b', 'u'], // for a fizz buzz entry form
    });
  }
  startStroke(event);
});

स्ट्रोक जोड़ना

pointerdown इवेंट, नया स्ट्रोक शुरू करने के लिए भी सही जगह है. ऐसा करने के लिए, HandwritingStroke का नया उदाहरण बनाएं. साथ ही, आपको मौजूदा समय को रेफ़रंस के तौर पर सेव करना चाहिए, ताकि बाद में जोड़े गए पॉइंट के लिए इसका इस्तेमाल किया जा सके:

function startStroke(event) {
  activeStroke = {
    stroke: new HandwritingStroke(),
    startTime: Date.now(),
  };
  addPoint(event);
}

एक बिंदु जोड़ें

स्ट्रोक बनाने के बाद, आपको सीधे उसमें पहला पॉइंट जोड़ना चाहिए. बाद में आपको और भी पॉइंट जोड़ने होंगे. इसलिए, पॉइंट बनाने के लॉजिक को अलग तरीके से लागू करना बेहतर होगा. नीचे दिए गए उदाहरण में, addPoint() का तरीका रेफ़रंस टाइमस्टैंप से बीते समय का हिसाब लगाता है. समय की जानकारी देना ज़रूरी नहीं है. हालांकि, इससे ऑब्जेक्ट की पहचान करने की क्वालिटी को बेहतर बनाया जा सकता है. इसके बाद, यह पॉइंटर इवेंट से X और Y निर्देशांक पढ़ता है और मौजूदा स्ट्रोक में पॉइंट जोड़ता है.

function addPoint(event) {
  const timeElapsed = Date.now() - activeStroke.startTime;
  activeStroke.stroke.addPoint({
    x: event.offsetX,
    y: event.offsetY,
    t: timeElapsed,
  });
}

जब पॉइंटर को स्क्रीन पर एक जगह से दूसरी जगह ले जाया जाता है, तब pointermove इवेंट हैंडलर को कॉल किया जाता है. उन पॉइंट को भी स्ट्रोक में जोड़ना होगा. अगर पॉइंटर "डाउन" स्थिति में नहीं है, तो भी इवेंट ट्रिगर हो सकता है. उदाहरण के लिए, माउस बटन को दबाए बिना कर्सर को स्क्रीन पर घुमाने पर. यहां दिए गए उदाहरण में, इवेंट हैंडलर यह जांच करता है कि कोई ऐक्टिव स्ट्रोक मौजूद है या नहीं. साथ ही, उसमें नया पॉइंट जोड़ता है.

canvas.addEventListener('pointermove', (event) => {
  if (activeStroke) {
    addPoint(event);
  }
});

टेक्स्ट की पहचान करना

जब उपयोगकर्ता फिर से पॉइंटर हटाता है, तो addStroke() तरीके को कॉल करके, अपने ड्रॉइंग में स्ट्रोक जोड़ा जा सकता है. यहां दिए गए उदाहरण में activeStroke को भी रीसेट किया गया है, ताकि pointermove हैंडलर, पूरे हो चुके स्ट्रोक में पॉइंट न जोड़ सके.

इसके बाद, ड्रॉइंग पर getPrediction() तरीके को कॉल करके, उपयोगकर्ता के इनपुट को पहचानने का समय आ गया है. आम तौर पर, पहचान करने में कुछ सौ मिलीसेकंड से भी कम समय लगता है. इसलिए, ज़रूरत पड़ने पर, अनुमान बार-बार चलाए जा सकते हैं. नीचे दिए गए उदाहरण में, हर स्ट्रोक के पूरा होने के बाद नया अनुमान लगाया जाता है.

canvas.addEventListener('pointerup', async (event) => {
  drawing.addStroke(activeStroke.stroke);
  activeStroke = null;

  const [mostLikelyPrediction, ...lessLikelyAlternatives] = await drawing.getPrediction();
  if (mostLikelyPrediction) {
    console.log(mostLikelyPrediction.text);
  }
  lessLikelyAlternatives?.forEach((alternative) => console.log(alternative.text));
});

यह तरीका एक प्रॉमिस दिखाता है, जो अनुमान के एक कलेक्शन के साथ हल होता है. इस कलेक्शन को, उनके होने की संभावना के हिसाब से क्रम में लगाया जाता है. एलिमेंट की संख्या इस बात पर निर्भर करती है कि आपने alternatives हिंट में कौनसी वैल्यू दी है. इस ऐरे का इस्तेमाल करके, उपयोगकर्ता को मिलते-जुलते विकल्प दिखाए जा सकते हैं. साथ ही, उनसे कोई विकल्प चुना जा सकता है. इसके अलावा, सबसे सही अनुमान को भी चुना जा सकता है. उदाहरण के लिए, मैंने ऐसा ही किया है.

अनुमान वाले ऑब्जेक्ट में, पहचाने गए टेक्स्ट के साथ-साथ सेगमेंटेशन का वैकल्पिक नतीजा भी शामिल होता है. इस बारे में अगले सेक्शन में बताया गया है.

सेगमेंटेशन के नतीजों के साथ ज़्यादा जानकारी

अगर टारगेट प्लैटफ़ॉर्म पर सेगमेंटेशन की सुविधा काम करती है, तो अनुमान वाले ऑब्जेक्ट में सेगमेंटेशन का नतीजा भी शामिल हो सकता है. यह एक कलेक्शन है, जिसमें पहचाने गए सभी हस्तलिखित सेगमेंट शामिल होते हैं. यह पहचाने गए ऐसे वर्ण (grapheme) का कॉम्बिनेशन होता है जिसे उपयोगकर्ता पहचान सकता है. साथ ही, इसमें पहचाने गए टेक्स्ट (beginIndex, endIndex) में इसकी पोज़िशन और उसे बनाने वाले स्ट्रोक और पॉइंट शामिल होते हैं.

if (mostLikelyPrediction.segmentationResult) {
  mostLikelyPrediction.segmentationResult.forEach(
    ({ grapheme, beginIndex, endIndex, drawingSegments }) => {
      console.log(grapheme, beginIndex, endIndex);
      drawingSegments.forEach(({ strokeIndex, beginPointIndex, endPointIndex }) => {
        console.log(strokeIndex, beginPointIndex, endPointIndex);
      });
    },
  );
}

इस जानकारी का इस्तेमाल करके, कैनवस पर पहचाने गए ग्राफ़ेम को फिर से ट्रैक किया जा सकता है.

पहचाने गए हर ग्राफ़ेम के चारों ओर बॉक्स बनाए जाते हैं

पहचान की पुष्टि करना

पहचान की प्रोसेस पूरी होने के बाद, HandwritingDrawing पर clear() और HandwritingRecognizer पर finish() तरीका कॉल करके, संसाधनों को खाली किया जा सकता है:

drawing.clear();
recognizer.finish();

डेमो

वेब कॉम्पोनेंट <handwriting-textarea>, बदलाव करने के लिए एक ऐसा कंट्रोल लागू करता है जो धीरे-धीरे बेहतर होता जाता है. यह कंट्रोल, लिखावट की पहचान करने की सुविधा देता है. बदलाव करने के कंट्रोल के सबसे नीचे दाएं कोने में मौजूद बटन पर क्लिक करके, ड्रॉइंग मोड चालू किया जा सकता है. ड्रॉइंग पूरी करने के बाद, वेब कॉम्पोनेंट अपने-आप टेक्स्ट की पहचान करने की प्रोसेस शुरू कर देगा और पहचाने गए टेक्स्ट को, बदलाव करने वाले कंट्रोल में वापस जोड़ देगा. अगर आपके डिवाइस पर, लिखावट पहचानने वाले एपीआई का इस्तेमाल नहीं किया जा सकता या प्लैटफ़ॉर्म पर अनुरोध की गई सुविधाएं काम नहीं करती हैं, तो 'बदलाव करें' बटन नहीं दिखेगा. हालांकि, बदलाव करने के बुनियादी कंट्रोल का इस्तेमाल <textarea> के तौर पर किया जा सकता है.

वेब कॉम्पोनेंट, languages और recognitiontype के साथ-साथ बाहर से पहचान करने के व्यवहार को तय करने के लिए प्रॉपर्टी और एट्रिब्यूट उपलब्ध कराता है. value एट्रिब्यूट की मदद से, कंट्रोल का कॉन्टेंट सेट किया जा सकता है:

<handwriting-textarea languages="en" recognitiontype="text" value="Hello"></handwriting-textarea>

वैल्यू में हुए किसी भी बदलाव के बारे में जानने के लिए, input इवेंट को सुना जा सकता है.

Glitch पर इस डेमो का इस्तेमाल करके, कॉम्पोनेंट को आज़माया जा सकता है. साथ ही, सोर्स कोड को भी देखना न भूलें. अपने ऐप्लिकेशन में कंट्रोल का इस्तेमाल करने के लिए, इसे npm से पाएं.

सुरक्षा और अनुमतियां

Chromium टीम ने वेब प्लैटफ़ॉर्म की बेहतर सुविधाओं का ऐक्सेस कंट्रोल करना में बताए गए मुख्य सिद्धांतों का इस्तेमाल करके, लिखावट पहचानने वाले एपीआई को डिज़ाइन और लागू किया है. इन सिद्धांतों में, उपयोगकर्ता कंट्रोल, पारदर्शिता, और काम करने के तरीके शामिल हैं.

उपयोगकर्ता कंट्रोल

उपयोगकर्ता, हैंडराइटिंग की पहचान करने वाले एपीआई को बंद नहीं कर सकता. यह सिर्फ़ एचटीटीपीएस के ज़रिए डिलीवर की जाने वाली वेबसाइटों के लिए उपलब्ध है. साथ ही, इसे सिर्फ़ टॉप-लेवल ब्राउज़िंग कॉन्टेक्स्ट से कॉल किया जा सकता है.

पारदर्शिता

लिखावट की पहचान करने की सुविधा चालू होने पर, इसकी कोई जानकारी नहीं मिलती. फ़िंगरप्रिंटिंग को रोकने के लिए, ब्राउज़र कई तरह के उपाय करता है. जैसे, संभावित गलत इस्तेमाल का पता चलने पर, उपयोगकर्ता को अनुमति का अनुरोध दिखाना.

अनुमति का बना रहना

फ़िलहाल, लिखावट पहचानने की सुविधा देने वाला एपीआई, अनुमतियों के लिए कोई प्रॉम्प्ट नहीं दिखाता. इसलिए, अनुमति को किसी भी तरह से सेव करने की ज़रूरत नहीं है.

सुझाव/राय दें या शिकायत करें

Chromium टीम को यह जानना है कि लिखावट पहचानने वाले एपीआई का इस्तेमाल करने का आपका अनुभव कैसा रहा.

हमें एपीआई के डिज़ाइन के बारे में बताएं

क्या एपीआई में कुछ ऐसा है जो आपकी उम्मीद के मुताबिक काम नहीं करता? क्या आपके आइडिया को लागू करने के लिए, कोई तरीका या प्रॉपर्टी मौजूद नहीं है? क्या आपका सुरक्षा मॉडल के बारे में कोई सवाल या टिप्पणी है? उससे जुड़े GitHub repo पर, खास समस्या की शिकायत करें या किसी मौजूदा समस्या में अपने सुझाव जोड़ें.

लागू करने से जुड़ी समस्या की शिकायत करना

क्या आपको Chromium को लागू करने में कोई गड़बड़ी मिली? या क्या इसे लागू करने का तरीका, खास जानकारी से अलग है? new.crbug.com पर गड़बड़ी की शिकायत करें. इसमें ज़्यादा से ज़्यादा जानकारी शामिल करें. साथ ही, गड़बड़ी को दोहराने के लिए आसान निर्देश दें. इसके बाद, Components बॉक्स में Blink>Handwriting डालें. Glitch, तुरंत और आसानी से समस्या की जानकारी शेयर करने के लिए बहुत अच्छा है.

एपीआई के लिए सहायता दिखाना

क्या आपको हैंडराइटिंग की पहचान करने वाले एपीआई का इस्तेमाल करना है? सार्वजनिक तौर पर सहायता करने से, Chromium टीम को सुविधाओं को प्राथमिकता देने में मदद मिलती है. साथ ही, इससे ब्राउज़र के अन्य वेंडर को यह पता चलता है कि इन सुविधाओं को उपलब्ध कराना कितना ज़रूरी है.

WICG के Discourse थ्रेड पर शेयर करें कि आपको इसका इस्तेमाल कैसे करना है. #HandwritingRecognition हैशटैग का इस्तेमाल करके, @ChromiumDev को ट्वीट करें और हमें बताएं कि इसका इस्तेमाल कहां और कैसे किया जा रहा है.

आभार

इस दस्तावेज़ की समीक्षा जो मेडली, हॉन्गलिन यू, और ज़िएवी क्वान ने की है.