Lee RowlandsSenior Developer
Sending Drupal entities to dialogflow with Chatbot API module
Services like dialogflow (formerly api.ai) do a much better job of natural language parsing (NLP) if they're aware of your entity names in advance.
For example, it can recognize that show me the weather in Bundabergis a request for weather in Bundaberg, if you've told it ahead of time that Bundaberg is a valid value for the City entity.
Having the entity values automatically update in your service of choice when they're created and changed in Drupal makes this much more efficient.
This article will show you how to achieve that.
This is where the chatbot_api_entities sub-module comes in.
When you enable this module you can browse to Admin -> Config -> Web Services -> Entity Collections to create a collection.
The UI looks something like this:
Each collection comprises an entity-type and bundle as well as a push handler and a query handler.
By default Chatbot API Entities comes with a query handler for each entity-type and a specific one for Users to exclude blocked users.
The api_ai_webhook module comes with a push handler for pushing entities to your dialogflow/api.ai account.
By default, these plugins query based on available entities and the push handler pushes the entity labels.
Writing your own query handler
If for example, you don't want to extract entities from entity labels, e.g. you might wish to collect unique values from a particular field. In this case you can write your own query handler.
Here's an example that will query speaker names from a session content type. The collection handed to the push handler will contain all published sessions.
namespace Drupal\your_module\Plugin\ChatbotApiEntities\QueryHandler;
use Drupal\chatbot_api_entities\Entity\EntityCollectionInterface;
use Drupal\chatbot_api_entities\Plugin\QueryHandlerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
/**
* Defines a query handler that just uses entity query to limit as appropriate.
*
* @QueryHandler(
* id = "speakers",
* label = @Translation("Query speakers from sessions"),
* )
*/
class SpeakerQuery extends QueryHandlerBase {
/**
* {@inheritdoc}
*/
public function query(EntityTypeManagerInterface $entityTypeManager, array $existing = [], EntityCollectionInterface $collection) {
$storage = $entityTypeManager->getStorage('node');
return $storage->loadMultiple($storage->getQuery()
->condition('type', 'session')
->exists('field_speaker_name')
->condition('status', 1)
->execute());
}
/**
* {@inheritdoc}
*/
public function applies($entity_type_id) {
return $entity_type_id === 'node';
}
}
Writing your own push handler
Whilst we've written our own query handler to load entities that we wish to extract values from, we need to write our own push handler to handle sending anything other than the label.
Here's an example push handler that will push field values as entities to Api.ai/dialogflow
<?php
namespace Drupal\your_module\Plugin\ChatbotApiEntities\PushHandler;
use Drupal\api_ai_webhook\Plugin\ChatbotApiEntities\PushHandler\ApiAiPushHandler;
use Drupal\chatbot_api_entities\Entity\EntityCollection;
use Drupal\Core\Entity\EntityInterface;
/**
* Defines a handler for pushing entities to api.ai.
*
* @PushHandler(
* id = "api_ai_webhook_speakers",
* label = @Translation("API AI entities endpoint (speakers)")
* )
*/
class SpeakerPush extends ApiAiPushHandler {
/**
* {@inheritdoc}
*/
protected function formatEntries(array $entities, EntityCollection $entityCollection) {
// Format for API.ai/dialogflow.
return array_map(function ($item) {
return [
'value' => $item,
'synonyms' => [],
];
},
// Key by name to remove duplicates.
array_reduce($entities, function (array $carry, EntityInterface $entity) {
$value = $entity->field_speaker_name->value;
$carry[$value] = $value;
return $carry;
}, []));
}
}
Learn more
If you're interested in learning more about Chatbots and conversational UI with Drupal, I'm presenting a session on these topics at Drupal South 2017, the Southern Hemisphere's biggest Drupal Camp. October 31st is the deadline for getting your tickets at standard prices, so if you plan to attend, be sure to get yours this week to avoid the price hike.
I hope to see you there.