التعرف على الكتابة اليدوية للمستخدمين

تتيح لك واجهة برمجة التطبيقات Handwriting Recognition API التعرّف على النص من خلال إدخال نص مكتوب بخط اليد أثناء كتابته.

ما هي واجهة برمجة التطبيقات Handwriting Recognition API؟

تتيح لك واجهة برمجة التطبيقات Handwriting Recognition API تحويل الكتابة بخط اليد (الحبر) من المستخدمين إلى نص. كانت بعض أنظمة التشغيل تتضمّن منذ فترة طويلة واجهات برمجة تطبيقات مماثلة، وبفضل هذه الميزة الجديدة، يمكن لتطبيقات الويب أخيرًا استخدام هذه الوظيفة. تحدث عملية الإحالة الناجحة مباشرةً على جهاز المستخدم، وتعمل حتى في وضع عدم الاتّصال بالإنترنت، وكل ذلك بدون إضافة أي مكتبات أو خدمات تابعة لجهات خارجية.

تُنفِّذ واجهة برمجة التطبيقات هذه ما يُعرف بالتعرّف "على الإنترنت" أو التعرّف في الوقت الفعلي تقريبًا. وهذا يعني أنّه يتم التعرّف على الإدخال المكتوب بخط اليد أثناء رسمه من قِبل المستخدم من خلال تسجيل الخطوط الفردية وتحليلها. على عكس الإجراءات "غير المتصلة بالإنترنت"، مثل التعرّف البصري على الأحرف (OCR)، حيث يتم معرفة المنتج النهائي فقط، يمكن أن توفّر الخوارزميات "المتصلة بالإنترنت" مستوى أعلى من الدقة بسبب الإشارات الإضافية، مثل التسلسل الزمني وضغط خطوط الحبر الفردية.

حالات الاستخدام المقترَحة لواجهة برمجة التطبيقات Handwriting Recognition API

تشمل أمثلة الاستخدام ما يلي:

  • تطبيقات تدوين الملاحظات التي يريد المستخدمون فيها تدوين ملاحظات مكتوبة بخط اليد وترجمتها إلى نص
  • تطبيقات النماذج التي يمكن للمستخدمين فيها استخدام القلم أو الإدخال باستخدام الإصبع بسبب القيود الزمنية
  • الألعاب التي تتطلّب ملء أحرف أو أرقام، مثل ألعاب الكلمات المتقاطعة أو لعبة "الجلاد" أو لعبة سودوكو

الوضع الحالي

تتوفّر واجهة برمجة التطبيقات Handwriting Recognition API من الإصدار (Chromium 99).

كيفية استخدام واجهة برمجة التطبيقات Handwriting Recognition API

رصد الميزات

يمكنك رصد توافق المتصفّح من خلال التحقّق من توفّر طريقة createHandwritingRecognizer() في كائن المتصفّح:

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

المفاهيم الأساسية

تحوِّل واجهة برمجة التطبيقات Handwriting Recognition API النص المكتوب بخط اليد إلى نص، بغض النظر عن طريقة الإدخال (الماوس أو اللمس أو القلم). تتضمّن واجهة برمجة التطبيقات أربعة عناصر رئيسية:

  1. تمثّل النقطة موضع المؤشر في وقت معيّن.
  2. تتألّف الخطوط من نقطة واحدة أو أكثر. يبدأ تسجيل الخطوط عندما يضع المستخدِم المؤشر على الشاشة (أي ينقر على زر الماوس الأساسي أو يلمس الشاشة بالقلم أو بالإصبع)، وينتهي عندما يرفع المؤشر مرة أخرى.
  3. يتكوّن الرسم من خط واحد أو أكثر. ويتم التعرّف الفعلي على هذا المستوى.
  4. تم ضبط أداة التعرّف على لغة الإدخال المتوقّعة. يتم استخدامه لإنشاء مثيل لرسم مع تطبيق إعدادات المعرّف.

يتم تنفيذ هذه المفاهيم كواجهات وقواميس محدّدة، وسنتناولها قريبًا.

