हैंडराइटिंग की पहचान करने वाले एपीआई की मदद से, हाथ से लिखे गए टेक्स्ट की पहचान रीयल टाइम में की जा सकती है.
Handwriting Recognition API क्या है?
हैंडराइटिंग की पहचान करने वाले एपीआई की मदद से, अपने उपयोगकर्ताओं की हैंडराइटिंग (स्याही) को टेक्स्ट में बदला जा सकता है. कुछ ऑपरेटिंग सिस्टम में, इस तरह के एपीआई पहले से ही शामिल हैं. इस नई सुविधा के साथ, आपके वेब ऐप्लिकेशन अब इस सुविधा का इस्तेमाल कर सकते हैं. यह कन्वर्ज़न, सीधे तौर पर उपयोगकर्ता के डिवाइस पर होता है. यह ऑफ़लाइन मोड में भी काम करता है. इसके लिए, तीसरे पक्ष की किसी भी लाइब्रेरी या सेवा को जोड़ने की ज़रूरत नहीं होती.
यह एपीआई, "ऑन-लाइन" या करीब-करीब रीयल-टाइम में पहचान करने की सुविधा लागू करता है. इसका मतलब है कि उपयोगकर्ता के हाथ से लिखे गए इनपुट को तब पहचाना जाता है, जब वह उसे एक-एक स्ट्रोक में कैप्चर और विश्लेषण करके बनाता है. ऑप्टिकल कैरेक्टर रिकग्निशन (ओसीआर) जैसी "ऑफ़लाइन" प्रक्रियाओं में, सिर्फ़ आखिरी प्रॉडक्ट के बारे में पता चलता है. इसके उलट, ऑनलाइन एल्गोरिदम ज़्यादा सटीक नतीजे दे सकते हैं. ऐसा इसलिए, क्योंकि वे समय के साथ होने वाले बदलाव और इंक स्ट्रोक के दबाव जैसे अतिरिक्त सिग्नल का इस्तेमाल करते हैं.
Handwriting Recognition API के इस्तेमाल के सुझाव
उदाहरण के लिए, इनका इस्तेमाल इन कामों के लिए किया जा सकता है:
- नोट लेने वाले ऐप्लिकेशन, जहां उपयोगकर्ता हाथ से लिखे गए नोट कैप्चर करना चाहते हैं और उन्हें टेक्स्ट में बदलना चाहते हैं.
- ऐसे फ़ॉर्म ऐप्लिकेशन जहां समय की कमी की वजह से, उपयोगकर्ता स्टाइलस या उंगली से इनपुट दे सकते हैं.
- ऐसे गेम जिनमें अक्षर या संख्याएं भरनी होती हैं. जैसे, क्रॉसवर्ड, हैंगमैन या सुडोकू.
मौजूदा स्थिति
लिखावट की पहचान करने वाला API, (Chromium 99) से उपलब्ध है.
Handwriting Recognition API का इस्तेमाल करने का तरीका
फ़ीचर का पता लगाने की सुविधा
ब्राउज़र में सुविधा काम करती है या नहीं, यह पता लगाने के लिए नेविगेटर ऑब्जेक्ट पर createHandwritingRecognizer()
तरीके की मौजूदगी की जांच करें:
if ('createHandwritingRecognizer' in navigator) {
// 🎉 The Handwriting Recognition API is supported!
}
मुख्य सिद्धांत
हस्तलेखन की पहचान करने वाला API, हाथ से लिखे गए इनपुट को टेक्स्ट में बदलता है. इससे कोई फ़र्क़ नहीं पड़ता कि इनपुट किस तरीके से दिया गया है (माउस, टच, स्टाइलस). इस एपीआई में चार मुख्य इकाइयां होती हैं:
- पॉइंट से पता चलता है कि किसी खास समय पर पॉइंटर कहां था.
- स्ट्रोक में एक या उससे ज़्यादा पॉइंट होते हैं. स्ट्रोक की रिकॉर्डिंग तब शुरू होती है, जब उपयोगकर्ता पॉइंटर को नीचे रखता है.इसका मतलब है कि वह माउस के प्राइमरी बटन पर क्लिक करता है या स्टाइलस या उंगली से स्क्रीन को छूता है. यह रिकॉर्डिंग तब खत्म होती है, जब वह पॉइंटर को वापस ऊपर उठाता है.
- ड्राइंग में एक या उससे ज़्यादा स्ट्रोक होते हैं. इस लेवल पर, असल में आवाज़ को पहचाना जाता है.
- पहचानकर्ता को, इनपुट के लिए इस्तेमाल की जाने वाली भाषा के हिसाब से कॉन्फ़िगर किया गया हो. इसका इस्तेमाल, पहचान करने वाले टूल के कॉन्फ़िगरेशन के साथ ड्राइंग का इंस्टेंस बनाने के लिए किया जाता है.
इन कॉन्सेप्ट को खास इंटरफ़ेस और डिक्शनरी के तौर पर लागू किया जाता है. इनके बारे में हम जल्द ही बात करेंगे.
पहचान करने वाला टूल बनाना
हाथ से लिखे गए टेक्स्ट को पहचानने के लिए, आपको navigator.createHandwritingRecognizer()
को कॉल करके और उसमें शर्तें पास करके, HandwritingRecognizer
का इंस्टेंस पाना होगा. लिखावट की पहचान करने के लिए किस मॉडल का इस्तेमाल किया जाना चाहिए, यह कंस्ट्रेंट तय करते हैं. फ़िलहाल, अपनी पसंद के हिसाब से भाषाओं की सूची तय की जा सकती है:
const recognizer = await navigator.createHandwritingRecognizer({
languages: ['en'],
});
यह तरीका, एक प्रॉमिस दिखाता है. जब ब्राउज़र आपके अनुरोध को पूरा कर सकता है, तब यह प्रॉमिस HandwritingRecognizer
के इंस्टेंस के साथ रिज़ॉल्व होता है. ऐसा न होने पर, यह गड़बड़ी के साथ प्रॉमिस को अस्वीकार कर देगा. साथ ही, लिखावट को पहचानने की सुविधा उपलब्ध नहीं होगी. इसलिए, आपको पहले यह क्वेरी करनी चाहिए कि रिकॉग्नाइज़र, पहचान करने की खास सुविधाओं के साथ काम करता है या नहीं.
पहचान करने वाले की सहायता के बारे में क्वेरी करना
navigator.queryHandwritingRecognizer()
को कॉल करके, यह पता लगाया जा सकता है कि टारगेट प्लैटफ़ॉर्म, हैंडराइटिंग की पहचान करने की उन सुविधाओं के साथ काम करता है या नहीं जिनका आपको इस्तेमाल करना है. यह तरीका, navigator.createHandwritingRecognizer()
तरीके की तरह ही कंस्ट्रेंट ऑब्जेक्ट लेता है. इसमें अनुरोध की गई भाषाओं की सूची होती है. अगर पहचान करने वाला कोई ऐसा टूल मिलता है जो इस सुविधा के साथ काम करता है, तो यह तरीका एक प्रॉमिस दिखाता है. इस प्रॉमिस को रिज़ॉल्व करने पर, एक नतीजा ऑब्जेक्ट मिलता है. ऐसा न होने पर, प्रॉमिस null
पर रिज़ॉल्व हो जाता है.
यहां दिए गए उदाहरण में, डेवलपर ने:
- को अंग्रेज़ी में लिखे गए टेक्स्ट का पता लगाना है
- जब उपलब्ध हो, तो कम संभावना वाले अन्य अनुमान पाएं
- सेगमेंटेशन के नतीजे का ऐक्सेस पाएं. इसका मतलब है कि पहचाने गए वर्णों के साथ-साथ, उन्हें बनाने वाले पॉइंट और स्ट्रोक भी ऐक्सेस किए जा सकते हैं
const result =
await navigator.queryHandwritingRecognizerSupport({
languages: ['en']
});
console.log(result?.textAlternatives); // true if alternatives are supported
console.log(result?.textSegmentation); // true if segmentation is supported
अगर ब्राउज़र, डेवलपर को ज़रूरी सुविधा के साथ काम करता है, तो नतीजे के ऑब्जेक्ट में इसकी वैल्यू true
पर सेट हो जाएगी. ऐसा न करने पर, इसे false
पर सेट कर दिया जाएगा.
इस जानकारी का इस्तेमाल करके, अपने ऐप्लिकेशन में कुछ सुविधाओं को चालू या बंद किया जा सकता है. इसके अलावा, अलग-अलग भाषाओं के लिए नई क्वेरी भेजी जा सकती है.
ड्रॉइंग बनाना
आपको अपने ऐप्लिकेशन में एक इनपुट एरिया उपलब्ध कराना होगा, जहां उपयोगकर्ता हाथ से लिखकर जानकारी डाल सके. परफ़ॉर्मेंस को बेहतर बनाने के लिए, हमारा सुझाव है कि आप इसे कैनवस ऑब्जेक्ट की मदद से लागू करें. इस लेख में, इस हिस्से को लागू करने के बारे में पूरी जानकारी नहीं दी गई है. हालांकि, इसे लागू करने का तरीका जानने के लिए, डेमो देखें.
नई ड्राइंग शुरू करने के लिए, पहचान करने वाले टूल पर startDrawing()
तरीके को कॉल करें. इस तरीके में, एक ऐसा ऑब्जेक्ट लिया जाता है जिसमें पहचान करने वाले एल्गोरिदम को बेहतर बनाने के लिए अलग-अलग हिंट शामिल होते हैं. सभी सुझाव वैकल्पिक हैं:
- डाला जा रहा टेक्स्ट: टेक्स्ट, ईमेल पते, नंबर या कोई वर्ण
(
recognitionType
) - इनपुट डिवाइस का टाइप: माउस, टच या स्टाइलस इनपुट (
inputType
) - ऊपर दिया गया टेक्स्ट (
textContext
) - कम संभावना वाली वैकल्पिक अनुमानों की संख्या जिन्हें दिखाया जाना चाहिए (
alternatives
) - उपयोगकर्ता के हिसाब से पहचान किए जा सकने वाले वर्णों ("ग्राफ़ेम") की सूची. उपयोगकर्ता के इन वर्णों को डालने की संभावना सबसे ज़्यादा होती है
(
graphemeSet
)
Handwriting Recognition API, Pointer Events के साथ अच्छी तरह से काम करता है. Pointer Events, किसी भी पॉइंटिंग डिवाइस से इनपुट पाने के लिए एक ऐब्स्ट्रैक्ट इंटरफ़ेस उपलब्ध कराते हैं. पॉइंटर इवेंट के आर्ग्युमेंट में, इस्तेमाल किए जा रहे पॉइंटर का टाइप शामिल होता है. इसका मतलब है कि इनपुट टाइप का पता अपने-आप लगाने के लिए, पॉइंटर इवेंट का इस्तेमाल किया जा सकता है. इस उदाहरण में, लिखावट की पहचान करने के लिए ड्राइंग अपने-आप बन जाती है. ऐसा तब होता है, जब लिखावट वाली जगह पर पहली बार pointerdown
इवेंट होता है. pointerType
खाली हो सकता है या इसे मालिकाना हक वाली वैल्यू पर सेट किया जा सकता है. इसलिए, मैंने एक जैसा होने की जांच करने की सुविधा जोड़ी है, ताकि यह पक्का किया जा सके कि ड्राइंग के इनपुट टाइप के लिए सिर्फ़ काम करने वाली वैल्यू सेट की गई हैं.
let drawing;
let activeStroke;
canvas.addEventListener('pointerdown', (event) => {
if (!drawing) {
drawing = recognizer.startDrawing({
recognitionType: 'text', // email, number, per-character
inputType: ['mouse', 'touch', 'stylus'].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
इवेंट को सुना जा सकता है.
GitHub पर मौजूद इस डेमो का इस्तेमाल करके, इस कॉम्पोनेंट को आज़माया जा सकता है. साथ ही, सोर्स कोड को भी ज़रूर देखें. अपने ऐप्लिकेशन में कंट्रोल का इस्तेमाल करने के लिए, इसे npm से पाएं.
सुरक्षा और अनुमतियां
Chromium टीम ने Handwriting Recognition API को डिज़ाइन और लागू किया है. इसके लिए, वेब प्लैटफ़ॉर्म की बेहतर सुविधाओं का ऐक्सेस कंट्रोल करना में बताए गए मुख्य सिद्धांतों का इस्तेमाल किया गया है. इनमें उपयोगकर्ता का कंट्रोल, पारदर्शिता, और एर्गोनॉमिक्स शामिल हैं.
उपयोगकर्ता के कंट्रोल
उपयोगकर्ता, Handwriting Recognition API को बंद नहीं कर सकता. यह सिर्फ़ उन वेबसाइटों के लिए उपलब्ध है जो HTTPS के ज़रिए डिलीवर की जाती हैं. साथ ही, इसे सिर्फ़ टॉप-लेवल ब्राउज़िंग कॉन्टेक्स्ट से कॉल किया जा सकता है.
पारदर्शिता
यह नहीं बताया जाता कि हैंडराइटिंग की पहचान करने की सुविधा चालू है या नहीं. फ़िंगरप्रिंटिंग को रोकने के लिए, ब्राउज़र कुछ तरीके अपनाता है. जैसे, जब उसे संभावित गलत इस्तेमाल का पता चलता है, तब वह उपयोगकर्ता को अनुमति मांगने वाला प्रॉम्प्ट दिखाता है.
अनुमति की स्थिति
फ़िलहाल, Handwriting Recognition API किसी भी अनुमति का प्रॉम्प्ट नहीं दिखाता है. इसलिए, अनुमति को किसी भी तरह से सेव करने की ज़रूरत नहीं होती.
सुझाव/राय दें या शिकायत करें
Chromium टीम, Handwriting Recognition API को इस्तेमाल करने से जुड़े आपके अनुभव के बारे में जानना चाहती है.
हमें एपीआई डिज़ाइन के बारे में बताएं
क्या एपीआई के बारे में कुछ ऐसा है जो आपकी उम्मीद के मुताबिक काम नहीं करता? इसके अलावा, क्या आपको अपने आइडिया को लागू करने के लिए, कुछ और तरीकों या प्रॉपर्टी की ज़रूरत है? क्या आपको सुरक्षा मॉडल के बारे में कोई सवाल पूछना है या कोई टिप्पणी करनी है? GitHub repo पर, स्पेसिफ़िकेशन से जुड़ी समस्या की शिकायत करें या किसी मौजूदा समस्या के बारे में अपने विचार जोड़ें.
लागू करने से जुड़ी समस्या की शिकायत करना
क्या आपको Chromium के इस्तेमाल में कोई गड़बड़ी मिली? या क्या लागू करने का तरीका, स्पेसिफ़िकेशन से अलग है?
new.crbug.com पर जाकर, गड़बड़ी की रिपोर्ट करें. इसमें ज़्यादा से ज़्यादा जानकारी शामिल करें. साथ ही, गड़बड़ी को दोहराने के लिए आसान निर्देश दें और कॉम्पोनेंट बॉक्स में Blink>Handwriting
डालें.
एपीआई के लिए सहायता दिखाना
क्या आपको हैंडराइटिंग की पहचान करने वाले एपीआई का इस्तेमाल करना है? सार्वजनिक तौर पर की गई आपकी मदद से, Chromium टीम को सुविधाओं को प्राथमिकता देने में मदद मिलती है. साथ ही, इससे ब्राउज़र बनाने वाली अन्य कंपनियों को यह पता चलता है कि इन सुविधाओं को सपोर्ट करना कितना ज़रूरी है.
WICG Discourse थ्रेड पर, हमें बताएं कि आपको इसका इस्तेमाल कैसे करना है. #HandwritingRecognition
हैशटैग का इस्तेमाल करके, @ChromiumDev को ट्वीट करें. साथ ही, हमें बताएं कि इसका इस्तेमाल कहां और कैसे किया जा रहा है.
सहायक लिंक्स
- सुविधा के बारे में जानकारी
- ड्राफ़्ट स्पेसिफ़िकेशन
- GitHub repo
- ChromeStatus
- Chromium में गड़बड़ी
- TAG की समीक्षा
- प्रोटोटाइप बनाने का इरादा
- WebKit-Dev थ्रेड
- Mozilla के स्टैंडर्ड की स्थिति
Acknowledgements
इस दस्तावेज़ की समीक्षा जो मेडली, होंगलिन यू, और जिएवेई कियान ने की है.