זיהוי המשתמשים שלך' כתב יד

ממשק ה-API לזיהוי כתבי יד מאפשר לכם לזהות טקסט מקלט בכתב יד בזמן ההתרחשות שלו.

מהו ממשק ה-API לזיהוי כתבי יד?

ה-API לזיהוי כתבי יד מאפשר להמיר כתב יד (דיו) מהמשתמשים שלכם לטקסט. חלק ממערכות ההפעלה כוללות כבר זמן רב ממשקי API כאלה, ובזכות היכולת החדשה הזו, אפליקציות האינטרנט שלכם יכולות להשתמש באופן סופי בפונקציונליות הזו. ההמרה מתבצעת ישירות במכשיר של המשתמש ופועלת גם במצב אופליין, וכל זה בלי להוסיף ספריות או שירותים של צד שלישי.

ה-API הזה מיישם זיהוי מה שמכונה 'באתר' או כמעט בזמן אמת. פירוש הדבר הוא שהקלט בכתב היד מזוהה בזמן שהמשתמש מצייר אותו, על ידי תיעוד וניתוח של התנועות הבודדות. בניגוד להליכים 'אופליין' כמו זיהוי תווים אופטי (OCR), שבהם רק המוצר הסופי ידוע, אלגוריתמים אונליין יכולים לספק רמת דיוק גבוהה יותר עקב אותות נוספים כמו רצף הזמן והלחץ של משיכות דיו נפרדות.

תרחישים לדוגמה של הצעות לשימוש בממשק ה-API לזיהוי כתבי יד

דוגמאות לשימושים:

  • אפליקציות לרישום הערות שבהן המשתמשים רוצים לתעד פתקים בכתב יד ולתרגם אותם לטקסט.
  • אפליקציות ב-Forms, שבהן המשתמשים יכולים להשתמש בקלט עט או באצבע בגלל מגבלות זמן.
  • משחקים שמחייבים מילוי של אותיות או מספרים, כמו תשבצים, תליינים או סודוקו.

הסטטוס הנוכחי

ממשק ה-API לזיהוי כתבי יד זמין מ-(Chromium 99).

איך משתמשים בממשק ה-API לזיהוי כתבי יד

זיהוי תכונות

כדי לזהות תמיכה בדפדפן, בודקים אם ה-method createHandwritingRecognizer() קיימת באובייקט הניווט:

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

מושגי ליבה

באמצעות ממשק ה-API לזיהוי כתבי יד אפשר להמיר קלט בכתב יד לטקסט, ללא קשר לשיטת הקלט (עכבר, מגע, עט). ה-API כולל ארבע ישויות עיקריות:

  1. נקודה מייצגת את המיקום של הסמן בזמן מסוים.
  2. קו חוצה כולל נקודה אחת או יותר. ההקלטה של הקו מתחילה כשהמשתמש מניח את הסמן כלפי מטה (כלומר, לוחץ על הלחצן הראשי בעכבר או נוגע במסך עם העט או האצבע), ומסתיימת כשהמשתמש מעלה את הסמן בחזרה.
  3. שרטוט כולל קו חוצה אחד או יותר. הזיהוי בפועל מתבצע ברמה הזו.
  4. המזהה מוגדר עם שפת הקלט הצפויה. הוא משמש ליצירת מכונה של שרטוט עם הגדרות המזהה.

העקרונות האלה מיושמים כממשקים ומילונים ספציפיים, ואסביר אותם בקרוב.

ישויות הליבה של ממשק ה-API לזיהוי כתבי יד: נקודה אחת או יותר מורכבות מקו חוצה, קו חוצה אחד או יותר יוצר שרטוט שהמזהה יוצר. הזיהוי בפועל מתבצע ברמת הציור.

יצירת מזהה

כדי לזהות טקסט מקלט בכתב יד, צריך לקבל מופע של HandwritingRecognizer על ידי קריאה ל-navigator.createHandwritingRecognizer() והפעלת אילוצים אליו. המגבלות קובעות את המודל לזיהוי כתב יד שבו צריך להשתמש. בשלב הזה אפשר לציין רשימה של שפות לפי סדר העדפה:

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

ה-method מחזירה הבטחה לפתרון באמצעות מופע של 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)

ה-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 כשהסמן מועבר במסך. צריך להוסיף גם את הנקודות האלה לקו. אפשר להגדיל את האירוע גם אם הסמן לא נמצא במצב 'למטה', לדוגמה, כשמזיזים את הסמן על המסך בלי ללחוץ על לחצן העכבר. ה-handler של אירועים מהדוגמה הבאה בודק אם קיים קו פעיל ומוסיף אליו את הנקודה החדשה.

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

זיהוי טקסט

כשהמשתמש מרים שוב את הסמן, אפשר להוסיף את הקו לשרטוט באמצעות קריאה ל-method addStroke(). הדוגמה הבאה גם מאפסת את activeStroke, כך שה-handler של pointermove לא יוסיף נקודות למסגרת שהושלם.

