Webhooki

Aby zapewnić jeszcze większą elastyczność przy tworzeniu działań, możesz przekazać logikę do usług internetowych HTTPS (realizacji). Działania mogą aktywować webhooki wysyłające żądania do punktu końcowego HTTPS. Oto kilka przykładów:

  • generowanie dynamicznego promptu na podstawie informacji podanych przez użytkownika;
  • Złożenie zamówienia w systemie zewnętrznym i potwierdzenie powodzenia.
  • Weryfikuję przedziały z danymi backendu.
Rysunek 1. Intencje i sceny wywołania mogą aktywować webhooki.

Aktywatory i moduły obsługi webhooka

Działania mogą aktywować webhooka w obrębie intencji lub scen wywołania, co spowoduje wysłanie żądania do punktu końcowego realizacji. Realizacja zawiera moduły obsługi webhooka, które przetwarzają ładunek JSON w żądaniu. Webhooki możesz aktywować w tych sytuacjach:

  • Po dopasowaniu intencji wywołania
  • Podczas wprowadzania sceny na scenie
  • Gdy warunek zostanie oceniony jako prawda na etapie warunku sceny
  • Podczas etapu wypełniania przedziałów sceny
  • Po dopasowaniu intencji na etapie wprowadzania sceny

Gdy aktywujesz webhooka w Akcjach, Asystent Google wyśle do Twojej realizacji żądanie z ładunkiem JSON zawierającym nazwę modułu obsługi, który ma przetworzyć zdarzenie. Punkt końcowy realizacji może przekierować zdarzenie do odpowiedniego modułu obsługi, aby przeprowadzić logikę i zwrócić odpowiednią odpowiedź z ładunkiem JSON.

Ładunki

Poniższe fragmenty kodu pokazują przykładowe żądania, które działania wysyłają do realizacji, oraz odpowiedź odsyłaną przez realizację. Więcej informacji znajdziesz w dokumentacji referencyjnej.

Przykładowe żądanie

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "example_session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Przykładowa odpowiedź

{
  "session": {
    "id": "example_session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "Hello World.",
      "text": ""
    }
  },
  "scene": {
    "name": "SceneName",
    "slots": {},
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  }
}

Interakcje w środowisku wykonawczym

Poniższe sekcje zawierają opis typowych zadań, które możesz wykonać w modułach obsługi webhooka.

Wysyłaj prośby

Za pomocą interaktywnego obszaru roboczego możesz tworzyć prompty zawierające prosty tekst, tekst sformatowany, karty, a nawet pełne wersje HTML. Dokumentacja promptów zawiera pełne informacje o tym, jak utworzyć prompt podczas obsługi zdarzenia webhooka. Te fragmenty kodu pokazują komunikat z prośbą o kartę:

Node.js

app.handle('rich_response', conv => {
  conv.add('This is a card rich response.');
  conv.add(new Card({
    title: 'Card Title',
    subtitle: 'Card Subtitle',
    text: 'Card Content',
    image: new Image({
      url: 'https://developers.google.com/assistant/assistant_96.png',
      alt: 'Google Assistant logo'
    })
  }));
});

Plik JSON odpowiedzi

{
  "session": {
    "id": "example_session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "content": {
      "card": {
        "title": "Card Title",
        "subtitle": "Card Subtitle",
        "text": "Card Content",
        "image": {
          "alt": "Google Assistant logo",
          "height": 0,
          "url": "https://developers.google.com/assistant/assistant_96.png",
          "width": 0
        }
      }
    },
    "firstSimple": {
      "speech": "This is a card rich response.",
      "text": ""
    }
  }
}

Parametry intencji odczytu

Gdy środowisko wykonawcze Asystenta pasuje do intencji, wyodrębnia zdefiniowane parametry. Pierwotna właściwość była wartością podaną przez użytkownika jako dane wejściowe, a potwierdzona właściwość to wartość, na podstawie której NLU ustalił(a) dane wejściowe na podstawie specyfikacji typu.

Node.js

conv.intent.params['param_name'].original
conv.intent.params['param_name'].resolved

Plik JSON żądania

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "intent_name",
    "params": {
      "slot_name": {
        "original": "1",
        "resolved": 1
      }
    },
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {},
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  },
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Odczytywanie języka użytkownika

