Overview¶
Installation¶
Version support¶
Note
dialogflow-fulfillment requires Python 3 or later.
Installing dialogflow-fulfillment¶
The preferred way to install dialogflow-fulfillment is from PyPI with pip, but it can be installed from source also.
From PyPI¶
To download dialogflow-fulfillment from PyPI with pip, simply run
$ pip install dialogflow-fulfillment
From source¶
In order to install dialogflow-fulfillment from the source code, you must clone the repository from GitHub:
$ git clone https://github.com/gcaccaos/dialogflow-fulfillment.git
Then, install dialogflow-fulfillment in editable (-e)
mode with pip:
$ cd dialogflow-fulfillment
$ pip install -e .[dev]
Examples¶
Dialogflow fulfillment webhook server with Flask¶
from logging import INFO
from typing import Dict
from flask import Flask, request
from flask.logging import create_logger
from dialogflow_fulfillment import WebhookClient
# Create Flask app and enable info level logging
app = Flask(__name__)
logger = create_logger(app)
logger.setLevel(INFO)
def handler(agent: WebhookClient) -> None:
"""Handle the webhook request."""
@app.route('/', methods=['POST'])
def webhook() -> Dict:
"""Handle webhook requests from Dialogflow."""
# Get WebhookRequest object
request_ = request.get_json(force=True)
# Log request headers and body
logger.info(f'Request headers: {dict(request.headers)}')
logger.info(f'Request body: {request_}')
# Handle request
agent = WebhookClient(request_)
agent.handle_request(handler)
# Log WebhookResponse object
logger.info(f'Response body: {agent.response}')
return agent.response
if __name__ == '__main__':
app.run(debug=True)
Dialogflow fulfillment webhook server with Django¶
from json import loads
from logging import getLogger
from django.http import HttpRequest, HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from dialogflow_fulfillment import WebhookClient
logger = getLogger('django.server.webhook')
def handler(agent: WebhookClient) -> None:
"""Handle the webhook request."""
@csrf_exempt
def webhook(request: HttpRequest) -> HttpResponse:
"""Handle webhook requests from Dialogflow."""
if request.method == 'POST':
# Get WebhookRequest object
request_ = loads(request.body)
# Log request headers and body
logger.info(f'Request headers: {dict(request.headers)}')
logger.info(f'Request body: {request_}')
# Handle request
agent = WebhookClient(request_)
agent.handle_request(handler)
# Log WebhookResponse object
logger.info(f'Response body: {agent.response}')
return JsonResponse(agent.response)
return HttpResponse()
Fulfillment overview¶
What is fulfillment?¶
Dialogflow’s console allows to create simple and static responses for user’s intents in conversations. In order to create more dynamic and complex responses, such as retrieving information from other services, the intent’s fulfillment setting must be enabled and a webhook service must be provided:
When an intent with fulfillment enabled is matched, Dialogflow sends a request to your webhook service with information about the matched intent. Your system can perform any required actions and respond to Dialogflow with information for how to proceed.
—Source: Fulfillment.
A detailed example¶
A representation of how data flows in a conversation between a user and a Dialogflow agent.¶
The above diagram is a simplified representation of how data flows in a conversation between a user and a Dialogflow agent through an user interface. In this example, the user’s intent is fulfilled by the agent with the help of a webhook service, allowing to handle more dynamic responses, like calling an external API to fetch some information.
The flow of data in a conversation with fulfillment enabled can be described as follows:
The user types a text into the application’s front-end in order to send a query to the agent.
The input is captured by the application’s back-end, which calls Dialogflow API’s detectIntent` resource, either via the official client or via HTTPS request in the form of a JSON. The request’s body contain a
QueryInput
object, which holds the user’s query (along with other information).Dialogflow detects the intent that corresponds to the user’s query and, since the intent in this example has the fulfillment setting enabled, posts a
WebhookRequest
object to the external webhook service via HTTPS in the form of a JSON. This object has aQueryResult
object, which also holds the user’s query and information about the detected intent, such as the corresponding action, detected entities and input or output contexts.The webhook service uses information from the
QueryResult
object (along with other data from theWebhookRequest
object) in order to determine how the conversation must go. For example, it could trigger some event by setting anEventInput
, change the value of a parameter in aContext
or generateMessage
objects using data from external services, such as APIs or databases.In this example, the webhook service calls an external API in order to fulfill the user’s query.
Then, a
WebhookResponse
object with the generated response data is returned to Dialogflow.Dialogflow validates the response, checking for present keys and value types, and returns a
DetectIntentResponse
object to the interface application.Finally, the application’s front-end displays the resulting response message(s) to the user.
Webhook client¶
- class WebhookClient(request)[source]¶
Bases:
object
A client class for handling webhook requests from Dialogflow.
This class allows to dinamically manipulate contexts and create responses to be sent back to Dialogflow (which will validate the response and send it back to the end-user).
- Parameters
request (dict) – The webhook request object (
WebhookRequest
) from Dialogflow.- Raises
TypeError – If the request is not a dictionary.
- Return type
See also
For more information about the webhook request object, see the WebhookRequest section in Dialogflow’s API reference.
- console_messages¶
The response messages defined for the intent.
- Type
- add(responses)[source]¶
Add response messages to be sent back to Dialogflow.
Examples
Adding a simple text response as a string:
>>> agent.add('Hi! How can I help you?')
Adding multiple rich responses one at a time:
>>> agent.add(Text('How are you feeling today?')) >>> agent.add(QuickReplies(quick_replies=['Happy :)', 'Sad :(']))
Adding multiple rich responses at once:
>>> responses = [ ... Text('How are you feeling today?'), ... QuickReplies(quick_replies=['Happy :)', 'Sad :(']) ... ] >>> agent.add(responses)
- Parameters
responses (str, RichResponse, list(str, RichResponse)) – A single response message or a list of response messages.
- Return type
- property followup_event: Optional[Dict[str, Any]]¶
The followup event to be triggered by the response.
Examples
Accessing the
followup_event
attribute:>>> agent.followup_event None
Assigning an event name to the
followup_event
attribute:>>> agent.followup_event = 'WELCOME' >>> agent.followup_event {'name': 'WELCOME', 'languageCode': 'en-US'}
Assigning an event dictionary to the
followup_event
attribute:>>> agent.followup_event = {'name': 'GOODBYE', 'languageCode': 'en-US'} >>> agent.followup_event {'name': 'GOODBYE', 'languageCode': 'en-US'}
- handle_request(handler)[source]¶
Handle the webhook request using a handler or a mapping of handlers.
In order to manipulate the conversation programatically, the handler function must receive an instance of
WebhookClient
as a parameter. Then, inside the function,WebhookClient
’s attributes and methods can be used to access and manipulate the webhook request attributes and generate the webhook response.Alternatively, this method can receive a mapping of handler functions for each intent.
Note
If a mapping of handler functions is provided, the name of the corresponding intent must be written exactly as it is in Dialogflow.
Finally, once the request has been handled, the generated webhook response can be accessed via the
response
attribute.Examples
Creating a simple handler function that sends a text and a collection of quick reply buttons to the end-user (the response is independent of the triggered intent):
>>> def handler(agent: WebhookClient) -> None: ... agent.add('How are you feeling today?') ... agent.add(QuickReplies(quick_replies=['Happy :)', 'Sad :(']))
Creating a mapping of handler functions for different intents:
>>> def welcome_handler(agent): ... agent.add('Hi!') ... agent.add('How can I help you?') ... >>> def fallback_handler(agent): ... agent.add('Sorry, I missed what you said.') ... agent.add('Can you say that again?') ... >>> handler = { ... 'Default Welcome Intent': welcome_handler, ... 'Default Fallback Intent': fallback_handler, ... }
- property response: Dict[str, Any]¶
The generated webhook response object (
WebhookResponse
).See also
For more information about the webhook response object, see the WebhookResponse section in Dialogflow’s API reference.
- Type
- set_followup_event(event)[source]¶
Set the followup event to be triggered by Dialogflow.
Warning
This method is deprecated and will be removed. Assign value to the
followup_event
attribute instead.- Parameters
event (str, dict) – The event to be triggered by Dialogflow.
- Warns
DeprecationWarning – Assign value to the
followup_event
attribute instead.- Return type
Contexts¶
- class Context(input_contexts, session)[source]¶
Bases:
object
A client class for accessing and manipulating input and output contexts.
This class provides an API that allows to create, edit or delete contexts during conversations.
- Parameters
- Return type
- input_contexts¶
The contexts that were active in the conversation when the intent was triggered by Dialogflow.
Rich responses¶
Card¶
- class Card(title=None, subtitle=None, image_url=None, buttons=None)[source]¶
Bases:
dialogflow_fulfillment.rich_responses.base.RichResponse
Send a card response to the end-user.
Examples
Constructing a
Card
response:>>> card = Card( ... title='What is your favorite color?', ... subtitle='Choose a color', ... buttons=[{'text': 'Red'}, {'text': 'Green'}, {'text': 'Blue'}] ... )
- Parameters
- Return type
See also
For more information about the
Card
response, see the Card responses section in Dialogflow’s documentation.- property buttons: Optional[List[Dict[str, str]]]¶
The buttons of the card response.
Examples
Accessing the
buttons
attribute:>>> card.buttons [{'text': 'Red'}, {'text': 'Green'}, {'text': 'Blue'}]
Assigning value to the
buttons
attribute:>>> card.buttons = [{'text': 'Cyan'}, {'text': 'Magenta'}] >>> card.buttons [{'text': 'Cyan'}, {'text': 'Magenta'}]
- property image_url: Optional[str]¶
The URL of the card response’s image.
Examples
Accessing the
image_url
attribute:>>> card.image_url None
Assigning value to the
image_url
attribute:>>> card.image_url = 'https://picsum.photos/200/300.jpg' >>> card.image_url 'https://picsum.photos/200/300.jpg'
- set_buttons(buttons=None)[source]¶
Set the buttons of the card response.
Warning
This method is deprecated and will be removed. Assign value to the
buttons
attribute instead
- set_image(image_url=None)[source]¶
Set the URL of the card response’s image.
Warning
This method is deprecated and will be removed. Assign value to the
image_url
attribute instead
- set_subtitle(subtitle=None)[source]¶
Set the subtitle of the card response.
Warning
This method is deprecated and will be removed. Assign value to the
subtitle
attribute instead
- set_title(title=None)[source]¶
Set the title of the card response.
Warning
This method is deprecated and will be removed. Assign value to the
title
attribute instead
- property subtitle: Optional[str]¶
The subtitle of the card response.
Examples
Accessing the
subtitle
attribute:>>> card.subtitle 'Choose a color'
Assigning value to the
subtitle
attribute:>>> card.subtitle = 'Select a color below' >>> card.subtitle 'Select a color below'
Image¶
- class Image(image_url=None)[source]¶
Bases:
dialogflow_fulfillment.rich_responses.base.RichResponse
Send an image response to the end-user.
Examples
Constructing an image response:
>>> image = Image('https://picsum.photos/200/300.jpg')
See also
For more information about the
Image
response, see the Image responses section in Dialogflow’s documentation.- property image_url: Optional[str]¶
The URL of the image response.
Examples
Accessing the
image_url
attribute:>>> image.image_url 'https://picsum.photos/200/300.jpg'
Assigning a value to the
image_url
attribute:>>> image.image_url = 'https://picsum.photos/200/300?blur.jpg' >>> image.image_url 'https://picsum.photos/200/300?blur.jpg'
Payload¶
- class Payload(payload=None)[source]¶
Bases:
dialogflow_fulfillment.rich_responses.base.RichResponse
Send a custom payload response to the end-user.
This type of rich response allows to create advanced, custom, responses.
Examples
Constructing a custom
Payload
response for file attachments:>>> payload_data = { ... 'attachment': 'https://example.com/files/some_file.pdf', ... 'type': 'application/pdf' ... } >>> payload = Payload(payload_data)
See also
For more information about the
Payload
response, see the Custom payload responses section in Dialogflow’s documentation.- property payload: Optional[Dict[Any, Any]]¶
The content of the custom payload response.
Examples
Accessing the
payload
attribute:>>> payload.payload {'attachment': 'https://example.com/files/some_file.pdf', 'type': 'application/pdf'}
Assigning a value to the
payload
attribute:>>> payload.payload = { ... 'attachment': 'https://example.com/files/another_file.zip', ... 'type': 'application/zip' ... } >>> payload.payload {'attachment': 'https://example.com/files/another_file.zip', 'type': 'application/zip'}
Quick Replies¶
- class QuickReplies(title=None, quick_replies=None)[source]¶
Bases:
dialogflow_fulfillment.rich_responses.base.RichResponse
Send a collection of quick replies to the end-user.
When a quick reply button is clicked, the corresponding reply text is sent back to Dialogflow as if the user had typed it.
Examples
Constructing a
QuickReplies
response:>>> quick_replies = QuickReplies('Choose an answer', ['Yes', 'No'])
- Parameters
- Return type
See also
For more information about the
QuickReplies
response, see the Quick reply responses section in Dialogflow’s documentation.- property quick_replies: Optional[Union[List[str], Tuple[str]]]¶
The texts for the quick reply buttons.
Examples
Accessing the
quick_replies
attribute:>>> quick_replies.quick_replies ['Yes', 'No']
Assigning a value to the
quick_replies
attribute:>>> quick_replies.quick_replies = ['Yes', 'No', 'Maybe'] >>> quick_replies.quick_replies ['Yes', 'No', 'Maybe']
- set_quick_replies(quick_replies=None)[source]¶
Set the texts for the quick reply buttons.
Warning
This method is deprecated and will be removed. Assign value to the
quick_replies
attribute instead.- Parameters
quick_replies (list, tuple(str), optional) – The texts for the quick reply buttons.
- Warns
DeprecationWarning – Assign value to the
quick_replies
attribute instead.- Return type
- set_title(title=None)[source]¶
Set the title of the quick reply buttons.
Warning
This method is deprecated and will be removed. Assign value to the
title
attribute instead.
Rich Response¶
- class RichResponse[source]¶
Bases:
object
The base (abstract) class for the different types of rich responses.
See also
For more information about the
RichResponse
, see the Rich response messages section in Dialogflow’s documentation.
Text¶
- class Text(text=None)[source]¶
Bases:
dialogflow_fulfillment.rich_responses.base.RichResponse
Send a basic (static) text response to the end-user.
Examples
Constructing a
Text
response:>>> text = Text('this is a text response')
See also
For more information about the
Text
response, see the Text responses section in Dialogflow’s documentation.- set_text(text=None)[source]¶
Set the content of the text response.
Warning
This method is deprecated and will be removed. Assign value to the
text
attribute instead.
Contributing guide¶
How can I contribute to dialogflow-fulfillment?¶
If you want to request an enhancement, report a bug, or simply have a question that has not been answered by the documentation, you are always welcome to create an issue on GitHub.
Change log¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
Unreleased¶
Removed¶
RichResponse’s set_* methods (use property attributes instead).
WebhookClient’s set_followup_event method (use property attribute instead).
0.4.4 - 2021-08-09¶
Fixed¶
Bug when the webhook request is an empty JSON.
Dependencies¶
Bump dependencies in requirements and setup files
0.4.3 - 2021-06-29¶
Added¶
Code of Conduct file.
Dependencies¶
Django example dependencies versions.
0.4.2 - 2020-11-29¶
Fixed¶
Bug when parsing WebhookRequest object in Django example (#1).
Bug when calling response in WebhookClient multiple times (#2).
0.4.1 - 2020-10-11¶
Added¶
Continuous integration and continuous deployment with Github Actions.
Improved¶
Health of the source code.
Documentation.
0.4.0 - 2020-09-12¶
Added¶
Getters and setters for RichResponse’s attributes (and deprecation warnings to set_*() methods).
Getter and setter for WebhookClient’s followup_event attribute (and deprecation warning to set_followup_event() method).
Docs: Examples to WebhookClient’s methods docstrings.
Docs: Examples to RichResponse’s attributes docstrings.
Docs: “See also” sections in RichResponse’s docstrings.
Docs: Type hints to WebhookClient’s handle_request() method’s docstring.
Docs: “Detailed example” section in “Fulfillment overview” page.
Improved¶
Typing annotations coverage.
0.3.0 - 2020-07-29¶
Added¶
Docs: Change log and contributing guide pages.
set_text() method for the Text response.
set_subtitle(), set_image() and set_buttons() methods for the Card response.
set_title() and set_quick_replies() to the QuickReplies response.
Fixed¶
Fix missing fields in Card and QuickReply responses.
Fix optional parameters for all rich responses.
Fix parsing of Image and Card responses from requests.
Fix RichResponse instantiation (shouldn’t be able to instantiate an abstract base class).
Improved¶
Docs: improve classes and methods docstrings.
Changed¶
Docs: Change theme to Read the Docs’ theme.
0.2.0 - 2020-07-17¶
Added¶
Tests for Context and WebhookClient.
Changed¶
Rewrite tests using pytest.
dialogflow-fulfillment is a package for Python that helps developers to create webhook services for Dialogflow.
The package provides an API for creating and manipulating response messages, output contexts and follow-up events in conversations.
See also
For more information about fulfillment and how it works, see Fulfillment overview.
A simple example¶
Working with dialogflow-fulfillment is as simple as passing a webhook request
object from Dialogflow (a.k.a. WebhookRequest
) to an instance of a
WebhookClient
and using a handler function (or a mapping of
functions for each intent) via the handle_request()
method:
from dialogflow_fulfillment import QuickReplies, WebhookClient
# Define a custom handler function
def handler(agent: WebhookClient) -> None:
"""
Handle the webhook request.
This handler sends a text message along with a quick replies
message back to Dialogflow, which uses the messages to build
the final response to the user.
"""
agent.add('How are you feeling today?')
agent.add(QuickReplies(quick_replies=['Happy :)', 'Sad :(']))
# Create an instance of the WebhookClient
agent = WebhookClient(request) # noqa: F821
# Handle the request using the handler function
agent.handle_request(handler)
The above code produces the resulting response object (a.k.a.
WebhookResponse
), which can be accessed via the
response
attribute:
{
'fulfillmentMessages': [
{
'text': {
'text': [
'How are you feeling today?'
]
}
},
{
'quickReplies': {
'quickReplies': [
'Happy :)',
'Sad :('
]
}
}
]
}
Installation¶
The preferred way to install dialogflow-fulfillment is from PyPI with pip:
$ pip install dialogflow-fulfillment
See also
For further details about the installation, see Installation.
Features¶
dialogflow-fulfillment’s key features are:
Webhook Client: handle webhook requests using a custom handler function or a map of handlers for each intent
Contexts: process input contexts and add, set or delete output contexts in conversations
Events: trigger follow-up events with optional parameters
Rich Responses: create and send the following types of rich response messages:
Text
Image
Card
Quick Replies
Payload
Limitations¶
Currently, dialogflow-fulfillment has some drawbacks, which will be addressed in the future:
No support for platform-specific responses