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 });
})
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.