Ta wartość odpowiada ustawieniom języka użytkownika Asystenta Google.

Node.js

conv.user.locale

JSON

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Pamięć do odczytu i zapisu

Pełne informacje o korzystaniu z różnych funkcji związanych z miejscem na dane znajdziesz w dokumentacji miejsca na dane.

Node.js

//read
conv.session.params.key
conv.user.params.key
conv.home.params.key

// write
conv.session.params.key = value
conv.user.params.key = value
conv.home.params.key = value 

Plik JSON żądania

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "session_id",
    "params": {
      "key": "value"
    },
    "typeOverrides": [],
    "languageCode": ""
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED",
      "key": "value"
    }
  },
  "home": {
    "params": {
      "key": "value"
    }
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Plik JSON odpowiedzi

{
  "session": {
    "id": "session_id",
    "params": {
      "key": "value"
    }
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "Hello world.",
      "text": ""
    }
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED",
      "key": "value"
    }
  },
  "home": {
    "params": {
      "key": "value"
    }
  }
}

Sprawdź możliwości urządzenia

Możesz sprawdzić możliwości urządzenia w zakresie obsługi różnych funkcji lub torów rozmów.

Node.js

const supportsRichResponse = conv.device.capabilities.includes("RICH_RESPONSE");
const supportsLongFormAudio = conv.device.capabilities.includes("LONG_FORM_AUDIO");
const supportsSpeech = conv.device.capabilities.includes("SPEECH");
const supportsInteractiveCanvas = conv.device.capabilities.includes("INTERACTIVE_CANVAS");

Plik JSON żądania

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": [],
    "languageCode": ""
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO",
      "INTERACTIVE_CANVAS"
    ]
  }
}

Pełną listę funkcji platformy znajdziesz w dokumentacji Capability.

Zastąpienia typu środowiska wykonawczego

Typy środowiska wykonawczego umożliwiają modyfikowanie specyfikacji typów w czasie działania. Możesz używać tej funkcji do wczytywania danych z innych źródeł w celu wypełnienia prawidłowych wartości danego typu. Możesz na przykład użyć zastąpień typu środowiska wykonawczego, aby dodać opcje dynamiczne do pytania ankietowego lub dodać pozycję dnia do menu.

Aby używać typów środowisk wykonawczych, musisz aktywować webhooka z poziomu akcji, który wywołuje moduł obsługi w realizacji. Potem możesz uzupełnić parametr session.typeOverrides w odpowiedzi na akcję. Dostępne tryby obejmują TYPE_MERGE, aby zachować istniejące wpisy typu, lub TYPE_REPLACE, aby zastąpić istniejące wpisy zastąpieniami.

Node.js

conv.session.typeOverrides = [{
    name: type_name,
    mode: 'TYPE_REPLACE',
    synonym: {
      entries: [
        {
          name: 'ITEM_1',
          synonyms: ['Item 1', 'First item']
        },
        {
          name: 'ITEM_2',
          synonyms: ['Item 2', 'Second item']
       },
       {
          name: 'ITEM_3',
          synonyms: ['Item 3', 'Third item']
        },
        {
          name: 'ITEM_4',
          synonyms: ['Item 4', 'Fourth item']
        },
    ]
  }
}];

Plik JSON odpowiedzi

{
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": [
      {
        "name": "type_name",
        "synonym": {
          "entries": [
            {
              "name": "ITEM_1",
              "synonyms": [
                "Item 1",
                "First item"
              ]
            },
            {
              "name": "ITEM_2",
              "synonyms": [
                "Item 2",
                "Second item"
              ]
            },
            {
              "name": "ITEM_3",
              "synonyms": [
                "Item 3",
                "Third item"
              ]
            },
            {
              "name": "ITEM_4",
              "synonyms": [
                "Item 4",
                "Fourth item"
              ]
            }
          ]
        },
        "typeOverrideMode": "TYPE_REPLACE"
      }
    ]
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": "This is an example prompt."
    }
  }
}

Włącz odchylenie mowy

Promowanie mowy umożliwia określanie wskazówek dla NLU, by poprawić dopasowanie intencji. Możesz określić maksymalnie 1000 wpisów.