العناصر الأساسية لواجهة برمجة التطبيقات Handwriting Recognition API: تتكون الخطوط من نقطة واحدة أو أكثر، ويتكون الرسم من خط واحد أو أكثر، وهو ما ينشئه معرّف النصوص. ويتم التعرّف الفعلي على مستوى الرسم.

إنشاء معرِّف

للتعرّف على النص من الإدخال المكتوب بخط اليد، عليك الحصول على مثيل من HandwritingRecognizer من خلال استدعاء navigator.createHandwritingRecognizer() وضبط القيود عليه. تحدِّد القيود نموذج التعرّف على الكتابة اليدوية الذي يجب استخدامه. يمكنك حاليًا تحديد قائمة باللغات حسب ترتيب التفضيل:

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

تُعرِض الطريقة وعدًا بحلّ مثيل HandwritingRecognizer عندما يتمكّن ال browser من تلبية طلبك. بخلاف ذلك، سيتم رفض الوعد مع ظهور خطأ، و لن تكون ميزة التعرّف على الكتابة اليدوية متاحة. لهذا السبب، قد تحتاج إلى الرجوع إلى فريق دعم المعرِّف بشأن ميزات معيّنة للتعرّف أولاً.

إتاحة ميزة طلب التعرّف

من خلال الاتصال برقم 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)

تتوافق واجهة Handwriting Recognition API بشكل جيد مع أحداث المؤشر التي توفّر واجهة مجردة لاستخدام الإدخال من أي جهاز مؤشر. تحتوي وسيطات حدث المؤشر على نوع المؤشر المستخدَم. وهذا يعني أنّه يمكنك استخدام أحداث المؤشر لتحديد نوع الإدخال تلقائيًا. في المثال التالي، يتم تلقائيًا إنشاء الرسم الخاص بالتعرّف على الكتابة اليدوية عند أول مرّة لحدث 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() على drawing. تستغرق عملية التعرّف عادةً أقل من بضع مئات من المللي ثانية، لذا يمكنك إجراء التنبؤات بشكل متكرّر إذا لزم الأمر. يُجري المثال التالي عملية توقّع جديدة بعد كلّ خطوة مكتملة.

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. يمكنك استخدام هذه الصفيف لتقديم خيارات للمطابقات المحتمَلة للمستخدم، وطلب تحديد أحد الخيارات. بدلاً من ذلك، يمكنك استخدام التوقع الأكثر ترجيحًا، وهو ما أفعل في المثال التالي.

يحتوي عنصر التوقّع على النص الذي تم التعرّف عليه ونتيجة اختيارية للتقسيم، وسأ discuss في القسم التالي.

إحصاءات تفصيلية مع نتائج التصنيف

يمكن أن يحتوي عنصر التوقّع أيضًا على نتيجة تقسيم إذا كانت المنصة المستهدَفة تتيح ذلك. هذا صفيف يحتوي على جميع أجزاء الكتابة اليدوية التي تم التعرّف عليها، وهي عبارة عن مجموعة من الأحرف التي يمكن للمستخدم التعرّف عليها (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);
      });
    },
  );
}

يمكنك استخدام هذه المعلومات لتتبُّع الرموز المرسومة التي تم التعرّف عليها على اللوحة مرة أخرى.

يتم رسم مربّعات حول كل حرف مُعرَّف.

التعرّف الكامل

بعد اكتمال عملية التعرّف، يمكنك تحرير الموارد من خلال استدعاء طريقة clear() في HandwritingDrawing وطريقة finish() فيHandwritingRecognizer:

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

عرض توضيحي

ينفِّذ عنصر الويب <handwriting-textarea> عنصر تحكّم في التعديل محسَّنًا بشكل تدريجي، ويمكنه التعرّف على الكتابة اليدوية. من خلال النقر على الزر في أسفل يسار عنصر التحكّم في التعديل، يمكنك تفعيل وضع الرسم. عند إكمال الرسم، سيبدأ عنصر الويب تلقائيًا عملية التعرّف ويضيف النص الذي تم التعرّف عليه مرة أخرى إلى عنصر التحكّم في التعديل. إذا لم يكن واجهة برمجة التطبيقات Handwriting Recognition متوافقة على الإطلاق، أو إذا كانت المنصة لا تتيح الميزات المطلوبة، سيتم إخفاء زر التعديل. يبقى عنصر التحكّم الأساسي في التعديل قابلاً للاستخدام <textarea>.

