פיתוח אפליקציית אינטרנט (Dialogflow)

אפליקציית אינטרנט היא ממשק המשתמש לפעולה שמשתמשת בלוח הציור האינטראקטיבי. תוכלו להשתמש בטכנולוגיות אינטרנט קיימות (HTML, CSS ו-JavaScript) כדי לעצב ולפתח את אפליקציית האינטרנט. ברוב המקרים, הכלי האינטראקטיבי יכול להציג תוכן מהאינטרנט כמו דפדפן, אבל יש כמה הגבלות שנאכפות לשמירה על הפרטיות והאבטחה של המשתמשים. לפני שמתחילים לעצב את ממשק המשתמש, כדאי לחשוב על עקרונות העיצוב שמתוארים בקטע Design guidelines.

קוד ה-HTML וה-JavaScript לאפליקציית האינטרנט שלך מבצעים את הפעולות הבאות:

  • רישום callbacks של אירוע 'לוח הציור האינטראקטיבי'.
  • הפעל את ספריית ה-JavaScript של לוח הציור האינטראקטיבי.
  • לספק לוגיקה מותאמת אישית לעדכון אפליקציית האינטרנט על סמך המצב.

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

אפשר להשתמש בכל שיטה לבניית ממשק המשתמש, אבל Google ממליצה להשתמש בספריות הבאות:

אדריכלות

Google ממליצה מאוד להשתמש בארכיטקטורה של דף יחיד לאפליקציות. הגישה הזו מאפשרת ביצועים אופטימליים ותומכת בחוויית משתמש מתמשכת בשיחה. אפשר להשתמש בלוח הציור האינטראקטיבי יחד עם מסגרות קצה כמו Vue, Angular ו-React, שעוזרות בניהול המצבים.

קובץ HTML

קובץ ה-HTML מגדיר את המראה של ממשק המשתמש שלך. הקובץ הזה גם טוען את ספריית ה-JavaScript האינטראקטיבית של Canvas, שמאפשרת תקשורת בין אפליקציית האינטרנט לבין הפעולה בשיחה.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Immersive Canvas Sample</title>
    <!-- Disable favicon requests -->
    <link rel="shortcut icon" type="image/x-icon" href="data:image/x-icon;,">
    <!-- Load Interactive Canvas JavaScript -->
    <script src="https://www.gstatic.com/assistant/df-asdk/interactivecanvas/api/interactive_canvas.min.js"></script>
    <!-- Load PixiJS for graphics rendering -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.7/pixi.min.js"></script>
    <!-- Load Stats.js for fps monitoring -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
    <!-- Load custom CSS -->
    <link rel="stylesheet" href="css/main.css">
  </head>
  <body>
    <div id="view" class="view">
      <div class="debug">
        <div class="stats"></div>
        <div class="logs"></div>
      </div>
    </div>
    <!-- Load custom JavaScript after elements are on page -->
    <script src="js/main.js"></script>
    <script src="js/log.js"></script>
  </body>
</html>

תקשורת בין תהליך מילוי הבקשה לבין אפליקציית האינטרנט

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

action.js

הקובץ מכיל את הקוד להגדרת callbacks ולהפעלת שיטות באמצעות interactiveCanvas. קריאה חוזרת (callback) מאפשרת לאפליקציית האינטרנט להגיב למידע או לבקשות מהפעולה בשיחה, בעוד ששיטות מאפשרות לשלוח מידע או בקשות אל הפעולה המזוהה.

מוסיפים את interactiveCanvas.ready(callbacks); לקובץ ה-HTML כדי לאתחל ולרשום callbacks:

//action.js
class Action {
  constructor(scene) {
    this.canvas = window.interactiveCanvas;
    this.scene = scene;
    const that = this;
    this.commands = {
      TINT: function(data) {
        that.scene.sprite.tint = data.tint;
      },
      SPIN: function(data) {
        that.scene.sprite.spin = data.spin;
      },
      RESTART_GAME: function(data) {
        that.scene.button.texture = that.scene.button.textureButton;
        that.scene.sprite.spin = true;
        that.scene.sprite.tint = 0x0000FF; // blue
        that.scene.sprite.rotation = 0;
      },
    };
  }

  /**
   * Register all callbacks used by Interactive Canvas
   * executed during scene creation time.
   *
   */
  setCallbacks() {
    const that = this;
    // declare interactive canvas callbacks
    const callbacks = {
      onUpdate(data) {
        try {
          that.commands[data.command.toUpperCase()](data);
        } catch (e) {
          // do nothing, when no command is sent or found
        }
      },
    };
    // called by the Interactive Canvas web app once web app has loaded to
    // register callbacks
    this.canvas.ready(callbacks);
  }
}

main.js

הקובץ הזה בונה את הסצנה של אפליקציית האינטרנט. בדוגמה הזו הוא מטפל גם במקרי ההצלחה והכשל של ההבטחה שהוחזרה עם sendTextQuery(). זהו קטע מתוך main.js:

// main.js
const view = document.getElementById('view');
// initialize rendering and set correct sizing
this.renderer = PIXI.autoDetectRenderer({
  transparent: true,
  antialias: true,
  resolution: this.radio,
  width: view.clientWidth,
  height: view.clientHeight,
});
view.appendChild(this.element);

// center stage and normalize scaling for all resolutions
this.stage = new PIXI.Container();
this.stage.position.set(view.clientWidth / 2, view.clientHeight / 2);
this.stage.scale.set(Math.max(this.renderer.width,
    this.renderer.height) / 1024);

// load a sprite from a svg file
this.sprite = PIXI.Sprite.from('triangle.svg');
this.sprite.anchor.set(0.5);
this.sprite.tint = 0x00FF00; // green
this.sprite.spin = true;
this.stage.addChild(this.sprite);