בשלב הבא, הגיע הזמן לזהות את הקלט של המשתמש, על ידי קריאה ל-method 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);
      });
    },
  );
}

אפשר להשתמש במידע הזה כדי לאתר שוב את הגרפים שזוהו באזור העריכה.

תיבות משורטטות סביב כל גרפים מזוהה

השלמת הזיהוי

לאחר השלמת הזיהוי, תוכלו לפנות משאבים על ידי קריאה ל-method clear() ב-HandwritingDrawing, ולשיטה finish() ב-HandwritingRecognizer:

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

הדגמה (דמו)

ברכיב האינטרנט <handwriting-textarea> מוטמע שיפורים הדרגתיים עם בקרת עריכה שמאפשרת זיהוי כתב יד. כדי להפעיל את מצב השרטוט, לוחצים על הלחצן בפינה השמאלית התחתונה של פקד העריכה. בסיום השרטוט, רכיב האינטרנט יתחיל את הזיהוי באופן אוטומטי ויוסיף את הטקסט המזוהה חזרה לפקד העריכה. אם אין תמיכה בכלל בממשק API לזיהוי כתבי יד, או שהפלטפורמה לא תומכת בתכונות הנדרשות, לחצן העריכה יוסתר. אבל אפשר להמשיך להשתמש בפקד העריכה הבסיסי כ-<textarea>.

רכיב האינטרנט מציע מאפיינים ומאפיינים להגדרת התנהגות הזיהוי מבחוץ, כולל languages ו-recognitiontype. אפשר להגדיר את התוכן של אמצעי הבקרה באמצעות המאפיין value:

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

כדי לקבל מידע על שינויים בערך, אפשר להאזין לאירוע input.

אפשר לנסות את הרכיב באמצעות ההדגמה הזו ב-Glitch. בנוסף, חשוב לבדוק את קוד המקור. כדי להשתמש בפקד באפליקציה, קבלו אותו מ-npm.

אבטחה והרשאות

צוות Chromium תכנן והטמיע את ממשק ה-API לזיהוי כתבי יד באמצעות עקרונות הליבה שהוגדרו בשליטה בגישה לתכונות מתקדמות של פלטפורמת אינטרנט, כולל בקרת משתמשים, שקיפות וארגונומיה.

שליטת משתמשים

המשתמשים לא יכולים להשבית את ממשק ה-API לזיהוי כתבי יד. הוא זמין רק לאתרים שמועברים דרך HTTPS, ואפשר לקרוא אותו רק מהקשר הגלישה ברמה העליונה.

שקיפות

אין אינדיקציה אם זיהוי כתב יד פעיל. כדי למנוע יצירה של טביעת אצבע דיגיטלית, הדפדפן נוקט אמצעים נגדיים, כמו הצגת בקשה להרשאה למשתמש כשהוא מזהה שימוש לרעה אפשרי.

שמירת ההרשאות

בשלב הזה לא מוצגות בקשות להרשאות מה-API של זיהוי כתב יד. כך, לא צריך לשמור על ההרשאה בשום צורה.

משוב

צוות Chromium רוצה לשמוע על החוויה שלך עם ממשק ה-API של זיהוי כתב יד.

מתארים את עיצוב ה-API

האם יש משהו ב-API שלא פועל כצפוי? או שיש שיטות או מאפיינים חסרים שאתם צריכים ליישם את הרעיון שלכם? יש לכם שאלה או הערה לגבי מודל האבטחה? דווחו על בעיית מפרט במאגר GitHub המתאים, או הוסיפו את דעתכם לגבי בעיה קיימת.

דיווח על בעיה בהטמעה

מצאת באג בהטמעה של Chromium? או שההטמעה שונה מהמפרט? דווחו על באג בכתובת new.crbug.com. הקפידו לכלול כמה שיותר פרטים, הוראות פשוטות לשחזור הבעיה ולהזין Blink>Handwriting בתיבה רכיבים. Glitch היא אפשרות טובה לשיתוף תגובות מהירות וקלות.

הצגת תמיכה ב-API

האם את/ה מתכנן/ת להשתמש בממשק ה-API לזיהוי כתבי יד? התמיכה הציבורית שלכם עוזרת לצוות Chromium לתעדף פיצ'רים ומראה לספקי דפדפנים אחרים עד כמה חשוב לתמוך בהם.

תוכלו לשתף את האופן שבו אתם מתכננים להשתמש בו בשרשור השיחה של WICG. שלחו ציוץ אל @ChromiumDev בעזרת ה-hashtag #HandwritingRecognition, וספרו לנו איפה אתם משתמשים בו ואיך אתם משתמשים בו.

אישורים

המאמר הזה נבדקו על ידי ג'ו מדלי, Honglin Yu וג'ייווי קיאן. התמונה הראשית (Hero) של Samir Bouaked בתוכנית Unbounce.