webhooks: Add Dialogflow integration.

With minor fixes by eeshangarg!

Fixes #6990
This commit is contained in:
Ricky
2018-01-12 18:19:11 +05:30
committed by Eeshan Garg
parent 45f0df6d31
commit 4b8bd0bc3b
12 changed files with 309 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -284,6 +284,7 @@ WEBHOOK_INTEGRATIONS = [
WebhookIntegration('circleci', ['continuous-integration'], display_name='CircleCI'),
WebhookIntegration('codeship', ['continuous-integration', 'deployment']),
WebhookIntegration('crashlytics', ['monitoring']),
WebhookIntegration('dialogflow', ['customer-support'], display_name='Dialogflow'),
WebhookIntegration('delighted', ['customer-support', 'marketing'], display_name='Delighted'),
WebhookIntegration(
'deskdotcom',

View File

View File

@@ -0,0 +1,28 @@
Get personal message notifications in Zulip for the results of your Dialogflow queries!
1. {!create-stream.md!}
1. Next, on your {{ settings_html|safe }}, [create a bot](/help/add-a-bot-or-integration) for
{{ integration_display_name }}. Make sure that you select
**Incoming webhook** as the **Bot type**.
The API key for an incoming webhook bot cannot be used to read messages out
of Zulip. Thus, using an incoming webhook bot lowers the security risk of
exposing the bot's API key to a third-party service.
Construct the URL for the Dialogflow bot using the bot's API key and your Zulip email.
The webhook URL should look like:
`{{api_url}}?api_key=BOT'S_API_KEY&email=foo@example.com`
Modify the parameters of the URL above where `api_key` is the API key of your Zulip bot
and `email` is your Zulip email.
1. Go to the **Fulfillment** settings of your Dialogflow app and enable **Webhooks**.
Set **URL** to the URL constructed above.
Go to **Intents** and at the bottom, check the box **Use webhook**
under **Fulfillment**.
{!congrats.md!}
![](/static/images/integrations/dialogflow/001.png)

View File

@@ -0,0 +1,45 @@
{
"id": "69316a96-cce1-4322-9bdc-d94e8298f0d2",
"timestamp": "2018-01-12T12:22:31.283Z",
"lang": "en",
"result": {
"source": "agent",
"resolvedQuery": "what's the weather in New Delhi",
"action": "yahooWeatherForecast",
"actionIncomplete": false,
"parameters": {
"geo-city": "New Delhi"
},
"contexts": [],
"metadata": {
"intentId": "a61266c2-b6af-4dc8-a7b9-72dfb11b72d8",
"webhookUsed": "true",
"webhookForSlotFillingUsed": "false",
"webhookResponseTime": 115,
"intentName": "weather-intent"
},
"fulfillment": {
"speech": "",
"source": "apiai-weather-webhook-sample",
"displayText": "",
"messages": [
{
"type": 0,
"speech": ""
}
]
},
"score": 0.7099999785423279
},
"alternateResult": {
"fulfillment": {
"speech": "Weather in New Delhi is nice!"
},
},
"status": {
"code": 200,
"errorType": "success",
"webhookTimedOut": false
},
"sessionId": "2507496e-8028-4be5-ac52-1624f752b188"
}

View File

@@ -0,0 +1,37 @@
{
"id": "1faaa328-dad8-4532-be7e-c4103dfdbf40",
"timestamp": "2018-01-12T12:09:15.699Z",
"lang": "en",
"result": {
"source": "agent",
"resolvedQuery": "how is the weather in Sunnyvale",
"action": "",
"actionIncomplete": false,
"parameters": {
"geo-city": "Sunnyvale"
},
"contexts": [],
"metadata": {
"intentId": "a61266c2-b6af-4dc8-a7b9-72dfb11b72d8",
"webhookUsed": "false",
"webhookForSlotFillingUsed": "false",
"intentName": "weather-intent"
},
"fulfillment": {
"speech": "The weather sure looks great !",
"messages": [
{
"type": 0,
"speech": "The weather sure looks great !"
}
]
},
"score": 1
},
"status": {
"code": 200,
"errorType": "success",
"webhookTimedOut": false
},
"sessionId": "2507496e-8028-4be5-ac52-1624f752b188"
}

View File

@@ -0,0 +1,14 @@
{
"id": "69316a96-cce1-4322-9bdc-d94e8298f0d2",
"timestamp": "2018-01-12T12:22:31.283Z",
"lang": "en",
"result": {
"resolvedQuery": "what's the weather in New Delhi",
},
"status": {
"code": 403,
"errorType": "fail",
"errorDetails": "Access Denied"
},
"sessionId": "2507496e-8028-4be5-ac52-1624f752b188"
}

View File

@@ -0,0 +1,45 @@
{
"id": "69316a96-cce1-4322-9bdc-d94e8298f0d2",
"timestamp": "2018-01-12T12:22:31.283Z",
"lang": "en",
"result": {
"source": "agent",
"resolvedQuery": "what's the weather in New Delhi",
"action": "yahooWeatherForecast",
"actionIncomplete": false,
"parameters": {
"geo-city": "New Delhi"
},
"contexts": [],
"metadata": {
"intentId": "a61266c2-b6af-4dc8-a7b9-72dfb11b72d8",
"webhookUsed": "true",
"webhookForSlotFillingUsed": "false",
"webhookResponseTime": 115,
"intentName": "weather-intent"
},
"fulfillment": {
"speech": "",
"source": "apiai-weather-webhook-sample",
"displayText": "",
"messages": [
{
"type": 0,
"speech": ""
}
]
},
"score": 0.7099999785423279
},
"alternateResult": {
"fulfillment": {
"speech": ""
},
},
"status": {
"code": 200,
"errorType": "success",
"webhookTimedOut": false
},
"sessionId": "2507496e-8028-4be5-ac52-1624f752b188"
}

View File

@@ -0,0 +1,40 @@
{
"id": "69316a96-cce1-4322-9bdc-d94e8298f0d2",
"timestamp": "2018-01-12T12:22:31.283Z",
"lang": "en",
"result": {
"source": "agent",
"resolvedQuery": "what's the weather in New Delhi",
"action": "yahooWeatherForecast",
"actionIncomplete": false,
"parameters": {
"geo-city": "New Delhi"
},
"contexts": [],
"metadata": {
"intentId": "a61266c2-b6af-4dc8-a7b9-72dfb11b72d8",
"webhookUsed": "true",
"webhookForSlotFillingUsed": "false",
"webhookResponseTime": 115,
"intentName": "weather-intent"
},
"fulfillment": {
"speech": "Today the weather in Delhi: Sunny, And the temperature is 65 F",
"source": "apiai-weather-webhook-sample",
"displayText": "Today the weather in Delhi: Sunny, And the temperature is 65 F",
"messages": [
{
"type": 0,
"speech": "Today the weather in Delhi: Sunny, And the temperature is 65 F"
}
]
},
"score": 0.7099999785423279
},
"status": {
"code": 200,
"errorType": "success",
"webhookTimedOut": false
},
"sessionId": "2507496e-8028-4be5-ac52-1624f752b188"
}

View File

@@ -0,0 +1,66 @@
# -*- coding: utf -*-
from typing import Text
from zerver.lib.test_classes import WebhookTestCase
class DialogflowHookTests(WebhookTestCase):
URL_TEMPLATE = u"/api/v1/external/dialogflow?api_key={api_key}&email=AARON@zulip.com"
def test_dialogflow_default(self) -> None:
self.url = self.build_webhook_url(
email="AARON@zulip.com",
username="aaron",
user_ip="127.0.0.1"
)
expected_message = u"Today the weather in Delhi: Sunny, And the tempreture is 65F"
self.send_and_test_private_message('default',
expected_message,
content_type="application/json")
def test_dialogflow_weather_app(self) -> None:
self.url = self.build_webhook_url(
email="AARON@zulip.com",
username="aaron",
user_ip="127.0.0.1"
)
expected_message = u"The weather sure looks great !"
self.send_and_test_private_message('weather_app',
expected_message,
content_type="application/json")
def test_dialogflow_alternate_result(self) -> None:
self.url = self.build_webhook_url(
email="AARON@zulip.com",
username="aaron",
user_ip="127.0.0.1"
)
expected_message = u"Weather in New Delhi is nice!"
self.send_and_test_private_message('alternate_result',
expected_message,
content_type="application/json")
def test_dialogflow_error_status(self) -> None:
self.url = self.build_webhook_url(
email="AARON@zulip.com",
username="aaron",
user_ip="127.0.0.1"
)
expected_message = u"403 - Access Denied"
self.send_and_test_private_message('error_status',
expected_message,
content_type="application/json")
def test_dialogflow_exception(self) -> None:
self.url = self.build_webhook_url(
email="AARON@zulip.com",
username="aaron",
user_ip="127.0.0.1"
)
expected_message = u"DialogFlow couldn't process your query."
self.send_and_test_private_message('exception',
expected_message,
content_type="application/json")
def get_body(self, fixture_name: Text) -> Text:
return self.fixture_data("dialogflow",
fixture_name,
file_type="json")

View File

@@ -0,0 +1,33 @@
# Webhooks for external integrations.
from typing import Text, Any, Dict
from django.http import HttpRequest, HttpResponse
from zerver.decorator import api_key_only_webhook_view
from zerver.lib.actions import check_send_private_message
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_success
from zerver.models import UserProfile, get_user_profile_by_email
@api_key_only_webhook_view("dialogflow")
@has_request_variables
def api_dialogflow_webhook(request: HttpRequest, user_profile: UserProfile,
payload: Dict[str, Any]=REQ(argument_type='body'),
email: str=REQ(default='foo')) -> HttpResponse:
status = payload["status"]["code"]
if status == 200:
result = payload["result"]["fulfillment"]["speech"]
if not result:
alternate_result = payload["alternateResult"]["fulfillment"]["speech"]
if not alternate_result:
body = u"DialogFlow couldn't process your query."
else:
body = alternate_result
else:
body = result
else:
error_status = payload["status"]["errorDetails"]
body = u"{} - {}".format(status, error_status)
profile = get_user_profile_by_email(email)
check_send_private_message(user_profile, request.client, profile, body)
return json_success()