diff --git a/.github/workflows/dialogflow.yaml b/.github/workflows/dialogflow.yaml new file mode 100644 index 0000000000..32e4437c09 --- /dev/null +++ b/.github/workflows/dialogflow.yaml @@ -0,0 +1,68 @@ +name: dialogflow +on: + push: + branches: + - main + paths: + - 'dialogflow/**' + pull_request: + paths: + - 'dialogflow/**' + pull_request_target: + types: [labeled] + paths: + - 'dialogflow/**' + schedule: + - cron: '0 0 * * 0' +jobs: + test: + if: ${{ github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' }} + runs-on: ubuntu-latest + timeout-minutes: 60 + permissions: + contents: 'write' + pull-requests: 'write' + id-token: 'write' + steps: + - uses: actions/checkout@v3.1.0 + with: + ref: ${{github.event.pull_request.head.sha}} + - uses: 'google-github-actions/auth@v1.0.0' + with: + workload_identity_provider: 'projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider' + service_account: 'kokoro-system-test@long-door-651.iam.gserviceaccount.com' + create_credentials_file: 'true' + access_token_lifetime: 600s + - uses: actions/setup-node@v3.5.1 + with: + node-version: 16 + - run: npm install + working-directory: dialogflow + - run: npm test + working-directory: dialogflow + env: + MOCHA_REPORTER_SUITENAME: dialogflow + MOCHA_REPORTER_OUTPUT: dialogflow_sponge_log.xml + MOCHA_REPORTER: xunit + - if: ${{ github.event.action == 'labeled' && github.event.label.name == 'actions:force-run' }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + try { + await github.rest.issues.removeLabel({ + name: 'actions:force-run', + owner: 'GoogleCloudPlatform', + repo: 'nodejs-docs-samples', + issue_number: context.payload.pull_request.number + }); + } catch (e) { + if (!e.message.includes('Label does not exist')) { + throw e; + } + } + - if: ${{ github.event_name == 'schedule'}} + run: | + curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L + chmod +x ./flakybot + ./flakybot --repo GoogleCloudPlatform/nodejs-docs-samples --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} diff --git a/.github/workflows/workflows.json b/.github/workflows/workflows.json index cfd118cd08..e3c110eeed 100644 --- a/.github/workflows/workflows.json +++ b/.github/workflows/workflows.json @@ -31,6 +31,7 @@ "datalabeling", "datastore/functions", "datacatalog/quickstart", + "dialogflow", "document-ai", "endpoints/getting-started", "endpoints/getting-started-grpc", diff --git a/dialogflow/.gitignore b/dialogflow/.gitignore new file mode 100644 index 0000000000..491f765ddb --- /dev/null +++ b/dialogflow/.gitignore @@ -0,0 +1,2 @@ +SampleAgent.zip +resources/pizza_order.wav diff --git a/dialogflow/create-intent.js b/dialogflow/create-intent.js new file mode 100644 index 0000000000..e2fc485b10 --- /dev/null +++ b/dialogflow/create-intent.js @@ -0,0 +1,99 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +/** + * Create an intent. + * @param {string} projectId The project to be used + * @param {string} displayName Display Name + * @param {string} trainingPhrasesParts Training Phrases + * @param {string} messageTexts Message Texts + */ +function main( + projectId = 'YOUR_PROJECT_ID', + displayName = 'YOUR_INTENT_DISPLAY_NAME', + trainingPhrasesParts = [ + 'Hello, What is weather today?', + 'How is the weather today?', + ], + messageTexts = ['Rainy', 'Sunny'] +) { + // [START dialogflow_create_intent] + + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // const projectId = 'The Project ID to use, e.g. 'YOUR_GCP_ID'; + // const displayName = 'The display name of the intent, e.g. 'MAKE_RESERVATION'; + // const trainingPhrasesParts = 'Training phrases, e.g. 'How many people are staying?'; + // const messageTexts = 'Message texts for the agent's response when the intent is detected, e.g. 'Your reservation has been confirmed'; + + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates the Intent Client + const intentsClient = new dialogflow.IntentsClient(); + + async function createIntent() { + // Construct request + + // The path to identify the agent that owns the created intent. + const agentPath = intentsClient.projectAgentPath(projectId); + + const trainingPhrases = []; + + trainingPhrasesParts.forEach(trainingPhrasesPart => { + const part = { + text: trainingPhrasesPart, + }; + + // Here we create a new training phrase for each provided part. + const trainingPhrase = { + type: 'EXAMPLE', + parts: [part], + }; + + trainingPhrases.push(trainingPhrase); + }); + + const messageText = { + text: messageTexts, + }; + + const message = { + text: messageText, + }; + + const intent = { + displayName: displayName, + trainingPhrases: trainingPhrases, + messages: [message], + }; + + const createIntentRequest = { + parent: agentPath, + intent: intent, + }; + + // Create the intent + const [response] = await intentsClient.createIntent(createIntentRequest); + console.log(`Intent ${response.name} created`); + } + + createIntent(); + + // [END dialogflow_create_intent] +} +main(...process.argv.slice(2)); diff --git a/dialogflow/detect-intent-TTS-response.v2.js b/dialogflow/detect-intent-TTS-response.v2.js new file mode 100644 index 0000000000..d8992692f7 --- /dev/null +++ b/dialogflow/detect-intent-TTS-response.v2.js @@ -0,0 +1,72 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; +async function main( + projectId = 'YOUR_PROJECT_ID', + sessionId = 'YOUR_SESSION_ID', + query = 'YOUR_QUERY', + languageCode = 'YOUR_LANGUAGE_CODE', + outputFile = 'YOUR_OUTPUT_FILE' +) { + // [START dialogflow_detect_intent_with_texttospeech_response] + // Imports the Dialogflow client library + const dialogflow = require('@google-cloud/dialogflow').v2; + + // Instantiate a DialogFlow client. + const sessionClient = new dialogflow.SessionsClient(); + + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // const projectId = 'ID of GCP project associated with your Dialogflow agent'; + // const sessionId = `user specific ID of session, e.g. 12345`; + // const query = `phrase(s) to pass to detect, e.g. I'd like to reserve a room for six people`; + // const languageCode = 'BCP-47 language code, e.g. en-US'; + // const outputFile = `path for audio output file, e.g. ./resources/myOutput.wav`; + + // Define session path + const sessionPath = sessionClient.projectAgentSessionPath( + projectId, + sessionId + ); + const fs = require('fs'); + const util = require('util'); + + async function detectIntentwithTTSResponse() { + // The audio query request + const request = { + session: sessionPath, + queryInput: { + text: { + text: query, + languageCode: languageCode, + }, + }, + outputAudioConfig: { + audioEncoding: 'OUTPUT_AUDIO_ENCODING_LINEAR_16', + }, + }; + sessionClient.detectIntent(request).then(responses => { + console.log('Detected intent:'); + const audioFile = responses[0].outputAudio; + util.promisify(fs.writeFile)(outputFile, audioFile, 'binary'); + console.log(`Audio content written to file: ${outputFile}`); + }); + } + detectIntentwithTTSResponse(); + // [END dialogflow_detect_intent_with_texttospeech_response] +} + +main(...process.argv.slice(2)); diff --git a/dialogflow/detect-intent-sentiment.v2.js b/dialogflow/detect-intent-sentiment.v2.js new file mode 100644 index 0000000000..dfcc312dc3 --- /dev/null +++ b/dialogflow/detect-intent-sentiment.v2.js @@ -0,0 +1,86 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; +async function main( + projectId = 'YOUR_PROJECT_ID', + sessionId = 'YOUR_SESSION_ID', + query = 'YOUR_QUERY', + languageCode = 'YOUR_LANGUAGE_CODE' +) { + // [START dialogflow_detect_intent_with_sentiment_analysis] + // Imports the Dialogflow client library + const dialogflow = require('@google-cloud/dialogflow').v2; + + // Instantiate a DialogFlow client. + const sessionClient = new dialogflow.SessionsClient(); + + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // const projectId = 'ID of GCP project associated with your Dialogflow agent'; + // const sessionId = `user specific ID of session, e.g. 12345`; + // const query = `phrase(s) to pass to detect, e.g. I'd like to reserve a room for six people`; + // const languageCode = 'BCP-47 language code, e.g. en-US'; + + // Define session path + const sessionPath = sessionClient.projectAgentSessionPath( + projectId, + sessionId + ); + + async function detectIntentandSentiment() { + // The text query request. + const request = { + session: sessionPath, + queryInput: { + text: { + text: query, + languageCode: languageCode, + }, + }, + queryParams: { + sentimentAnalysisRequestConfig: { + analyzeQueryTextSentiment: true, + }, + }, + }; + + // Send request and log result + const responses = await sessionClient.detectIntent(request); + 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.'); + } + if (result.sentimentAnalysisResult) { + console.log('Detected sentiment'); + console.log( + ` Score: ${result.sentimentAnalysisResult.queryTextSentiment.score}` + ); + console.log( + ` Magnitude: ${result.sentimentAnalysisResult.queryTextSentiment.magnitude}` + ); + } else { + console.log('No sentiment Analysis Found'); + } + // [END dialogflow_detect_intent_with_sentiment_analysis] + } + detectIntentandSentiment(); +} +main(...process.argv.slice(2)); diff --git a/dialogflow/detect.js b/dialogflow/detect.js new file mode 100644 index 0000000000..ef4e50f045 --- /dev/null +++ b/dialogflow/detect.js @@ -0,0 +1,486 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +function detectTextIntent(projectId, sessionId, queries, languageCode) { + // [START dialogflow_detect_intent_text] + + /** + * TODO(developer): UPDATE these variables before running the sample. + */ + // projectId: ID of the GCP project where Dialogflow agent is deployed + // const projectId = 'PROJECT_ID'; + // sessionId: String representing a random number or hashed user identifier + // const sessionId = '123456'; + // queries: A set of sequential queries to be send to Dialogflow agent for Intent Detection + // const queries = [ + // 'Reserve a meeting room in Toronto office, there will be 5 of us', + // 'Next monday at 3pm for 1 hour, please', // Tell the bot when the meeting is taking place + // 'B' // Rooms are defined on the Dialogflow agent, default options are A, B, or C + // ] + // languageCode: Indicates the language Dialogflow agent should use to detect intents + // const languageCode = 'en'; + + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates a session client + const sessionClient = new dialogflow.SessionsClient(); + + async function detectIntent( + projectId, + sessionId, + query, + contexts, + languageCode + ) { + // The path to identify the agent that owns the created intent. + const sessionPath = sessionClient.projectAgentSessionPath( + projectId, + sessionId + ); + + // The text query request. + const request = { + session: sessionPath, + queryInput: { + text: { + text: query, + languageCode: languageCode, + }, + }, + }; + + if (contexts && contexts.length > 0) { + request.queryParams = { + contexts: contexts, + }; + } + + const responses = await sessionClient.detectIntent(request); + return responses[0]; + } + + async function executeQueries(projectId, sessionId, queries, languageCode) { + // Keeping the context across queries let's us simulate an ongoing conversation with the bot + let context; + let intentResponse; + for (const query of queries) { + try { + console.log(`Sending Query: ${query}`); + intentResponse = await detectIntent( + projectId, + sessionId, + query, + context, + languageCode + ); + console.log('Detected intent'); + console.log( + `Fulfillment Text: ${intentResponse.queryResult.fulfillmentText}` + ); + // Use the context from this response for next queries + context = intentResponse.queryResult.outputContexts; + } catch (error) { + console.log(error); + } + } + } + executeQueries(projectId, sessionId, queries, languageCode); + // [END dialogflow_detect_intent_text] +} + +async function detectEventIntent( + projectId, + sessionId, + eventName, + languageCode +) { + const {struct} = require('pb-util'); + + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates a session client + const sessionClient = new dialogflow.SessionsClient(); + + // The path to identify the agent that owns the created intent. + const sessionPath = sessionClient.projectAgentSessionPath( + projectId, + sessionId + ); + + // The text query request. + const request = { + session: sessionPath, + queryInput: { + event: { + name: eventName, + parameters: struct.encode({foo: 'bar'}), + languageCode: languageCode, + }, + }, + }; + + const [response] = await sessionClient.detectIntent(request); + console.log('Detected intent'); + const result = response.queryResult; + // Instantiates a context client + const contextClient = new dialogflow.ContextsClient(); + + 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.'); + } + const parameters = JSON.stringify(struct.decode(result.parameters)); + console.log(` Parameters: ${parameters}`); + if (result.outputContexts && result.outputContexts.length) { + console.log(' Output contexts:'); + result.outputContexts.forEach(context => { + const contextId = + contextClient.matchContextFromProjectAgentSessionContextName( + context.name + ); + const contextParameters = JSON.stringify( + struct.decode(context.parameters) + ); + console.log(` ${contextId}`); + console.log(` lifespan: ${context.lifespanCount}`); + console.log(` parameters: ${contextParameters}`); + }); + } +} + +async function detectAudioIntent( + projectId, + sessionId, + filename, + encoding, + sampleRateHertz, + languageCode +) { + // [START dialogflow_detect_intent_audio] + const fs = require('fs'); + const util = require('util'); + const {struct} = require('pb-util'); + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates a session client + const sessionClient = new dialogflow.SessionsClient(); + + // The path to identify the agent that owns the created intent. + const sessionPath = sessionClient.projectAgentSessionPath( + projectId, + sessionId + ); + + // Read the content of the audio file and send it as part of the request. + const readFile = util.promisify(fs.readFile); + const inputAudio = await readFile(filename); + const request = { + session: sessionPath, + queryInput: { + audioConfig: { + audioEncoding: encoding, + sampleRateHertz: sampleRateHertz, + languageCode: languageCode, + }, + }, + inputAudio: inputAudio, + }; + + // Recognizes the speech in the audio and detects its intent. + const [response] = await sessionClient.detectIntent(request); + + console.log('Detected intent:'); + const result = response.queryResult; + // Instantiates a context client + const contextClient = new dialogflow.ContextsClient(); + + 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.'); + } + const parameters = JSON.stringify(struct.decode(result.parameters)); + console.log(` Parameters: ${parameters}`); + if (result.outputContexts && result.outputContexts.length) { + console.log(' Output contexts:'); + result.outputContexts.forEach(context => { + const contextId = + contextClient.matchContextFromProjectAgentSessionContextName( + context.name + ); + const contextParameters = JSON.stringify( + struct.decode(context.parameters) + ); + console.log(` ${contextId}`); + console.log(` lifespan: ${context.lifespanCount}`); + console.log(` parameters: ${contextParameters}`); + }); + } + // [END dialogflow_detect_intent_audio] +} + +async function streamingDetectIntent( + projectId, + sessionId, + filename, + encoding, + sampleRateHertz, + languageCode +) { + // [START dialogflow_detect_intent_streaming] + const fs = require('fs'); + const util = require('util'); + const {Transform, pipeline} = require('stream'); + const {struct} = require('pb-util'); + + const pump = util.promisify(pipeline); + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates a session client + const sessionClient = new dialogflow.SessionsClient(); + + // The path to the local file on which to perform speech recognition, e.g. + // /path/to/audio.raw const filename = '/path/to/audio.raw'; + + // The encoding of the audio file, e.g. 'AUDIO_ENCODING_LINEAR_16' + // const encoding = 'AUDIO_ENCODING_LINEAR_16'; + + // The sample rate of the audio file in hertz, e.g. 16000 + // const sampleRateHertz = 16000; + + // The BCP-47 language code to use, e.g. 'en-US' + // const languageCode = 'en-US'; + const sessionPath = sessionClient.projectAgentSessionPath( + projectId, + sessionId + ); + + const initialStreamRequest = { + session: sessionPath, + queryInput: { + audioConfig: { + audioEncoding: encoding, + sampleRateHertz: sampleRateHertz, + languageCode: languageCode, + }, + }, + }; + + // Create a stream for the streaming request. + const detectStream = sessionClient + .streamingDetectIntent() + .on('error', console.error) + .on('data', data => { + if (data.recognitionResult) { + console.log( + `Intermediate transcript: ${data.recognitionResult.transcript}` + ); + } else { + console.log('Detected intent:'); + + const result = data.queryResult; + // Instantiates a context client + const contextClient = new dialogflow.ContextsClient(); + + 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.'); + } + const parameters = JSON.stringify(struct.decode(result.parameters)); + console.log(` Parameters: ${parameters}`); + if (result.outputContexts && result.outputContexts.length) { + console.log(' Output contexts:'); + result.outputContexts.forEach(context => { + const contextId = + contextClient.matchContextFromProjectAgentSessionContextName( + context.name + ); + const contextParameters = JSON.stringify( + struct.decode(context.parameters) + ); + console.log(` ${contextId}`); + console.log(` lifespan: ${context.lifespanCount}`); + console.log(` parameters: ${contextParameters}`); + }); + } + } + }); + + // Write the initial stream request to config for audio input. + detectStream.write(initialStreamRequest); + + // Stream an audio file from disk to the Conversation API, e.g. + // "./resources/audio.raw" + await pump( + fs.createReadStream(filename), + // Format the audio stream into the request format. + new Transform({ + objectMode: true, + transform: (obj, _, next) => { + next(null, {inputAudio: obj}); + }, + }), + detectStream + ); + // [END dialogflow_detect_intent_streaming] +} + +const cli = require('yargs') + .demand(1) + .options({ + projectId: { + alias: 'p', + default: process.env.GCLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT, + description: + 'The Project ID to use. Defaults to the value of the ' + + 'GCLOUD_PROJECT or GOOGLE_CLOUD_PROJECT environment variables.', + requiresArg: true, + type: 'string', + }, + sessionId: { + alias: 's', + default: require('uuid').v1(), + type: 'string', + requiresArg: true, + description: + 'The identifier of the detect session. Defaults to a random UUID.', + }, + languageCode: { + alias: 'l', + default: 'en-US', + type: 'string', + requiresArg: true, + description: 'The language code of the query. Defaults to "en-US".', + }, + encoding: { + alias: 'e', + default: 'AUDIO_ENCODING_LINEAR_16', + choices: [ + 'AUDIO_ENCODING_LINEAR_16', + 'AUDIO_ENCODING_FLAC', + 'AUDIO_ENCODING_MULAW', + 'AUDIO_ENCODING_AMR', + 'AUDIO_ENCODING_AMR_WB', + 'AUDIO_ENCODING_OGG_OPUS', + 'AUDIO_ENCODING_SPEEX_WITH_HEADER_BYTE', + ], + requiresArg: true, + description: 'The encoding of the input audio.', + }, + sampleRateHertz: { + alias: 'r', + type: 'number', + description: + 'The sample rate in Hz of the input audio. Only ' + + 'required if the input audio is in raw format.', + }, + }) + .demandOption( + 'projectId', + "Please provide your Dialogflow agent's project ID with the -p flag or through the GOOGLE_CLOUD_PROJECT env var" + ) + .command( + 'text', + 'Detects the intent for text queries.', + { + queries: { + alias: 'q', + array: true, + string: true, + demandOption: true, + requiresArg: true, + description: 'An array of text queries', + }, + }, + opts => + detectTextIntent( + opts.projectId, + opts.sessionId, + opts.queries, + opts.languageCode + ) + ) + .command( + 'event ', + 'Detects the intent for a client-generated event name.', + {}, + opts => + detectEventIntent( + opts.projectId, + opts.sessionId, + opts.eventName, + opts.languageCode + ) + ) + .command( + 'audio ', + 'Detects the intent for audio queries in a local file.', + {}, + opts => + detectAudioIntent( + opts.projectId, + opts.sessionId, + opts.filename, + opts.encoding, + opts.sampleRateHertz, + opts.languageCode + ) + ) + .command( + 'stream ', + 'Detects the intent in a local audio file by streaming it to the ' + + 'Conversation API.', + {}, + opts => + streamingDetectIntent( + opts.projectId, + opts.sessionId, + opts.filename, + opts.encoding, + opts.sampleRateHertz, + opts.languageCode + ) + ) + .example( + 'node $0 text -q "hello" "book a room" "Mountain View" ' + + '"today" "230pm" "half an hour" "two people" "A" "yes"' + ) + .example('node $0 event order_pizza') + .example('node $0 audio resources/book_a_room.wav -r 16000') + .example('node $0 stream resources/mountain_view.wav -r 16000') + .wrap(120) + .recommendCommands() + .epilogue( + 'For more information, see https://cloud.google.com/dialogflow-enterprise/docs' + ) + .help() + .strict(); + +if (module === require.main) { + cli.parse(process.argv.slice(2)); +} diff --git a/dialogflow/detect.v2beta1.js b/dialogflow/detect.v2beta1.js new file mode 100644 index 0000000000..e3bcb81d03 --- /dev/null +++ b/dialogflow/detect.v2beta1.js @@ -0,0 +1,453 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const sessionId = require('uuid').v1(); +const util = require('util'); + +async function createKnowledgeBase(projectId, displayName) { + // [START dialogflow_create_knowledge_base] + // Imports the Dialogflow client library + const dialogflow = require('@google-cloud/dialogflow').v2beta1; + + // Instantiate a DialogFlow client. + const client = new dialogflow.KnowledgeBasesClient(); + + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // const projectId = 'ID of GCP project associated with your Dialogflow agent'; + // const displayName = `your knowledge base display name, e.g. myKnowledgeBase`; + + const formattedParent = 'projects/' + projectId; + const knowledgeBase = { + displayName: displayName, + }; + const request = { + parent: formattedParent, + knowledgeBase: knowledgeBase, + }; + + const [result] = await client.createKnowledgeBase(request); + console.log(`Name: ${result.name}`); + console.log(`displayName: ${result.displayName}`); + + // [END dialogflow_create_knowledge_base] +} + +/* + *This test is commented until the proto change for dialogflow/v2beta1 is finished. + */ +// async function createDocument( +// projectId, +// knowledgeBaseFullName, +// documentPath, +// documentName, +// knowledgeTypes, +// mimeType +// ) { +// // [START dialogflow_create_document] +// // Imports the Dialogflow client library +// const dialogflow = require('@google-cloud/dialogflow').v2beta1; + +// // Instantiate a DialogFlow Documents client. +// const client = new dialogflow.DocumentsClient({ +// projectId: projectId, +// }); + +// /** +// * TODO(developer): Uncomment the following lines before running the sample. +// */ +// // const projectId = 'ID of GCP project associated with your Dialogflow agent'; +// // const knowledgeBaseFullName = `the full path of your knowledge base, e.g my-Gcloud-project/myKnowledgeBase`; +// // const documentPath = `path of the document you'd like to add, e.g. https://dialogflow.com/docs/knowledge-connectors`; +// // const documentName = `displayed name of your document in knowledge base, e.g. myDoc`; +// // const knowledgeTypes = `The Knowledge type of the Document. e.g. FAQ`; +// // const mimeType = `The mime_type of the Document. e.g. text/csv, text/html,text/plain, text/pdf etc.`; + +// const request = { +// parent: knowledgeBaseFullName, +// document: { +// knowledgeTypes: [knowledgeTypes], +// displayName: documentName, +// contentUri: documentPath, +// source: 'contentUri', +// mimeType: mimeType, +// }, +// }; + +// const [operation] = await client.createDocument(request); +// const [response] = await operation.promise(); + +// console.log('Document created'); +// console.log(`Content URI...${response.contentUri}`); +// console.log(`displayName...${response.displayName}`); +// console.log(`mimeType...${response.mimeType}`); +// console.log(`name...${response.name}`); +// console.log(`source...${response.source}`); + +// // [END dialogflow_create_document] +// } + +async function detectIntentandSentiment( + projectId, + sessionId, + query, + languageCode +) { + // [START dialogflow_detect_intent_with_sentiment_analysis] + // Imports the Dialogflow client library + const dialogflow = require('@google-cloud/dialogflow').v2beta1; + // Instantiate a DialogFlow client. + const sessionClient = new dialogflow.SessionsClient(); + + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // const projectId = 'ID of GCP project associated with your Dialogflow agent'; + // const sessionId = `user specific ID of session, e.g. 12345`; + // const query = `phrase(s) to pass to detect, e.g. I'd like to reserve a room for six people`; + // const languageCode = 'BCP-47 language code, e.g. en-US'; + + // Define session path + const sessionPath = sessionClient.projectAgentSessionPath( + projectId, + sessionId + ); + + // The text query request. + const request = { + session: sessionPath, + queryInput: { + text: { + text: query, + languageCode: languageCode, + }, + }, + queryParams: { + sentimentAnalysisRequestConfig: { + analyzeQueryTextSentiment: true, + }, + }, + }; + + // Send request and log result + const responses = await sessionClient.detectIntent(request); + 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.'); + } + if (result.sentimentAnalysisResult) { + console.log('Detected sentiment'); + console.log( + ` Score: ${result.sentimentAnalysisResult.queryTextSentiment.score}` + ); + console.log( + ` Magnitude: ${result.sentimentAnalysisResult.queryTextSentiment.magnitude}` + ); + } else { + console.log('No sentiment Analysis Found'); + } + // [END dialogflow_detect_intent_with_sentiment_analysis] +} + +async function detectIntentwithTexttoSpeechResponse( + projectId, + sessionId, + query, + languageCode, + outputFile +) { + // [START dialogflow_detect_intent_with_texttospeech_response] + // Imports the Dialogflow client library + const dialogflow = require('@google-cloud/dialogflow').v2beta1; + // Instantiate a DialogFlow client. + const sessionClient = new dialogflow.SessionsClient(); + + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // const projectId = 'ID of GCP project associated with your Dialogflow agent'; + // const sessionId = `user specific ID of session, e.g. 12345`; + // const query = `phrase(s) to pass to detect, e.g. I'd like to reserve a room for six people`; + // const languageCode = 'BCP-47 language code, e.g. en-US'; + // const outputFile = `path for audio output file, e.g. ./resources/myOutput.wav`; + + // Define session path + const sessionPath = sessionClient.projectAgentSessionPath( + projectId, + sessionId + ); + const fs = require('fs'); + + // The audio query request + const request = { + session: sessionPath, + queryInput: { + text: { + text: query, + languageCode: languageCode, + }, + }, + outputAudioConfig: { + audioEncoding: 'OUTPUT_AUDIO_ENCODING_LINEAR_16', + }, + }; + + const responses = await sessionClient.detectIntent(request); + console.log('Detected intent:'); + const audioFile = responses[0].outputAudio; + await util.promisify(fs.writeFile)(outputFile, audioFile, 'binary'); + console.log(`Audio content written to file: ${outputFile}`); + // [END dialogflow_detect_intent_with_texttospeech_response] +} + +async function detectIntentKnowledge( + projectId, + sessionId, + languageCode, + knowledgeBaseId, + query +) { + // [START dialogflow_detect_intent_knowledge] + // Imports the Dialogflow client library + const dialogflow = require('@google-cloud/dialogflow').v2beta1; + // Instantiate a DialogFlow client. + const sessionClient = new dialogflow.SessionsClient(); + + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // const projectId = 'ID of GCP project associated with your Dialogflow agent'; + // const sessionId = `user specific ID of session, e.g. 12345`; + // const languageCode = 'BCP-47 language code, e.g. en-US'; + // const knowledgeBaseId = `the ID of your KnowledgeBase`; + // const query = `phrase(s) to pass to detect, e.g. I'd like to reserve a room for six people`; + + // Define session path + const sessionPath = sessionClient.projectAgentSessionPath( + projectId, + sessionId + ); + const knowledgeBasePath = + 'projects/' + projectId + '/knowledgeBases/' + knowledgeBaseId + ''; + + // The audio query request + const request = { + session: sessionPath, + queryInput: { + text: { + text: query, + languageCode: languageCode, + }, + }, + queryParams: { + knowledgeBaseNames: [knowledgeBasePath], + }, + }; + + const responses = await sessionClient.detectIntent(request); + const result = responses[0].queryResult; + console.log(`Query text: ${result.queryText}`); + console.log(`Detected Intent: ${result.intent.displayName}`); + console.log(`Confidence: ${result.intentDetectionConfidence}`); + console.log(`Query Result: ${result.fulfillmentText}`); + if (result.knowledgeAnswers && result.knowledgeAnswers.answers) { + const answers = result.knowledgeAnswers.answers; + console.log(`There are ${answers.length} answer(s);`); + answers.forEach(a => { + console.log(` answer: ${a.answer}`); + console.log(` confidence: ${a.matchConfidence}`); + console.log(` match confidence level: ${a.matchConfidenceLevel}`); + }); + } + // [END dialogflow_detect_intent_knowledge] +} + +const cli = require('yargs') + .demand(1) + .options({ + documentId: { + alias: 'd', + type: 'string', + requiresArg: true, + description: 'Full path of document in knowledge base', + }, + documentName: { + alias: 'm', + type: 'string', + default: 'testDoc', + requiresArg: true, + description: 'Name of Document to Create', + }, + documentPath: { + alias: 'z', + type: 'string', + requiresArg: true, + description: 'uri of document to be added', + }, + knowledgeBaseName: { + alias: 'k', + default: 'TestKnowledgeBase', + type: 'string', + requiresArg: true, + description: 'The name of the knowledge base to search from', + }, + knowledgeBaseFullName: { + alias: 'n', + type: 'string', + requiresArg: true, + description: 'full path knowledge base', + }, + knowledgeTypes: { + alias: 't', + type: 'string', + default: 'FAQ', + requiresArg: true, + description: 'The Knowledge type of the Document.', + }, + languageCode: { + alias: 'l', + default: 'en-US', + type: 'string', + requiresArg: true, + description: 'The language code of the query. Defaults to "en-US".', + }, + mimeType: { + alias: 'y', + default: 'text/html', + type: 'string', + requiresArg: true, + description: 'The mime_type of the Document', + }, + outputFile: { + alias: 'f', + default: './resources/output.wav', + global: true, + requiresArg: true, + type: 'string', + }, + projectId: { + alias: 'p', + default: process.env.GCLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT, + description: + 'The Project ID to use. Defaults to the value of the ' + + 'GCLOUD_PROJECT or GOOGLE_CLOUD_PROJECT environment variables.', + requiresArg: true, + type: 'string', + }, + query: { + alias: 'q', + array: true, + string: true, + demandOption: true, + requiresArg: true, + description: 'An array of text queries', + default: 'Where is my data stored?', + }, + sessionId: { + alias: 's', + default: sessionId, + type: 'string', + requiresArg: true, + description: + 'The identifier of the detect session. Defaults to a random UUID.', + }, + }) + .command('createKnowledgeBase', 'Creates a new knowledge base', {}, opts => + createKnowledgeBase(opts.projectId, opts.knowledgeBaseName) + ) + /** + * TODO(developer): Uncomment the following lines until proto updates for dialogflow/v2beta1 is complete. + * This method should be annotated with (google.longrunning.operationInfo) to generate LRO methods. + * Now it's a simple method, without proper LRO response, so it fails because `promise() is not a function`. + */ + // .command( + // 'createDocument', + // 'Creates a new document for this knowledge base', + // {}, + // opts => + // createDocument( + // opts.projectId, + // opts.knowledgeBaseFullName, + // opts.documentPath, + // opts.documentName, + // opts.knowledgeTypes, + // opts.mimeType + // ) + // ) + .command( + 'detectIntentwithTexttoSpeechResponse', + 'Detects the intent of text input, outputs .wav file to target location', + {}, + opts => + detectIntentwithTexttoSpeechResponse( + opts.projectId, + opts.sessionId, + opts.query, + opts.languageCode, + opts.outputFile + ) + ) + .command( + 'detectIntentKnowledge', + 'Detects answers from knowledge base queries', + {}, + opts => + detectIntentKnowledge( + opts.projectId, + opts.sessionId, + opts.languageCode, + opts.knowledgeBaseFullName, + opts.query + ) + ) + .command( + 'detectIntentandSentiment', + 'Detects sentiment with detect Intent query', + {}, + opts => + detectIntentandSentiment( + opts.projectId, + opts.sessionId, + opts.query, + opts.languageCode + ) + ) + .example('node $0 createKnowledgeBase -k "newTestKnowledgeBase"') + .example( + 'node $0 createDocument -n "KNOWLEDGEBASEFULLNAME" -p "URIHTMLPATHTODOC" -m "MyDoc"' + ) + .example('node $0 detectIntentwithTexttoSpeechResponse "How do I sign up?"') + .example('node $0 detectIntentKnowledge -q "how do i sign up?"') + .example( + 'node $0 detectIntentandSentiment "Book a great room for six great folks!"' + ) + .wrap(120) + .recommendCommands() + .epilogue( + 'For more information, see https://cloud.google.com/dialogflow-enterprise/docs' + ) + .help() + .strict(); + +if (module === require.main) { + cli.parse(process.argv.slice(2)); +} diff --git a/dialogflow/list-intents.js b/dialogflow/list-intents.js new file mode 100644 index 0000000000..2aeca9f8c4 --- /dev/null +++ b/dialogflow/list-intents.js @@ -0,0 +1,74 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +/** + * List of all intents in the specified project. + * @param {string} projectId The project to be used + */ +function main(projectId = 'YOUR_PROJECT_ID') { + // [START dialogflow_list_intents] + + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // const projectId = 'The Project ID to use, e.g. 'YOUR_GCP_ID'; + + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates clients + const intentsClient = new dialogflow.IntentsClient(); + + async function listIntents() { + // Construct request + + // The path to identify the agent that owns the intents. + const projectAgentPath = intentsClient.projectAgentPath(projectId); + + console.log(projectAgentPath); + + const request = { + parent: projectAgentPath, + }; + + // Send the request for listing intents. + const [response] = await intentsClient.listIntents(request); + response.forEach(intent => { + console.log('===================='); + console.log(`Intent name: ${intent.name}`); + console.log(`Intent display name: ${intent.displayName}`); + console.log(`Action: ${intent.action}`); + console.log(`Root folowup intent: ${intent.rootFollowupIntentName}`); + console.log(`Parent followup intent: ${intent.parentFollowupIntentName}`); + + console.log('Input contexts:'); + intent.inputContextNames.forEach(inputContextName => { + console.log(`\tName: ${inputContextName}`); + }); + + console.log('Output contexts:'); + intent.outputContexts.forEach(outputContext => { + console.log(`\tName: ${outputContext.name}`); + }); + }); + } + + listIntents(); + + // [END dialogflow_list_intents] +} + +main(...process.argv.slice(2)); diff --git a/dialogflow/listTrainingPhrases.js b/dialogflow/listTrainingPhrases.js new file mode 100644 index 0000000000..876a793a83 --- /dev/null +++ b/dialogflow/listTrainingPhrases.js @@ -0,0 +1,43 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(projectId, intentId) { + // [START dialogflow_list_training_phrases] + const {IntentsClient} = require('@google-cloud/dialogflow'); + + // Create the intents client + const intentClient = new IntentsClient(); + + // Specify working intent + const intentName = `projects/${projectId}/agent/intents/${intentId}`; + + // Compose the get-intent request + const getIntentRequest = { + name: intentName, + intentView: 'INTENT_VIEW_FULL', + }; + + const intent = await intentClient.getIntent(getIntentRequest); + + console.log(intent[0].trainingPhrases); + // [END dialogflow_list_training_phrases] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/dialogflow/package.json b/dialogflow/package.json new file mode 100644 index 0000000000..d17cac0bcb --- /dev/null +++ b/dialogflow/package.json @@ -0,0 +1,27 @@ +{ + "name": "nodejs-docs-samples-conversation", + "private": true, + "license": "Apache-2.0", + "author": "Google LLC", + "repository": "googleapis/nodejs-dialogflow", + "files": [ + "*.js", + "resources" + ], + "engines": { + "node": ">=12.0.0" + }, + "scripts": { + "test": "mocha system-test --timeout=600000" + }, + "dependencies": { + "@google-cloud/dialogflow": "^5.3.0", + "pb-util": "^1.0.0", + "uuid": "^9.0.0", + "yargs": "^16.0.0" + }, + "devDependencies": { + "chai": "^4.2.0", + "mocha": "^8.0.0" + } +} diff --git a/dialogflow/resource.js b/dialogflow/resource.js new file mode 100644 index 0000000000..5814b873de --- /dev/null +++ b/dialogflow/resource.js @@ -0,0 +1,278 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +// ///////////////////////////////////////////////////////////////////////////// +// Operations for intents +// ///////////////////////////////////////////////////////////////////////////// + +async function deleteIntent(projectId, intentId) { + // [START dialogflow_delete_intent] + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates clients + const intentsClient = new dialogflow.IntentsClient(); + + const intentPath = intentsClient.projectAgentIntentPath(projectId, intentId); + + const request = {name: intentPath}; + + // Send the request for deleting the intent. + const result = await intentsClient.deleteIntent(request); + console.log(`Intent ${intentPath} deleted`); + return result; + // [END dialogflow_delete_intent] +} + +// ///////////////////////////////////////////////////////////////////////////// +// Operations for session entity type +// ///////////////////////////////////////////////////////////////////////////// + +async function createSessionEntityType( + projectId, + sessionId, + entityValues, + entityTypeDisplayName, + entityOverrideMode +) { + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates clients + const sessionEntityTypesClient = new dialogflow.SessionEntityTypesClient(); + + const sessionPath = sessionEntityTypesClient.projectAgentSessionPath( + projectId, + sessionId + ); + const sessionEntityTypePath = + sessionEntityTypesClient.projectAgentSessionEntityTypePath( + projectId, + sessionId, + entityTypeDisplayName + ); + + // Here we use the entity value as the only synonym. + const entities = []; + entityValues.forEach(entityValue => { + entities.push({ + value: entityValue, + synonyms: [entityValue], + }); + }); + + const sessionEntityTypeRequest = { + parent: sessionPath, + sessionEntityType: { + name: sessionEntityTypePath, + entityOverrideMode: entityOverrideMode, + entities: entities, + }, + }; + + const [response] = await sessionEntityTypesClient.createSessionEntityType( + sessionEntityTypeRequest + ); + console.log('SessionEntityType created:'); + console.log(response); +} + +async function listSessionEntityTypes(projectId, sessionId) { + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates clients + const sessionEntityTypesClient = new dialogflow.SessionEntityTypesClient(); + const sessionPath = sessionEntityTypesClient.projectAgentSessionPath( + projectId, + sessionId + ); + + const request = { + parent: sessionPath, + }; + + // Send the request for retrieving the sessionEntityType. + const [response] = await sessionEntityTypesClient.listSessionEntityTypes( + request + ); + response.forEach(sessionEntityType => { + console.log(`Session entity type name: ${sessionEntityType.name}`); + console.log(`Number of entities: ${sessionEntityType.entities.length}\n`); + }); +} + +async function deleteSessionEntityType( + projectId, + sessionId, + entityTypeDisplayName +) { + // Imports the Dialogflow library + const dialogflow = require('@google-cloud/dialogflow'); + + // Instantiates clients + const sessionEntityTypesClient = new dialogflow.SessionEntityTypesClient(); + + // The path to identify the sessionEntityType to be deleted. + const sessionEntityTypePath = + sessionEntityTypesClient.projectAgentSessionEntityTypePath( + projectId, + sessionId, + entityTypeDisplayName + ); + + const request = { + name: sessionEntityTypePath, + }; + + // Send the request for retrieving the sessionEntityType. + const result = await sessionEntityTypesClient.deleteSessionEntityType( + request + ); + console.log(`Session entity type ${entityTypeDisplayName} deleted`); + return result; +} + +// ///////////////////////////////////////////////////////////////////////////// +// Command line interface. +// ///////////////////////////////////////////////////////////////////////////// +const cli = require('yargs') + .demand(1) + .options({ + projectId: { + alias: 'p', + default: process.env.GCLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT, + description: + 'The Project ID to use. Defaults to the value of the ' + + 'GCLOUD_PROJECT or GOOGLE_CLOUD_PROJECT environment variables.', + requiresArg: true, + type: 'string', + }, + }) + .demandOption( + 'projectId', + "Please provide your Dialogflow agent's project ID with the -p flag or through the GOOGLE_CLOUD_PROJECT env var" + ) + .boolean('force') + .alias('force', ['f']) + .describe('force', 'force operation without a prompt') + .command( + 'delete-intent', + 'Delete Intent', + { + intentId: { + alias: 'i', + string: true, + demandOption: true, + requiresArg: true, + description: 'Intent Id', + }, + }, + opts => deleteIntent(opts.projectId, opts.intentId) + ) + .command( + 'create-session-entity-type', + 'Create entity type', + { + sessionId: { + alias: 's', + string: true, + demandOption: true, + requiresArg: true, + description: 'Display Name', + }, + entityValues: { + alias: 'e', + array: true, + demandOption: true, + requiresArg: true, + description: 'The kind of entity. KIND_MAP or KIND_LIST.', + }, + entityTypeDisplayName: { + alias: 'd', + string: true, + demandOption: true, + requiresArg: true, + description: 'Display Name', + }, + entityOverrideMode: { + alias: 'o', + string: true, + demandOption: true, + requiresArg: true, + description: 'Display Name', + }, + }, + opts => + createSessionEntityType( + opts.projectId, + opts.sessionId, + opts.entityValues, + opts.entityTypeDisplayName, + opts.entityOverrideMode + ) + ) + .command( + 'list-session-entity-types', + 'List entity types', + { + sessionId: { + alias: 's', + string: true, + demandOption: true, + requiresArg: true, + description: 'Display Name', + }, + }, + opts => listSessionEntityTypes(opts.projectId, opts.sessionId) + ) + .command( + 'delete-session-entity-type', + 'Delete entity type', + { + sessionId: { + alias: 's', + string: true, + demandOption: true, + requiresArg: true, + description: 'Display Name', + }, + entityTypeDisplayName: { + alias: 'd', + string: true, + demandOption: true, + requiresArg: true, + description: 'Display Name', + }, + }, + opts => + deleteSessionEntityType( + opts.projectId, + opts.sessionId, + opts.entityTypeDisplayName + ) + ) + .wrap(120) + .recommendCommands() + .epilogue( + 'For more information, see https://cloud.google.com/dialogflow-enterprise/docs' + ) + .help() + .strict(); + +if (module === require.main) { + cli.parse(process.argv.slice(2)); +} diff --git a/dialogflow/resources/230pm.wav b/dialogflow/resources/230pm.wav new file mode 100644 index 0000000000..7509eca784 Binary files /dev/null and b/dialogflow/resources/230pm.wav differ diff --git a/dialogflow/resources/RoomReservation.zip b/dialogflow/resources/RoomReservation.zip new file mode 100644 index 0000000000..558e80f1e1 Binary files /dev/null and b/dialogflow/resources/RoomReservation.zip differ diff --git a/dialogflow/resources/book_a_room.wav b/dialogflow/resources/book_a_room.wav new file mode 100644 index 0000000000..9124e92794 Binary files /dev/null and b/dialogflow/resources/book_a_room.wav differ diff --git a/dialogflow/resources/half_an_hour.wav b/dialogflow/resources/half_an_hour.wav new file mode 100644 index 0000000000..71010a871b Binary files /dev/null and b/dialogflow/resources/half_an_hour.wav differ diff --git a/dialogflow/resources/mountain_view.wav b/dialogflow/resources/mountain_view.wav new file mode 100644 index 0000000000..1c5437f7cb Binary files /dev/null and b/dialogflow/resources/mountain_view.wav differ diff --git a/dialogflow/resources/output.wav b/dialogflow/resources/output.wav new file mode 100644 index 0000000000..1ef1acb7ad Binary files /dev/null and b/dialogflow/resources/output.wav differ diff --git a/dialogflow/resources/today.wav b/dialogflow/resources/today.wav new file mode 100644 index 0000000000..d47ed78b35 Binary files /dev/null and b/dialogflow/resources/today.wav differ diff --git a/dialogflow/resources/two_people.wav b/dialogflow/resources/two_people.wav new file mode 100644 index 0000000000..5114ebbd31 Binary files /dev/null and b/dialogflow/resources/two_people.wav differ diff --git a/dialogflow/set-agent.js b/dialogflow/set-agent.js new file mode 100644 index 0000000000..8d6147733a --- /dev/null +++ b/dialogflow/set-agent.js @@ -0,0 +1,50 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +// parentID is the projectID and displayName is customized by user +async function main(parentId, displayName) { + // [START dialogflow_set_agent_sample] + const {AgentsClient} = require('@google-cloud/dialogflow'); + + // make sure to pass projectID as the input parameter + const parent = 'projects/' + parentId + '/locations/global'; + + const agent = { + parent: parent, + displayName: displayName, + defaultLanguageCode: 'en', + timeZone: 'America/Los_Angeles', + }; + + const client = new AgentsClient(); + + async function setAgent() { + const request = { + agent, + }; + + const [response] = await client.setAgent(request); + console.log(`response: ${JSON.stringify(response, null, 2)}`); + } + await setAgent(); + // [END dialogflow_set_agent_sample] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/dialogflow/system-test/create-document.v2beta1.test.js b/dialogflow/system-test/create-document.v2beta1.test.js new file mode 100644 index 0000000000..3b8e618c0b --- /dev/null +++ b/dialogflow/system-test/create-document.v2beta1.test.js @@ -0,0 +1,61 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; +/** + * TODO(developer): Uncomment the following lines until proto updates for dialogflow/v2beta1 is complete. + */ +// const {assert} = require('chai'); +const {describe, after, before} = require('mocha'); +// const {execSync} = require('child_process'); +const uuid = require('uuid').v4; +const dialogflow = require('@google-cloud/dialogflow').v2beta1; + +// const cmd = 'node detect.v2beta1.js createDocument'; +// const testDocName = 'TestDoc'; +// const testDocumentPath = 'https://cloud.google.com/storage/docs/faq'; + +// const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +describe('create a document', () => { + const client = new dialogflow.KnowledgeBasesClient(); + let knowledgeBaseName; + + before('create a knowledge base for the document', async () => { + const projectId = await client.getProjectId(); + const request = { + parent: 'projects/' + projectId, + knowledgeBase: { + displayName: `${uuid().split('-')[0]}-TestKnowledgeBase`, + }, + }; + + const [result] = await client.createKnowledgeBase(request); + knowledgeBaseName = result.name; + }); + + // it('should create a document', () => { + // const output = exec( + // `${cmd} -n "${knowledgeBaseName}" -z "${testDocumentPath}" -m "${testDocName}"` + // ); + // assert.include(output, 'Document created'); + // }); + + after('delete created document', async () => { + await client.deleteKnowledgeBase({ + name: knowledgeBaseName, + force: true, + }); + }); +}); diff --git a/dialogflow/system-test/create-intent.test.js b/dialogflow/system-test/create-intent.test.js new file mode 100644 index 0000000000..5bb707b40b --- /dev/null +++ b/dialogflow/system-test/create-intent.test.js @@ -0,0 +1,45 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {after, describe, it} = require('mocha'); +const execSync = require('child_process').execSync; +const uuid = require('uuid'); +const projectId = + process.env.GCLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT; +const dialogflow = require('@google-cloud/dialogflow'); + +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +describe('create intent', () => { + const client = new dialogflow.IntentsClient(); + const cmd = 'node create-intent.js'; + const displayName = `fake_display_name_${uuid.v4().split('-')[0]}`; + let intentId; + + it('should create an intent', async () => { + const output = exec(`${cmd} ${projectId} ${displayName}`); + assert.include(output, 'intents'); + intentId = output.split(' ')[1].split('/')[4]; + }); + + after('delete the created intent', async () => { + const projectId = await client.getProjectId(); + const intentPath = client.projectAgentIntentPath(projectId, intentId); + const request = {name: intentPath}; + await client.deleteIntent(request); + }); +}); diff --git a/dialogflow/system-test/create-knowledge-base.v2beta1.test.js b/dialogflow/system-test/create-knowledge-base.v2beta1.test.js new file mode 100644 index 0000000000..e490a5275d --- /dev/null +++ b/dialogflow/system-test/create-knowledge-base.v2beta1.test.js @@ -0,0 +1,44 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, after, it} = require('mocha'); +const {execSync} = require('child_process'); +const uuid = require('uuid').v4; +const dialogflow = require('@google-cloud/dialogflow').v2beta1; + +const cmd = 'node detect.v2beta1.js createKnowledgeBase'; +const testKnowledgeBaseName = `${uuid().split('-')[0]}-TestKnowledgeBase`; + +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +describe('create a knowledge base', () => { + const client = new dialogflow.KnowledgeBasesClient(); + let knowledgeBaseName; + + it('should create a knowledge base', () => { + const output = exec(`${cmd} -k ${testKnowledgeBaseName}`); + assert.include(output, `displayName: ${testKnowledgeBaseName}`); + + knowledgeBaseName = output.split('\n')[0].split(':')[1].trim(); + }); + + after('delete created knowledge base', async () => { + await client.deleteKnowledgeBase({ + name: knowledgeBaseName, + }); + }); +}); diff --git a/dialogflow/system-test/create-session-entity-type.test.js b/dialogflow/system-test/create-session-entity-type.test.js new file mode 100644 index 0000000000..08768381cd --- /dev/null +++ b/dialogflow/system-test/create-session-entity-type.test.js @@ -0,0 +1,64 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {after, before, describe, it} = require('mocha'); +const execSync = require('child_process').execSync; +const uuid = require('uuid'); +const dialogflow = require('@google-cloud/dialogflow'); +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +describe('create session entity type', () => { + const client = new dialogflow.EntityTypesClient(); + const cmd = 'node resource.js'; + const sessionId = uuid.v1(); + const displayName = `fake_display_name_${uuid.v4().split('-')[0]}`; + const synonym1 = 'synonym_1'; + const synonym2 = 'synonym_2'; + let entityTypeId; + + before('create an entity type', async () => { + const projectId = await client.getProjectId(); + const createEntityTypeRequest = { + parent: client.projectAgentPath(projectId), + entityType: { + displayName: displayName, + kind: 'KIND_MAP', + }, + }; + + const responses = await client.createEntityType(createEntityTypeRequest); + entityTypeId = responses[0].name.split('/')[4]; + }); + + it('should Create a Session Entity Type', async () => { + const output = exec( + `${cmd} create-session-entity-type -s ${sessionId} -e ${synonym1} -e ${synonym2} -d ${displayName} -o ENTITY_OVERRIDE_MODE_OVERRIDE` + ); + assert.include(output, sessionId); + assert.include(output, displayName); + assert.include(output, synonym1); + assert.include(output, synonym2); + }); + + after('delete the created entity type', async () => { + const projectId = await client.getProjectId(); + const request = { + name: client.projectAgentEntityTypePath(projectId, entityTypeId), + }; + await client.deleteEntityType(request); + }); +}); diff --git a/dialogflow/system-test/delete-intent.test.js b/dialogflow/system-test/delete-intent.test.js new file mode 100644 index 0000000000..7786ffa6fc --- /dev/null +++ b/dialogflow/system-test/delete-intent.test.js @@ -0,0 +1,65 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, before, it} = require('mocha'); +const execSync = require('child_process').execSync; +const uuid = require('uuid'); +const dialogflow = require('@google-cloud/dialogflow'); + +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +describe('delete intent', () => { + const client = new dialogflow.IntentsClient(); + const cmd = 'node resource.js'; + const displayName = `fake_display_name_${uuid.v4().split('-')[0]}`; + let intentId; + + before('create the intent', async () => { + const projectId = await client.getProjectId(); + const createIntentRequest = { + parent: client.projectAgentPath(projectId), + intent: { + displayName: displayName, + trainingPhrases: [ + { + type: 'EXAMPLE', + parts: [ + { + text: 'training_phrase_1', + }, + ], + }, + ], + messages: [ + { + text: { + text: ['message1', 'message2'], + }, + }, + ], + }, + }; + + const responses = await client.createIntent(createIntentRequest); + intentId = responses[0].name.split('/')[4]; + }); + + it('should delete an intent', async () => { + const output = exec(`${cmd} delete-intent -i ${intentId}`); + assert.include(output, intentId); + }); +}); diff --git a/dialogflow/system-test/delete-session-entity-type.test.js b/dialogflow/system-test/delete-session-entity-type.test.js new file mode 100644 index 0000000000..01526258b8 --- /dev/null +++ b/dialogflow/system-test/delete-session-entity-type.test.js @@ -0,0 +1,81 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, after, before, it} = require('mocha'); +const execSync = require('child_process').execSync; +const uuid = require('uuid'); +const dialogflow = require('@google-cloud/dialogflow'); +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +describe('delete session entity types', () => { + const client = new dialogflow.EntityTypesClient(); + const sessionClient = new dialogflow.SessionEntityTypesClient(); + const cmd = 'node resource.js'; + const sessionId = uuid.v1(); + const displayName = `fake_display_name_${uuid.v4().split('-')[0]}`; + let entityTypeId; + + before('create a session entity type', async () => { + // First create an entity type + const projectId = await client.getProjectId(); + const createEntityTypeRequest = { + parent: client.projectAgentPath(projectId), + entityType: { + displayName: displayName, + kind: 'KIND_MAP', + }, + }; + + const responses = await client.createEntityType(createEntityTypeRequest); + entityTypeId = responses[0].name.split('/')[4]; + + // Create the session entity type + const sessionEntityTypeRequest = { + parent: sessionClient.projectAgentSessionPath(projectId, sessionId), + sessionEntityType: { + name: sessionClient.projectAgentSessionEntityTypePath( + projectId, + sessionId, + displayName + ), + entityOverrideMode: 'ENTITY_OVERRIDE_MODE_OVERRIDE', + entities: [ + { + value: 'synonym1', + synonyms: ['synonym2'], + }, + ], + }, + }; + await sessionClient.createSessionEntityType(sessionEntityTypeRequest); + }); + + it('should Delete the Session Entity Type', async () => { + const output = exec( + `${cmd} delete-session-entity-type -s ${sessionId} -d ${displayName}` + ); + assert.include(output, displayName); + }); + + after('delete the created entity type', async () => { + const projectId = await client.getProjectId(); + const request = { + name: client.projectAgentEntityTypePath(projectId, entityTypeId), + }; + await client.deleteEntityType(request); + }); +}); diff --git a/dialogflow/system-test/detect.test.js b/dialogflow/system-test/detect.test.js new file mode 100644 index 0000000000..38d7a6ad26 --- /dev/null +++ b/dialogflow/system-test/detect.test.js @@ -0,0 +1,71 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const execSync = require('child_process').execSync; +const cmd = 'node detect.js'; +const cmd_tts = 'node detect-intent-TTS-response.v2.js'; +const cmd_sentiment = 'node detect-intent-sentiment.v2.js'; +const projectId = + process.env.GCLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT; +const testQuery = 'Where is my data stored?'; + +const audioFilepathBookARoom = path + .join(__dirname, '../resources/book_a_room.wav') + .replace(/(\s+)/g, '\\$1'); + +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +describe('basic detection', () => { + it('should detect text queries', async () => { + const stdout = exec(`${cmd} text -q "hello"`); + assert.include(stdout, 'Detected intent'); + }); + + it('should detect event query', async () => { + const stdout = exec(`${cmd} event WELCOME`); + assert.include(stdout, 'Query: WELCOME'); + }); + + it('should detect audio query', async () => { + const stdout = exec(`${cmd} audio ${audioFilepathBookARoom} -r 16000`); + assert.include(stdout, 'Detected intent'); + }); + + it('should detect audio query in streaming fashion', async () => { + const stdout = exec(`${cmd} stream ${audioFilepathBookARoom} -r 16000`); + assert.include(stdout, 'Detected intent'); + }); + + it('should detect Intent with Text to Speech Response', async () => { + const stdout = exec( + `${cmd_tts} ${projectId} 'SESSION_ID' '${testQuery}' 'en-US' './resources/output.wav'` + ); + assert.include( + stdout, + 'Audio content written to file: ./resources/output.wav' + ); + }); + + it('should detect sentiment with intent', async () => { + const stdout = exec( + `${cmd_sentiment} ${projectId} 'SESSION_ID' '${testQuery}' 'en-US'` + ); + assert.include(stdout, 'Detected sentiment'); + }); +}); diff --git a/dialogflow/system-test/detect.v2beta1.test.js b/dialogflow/system-test/detect.v2beta1.test.js new file mode 100644 index 0000000000..b99364a865 --- /dev/null +++ b/dialogflow/system-test/detect.v2beta1.test.js @@ -0,0 +1,48 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const {execSync} = require('child_process'); + +const cmd = 'node detect.v2beta1.js'; +const testQuery = 'Where is my data stored?'; + +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +describe('v2beta1 detection', () => { + it('should detect intent with a knowledge base', () => { + const output = exec( + `${cmd} detectIntentKnowledge -q "${testQuery}" -n "OTAxMTY2MTA3MjkyNjUwNzAwOA"` + ); + assert.include(output, 'Detected Intent:'); + }); + + it('should detect Intent with Text to Speech Response', () => { + const output = exec( + `${cmd} detectIntentwithTexttoSpeechResponse -q "${testQuery}"` + ); + assert.include( + output, + 'Audio content written to file: ./resources/output.wav' + ); + }); + + it('should detect sentiment with intent', () => { + const output = exec(`${cmd} detectIntentandSentiment -q "${testQuery}"`); + assert.include(output, 'Detected sentiment'); + }); +}); diff --git a/dialogflow/system-test/list-session-entity-types.test.js b/dialogflow/system-test/list-session-entity-types.test.js new file mode 100644 index 0000000000..6fd85cb778 --- /dev/null +++ b/dialogflow/system-test/list-session-entity-types.test.js @@ -0,0 +1,86 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, after, before, it} = require('mocha'); +const execSync = require('child_process').execSync; +const uuid = require('uuid'); +const dialogflow = require('@google-cloud/dialogflow'); +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +const {delay} = require('./util'); + +describe('list session entity types', () => { + const client = new dialogflow.EntityTypesClient(); + const sessionClient = new dialogflow.SessionEntityTypesClient(); + const cmd = 'node resource.js'; + const sessionId = uuid.v1(); + const displayName = `fake_display_name_${uuid.v4().split('-')[0]}`; + let entityTypeId; + + before('create a session entity type', async () => { + // First create an entity type + const projectId = await client.getProjectId(); + const createEntityTypeRequest = { + parent: client.projectAgentPath(projectId), + entityType: { + displayName: displayName, + kind: 'KIND_MAP', + }, + }; + + const responses = await client.createEntityType(createEntityTypeRequest); + entityTypeId = responses[0].name.split('/')[4]; + + // Create the session entity type + const sessionEntityTypeRequest = { + parent: sessionClient.projectAgentSessionPath(projectId, sessionId), + sessionEntityType: { + name: sessionClient.projectAgentSessionEntityTypePath( + projectId, + sessionId, + displayName + ), + entityOverrideMode: 'ENTITY_OVERRIDE_MODE_OVERRIDE', + entities: [ + { + value: 'synonym1', + synonyms: ['synonym2'], + }, + ], + }, + }; + await sessionClient.createSessionEntityType(sessionEntityTypeRequest); + }); + + it('should List the Session Entity Type', async function () { + this.retries(5); + await delay(this.test); + + const output = exec(`${cmd} list-session-entity-types -s ${sessionId}`); + assert.include(output, sessionId); + assert.include(output, displayName); + assert.include(output, 'Number of entities'); + }); + + after('delete the created entity type', async () => { + const projectId = await client.getProjectId(); + const request = { + name: client.projectAgentEntityTypePath(projectId, entityTypeId), + }; + await client.deleteEntityType(request); + }); +}); diff --git a/dialogflow/system-test/listTrainingPhrases.test.js b/dialogflow/system-test/listTrainingPhrases.test.js new file mode 100644 index 0000000000..bfcd6b3657 --- /dev/null +++ b/dialogflow/system-test/listTrainingPhrases.test.js @@ -0,0 +1,38 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, before, it} = require('mocha'); +const dialogflow = require('@google-cloud/dialogflow'); +const execSync = require('child_process').execSync; +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); + +describe('list training phrases', () => { + const intentId = 'e8f6a63e-73da-4a1a-8bfc-857183f71228'; + const intentClient = new dialogflow.IntentsClient(); + const cmd = 'node listTrainingPhrases.js'; + let [projectId] = ''; + + before('get intent ID', async () => { + // The path to identify the agent that owns the intent. + projectId = await intentClient.getProjectId(); + }); + + it('should list training phrases in an intent', async () => { + const output = exec(`${cmd} ${projectId} ${intentId}`); + assert.include(output, 'EXAMPLE'); + }); +}); diff --git a/dialogflow/system-test/set-agent.test.js b/dialogflow/system-test/set-agent.test.js new file mode 100644 index 0000000000..77875c4b5b --- /dev/null +++ b/dialogflow/system-test/set-agent.test.js @@ -0,0 +1,27 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +// We cannot test setAgent because Dialogflow ES can only have one agent +// and if we create a agent it will delete the exisitng testing agent and +// would cause all tests to fail +describe('create agent', () => { + it('should create an intent', async () => { + assert.isTrue(true); + }); +}); diff --git a/dialogflow/system-test/update-intent.test.js b/dialogflow/system-test/update-intent.test.js new file mode 100644 index 0000000000..eb115e7fa4 --- /dev/null +++ b/dialogflow/system-test/update-intent.test.js @@ -0,0 +1,51 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, before, it} = require('mocha'); +const execSync = require('child_process').execSync; +const uuid = require('uuid'); +const dialogflow = require('@google-cloud/dialogflow'); +const exec = cmd => execSync(cmd, {encoding: 'utf8'}); +const projectId = + process.env.GCLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT; +const intentID = []; + +describe('update intent', () => { + const intentClient = new dialogflow.IntentsClient(); + const cmd = 'node update-intent.js'; + const displayName = `fake_display_name_${uuid.v4().split('-')[0]}`; + + before('get intent ID', async () => { + // The path to identify the agent that owns the intents. + + const projectAgentPath = intentClient.projectAgentPath(projectId); + + const intentRequest = { + parent: projectAgentPath, + }; + + const [response] = await intentClient.listIntents(intentRequest); + response.forEach(intent => { + intentID.push(intent.name.split('/')[4]); + }); + }); + + it('should update an intent using fieldmasks', async () => { + const output = exec(`${cmd} ${projectId} ${intentID[0]} ${displayName}`); + assert.include(output, displayName); + }); +}); diff --git a/dialogflow/system-test/util.js b/dialogflow/system-test/util.js new file mode 100644 index 0000000000..f3a0b2c158 --- /dev/null +++ b/dialogflow/system-test/util.js @@ -0,0 +1,28 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// DialogFlow tests sometimes run into quota issues, for which +// retrying with a backoff is a good strategy: +module.exports = { + async delay(test) { + const retries = test.currentRetry(); + if (retries === 0) return; // no retry on the first failure. + // see: https://cloud.google.com/storage/docs/exponential-backoff: + const ms = Math.pow(2, retries) * 1000 + Math.random() * 2000; + return new Promise(done => { + console.info(`retrying "${test.title}" in ${ms}ms`); + setTimeout(done, ms); + }); + }, +}; diff --git a/dialogflow/system-test/webhook.test.js b/dialogflow/system-test/webhook.test.js new file mode 100644 index 0000000000..d5d8bd5082 --- /dev/null +++ b/dialogflow/system-test/webhook.test.js @@ -0,0 +1,46 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const webhook = require('../webhook'); + +const request = { + body: { + queryResult: { + intent: { + name: 'projects/galstarter-316823/agent/intents/00c2877d-2440-447f-8dc1-045623a55bd4', + displayName: 'Default Welcome Intent', + }, + }, + }, +}; + +describe('create agent', () => { + it('should test webhook returns correct response', async () => { + const temp = JSON.stringify(request); + let response = ''; + + const res = { + send: function (s) { + response = JSON.stringify(s); + }, + }; + + webhook.handleWebhook(JSON.parse(temp), res); + assert.include(response, 'Hello from a GCF Webhook'); + }); +}); diff --git a/dialogflow/update-intent.js b/dialogflow/update-intent.js new file mode 100644 index 0000000000..64d70e1055 --- /dev/null +++ b/dialogflow/update-intent.js @@ -0,0 +1,50 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements + +async function main(projectId, intentId, displayName) { + // [START dialogflow_update_intent_sample] + const {IntentsClient} = require('@google-cloud/dialogflow'); + + const intentClient = new IntentsClient(); + + const agentPath = intentClient.projectAgentPath(projectId); + const intentPath = agentPath + '/intents/' + intentId; + + const intent = await intentClient.getIntent({name: intentPath}); + intent[0].displayName = displayName; + const updateMask = { + paths: ['display_name'], + }; + + const updateIntentRequest = { + intent: intent[0], + updateMask: updateMask, + languageCode: 'en', + }; + + //Send the request for update the intent. + const result = await intentClient.updateIntent(updateIntentRequest); + console.log(result); + // [END dialogflow_update_intent_sample] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/dialogflow/webhook.js b/dialogflow/webhook.js new file mode 100644 index 0000000000..d8ba914209 --- /dev/null +++ b/dialogflow/webhook.js @@ -0,0 +1,65 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +// [START dialogflow_es_webhook] + +// TODO: Add handleWebhook to 'Entry point' in the Google Cloud Function +exports.handleWebhook = (request, response) => { + const tag = request.body.queryResult.intent.displayName; + + let jsonResponse = {}; + if (tag === 'Default Welcome Intent') { + //fulfillment response to be sent to the agent if the request tag is equal to "welcome tag" + jsonResponse = { + fulfillment_messages: [ + { + text: { + //fulfillment text response to be sent to the agent + text: ['Hello from a GCF Webhook'], + }, + }, + ], + }; + } else if (tag === 'get-name') { + //fulfillment response to be sent to the agent if the request tag is equal to "welcome tag" + jsonResponse = { + fulfillment_messages: [ + { + text: { + //fulfillment text response to be sent to the agent + text: ['My name is Flowhook'], + }, + }, + ], + }; + } else { + jsonResponse = { + //fulfillment text response to be sent to the agent if there are no defined responses for the specified tag + fulfillment_messages: [ + { + text: { + ////fulfillment text response to be sent to the agent + text: [ + `There are no fulfillment responses defined for "${tag}"" tag`, + ], + }, + }, + ], + }; + } + response.send(jsonResponse); +}; +// [END dialogflow_es_webhook]