Webhooki

Aby zapewnić Ci jeszcze większą elastyczność podczas tworzenia działań, możesz przekazać logikę do usług internetowych HTTPS (realizacja). Twoje działania mogą wywoływać webhooki, które wysyłają żądania do punktu końcowego HTTPS. Oto kilka przykładów tego, co możesz zrobić w ramach realizacji:

  • Generowanie dynamicznego prompta na podstawie informacji podanych przez użytkownika.
  • Składanie zamówienia w systemie zewnętrznym i potwierdzanie jego realizacji.
  • Sprawdzanie poprawności slotów za pomocą danych backendu.
Rysunek 1. Webhooki mogą być wywoływane przez intencje wywołania i sceny.

Czynniki uruchamiające i obsługujące webhooki

Twoje działania mogą wywoływać webhook w ramach intencji wywołania lub scen, który wysyła żądanie do punktu końcowego realizacji. Realizacja zawiera obsługę webhooków, która przetwarza ładunek JSON w żądaniu. Webhooki możesz wywoływać w tych sytuacjach:

  • Po dopasowaniu intencji wywołania
  • Podczas etapu wejścia do sceny
  • Gdy warunek na etapie warunku sceny zwraca wartość „prawda”
  • Podczas etapu wypełniania slotów w scenie
  • Gdy na etapie wprowadzania danych w scenie nastąpi dopasowanie intencji

Gdy wywołasz webhook w swoich działaniach, Asystent Google wyśle do realizacji żądanie z ładunkiem JSON, które zawiera nazwę obsługi, która ma przetworzyć zdarzenie. Punkt końcowy realizacji może przekierować zdarzenie do odpowiedniej obsługi, aby wykonać logikę i zwrócić odpowiednią odpowiedź z ładunkiem JSON.

Ładunki

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

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

W sekcjach poniżej opisujemy typowe zadania, które możesz wykonywać w ramach obsługi webhooków.

Wysyłanie promptów

Możesz tworzyć prompty z prostym tekstem, tekstem sformatowanym, kartami, a nawet pełnymi promptami HTML obsługiwanymi przez aplikację internetową z Interactive Canvas. W dokumentacji promptów znajdziesz pełne informacje o tym, jak utworzyć prompt podczas obsługi zdarzenia webhooka. Poniższe fragmenty kodu pokazują prompt karty:

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

Odpowiedź JSON

{
  "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": ""
    }
  }
}

Odczytywanie parametrów intencji

Gdy środowisko wykonawcze Asystenta dopasuje intencję, wyodrębni wszystkie zdefiniowane parametry. Właściwość original (oryginalna) to dane wejściowe podane przez użytkownika, a właściwość resolved (rozwiązana) to dane wejściowe, które NLU rozwiązało na podstawie specyfikacji typu.

Node.js

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

Żądanie JSON

{
  "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 ustawień regionalnych użytkownika

Ta wartość odpowiada ustawieniom regionalnym użytkownika w Asystencie 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"
    ]
  }
}

Odczytywanie i zapisywanie danych w pamięci

Więcej informacji o korzystaniu z różnych funkcji pamięci znajdziesz w dokumentacji pamięci.

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 

Żądanie JSON

{
  "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"
    ]
  }
}

Odpowiedź JSON

{
  "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"
    }
  }
}

Sprawdzanie możliwości urządzenia

Możesz sprawdzić możliwości urządzenia, aby zapewnić różne wrażenia lub przebiegi rozmowy.

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");

Żądanie JSON

{
  "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ę możliwości powierzchni znajdziesz w Capability dokumentacji.

Zastępowanie typu środowiska wykonawczego

Typy środowiska wykonawczego pozwalają modyfikować specyfikacje typów w środowisku wykonawczym. Możesz użyć tej funkcji, aby wczytywać dane z innych źródeł i wypełniać nimi prawidłowe wartości typu. Możesz na przykład użyć zastępowania typu środowiska wykonawczego, aby dodać dynamiczne opcje do pytania w ankiecie lub dodać codzienny element do menu.

Aby używać typów środowiska wykonawczego, wywołaj webhook z działania, który wywołuje obsługę w realizacji. Następnie możesz wypełnić parametr session.typeOverrides w odpowiedzi do działania. Dostępne tryby to TYPE_MERGE (zachowuje istniejące wpisy typu) i TYPE_REPLACE (zastępuje 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']
        },
    ]
  }
}];

Odpowiedź JSON

{
  "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."
    }
  }
}

Ustawianie preferencji dotyczących mowy