Node.js

conv.expected.speech = ['value_1', 'value_2']
conv.expected.language = 'locale_string'

Plik JSON odpowiedzi

{
  "session": {
    "id": "session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": "This is an example prompt."
    }
  },
  "expected": {
    "speech": "['value_1', 'value_2']",
    "language": "locale_string"
  }
}

Sceny przejściowe

Oprócz definiowania przejść statycznych w projekcie Actions możesz też powodować, że przełączanie scen odbywa się w czasie działania.

Node.js

app.handle('transition_to_hidden_scene', conv => {
  // Dynamic transition
  conv.scene.next.name = "HiddenScene";
});

Plik JSON odpowiedzi

{
  "session": {
    "id": "session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": ""
    }
  },
  "scene": {
    "name": "SceneName",
    "slots": {},
    "next": {
      "name": "HiddenScene"
    }
  }
}

Odczytywanie przedziałów scen

Podczas wypełniania przedziałów możesz użyć realizacji, aby zweryfikować boks lub sprawdzić stan wypełnienia (SlotFillingStatus).

Node.js

conv.scene.slotFillingStatus  // FINAL means all slots are filled
conv.scene.slots  // Object that contains all the slots
conv.scene.slots['slot_name'].<property_name> // Accessing a specific slot's properties

Załóżmy, że chcesz wyodrębnić strefę czasową z odpowiedzi. W tym przykładzie nazwa boksu to datetime1. Aby uzyskać strefę czasową, użyj:

conv.scene.slots['datetime1'].value.time_zone.id

Plik JSON żądania

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "",
    "params": {
      "slot_name": {
        "original": "1",
        "resolved": 1
      }
    },
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "FINAL",
    "slots": {
      "slot_name": {
        "mode": "REQUIRED",
        "status": "SLOT_UNSPECIFIED",
        "updated": true,
        "value": 1
      }
    },
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  },
  "session": {
    "id": "session_id",
    "params": {
      "slot_name": 1
    },
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Unieważnij przedziały scen

Możesz unieważnić przedziały i poprosić użytkownika o podanie nowej wartości.

Node.js

conv.scene.slots['slot_name'].status = 'INVALID'

Plik JSON odpowiedzi

{
  "session": {
    "id": "session_id",
    "params": {
      "slot_name": 1
    }
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": ""
    }
  },
  "scene": {
    "name": "SceneName",
    "slots": {
      "slot_name": {
        "mode": "REQUIRED",
        "status": "INVALID",
        "updated": true,
        "value": 1
      }
    },
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  }
}

Opcje programistyczne

Actions Builder ma wbudowany edytor o nazwie edytor Cloud Functions, który umożliwia kompilowanie i wdrażanie funkcji w Cloud Functions dla Firebase bezpośrednio w konsoli. Możesz też utworzyć i wdrożyć realizację w wybranym hostingu oraz zarejestrować punkt końcowy realizacji HTTPS jako moduł obsługi webhooka.

Edytor wbudowany

Aby programować za pomocą edytora Cloud Functions:

  1. Utwórz plik sdk/webhooks/ActionsOnGoogleFulfillment.yaml i zdefiniuj moduły obsługi akcji oraz wbudowaną funkcję w Cloud Functions używaną do realizacji.
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc
    inlineCloudFunction:
      executeFunction: ActionsOnGoogleFulfillment
        
  2. Utwórz folder sdk/webhooks/ActionsOnGoogleFulfillment i dodaj plik index.js implementujący zdefiniowane wcześniej moduły obsługi oraz plik package.json, który określa wymagania npm w Twoim kodzie.
    // index.js
    const {conversation} = require('@assistant/conversation');
    const functions = require('firebase-functions');
    
    const app = conversation();
    
    app.handle('questionOnEnterFunc', conv => {
      conv.add('questionOnEnterFunc triggered on webhook');
    });
    
    app.handle('fruitSlotValidationFunc', conv => {
      conv.add('fruitSlotValidationFunc triggered on webhook');
    });
    
    exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
        
    // package.json
    {
      "name": "ActionsOnGoogleFulfillment",
      "version": "0.1.0",
      "description": "Actions on Google fulfillment",
      "main": "index.js",
      "dependencies": {
        "@assistant/conversation": "^3.0.0",
        "firebase-admin": "^5.4.3",
        "firebase-functions": "^0.7.1"
      }
    }
        