// toggle spin on touch events of the triangle
this.sprite.interactive = true;
this.sprite.buttonMode = true;
this.sprite.on('pointerdown', () => {
  this.sprite.spin = !this.sprite.spin;
});

תמיכה באינטראקציות מגע

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

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

תוכלו לראות דוגמה לכך בדוגמה, באמצעות ספריית Pixi.js:

...
this.sprite = PIXI.Sprite.from('triangle.svg');
...
this.sprite.interactive = true; // Enables interaction events
this.sprite.buttonMode = true; // Changes `cursor` property to `pointer` for PointerEvent
this.sprite.on('pointerdown', () => {
  this.sprite.spin = !this.sprite.spin;
});
...

במקרה כזה, הערך של המשתנה spin נשלח דרך ה-API של interactiveCanvas כקריאה חוזרת (callback) של update. למילוי הבקשה יש לוגיקה שמפעילה Intent על סמך הערך של spin.

...
app.intent('pause', (conv) => {
  conv.ask(`Ok, I paused spinning. What else?`);
  conv.ask(new HtmlResponse({
    data: {
      spin: false,
    },
  }));
});
...

הוספת עוד תכונות

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

sendTextQuery()

השיטה sendTextQuery() שולחת שאילתות טקסט אל הפעולה בשיחה כדי להפעיל באופן פרוגרמטי Intent. בדוגמה הזו נעשה שימוש ב-sendTextQuery() כדי להפעיל מחדש את המשחק המסתובב במשולש כשהמשתמש לוחץ על לחצן. כשהמשתמש לוחץ על הלחצן 'הפעלה מחדש של המשחק', sendTextQuery() קורא לכוונה Restart game ומחזיר הבטחה. ההבטחה הזו מסתיימת ב-SUCCESS אם הכוונה מופעלת, וב-BLOCKED אם לא. קטע הקוד הבא מפעיל את הכוונה (Intent) ומטפל במקרי ההצלחה והכשל של ההבטחה:

//main.js
...
that.action.canvas.sendTextQuery('Restart game')
    .then((res) => {
      if (res.toUpperCase() === 'SUCCESS') {
        console.log(`Request in flight: ${res}`);
        that.button.texture = that.button.textureButtonDisabled;
        that.sprite.spin = false;
      } else {
        console.log(`Request in flight: ${res}`);
      }
    });
...

אם ההבטחה מסתיימת ב-SUCCESS, ה-Intent Restart game שולח HtmlResponse לאפליקציית האינטרנט שלכם:

//index.js
...
app.intent('restart game', (conv) => {
  conv.ask(new HtmlResponse({
    data: {
      command: 'RESTART_GAME',
    },
...

HtmlResponse זה מפעיל את הקריאה החוזרת (callback) של onUpdate(), שמפעילה את הקוד בקטע הקוד RESTART_GAME הבא:

//action.js
...
RESTART_GAME: function(data) {
  that.scene.button.texture = that.scene.button.textureButton;
  that.scene.sprite.spin = true;
  that.scene.sprite.tint = 0x0000FF; // blue
  that.scene.sprite.rotation = 0;
},
...

OnTtsMark()

הקריאה החוזרת (callback) של OnTtsMark() מתבצעת כשכוללים תג <mark> עם שם ייחודי בתגובת ה-SSML למשתמש. בקטעים הבאים מתוך דוגמת איש השלג, OnTtsMark() מסנכרן את האנימציה של אפליקציית האינטרנט עם פלט ה-TTS התואם. לאחר שאומרת הפעולה למשתמש מצטערים, אבדה, אפליקציית האינטרנט מאייתת את המילה הנכונה ומציגה למשתמש את האותיות.

ה-Intent Game Over Reveal Word כולל סימן מותאם אישית בתגובה למשתמש כשהוא מפסיד במשחק:

//index.js
...
app.intent('Game Over Reveal Word', (conv, {word}) => {
  conv.ask(`<speak>Sorry, you lost.<mark name="REVEAL_WORD"/> The word is ${word}.` +
    `${PLAY_AGAIN_INSTRUCTIONS}</speak>`);
  conv.ask(new HtmlResponse());
});
...

לאחר מכן קטע הקוד הבא רושם את הקריאה החוזרת (callback) OnTtsMark(), בודק את שם הסימן ומפעיל את הפונקציה revealCorrectWord(), שמעדכנת את אפליקציית האינטרנט:

//action.js
...
setCallbacks() {
  const that = this;
  // declare assistant canvas action callbacks
  const callbacks = {
    onTtsMark(markName) {
      if (markName === 'REVEAL_WORD') {
        // display the correct word to the user
        that.revealCorrectWord();
      }
    },
...

הגבלות

במהלך הפיתוח של אפליקציית האינטרנט, צריך להביא בחשבון את ההגבלות הבאות:

  • אין קובצי cookie
  • אין אחסון מקומי
  • אין מיקום גיאוגרפי
  • אין שימוש במצלמה
  • ללא חלונות קופצים
  • לא לחרוג ממגבלת הזיכרון של 200MB
  • כותרת של צד שלישי תופסת את החלק העליון של המסך
  • אי אפשר להחיל סגנונות על סרטונים
  • אפשר להשתמש רק ברכיב מדיה אחד בכל פעם
  • אין וידאו בפרוטוקול HLS
  • אין מסד נתונים של Web SQL
  • אין תמיכה בממשק SpeechRecognition של Web Speech API.
  • אין הקלטת אודיו או וידאו
  • הגדרת המצב הכהה לא רלוונטית

שיתוף משאבים בין מקורות

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