建構網頁應用程式 (Dialogflow)

網頁應用程式是指使用互動式畫布的動作的使用者介面。別擔心!您可以使用 現有的網頁技術 (HTML、CSS 和 JavaScript) 來設計及開發 即可快速導入 API互動式畫布大部分情況下, 但受到一些限制 保護使用者隱私與安全開始設計 UI 之前,請考慮 Design guidelines 所述設計原則 專區。

網頁應用程式的 HTML 和 JavaScript 會執行下列操作:

  • 註冊互動式畫布事件回呼
  • 初始化互動式畫布 JavaScript 程式庫。
  • 提供用於根據狀態更新網頁應用程式的自訂邏輯。

本頁將說明建構網頁應用程式的建議做法,以及如何啟用 網頁應用程式和執行要求之間的通訊,以及一般指南和 以及

雖然您可以使用任何方法建構 UI,但 Google 建議您使用下列做法 程式庫:

架構

Google 強烈建議使用單頁應用程式架構。 這種做法可發揮最佳效能,並支援持續運作 對話式使用者體驗互動式畫布可與 包括 VueAngularReact、 這有助於管理狀態

HTML 檔案

HTML 檔案會定義使用者介面的外觀。這個檔案也會載入 Canvas JavaScript 程式庫,啟用通訊功能 與對話式動作之間有何關聯

<!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

這個檔案內含要定義 回呼 並叫用方法interactiveCanvas。「回呼」功能可讓網頁應用程式回應 接收對話動作「來自」的資訊或要求 可讓使用者將資訊或要求「傳送至」對話動作。

interactiveCanvas.ready(callbacks); 加入 HTML 檔案,即可初始化並 註冊回呼

//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 變數的值會透過 interactiveCanvas API 做為 update 回呼。執行要求有邏輯 根據 spin 的值觸發意圖。

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

新增其他功能

現在您已經瞭解基本概念,現在可以強化及自訂動作了 搭配 Canvas 專用的 API本節說明如何實作這些 API 以及互動式畫布動作

sendTextQuery()

sendTextQuery() 方法會將文字查詢傳送至對話動作 透過程式輔助方式叫用意圖此範例使用 sendTextQuery() 來 當使用者點選按鈕時,重新啟動三角形轉動的遊戲。當使用者 按一下 [重新啟動遊戲]按鈕,sendTextQuery() 會呼叫 Restart game 並傳回承諾使用的值如果意圖是 SUCCESS, 否則會觸發 BLOCKED。下列程式碼片段會觸發意圖 並處理承諾的成功和失敗案例:

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

如果承諾的結果產生 SUCCESSRestart game 意圖就會傳送 HtmlResponse。 為您的網頁應用程式:

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

這個 HtmlResponse 會觸發 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()

當您在以下項目中加入擁有不重複名稱的 <mark> 標記時,系統會呼叫 OnTtsMark() 回呼 您的 SSML 回應以下摘錄自雪人範例的摘錄中 OnTtsMark() 會將網頁應用程式的動畫與對應的 TTS 同步處理 輸出內容使用者「很抱歉,你遺失了」動作時,網頁應用程式會拼寫錯誤 正確的字詞並向使用者顯示字母。

意圖 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());
});
...

下列程式碼片段會註冊 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
  • 沒有本機儲存空間
  • 無地理位置
  • 未使用攝影機
  • 沒有彈出式視窗
  • 將記憶體用量限制在 200 MB 以下
  • 第三方標頭佔據畫面的上方部分
  • 影片未套用任何樣式
  • 一次只能使用一個媒體元素
  • 沒有 HTTP 即時串流影片
  • 沒有任何網路 SQL 資料庫
  • 不支援 SpeechRecognition 介面 Web Speech API
  • 沒有錄音或錄影
  • 無法使用深色模式設定
,瞭解如何調查及移除這項存取權。

跨源資源共享

因為互動式畫布網頁應用程式是由 iframe 代管,且來源已設定 設為空值,您必須啟用跨源資源共享 (CORS) 網路伺服器和儲存空間資源這樣一來,您的素材資源就能接受 來自空值來源的要求。