Ustawianie preferencji dotyczących mowy pozwala określać wskazówki dla NLU, aby poprawić dopasowywanie intencji. Możesz określić maksymalnie 1000 wpisów.

Node.js

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

Odpowiedź JSON

{
  "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"
  }
}

Przechodzenie między scenami

Oprócz definiowania statycznych przejść w projekcie działań możesz też powodować przejścia między scenami w środowisku wykonawczym.

Node.js

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

Odpowiedź JSON

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

Odczytywanie slotów sceny

Podczas wypełniania slotów możesz użyć realizacji, aby sprawdzić poprawność slotu lub sprawdzić stan wypełniania slotów (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 na przykład, że chcesz wyodrębnić strefę czasową z odpowiedzi. W tym przykładzie nazwa slotu to datetime1. Aby uzyskać strefę czasową, użyj:

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

Żądanie JSON

{
  "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żnianie slotów sceny

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

Node.js

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

Odpowiedź JSON

{
  "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 programowania

Actions Builder udostępnia edytor wbudowany o nazwie Edytor Cloud Functions, który pozwala tworzyć i wdrażać funkcję w Cloud Functions dla Firebase bezpośrednio w konsoli. Możesz też tworzyć i wdrażać realizację w wybranym przez siebie hostingu oraz zarejestrować punkt końcowy realizacji HTTPS jako obsługę webhooka.

Edytor wbudowany

Aby programować za pomocą edytora Cloud Functions:

  1. Utwórz plik sdk/webhooks/ActionsOnGoogleFulfillment.yaml, i zdefiniuj obsługi dla działania oraz wbudowanej funkcji w Cloud Functions używanej do realizacji.
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc
    inlineCloudFunction:
      executeFunction: ActionsOnGoogleFulfillment
        
  2. Utwórz folder sdk/webhooks/ActionsOnGoogleFulfillment, i dodaj plik index.js, który implementuje wcześniej zdefiniowane obsługi oraz plik package.json, który określa wymagania npm dotyczące kodu.
    // 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

W tej sekcji opisujemy, jak skonfigurować Cloud Functions dla Firebase jako usługę realizacji dla działania konwersacyjnego. Możesz jednak wdrożyć realizację w wybranej przez siebie usłudze hostingowej.

Konfigurowanie środowiska

Jeśli używasz Cloud Functions dla Firebase jako usługi realizacji, 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:

  1. Pobierz i zainstaluj Node.js.
  2. Skonfiguruj i zainicjuj wiersz poleceń Firebase. Jeśli po użyciu tego polecenia wyświetli się błąd EACCES, być może trzeba zmienić uprawnienia npm.

    npm install -g firebase-tools
    
  3. Uwierzytelnij narzędzie Firebase za pomocą konta Google:

    firebase login
    
  4. Uruchom katalog projektu, w którym zapisano projekt działań. Zostaniesz poproszony(-a) o wybranie funkcji wiersza poleceń Firebase, które chcesz skonfigurować w projekcie działań. Wybierz Functions i inne funkcje, których możesz używać, np. Firestore, a następnie naciśnij Enter, aby potwierdzić i kontynuować:

    $ cd <ACTIONS_PROJECT_DIRECTORY>
    $ firebase init
    
  5. Powiąż narzędzie Firebase z projektem działań, wybierając go za pomocą klawiszy strzałek na liście projektów:

  6. Po wybraniu projektu narzędzie Firebase rozpocznie konfigurację funkcji i zapyta, jakiego języka chcesz używać. Wybierz język 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 wykrywania prawdopodobnych błędów i wymuszania stylu, wpisując Y lub N:

    ? Do you want to use ESLint to catch probable bugs and enforce style? (Y/n)
  8. Pobierz zależności projektu, wpisując Y w odpowiedzi na prompt:

    ? 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. Pobierz zależności realizacji i wdróż funkcję realizacji:

    $ npm install
    $ firebase deploy --only functions
    

    Wdrażanie potrwa kilka minut. Po zakończeniu zobaczysz dane wyjściowe podobne do tych. Aby wprowadzić adres URL funkcji w Dialogflow, musisz znać 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, aby użyć go w następnej sekcji.

Rejestrowanie obsługi webhooka

  1. Utwórz plik sdk/webhooks/ActionsOnGoogleFulfillment.yaml, i zdefiniuj obsługi dla działania oraz adres URL żądań webhooka.
    httpsEndpoint:
      baseUrl: https://my.web.hook/ActionsOnGoogleFulfillment
      endpointApiVersion: 2
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc