สร้างเว็บแอป (Dialogflow)

เว็บแอปคือ UI สำหรับการดำเนินการที่ใช้ Interactive Canvas คุณสามารถใช้ เทคโนโลยีเว็บที่มีอยู่ (HTML, CSS และ JavaScript) เพื่อออกแบบและพัฒนา เว็บแอปของคุณ โดยส่วนใหญ่แล้ว Interactive Canvas จะสามารถแสดงผลเนื้อหาเว็บได้ เช่น เบราว์เซอร์ แต่มีข้อจำกัดบางประการที่บังคับใช้ ความเป็นส่วนตัวและความปลอดภัยของผู้ใช้ ก่อนที่จะเริ่มออกแบบ UI คุณควรพิจารณา หลักการออกแบบที่ระบุไว้ใน Design guidelines

HTML และ JavaScript สำหรับเว็บแอปทำงานต่อไปนี้

  • ลงทะเบียนการติดต่อกลับของกิจกรรม Interactive Canvas
  • เริ่มต้นไลบรารี JavaScript ของ Interactive Canvas
  • ระบุตรรกะที่กำหนดเองสำหรับการอัปเดตเว็บแอปตามสถานะ

หน้านี้จะกล่าวถึงวิธีต่างๆ ที่แนะนำในการสร้างเว็บแอป รวมถึงวิธีเปิดใช้ การสื่อสารระหว่างเว็บแอปกับการดำเนินการตามคำสั่งซื้อ รวมถึงหลักเกณฑ์ทั่วไปและ ข้อจำกัด

แม้ว่าคุณจะสามารถใช้วิธีสร้าง UI ด้วยวิธีใดก็ได้ แต่ Google ขอแนะนําให้ใช้วิธีต่อไปนี้ ไลบรารี:

  • Greensock: สำหรับการสร้างภาพเคลื่อนไหวที่ซับซ้อน
  • Pixi.js: สำหรับการวาดกราฟิก 2D บน WebGL
  • Three.js: สำหรับการวาดกราฟิก 3D บน WebGL
  • ภาพวาด HTML5 Canvas: สำหรับภาพวาดง่ายๆ
  • องค์ประกอบ DOM: สำหรับเนื้อหาแบบคงที่

สถาปัตยกรรม

Google ขอแนะนำเป็นอย่างยิ่งให้ใช้สถาปัตยกรรมแอปพลิเคชันหน้าเว็บเดียว วิธีนี้จะทำให้ได้รับประสิทธิภาพสูงสุดและสนับสนุน ประสบการณ์ของผู้ใช้ การสนทนาได้อย่างมีประสิทธิภาพ Interactive Canvas สามารถใช้ร่วมกับ เฟรมเวิร์กฟรอนท์เอนด์ เช่น Vue Angular และ React ซึ่งจะช่วยในการจัดการรัฐ

ไฟล์ HTML

ไฟล์ HTML จะกำหนดรูปลักษณ์ของ UI ไฟล์นี้ยังโหลดแท็ก Interactive ไลบรารี 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>

สื่อสารระหว่าง Fulfillment กับเว็บแอป

เมื่อสร้างเว็บแอป Fulfillment และโหลดสำเร็จแล้วใน คลัง Canvas ใน ไฟล์เว็บแอป คุณจะต้องกำหนดวิธีที่เว็บแอปและ Fulfillment ทำงานร่วมกัน ถึง ให้ทำเช่นนี้ แก้ไขไฟล์ที่มีตรรกะเว็บแอปของคุณ

action.js

ไฟล์นี้มีโค้ดที่จะกำหนด Callback และเรียกใช้วิธีการ จนถึง interactiveCanvas Callback จะช่วยให้เว็บแอปตอบกลับ ข้อมูลหรือคำขอจากการกระทำที่เป็นการสนทนา ในขณะที่เมธอด ให้วิธีส่งข้อมูลหรือคำขอไปยังการดำเนินการเชิงสนทนา

เพิ่ม interactiveCanvas.ready(callbacks); ลงในไฟล์ HTML เพื่อเริ่มต้นและ Callback ที่ลงทะเบียน:

