dialogflow-cxpartial-response

How can I send a partial response to a chat widget using Dialogflow CX?


I have created an agent in Dialogflow CX that uses a webhook to address external APIs for certain queries. However, there is often a wait time when making API calls, so I want to inform the user in advance by sending a partial response such as "Moment I'll look that up". I have tested the partial response option in Dialogflow CX, and it works as intended. However, when the agent is used in production with a chat widget, Dialogflow forwards all text messages at once, without using the partial response.

How can I implement the partial response so that the user receives the initial message first, followed by the information from the API call a few seconds later? I am looking for a solution that will work in production, not just in the Dialogflow environment.

Here is my current code for reference:

// Import dependencies
const functions = require('@google-cloud/functions-framework');
const { TiledeskChatbotClient } = require('@tiledesk/tiledesk-chatbot-client');
const { SessionsClient } = require('@google-cloud/dialogflow-cx');
const { createPool } = require('generic-pool');

// Set configuration constants for Dialogflow
const dfProjectId = '___ProjectId___';
const dfLocationId = '___LocationId___';
const dfAgentId = '___AgentId___';
const dfLanguageCode = 'en';

// Create a connection pool for the Dialogflow client
const dialogflowPool = createPool({
  // Create a new client when acquiring a connection
  create: () => new SessionsClient({ apiEndpoint: `${dfLocationId}-dialogflow.googleapis.com` }),
  // Close the client when releasing a connection
  destroy: client => client.close(),
  // Maximum number of connections in the pool
  max: 10,
  // Minimum number of connections to keep in the pool
  min: 2,
  // How long a connection can be idle before it is closed
  idleTimeoutMillis: 30000,
});

async function detectIntentText(userMessage, requestId, languageCode, tdClient) {
  let dialogflowClient;
  try {
    // Acquire a client from the connection pool
    dialogflowClient = await dialogflowPool.acquire();

    // Set the session path and query for the given user message
    const sessionPath = dialogflowClient.projectLocationAgentSessionPath(dfProjectId, dfLocationId, dfAgentId, requestId);
    const request = {
      session: sessionPath,
      queryInput: {
        text: {
          text: userMessage,
        },
        languageCode,
      },
      enablePartialResponse: true,
    };
    // Get the response from Dialogflow
    const [response] = await dialogflowClient.detectIntent(request);

    const responseMessages = response.queryResult.responseMessages;

    // Loop over each response message and text and send a message to Tiledesk
    for (const responseMessage of responseMessages) {
      const texts = responseMessage.text.text;
      for (const text of texts) {
        console.log(`* ${text}`);

        const message = {
          text,
        };
        console.log(message);
        await tdClient.sendMessage(message);

        // Wait for 1.5 seconds before sending the next message  
        await new Promise(resolve => setTimeout(resolve, 1500));
      }
    }
  } finally {
    // Release the client back to the connection pool
    if (dialogflowClient) {
      await dialogflowPool.release(dialogflowClient);
    }
  }
}

functions.http('helloHttp', async (req, res) => {
  // Receive request from Tiledesk
  const tdClient = new TiledeskChatbotClient({
    request: req,
    APIKEY: '__APIKEY__',
  });

  // Extract user message and request ID
  const userMessage = tdClient.text;
  const requestId = tdClient.requestId;

  // Call detectIntentText to handle the user message and send a response to Tiledesk
  await detectIntentText(userMessage, requestId, dfLanguageCode, tdClient);

  // Send a success response to Tiledesk
  res.status(200).send({ success: true });
})

Solution

  • Try to use the Streaming Detect Intent method (RPC API). In the Streaming Detect Intent Request, make sure to set enable_partial_response to true. You can see an example on this page

    As far as I know, this is the only way to get the partial response to work outside the Dialogflow environment.

    Here is the example.