Dialogflow Fulfillment PHP Library
This Library is inspired by dialogflow/dialogflow-fulfillment-nodejs.
It supports Dialogflow's fulfillment webhook JSON requests and responses for v1 and v2 agents.
For full class reference please refer to the doc.
Installation
Install via composer: composer require eristemena/dialogflow-fulfillment-webhook-php
.
Usage
Initiate Agent
To initiate agent, use \Dialogflow\WebhookClient
constructor with input parameter as array of request coming from Dialogflow.
In Vanilla PHP, this can be done as follow,
use Dialogflow\WebhookClient;
$agent = new WebhookClient(json_decode(file_get_contents('php://input'),true));
// or
$agent = WebhookClient::fromData($_POST);
or if you're using Laravel,
$agent = \Dialogflow\WebhookClient::fromData($request->json()->all());
Get Request Info
$intent = $agent->getIntent();
$action = $agent->getAction();
$query = $agent->getQuery();
$parameters = $agent->getParameters();
$session = $agent->getSession();
$contexts = $agent->getContexts();
$language = $agent->getLocale();
- Request Source (ex:
google
,facebook
,slack
, etc)
$originalRequest = $agent->getRequestSource();
- Original Request, platform specific payload
$originalRequest = $agent->getOriginalRequest();
- Agent Version (1 or 2)
$agentVersion = $agent->getAgentVersion();
Send Reply
To send a reply, use reply()
method.
$agent->reply('Hi, how can I help?');
Then use render()
to get response in array. All you have to do is to print the array as JSON,
header('Content-type: application/json');
echo json_encode($agent->render());
or in Laravel,
return response()->json($agent->render());
The response payload will be automatically formatted according to Agent Version of the request.
Rich Message
Text
$text = \Dialogflow\RichMessage\Text::create()
->text('This is text')
->ssml('<speak>This is <say-as interpret-as="characters">ssml</say-as></speak>')
;
$agent->reply($text);
Image
$image = \Dialogflow\RichMessage\Image::create('https://www.example.com/image.png');
$agent->reply($image);
Card
$card = \Dialogflow\RichMessage\Card::create()
->title('This is title')
->text('this is text body')
->image('https://www.example.com/image.png')
->button('This is a button', 'https://docs.dialogflow.com/')
;
$agent->reply($card);
Suggestion
$suggestion = \Dialogflow\RichMessage\Suggestion::create(['Suggestion one', 'Suggestion two']);
$agent->reply($suggestion);
Custom payload
if ($agent->getRequestSource()=='google') {
$agent->reply(\Dialogflow\RichMessage\Payload::create([
'expectUserResponse' => false
]));
}
Actions on Google
This library also supports Actions on Google specific functionalities. It's still under development, so more features will be added in the future.
To use Actions on Google Dialogflow Conversation object, you must first need to ensure the requestSource
is coming from Google Assistant,
if ($agent->getRequestSource()=='google') {
$conv = $agent->getActionConversation();
// here you can use the rest of Actions on Google responses and helpers
$agent->reply($conv);
}
or you can just call getActionConversation()
method, and it will return null
if the request doesn't come from Google Assistant.
$conv = $agent->getActionConversation();
if ($conv) {
// here you can use the rest of Actions on Google responses and helpers
} else {
// the request does not come from Google Assistant
}
Send Reply
Using Dialogflow Conversation object, you can send a reply in two ways,
- Send a reply and close the conversation
$conv->close('Have a nice day!');
- Send a reply and wait for user's response
$conv->ask('Hi, how can I help?');
Responses
Simple Response
Please see the documentation here.
use Dialogflow\Action\Responses\SimpleResponse;
$conv->ask(SimpleResponse::create()
->displayText('Hello, how can i help?')
->ssml('<speak>Hello,<break time="0.5s"/> <prosody rate="slow">how can i help?</prosody></speak>')
);
Image
use Dialogflow\Action\Responses\Image;
$conv->close(Image::create('https://picsum.photos/400/300'));
Basic Card
Please see the documentation here.
use Dialogflow\Action\Responses\BasicCard;
$conv->close(BasicCard::create()
->title('This is a title')
->formattedText('This is a subtitle')
->image('https://picsum.photos/400/300')
->button('This is a button', 'https://docs.dialogflow.com/')
);
List
Please see the documentation here.
The single-select list presents the user with a vertical list of multiple items and allows the user to select a single one. Selecting an item from the list generates a user query (chat bubble) containing the title of the list item.
use Dialogflow\Action\Questions\ListCard;
use Dialogflow\Action\Questions\ListCard\Option;
$conv->ask('Please choose below');
$conv->ask(ListCard::create()
->title('This is a title')
->addOption(Option::create()
->key('OPTION_1')
->title('Option 1')
->synonyms(['option one','one'])
->description('Select option 1')
->image('https://picsum.photos/48/48')
)
->addOption(Option::create()
->key('OPTION_2')
->title('Option 2')
->synonyms(['option two','two'])
->description('Select option 2')
->image('https://picsum.photos/48/48')
)
);
To capture the option selected by user, create a Dialogflow intent with the actions_intent_OPTION
event. Assuming you name the intent as Get Option
, you can get the argument as follow,
if ('Get Option'==$agent->getIntent()) {
$conv = $agent->getActionConversation();
$option = $conv->getArguments()->get('OPTION');
switch ($option) {
case 'OPTION_1':
$conv->close('You choose option 1');
break;
case 'OPTION_2':
$conv->close('You choose option 2');
break;
default:
$conv->close('Sorry, i do not understand');
break;
}
}
Carousel
Please see the documentation here.
The carousel scrolls horizontally and allows for selecting one item. Compared to the list selector, it has large tiles-allowing for richer content. The tiles that make up a carousel are similar to the basic card with image. Selecting an item from the carousel will simply generate a chat bubble as the response just like with list selector.
use Dialogflow\Action\Questions\Carousel;
use Dialogflow\Action\Questions\Carousel\Option;
$conv->ask('Please choose below');
$conv->ask(
Carousel::create()
->Option(
Option::create()
->key('OPTION_1')
->title('Option 1')
->synonyms(['option one', 'one'])
->description('Select option 1')
->image('https://picsum.photos/300/300')
)
->Option(
Option::create()
->key('OPTION_2')
->title('Option 2')
->synonyms(['option two', 'two'])
->description('Select option 2')
->image('https://picsum.photos/300/300')
)
->Option(
Option::create()
->key('OPTION_3')
->title('Option 3')
->synonyms(['option three', 'three'])
->description('Select option 3')
->image('https://picsum.photos/300/300')
)
->Option(
Option::create()
->key('OPTION_4')
->title('Option 4')
->synonyms(['option four', 'four'])
->description('Select option 4')
->image('https://picsum.photos/300/300')
)
);
To check if the user granted you the information and then access the data, create a Dialogflow intent with the actions_intent_OPTION
event. Assuming you name the intent as Get Option
, you can get the argument as follow,
if ('Get Option'==$agent->getIntent()) {
$conv = $agent->getActionConversation();
$option = $conv->getArguments()->get('OPTION');
switch ($option) {
case 'OPTION_1':
$conv->close('You choose option 1');
break;
case 'OPTION_2':
$conv->close('You choose option 2');
break;
case 'OPTION_3':
$conv->close('You choose option 3');
break;
case 'OPTION_4':
$conv->close('You choose option 4');
break;
default:
$conv->close('Sorry, i do not understand');
break;
}
}
Browsing Carousel
Please see the documentation here.
A browsing carousel is a rich response, similar to the carousel response as it scrolls horizontally and allows users to select a tile. Browsing carousels are designed specifically for web content by opening the selected tile in a web browser (or an AMP browser if all tiles are AMP-enabled). The browsing carousel will also persist on the user's Assistant surface for browsing later.
use Dialogflow\Action\Responses\BrowseCarousel;
use Dialogflow\Action\Responses\BrowseCarousel\Option;
$conv->ask('Please choose below');
$conv->ask(
BrowseCarousel::create()
->imageDisplayOptions('CROPPED')
->addOption(
Option::create()
->title('Title of item 1')
->description('Description of item 1')
->footer('Item 1 footer')
->url('http://www.example.com')
->image('https://picsum.photos/300/300')
)
->addOption(
Option::create()
->title('Title of item 2')
->description('Description of item 2')
->footer('Item 2 footer')
->url('http://www.example.com')
->image('https://picsum.photos/300/300')
)
->addOption(
Option::create()
->title('Title of item 3')
->description('Description of item 3')
->footer('Item 3 footer')
->url('http://www.example.com')
->image('https://picsum.photos/300/300')
)
->addOption(
Option::create()
->title('Title of item 4')
->description('Description of item 4')
->footer('Item 4 footer')
->url('http://www.example.com')
->image('https://picsum.photos/300/300')
)
);
No follow-up fulfillment is necessary for user interactions with browse carousel items, since the carousel handles the browser handoff.
Suggestion Chip
Please see the documentation here.
use Dialogflow\Action\Responses\LinkOutSuggestion;
use Dialogflow\Action\Responses\Suggestions;
$conv->ask('Please choose');
$conv->ask(new Suggestions(['Suggestion 1', 'Suggestion 2']));
$conv->ask(new Suggestions('Suggestion 3'));
$conv->ask(new LinkOutSuggestion('Website', 'http://www.example.com'));
Media Responses
Please see the documentation here.
Media responses let your Actions play audio content with a playback duration longer than the 120-second limit of SSML. The primary component of a media response is the single-track card.
use Dialogflow\Action\Responses\MediaObject;
use Dialogflow\Action\Responses\MediaResponse;
use Dialogflow\Action\Responses\Suggestions;
$conv->ask('Here you go');
$conv->ask(
new MediaResponse(
MediaObject::create('http://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3')
->name('Jazz in Paris')
->description('A funky Jazz tune')
->icon('http://storage.googleapis.com/automotive-media/album_art.jpg')
->image('http://storage.googleapis.com/automotive-media/album_art.jpg')
)
);
$conv->ask(new Suggestions(['Pause', 'Stop', 'Start over']));
Helpers
User information
Please see the documentation here.
use Dialogflow\Action\Questions\Permission;
$conv->ask(Permission::create('To address you by name and know your location', ['NAME', 'DEVICE_PRECISE_LOCATION']));
To check if the user granted you the information and then access the data, create a Dialogflow intent with the actions_intent_PERMISSION
event. Assuming you name the intent as Get Permission
, you can get the information as follow,
if ('Get Permission'==$agent->getIntent()) {
$conv = $agent->getActionConversation();
$approved = $conv->getArguments()->get('PERMISSION');
if ($approved) {
$name = $conv->getUser()->getName()->getDisplay();
$latlng = $conv->getDevice()->getLocation()->getCoordinates();
$lat = $latlng->getLatitude();
$lng = $latlng->getLongitude();
$conv->close('Got it, your name is ' . $name . ' and your coordinates are ' . $lat . ', ' . $lng);
} else {
$conv->close('Never mind then');
}
}
Date and Time
Please see the documentation here.
use Dialogflow\Action\Questions\DateTime;
$conv->ask(new DateTime('When do you want to come in?', 'What is the best date to schedule your appointment?', 'What time of day works best for you?'));
To check if the user granted access and then access the data, create a Dialogflow intent with the actions_intent_DATETIME
event. Assuming you name the intent as Get Date Time
, you can get the information as follow,
if ('Get Date Time'==$agent->getIntent()) {
$conv = $agent->getActionConversation();
$date = $conv->getArguments()->get('DATETIME');
if ($date) {
$conv->close('Ok, got it, i will see you at ' . $date->format('r'));
} else {
$conv->close('Never mind then');
}
}
Place and Location
Please see the documentation here.
use Dialogflow\Action\Questions\Place;
$conv->ask(new Place('Where do you want to have lunch?', 'To find lunch locations'));
To check if the user granted access and then access the data, create a Dialogflow intent with the actions_intent_PLACE
event. Assuming you name the intent as Get Place
, you can get the information as follow,
if ('Get Place'==$agent->getIntent()) {
$conv = $agent->getActionConversation();
$place = $conv->getArguments()->get('PLACE');
if ($place) {
$conv->close('Ok, got it, we\'ll meet at ' . $place->getFormattedAddress());
} else {
$conv->close('Never mind then');
}
}
Confirmation
Please see the documentation here.
use Dialogflow\Action\Questions\Confirmation;
$conv->ask(new Confirmation('Can you confirm?'));
To check if the user confirmed or not, create a Dialogflow intent with the actions_intent_CONFIRMATION
event. Assuming you name the intent as Get Confirmation
, you can get the information as follow,
if ('Get Confirmation'==$agent->getIntent()) {
$conv = $agent->getActionConversation();
$confirmed = $conv->getArguments()->get('CONFIRMATION');
if ($confirmed) {
$conv->close('Ok, it is confirmed');
} else {
$conv->close('Alright then, it is canceled');
}
}
Surface Capabilities
Google Assistant can be used on a variety of surfaces such as mobile devices that support audio and display experiences or a Google Home device that supports audio-only experiences.
To design and build conversations that work well on all surfaces, use surface capabilities to control and scope your conversations properly.
$surface = $conv->getSurface();
if ($surface->hasScreen()) {
// surface has screen
} elseif ($surface->hasAudio()) {
// surface has audio
} elseif ($surface->hasMediaPlayback()) {
// surface can play audio
} elseif ($surface->hasWebBrowser()) {
// user can interact with the content in a web browser
}