//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;
});

รองรับการโต้ตอบการสัมผัส

การดำเนินการ Interactive Canvas สามารถตอบสนองต่อการแตะของผู้ใช้ได้เช่นเดียวกับ จากเสียงร้องของเด็กๆ ตาม หลักเกณฑ์การออกแบบ Interactive Canvas คุณควรพัฒนาการดำเนินการให้เป็นแบบ "เน้นเสียงเป็นหลัก" อย่างไรก็ตาม บางคนมีความฉลาด จอแสดงผลรองรับการโต้ตอบการสัมผัส

การสนับสนุนการสัมผัสคล้ายกับการสนับสนุนการสนทนา อย่างไรก็ตาม แทนที่จะส่งเสียงตอบกลับจากผู้ใช้ 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 จะส่งผ่านพารามิเตอร์ interactiveCanvas API เป็น Callback update การดำเนินการตามคำสั่งซื้อมีตรรกะ ที่เรียกใช้ Intent ตามค่าของ spin

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

เพิ่มฟีเจอร์อื่นๆ

เมื่อทราบข้อมูลเบื้องต้นแล้ว คุณก็ปรับปรุงและปรับแต่งการดำเนินการได้ ด้วย API สำหรับ Canvas โดยเฉพาะ ส่วนนี้อธิบายวิธีนำ API เหล่านี้ไปใช้ ในการทำงานของ Interactive Canvas

sendTextQuery()

เมธอด sendTextQuery() จะส่งข้อความค้นหาไปยังการดำเนินการแบบสนทนา เพื่อเรียกใช้ Intent แบบเป็นโปรแกรม ตัวอย่างนี้ใช้ sendTextQuery() เพื่อ รีสตาร์ทเกมหมุนสามเหลี่ยมเมื่อผู้ใช้คลิกปุ่ม เมื่อผู้ใช้ คลิกที่ "เริ่มเกมใหม่" sendTextQuery() เรียก Restart game และมอบคำสัญญา คำสัญญานี้จะส่งผลให้ SUCCESS หาก Intent และ 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 ต่อผู้ใช้ ในบทคัดย่อต่อไปนี้จาก Snowman sample 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();
      }
    },
...

ข้อจำกัด

โปรดคำนึงถึงข้อจำกัดต่อไปนี้เมื่อคุณพัฒนาเว็บแอป

  • ไม่มีคุกกี้
  • ไม่มีพื้นที่เก็บข้อมูลในเครื่อง
  • ไม่มีข้อมูลตำแหน่งทางภูมิศาสตร์
  • ไม่ได้ใช้กล้อง
  • ไม่มีป๊อปอัป
  • ใช้หน่วยความจำไม่เกิน 200MB
  • ส่วนหัว 3P แสดงที่ส่วนบนของหน้าจอ
  • ไม่มีรูปแบบที่ใช้กับวิดีโอได้
  • ใช้องค์ประกอบสื่อได้ครั้งละ 1 รายการเท่านั้น
  • ไม่มีวิดีโอ HLS
  • ไม่มีฐานข้อมูล SQL ในเว็บ
  • ไม่รองรับอินเทอร์เฟซ SpeechRecognition ของ Web Speech API
  • ไม่มีการบันทึกเสียงหรือวิดีโอ
  • การตั้งค่าโหมดมืดไม่เกี่ยวข้อง

การแชร์ทรัพยากรข้ามแหล่งที่มา

เนื่องจากเว็บแอป Interactive Canvas โฮสต์อยู่ใน iframe และมีการตั้งค่าต้นทาง เป็นค่าว่าง คุณต้องเปิดใช้การแชร์ทรัพยากรแบบข้ามต้นทาง (CORS) สำหรับเว็บเซิร์ฟเวอร์และทรัพยากรพื้นที่เก็บข้อมูลของคุณ วิธีนี้ช่วยให้เนื้อหาของคุณยอมรับ คำขอจากต้นทางที่ไม่มีข้อมูล