Skip to main content
Start of main content.

Sending Drupal entities to dialogflow with Chatbot API module

by lee.rowlands /

Share this post on social media

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:

Screenshot from Drupal showing entity collections in Chatbot API Entities module

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.