Zewnętrzny punkt końcowy HTTPS

Z tej sekcji dowiesz się, jak skonfigurować Cloud Functions dla Firebase jako usługę realizacji akcji dotyczącej rozmów. Możesz jednak wdrożyć realizację w wybranej usłudze hostingowej.

Konfigurowanie środowiska

Jeśli używasz Cloud Functions dla Firebase jako usługi realizacji zamówień, zalecamy stosowanie tej struktury projektu:

ProjectFolder        - Root folder for the project
  sdk                - Actions project configuration files
  functions          - Cloud functions for Firebase files

Aby skonfigurować środowisko, wykonaj te czynności:

  1. Pobierz i zainstaluj Node.js.
  2. Skonfiguruj i zainicjuj interfejs wiersza poleceń Firebase. Jeśli poniższe polecenie nie powiedzie się i pojawi się błąd EACCES, może być konieczna zmiana uprawnień npm.

    npm install -g firebase-tools
    
  3. Uwierzytelnij narzędzie Firebase na koncie Google:

    firebase login
    
  4. Uruchom katalog projektu, w którym został zapisany projekt Actions. Pojawi się prośba o wybranie funkcji interfejsu wiersza poleceń Firebase, które chcesz skonfigurować dla projektu w Actions. Wybierz Functions i inne funkcje, których chcesz używać, na przykład Firestore, a następnie naciśnij Enter, aby potwierdzić i kontynuować:

    $ cd <ACTIONS_PROJECT_DIRECTORY>
    $ firebase init
    
  5. Powiąż narzędzie Firebase z projektem w Actions, wybierając je za pomocą klawiszy strzałek do poruszania się po liście projektów:

  6. Po wybraniu projektu narzędzie Firebase rozpocznie konfigurację funkcji i zapyta, jakiego języka chcesz użyć. Wybierz za pomocą klawiszy strzałek i naciśnij Enter, aby kontynuować.

    === Functions Setup
    A functions directory will be created in your project with a Node.js
    package pre-configured. Functions can be deployed with firebase deploy.
    
    ? What language would you like to use to write Cloud Functions? (Use arrow keys)
    > JavaScript
    TypeScript
    
  7. Wybierz, czy chcesz używać ESLint do wychwytywania prawdopodobnych błędów i egzekwowania stylu, wpisując Y lub N:

    ? Do you want to use ESLint to catch probable bugs and enforce style? (Y/n)
  8. Aby uzyskać zależności projektu, wpisz w wierszu Y:

    ? Do you want to install dependencies with npm now? (Y/n)

    Po zakończeniu konfiguracji zobaczysz dane wyjściowe podobne do tych:

    ✔  Firebase initialization complete!
    
  9. Zainstaluj zależność @assistant/conversation:

    $ cd <ACTIONS_PROJECT_DIRECTORY>/functions
    $ npm install @assistant/conversation --save
    
  10. Uzyskaj zależności dotyczące realizacji i wdróż funkcję realizacji:

    $ npm install
    $ firebase deploy --only functions
    

    Wdrożenie trwa kilka minut. Gdy skończysz, zobaczysz dane wyjściowe podobne do tych poniżej. Aby wprowadzić w Dialogflow, potrzebny będzie adres URL funkcji.

    ✔  Deploy complete!
    Project Console: https://console.firebase.google.com/project/<PROJECT_ID>/overview Function URL (<FUNCTION_NAME>): https://us-central1-<PROJECT_ID>.cloudfunctions.net/<FUNCTION_NAME>
  11. Skopiuj adres URL realizacji zamówienia, aby użyć go w następnej sekcji.

Zarejestruj moduł obsługi webhooka

  1. Utwórz plik sdk/webhooks/ActionsOnGoogleFulfillment.yaml i określ moduły obsługi akcji oraz adres URL żądań webhooka.
    httpsEndpoint:
      baseUrl: https://my.web.hook/ActionsOnGoogleFulfillment
      endpointApiVersion: 2
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc