Step-by-step guide to making an HTTP request in DialogFlow v2 with JavaScript using AJAX

I came across this example on the DialogFlow official site, demonstrating how to use Node.js. It seems to be working fine, but I'm unsure about integrating it into my web application.

Can I merge this with my existing JavaScript jQuery code? Also, if I integrate it, do I still need to run node index.js separately?

const projectId = 'xxx'; //https://dialogflow.com/docs/agents#settings
const sessionId = 'xxxxx';
const query = 'Hello';
const languageCode = 'en-US';

// Setting up DialogFlow client.
const dialogflow = require('dialogflow');
const sessionClient = new dialogflow.SessionsClient();

// Define session path.
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
console.log(sessionPath);
// Text query request.
const request = {
  session: sessionPath,
  queryInput: {
    text: {
      text: query,
      languageCode: languageCode,
    },
  },
};

// Sending request and displaying result.
sessionClient
  .detectIntent(request)
  .then(responses => {
    console.log('Detected intent');
    const result = responses[0].queryResult;
    console.log(`  Query: ${result.queryText}`);
    console.log(`  Response: ${result.fulfillmentText}`);
    if (result.intent) {
      console.log(`  Intent: ${result.intent.displayName}`);
    } else {
      console.log(`  No intent matched.`);
    }
  })
  .catch(err => {
    console.error('ERROR:', err);
  });

Is there an alternative way to use DialogFlow v2 with just normal JavaScript, jQuery, and AJAX without the need to run node index.js every time?

Using DialogFlow v1 was more straightforward for me. The setup looked something like this:

fetch(url, {
    body: JSON.stringify(data),
    // cache: 'no-cache',
    // credentials: 'same-origin',
    headers: {
        'content-type': 'application/json',
        "Authorization": "Bearer " + configs.accessToken,
    },
    method: 'POST',
    mode: 'cors',
    redirect: 'follow',
    referrer: 'no-referrer',
})
    .then(response => response.json()) // parses response to JSON

Answer №1

It has been mentioned by others previously that the access token is valid for one hour before expiring. To ensure continuous access, it is essential to periodically request a new access token by making an HTTP call to the API. Detailed instructions on how to generate the necessary signature and utilize it can be found at https://developers.google.com/identity/protocols/OAuth2ServiceAccount.

Upon receiving the json file from the service account containing the private key and designated email address (generated by the service account), the jsrsasign library available at https://github.com/kjur/jsrsasign can be used to generate a JSON Web Signature (JWS) and subsequently a JSON Web Token (JWT) required for obtaining the access token.

Following this, as explained earlier, you can proceed to make the call to Dialogflow V2 using jQuery.

The following code snippet illustrates the process utilized:

Generating the JWT (using the related library):

function _genJWS() {
    var header = '{"alg":"RS256","typ":"JWT"}';
    var claimSet = jwtClaimSet();
    var privateKey = jwtPrivateKey();

    var sHead = newline_toDos(header);
    var head = KJUR.jws.JWS.readSafeJSONString(sHead);
    var sPayload = newline_toDos(claimSet);
    var sPemPrvKey = privateKey;

    var jws = new KJUR.jws.JWS();
    var sResult = null;
    try {
        prv = KEYUTIL.getKey(sPemPrvKey);

        sResult = KJUR.jws.JWS.sign(head.alg, sHead, sPayload, prv);
    } catch (ex) {
        alert("Error: " + ex);
    }
    return sResult;
}

Requesting the access token:

function _requestAccessToken() {
    var access_token = accessToken;
    var assertion = _genJWS();
    console.log('Assertion: ' + assertion);
    jQuery.ajax({
        type: "POST",
        url: "https://www.googleapis.com/oauth2/v4/token",
        contentType: "application/x-www-form-urlencoded",
        dataType: "json",
        data: "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + assertion,
        success: function(response) {
            console.log("success");
            console.log(response);
            access_token = response.access_token;
            console.log(access_token);
        },
        error: function() {
            console.log("Error");
        }
    });
    return access_token;
}

Subsequently, use the obtained access token to initiate the HTTP call to Dialogflow.

Trust this information proves useful.

Answer №2

If you want to interact with Dialogflow's V2 API using jQuery, you can easily make a call to the detectIntent endpoint.

For details on the URL and request formats, take a look at the information provided in the API documentation:

POST https://dialogflow.googleapis.com/v2/{session=projects/*/agent/sessions/*}:detectIntent

{
  "queryParams": {
    object(QueryParameters)
  },
  "queryInput": {
    object(QueryInput)
  },
  "inputAudio": string
}

When it comes to authentication, you'll need to follow a slightly different process. Rather than using an access token, you will create a service account and key through the Cloud dashboard. The steps are outlined in detail on this documentation page.

Answer №3

Click here for instructions on setting up authentication in DialogFlow

If you have followed the steps outlined in the link above and successfully created service keys, you should have a JSON file with the following structure:

{
    "type": "",
    "project_id": "",
    "private_key_id": "",
    "private_key": "",
    "client_email": "",
    "client_id": "",
    "auth_uri": "",
    "token_uri": "",
    "auth_provider_x509_cert_url": "",
    "client_x509_cert_url": ""
  }  

Once you have obtained this file, run the following two commands (make sure to install gcloud CLI if you haven't already):

gcloud auth activate-service-account --key-file=<service-account-key-file.json>
gcloud auth print-access-token

After obtaining the access token, you can provide it to your program as an environment variable or hardcode it into your code. To make an HTTP POST request, you can use a library like axios. Here is a sample code snippet using axios in a React project to detect intent:

import axios from "axios";

const DIALOG_FLOW_TOKEN = process.env.REACT_APP_DIALOG_FLOW_TOKEN;
const DIALOG_FLOW_API_ROOT_URL = "https://dialogflow.googleapis.com/v2";
const YOUR_PROJECT_ID = <YOUR_PROJECT_ID>;
const SESSION_ID = <SESSION_ID>;
const URL = `${DIALOG_FLOW_API_ROOT_URL}/projects/${YOUR_PROJECT_ID}/agent/sessions/${SESSION_ID}:detectIntent`;

var config = {
    headers: {
        "Authorization": "Bearer " + DIALOG_FLOW_TOKEN,
        "Content-Type": "application/json"
    }
};

export function sendText(text) {
    var bodyParameters = {
        "queryInput": { "text": { "text": text, "languageCode": "en" } },
    };

    const request = axios.post(
        URL,
        bodyParameters,
        config
    );

    return request;
} 

Answer №4

In the following code snippet, we demonstrate how to establish communication between a web application and Dialogflow NLU. In order to obtain an access token, the Google Cloud SDK can be utilized, which has a validity period of one hour. To work around this limitation, consider retrieving the token from a separate service before initiating a call to Dialogflow.

$(document).ready(function(){

$("button").click(function(){

    $.ajax({
        type: "POST",
        url: "https://dialogflow.googleapis.com/v2/projects/YOUR-PROJECT-NAME/agent/sessions/SESSIONIDOFYOURCHOICE:detectIntent",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        headers: {
            "Authorization": "Bearer " + "YOUR ACCESS TOKEN GOES HERE",
        },
        data: JSON.stringify({ "queryInput":{
            "text":{
                "text":"YOUR QUERY TO NLU",
                "languageCode":"en-US"
            }
        } }),
        success: function(data) {
            $("#div").html(data.queryResult.fulfillmentText);
        },
        error: function() {
            console.log("Internal Server Error");
        }
    });     

});

});

Answer №5

I have discovered a method to generate a valid access-token directly from frontend (browser) JavaScript.

1) Start by installing the npm package jsrsasign from npm.

2) Include the files from this Gist into your project: https://gist.github.com/Venryx/bfa9b69583638dfbf611a9f292721a75

3) Fill in the values for all the constants at the beginning of DialogFlowExample.ts.

You can find your service account details at:

The email of the service account is listed in the table, and its private key (if you have one) can be located in the downloaded key json file. If you are unsure about the location of the key json file or haven't created one yet, you can use "Actions->Create key" to generate a new one.

4) Invoke GetAccessToken with your claim set and private key (refer to Gist for an example). It will provide a promise.

5) Once the access-token is acquired, the promise will be resolved with the obtained token. (The function stores the access-token for 60 minutes. After that timeframe, the token expires, so calling the function again will retrieve a new one.)

Illustration

The linked Gist presents an almost-complete usage scenario for converting audio segments to text using DialogFlow. The only missing part is how to fetch the "segment of audio".

To learn more about that, refer to part 1 of my response here:

Answer №6

This method has been effective for me.

const chatbot = require('dialogflow');
var botId = ""; // input your unique project ID in dialogflow settings
var sessionId = ""; // session ID
var configuration = {
    keyFilename: './google.json'
};

var userSession = new chatbot.SessionsClient(configuration);