يقدّم مكوّن الويب سمات وخصائص لتحديد سلوك التعرّف من الخارج، بما في ذلك languages وrecognitiontype. يمكنك ضبط محتوى عنصر التحكّم من خلال سمة value:

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

لمعرفة أي تغييرات تطرأ على القيمة، يمكنك الاستماع إلى الحدث input.

يمكنك تجربة المكوّن باستخدام هذا الإصدار التجريبي على Glitch. احرص أيضًا على إلقاء نظرة على رمز المصدر. لاستخدام عنصر التحكّم في تطبيقك، يمكنك الحصول عليه من npm.

الأمان والأذونات

صمم فريق Chromium واجهة Handwriting Recognition API ونفّذها باستخدام المبادئ الأساسية المحدّدة في مقالة التحكّم في الوصول إلى ميزات فعّالة لمنصّة الويب، بما في ذلك التحكّم الذي يمارسه المستخدم والشفافية وسهولة الاستخدام.

التحكّم في المستخدم

لا يمكن للمستخدم إيقاف واجهة برمجة التطبيقات Handwriting Recognition API. ولا يتوفّر إلا للمواقع الإلكترونية التي يتم عرضها من خلال HTTPS، ولا يمكن استدعاؤها إلا من سياق التصفّح على مستوى أعلى.

الشفافية

لا تتوفّر أي إشارة إلى ما إذا كانت ميزة التعرّف على الكتابة اليدوية مفعّلة. لمنع تقنية "البصمة الرقمية"، ينفِّذ المتصفّح إجراءات مضادة، مثل عرض طلب الحصول على إذن للمستخدم عند رصده إساءة استخدام محتملة.

الاحتفاظ بالأذونات

لا تعرض واجهة برمجة التطبيقات Handwriting Recognition API حاليًا أي طلبات للحصول على أذونات. وبالتالي، ليس من الضروري الاحتفاظ بالإذن بأي شكل من الأشكال.

ملاحظات

يريد فريق Chromium معرفة تجاربك مع واجهة برمجة التطبيقات Handwriting Recognition API.

أخبِرنا عن تصميم واجهة برمجة التطبيقات.

هل هناك مشكلة في واجهة برمجة التطبيقات لا تعمل على النحو المتوقّع؟ هل هناك طُرق أو سمات مفقودة تحتاجها لتنفيذ فكرتك؟ هل لديك سؤال أو تعليق حول ملف أمان الحساب؟ يمكنك الإبلاغ عن مشكلة في المواصفات في مستودع GitHub المقابل، أو إضافة ملاحظاتك إلى مشكلة حالية.

الإبلاغ عن مشكلة في التنفيذ

هل عثرت على خطأ في عملية تنفيذ Chromium؟ أم أنّ عملية التنفيذ مختلفة عن المواصفات؟ يمكنك الإبلاغ عن خلل على الرابط new.crbug.com. احرص على تضمين أكبر قدر ممكن من التفاصيل، وتعليمات بسيطة لإعادة إنتاج الخلل، وأدخِل Blink>Handwriting في مربّع المكوّنات. يُعدّ تطبيق Glitch مثاليًا لمشاركة عمليات إعادة الإنتاج بسرعة وسهولة.

إظهار الدعم لواجهة برمجة التطبيقات

هل تخطّط لاستخدام واجهة برمجة التطبيقات Handwriting Recognition API؟ يساعد دعمك العلني فريق Chromium في تحديد الميزات ذات الأولوية وإظهار مدى أهمية توفيرها لمطوّري المتصفّحات الآخرين.

شارِك كيفية استخدامك له في سلسلة محادثات Discourse في WICG. أرسِل تغريدة إلى حساب ‎@ChromiumDev باستخدام الهاشتاغ #HandwritingRecognition وأطلِعنا على مكان استخدامك للميزة وطريقة استخدامك لها.

الشكر والتقدير

راجع هذا المستند كلّ من جو ميدلي، هونغلين يو وجيوي تشياو.