async function sendMessageToChatbot(textMessage) {
    const sessionPath = userSession.sessionPath(botId, sessionId);
    const request = {
        session: sessionPath,
        queryInput: {
            text: {
                text: textMessage,
                languageCode: 'en'
            }
        }
    };

    try {
        let [responses] = await userSession.detectIntent(request);
        console.log(responses);
    } catch (error) {
        console.error('Error sending message to Chatbot:', error);
        throw error;
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When a visitor accesses a webpage, enable port listening with Node.js and Express

Struggling to navigate the world of node.js, express, and port listening. My code is functioning properly, but only if I manually enter 'node index.js' in terminal to listen on port 3000... After hours of searching for a solution, my head is spi ...

Arranging Material UI tabs on both sides

I'm currently working with Material UI tabs and I'm trying to achieve a layout where some tabs are positioned to the left and others to the right. For instance, if I have 5 tabs, I want 3 on the left and 2 on the right. I've tried placing th ...

Dealing with multiple event emissions in Express-generator with Socket.io

I recently created a node app using express generator and successfully integrated socket.io in the application. I followed this procedure to ensure that Socket connection and listening server are set up properly, allowing me to make io available throughout ...

Tips on avoiding a div from causing its parent's mousemove event to activate if it is concealed

I have a collection of media content with a set of controls positioned above it. I am attempting to implement functionality where the controls will disappear when the user's mouse is inactive and reappear upon mouse movement. However, I am facing an ...

Remove element from associative array in TypeScript

I encountered a code snippet like the one below let failures: Map<string, Array<string>> = new Map([ ['1', ['a', 'b']], ['2', ['c', 'd']], ['3', ['e', ' ...

Secondary Electron window not properly receiving IPC messages

While developing my TypeScript code that is linked to the HTML being executed by my application, I encountered an issue with creating a new window for my settings. It seems that the preloaded script is loaded onto the new window upon opening, but the windo ...

Is it possible to modify the CSS styles for a specific portion of an input value?

Currently, I am in the process of developing a form using React.js where a specific input must match the label written above it. Here is an example: https://i.stack.imgur.com/S2wOV.png If there happens to be a typo, the text should turn red like this: h ...

Verify whether an array in javascript consists of multiple values

[ { _id: "646231c54574e0e7ffc569e9", users: [ { _id: "6461ef44496eff14402778af", name: "Salman Khan" }, { _id: "6461f15bb4e0a6c7addc9fb0", name: "Yash ...

Error in Firefox when converting a string to a date in JavaScript using the format mm-dd-yyyy

Hi, I am encountering an issue with converting a string in the format mm-dd-yyyy into a date object. While it works perfectly fine in Internet Explorer and Chrome, it does not work in Firefox as it returns an invalid date at times. I have also tried using ...

Refining/searching with selectors in AJAX response

As someone who is new to javascript and coding in general, I am facing a challenge with filtering and manipulating data received through an AJAX request. Unfortunately, I do not have access to the server-side code. The server responds with rota information ...

Executing function after completion of ajax call

I have 2 buttons and 3 links that trigger an ajax request. I want to display an alert only when the request initiated by one of the buttons is completed, but not when a link is clicked. Below is my code: HTML: <button id="ajax1">Ajax 1</button&g ...

Trigger the click event on the ul element instead of the li element using jQuery

Is there a way to make the click event only affect ul tags and not all li elements using jQuery? <!-- HTML --> <ul class="wrap"> <li>test1</li> <li>test2</li> <li>test3</li> </ul> I attemp ...

Developing JavaScript regular expressions with exclusions within a specified range

The regular expression I am currently using ... var my_var = new RegExp('^[a-zA-Z0-9 ]+$') ... This regex selects characters a-z, A-Z, 0-9, and space while excluding all other characters. However, I now want to include '(', ')& ...

How can we alter all elements that are missing an index?

Is there a way to selectively hide all elements with the class .dropdown-menu, except for the second one? I've tried using the following code snippet, but it doesn't seem to be working: $('.dropdown-menu').not().eq(1).hide(); If anyon ...

Three divs are set in place, with two of them of fixed width while the third div is

Looking for a layout with specific positioning and fixed widths: One box on the left, one box on the right, each with a width of 200px. The middle div should adjust to take up the remaining space. Any suggestions are appreciated. Thank you! ...

Dynamically update a directive array in Vue.js based on real-time changes

In my Vue project, I have an array defined in the data() method that is populated through a custom directive in its bind hook. Here's the code snippet: import Vue from 'vue' export default { el: '#showingFilters', name: "Filte ...

Error in inferring argument types for a generic interface function in Typescript

Unique interface export interface DataService { getByTypeId<T extends number | string>(id: T): Promise<SomeType>; } Additionally, the implementation export class BService implements DataService { async getByTypeId(id: number): Promise&l ...

angular table disabled based on condition

I have a table in my HTML file and I am trying to figure out how to disable the onClick function if the start date is greater than the current date. <ng-container matColumnDef="d"> <th mat-header-cell ...

Adjust css style based on the current time of day

I recently came across this fascinating tutorial that demonstrates an animation changing from day to night every 30 minutes. The concept is very appealing, but I began contemplating how to adapt this animation to reflect real-time changes between day and ...

JavaScript: How can I remove it when I click anywhere on the webpage with onClick?

A challenge I'm facing involves creating a form with an input field that changes its border color when clicked. My goal is for the border to return to its original color when clicking anywhere else on the page. -HTML <form action=""> ...