From de2f35952ab2e81ea27252572c7f288055952b43 Mon Sep 17 00:00:00 2001 From: Noah Negrey Date: Fri, 21 Sep 2018 12:25:20 -0700 Subject: [PATCH] =?UTF-8?q?Update=20old=20samples=20to=20new=20agent=20usi?= =?UTF-8?q?ng=20Room=20Reservations=20and=20match=20can=E2=80=A6=20(#162)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dialogflow/resource.js | 1789 ++++++----------- dialogflow/system-test/detect.v2beta1.test.js | 1 - dialogflow/system-test/resource_test.js | 231 ++- 3 files changed, 711 insertions(+), 1310 deletions(-) diff --git a/dialogflow/resource.js b/dialogflow/resource.js index 2ed70ea837..34c2095155 100644 --- a/dialogflow/resource.js +++ b/dialogflow/resource.js @@ -15,99 +15,51 @@ 'use strict'; -const grpc = require('grpc'); -const structjson = require('./structjson.js'); -const prompt = require('prompt'); - // ///////////////////////////////////////////////////////////////////////////// // Operations for entity types. // ///////////////////////////////////////////////////////////////////////////// -function createEntityTypes(projectId) { - // [START dialogflow_create_entity] +function createEntityType(projectId, displayName, kind) { + // [START dialogflow_create_entity_type] // Imports the Dialogflow library const dialogflow = require('dialogflow'); // Instantiates clients const entityTypesClient = new dialogflow.EntityTypesClient(); - const intentsClient = new dialogflow.IntentsClient(); // The path to the agent the created entity type belongs to. - const agentPath = intentsClient.projectAgentPath(projectId); - - const promises = []; - - // Create an entity type named "size", with possible values of small, medium - // and large and some synonyms. - const sizeRequest = { - parent: agentPath, - entityType: { - displayName: 'size', - kind: 'KIND_MAP', - autoExpansionMode: 'AUTO_EXPANSION_MODE_UNSPECIFIED', - entities: [ - {value: 'small', synonyms: ['small', 'petit']}, - {value: 'medium', synonyms: ['medium']}, - {value: 'large', synonyms: ['large', 'big']}, - ], - }, - }; - promises.push( - entityTypesClient - .createEntityType(sizeRequest) - .then(responses => { - console.log('Created size entity type:'); - logEntityType(responses[0]); - }) - .catch(err => { - console.error('Failed to create size entity type:', err); - }) - ); + const agentPath = entityTypesClient.projectAgentPath(projectId); - // Create an entity of type named "topping", with possible values without - // synonyms. - const toppingRequest = { + const createEntityTypeRequest = { parent: agentPath, entityType: { - displayName: 'topping', - kind: 'KIND_LIST', - autoExpansionMode: 'AUTO_EXPANSION_MODE_UNSPECIFIED', - entities: [ - {value: 'tomato', synonyms: ['tomato']}, - {value: 'tuna', synonyms: ['tuna']}, - {value: 'cheddar', synonyms: ['cheddar']}, - {value: 'mushrooms', synonyms: ['mushrooms']}, - ], + displayName: displayName, + kind: kind, }, }; - promises.push( - entityTypesClient - .createEntityType(toppingRequest) - .then(responses => { - console.log('Created topping entity type:'); - logEntityType(responses[0]); - }) - .catch(err => { - console.error('Failed to create topping entity type:', err); - }) - ); - return Promise.all(promises); - // [END dialogflow_create_entity] + entityTypesClient + .createEntityType(createEntityTypeRequest) + .then(responses => { + console.log(`Created ${responses[0].name} entity type`); + }) + .catch(err => { + console.error('Failed to create size entity type:', err); + }); + // [END dialogflow_create_entity_type] } function listEntityTypes(projectId) { + // [START dialogflow_list_entity_types] // Imports the Dialogflow library const dialogflow = require('dialogflow'); // Instantiates clients const entityTypesClient = new dialogflow.EntityTypesClient(); - const intentsClient = new dialogflow.IntentsClient(); // The path to the agent the entity types belong to. - const agentPath = intentsClient.projectAgentPath(projectId); + const agentPath = entityTypesClient.projectAgentPath(projectId); - // The request. const request = { parent: agentPath, }; @@ -116,1103 +68,477 @@ function listEntityTypes(projectId) { return entityTypesClient .listEntityTypes(request) .then(responses => { + responses[0].forEach(entityType => { + console.log(`Entity type name: ${entityType.name}`); + console.log(`Entity type display name: ${entityType.displayName}`); + console.log(`Number of entities: ${entityType.entities.length}\n`); + }); return responses[0]; }) .catch(err => { console.error('Failed to list entity types:', err); }); + // [END dialogflow_list_entity_types] } -function clearEntityTypes(projectId) { - // List all entity types then delete all of them. - return listEntityTypes(projectId).then(entityTypes => { - return Promise.all( - entityTypes.map(entityType => { - return deleteEntityType(entityType); - }) - ); - }); -} - -function deleteEntityType(entityType) { - // [START dialogflow_delete_entity] +function deleteEntityType(projectId, entityTypeId) { + // [START dialogflow_delete_entity_type] // Imports the Dialogflow library const dialogflow = require('dialogflow'); // Instantiates clients const entityTypesClient = new dialogflow.EntityTypesClient(); - // The request. + const entityTypePath = entityTypesClient.entityTypePath( + projectId, + entityTypeId + ); + const request = { - name: entityType.name, + name: entityTypePath, }; + // Call the client library to delete the entity type. return entityTypesClient .deleteEntityType(request) .then(() => { - console.log(`Entity type ${entityType.displayName} deleted`); + console.log(`Entity type ${entityTypePath} deleted`); }) .catch(err => { - console.error( - `Failed to delete entity type ${entityType.displayName}:`, - err - ); + console.error(`Failed to delete entity type ${entityTypePath}:`, err); }); - // [END dialogflow_delete_entity] + // [END dialogflow_delete_entity_type] } -function showEntityTypes(projectId) { - // List all entity types then delete all of them. - return listEntityTypes(projectId).then(entityTypes => { - return Promise.all( - entityTypes.map(entityType => { - return getEntityType(entityType); - }) - ); - }); -} +// ///////////////////////////////////////////////////////////////////////////// +// Operations for entities. +// ///////////////////////////////////////////////////////////////////////////// -function getEntityType(entityType) { +function createEntity(projectId, entityTypeId, entityValue, synonyms) { + // [START dialogflow_create_entity] // Imports the Dialogflow library const dialogflow = require('dialogflow'); - // Instantiates client + // Instantiates clients const entityTypesClient = new dialogflow.EntityTypesClient(); - // The request. - const request = {name: entityType.name}; + // The path to the agent the created entity belongs to. + const agentPath = entityTypesClient.entityTypePath(projectId, entityTypeId); - // Call the client library to retrieve an entity type. - return entityTypesClient - .getEntityType(request) + const entity = { + value: entityValue, + synonyms: synonyms, + }; + + const createEntitiesRequest = { + parent: agentPath, + entities: [entity], + }; + + entityTypesClient + .batchCreateEntities(createEntitiesRequest) .then(responses => { - console.log('Found entity type:'); - logEntityType(responses[0]); + console.log('Created entity type:'); + console.log(responses[0]); }) .catch(err => { - console.error(`Failed to get entity type ${entityType.displayName}`, err); + console.error('Failed to create size entity type:', err); }); + // [END dialogflow_create_entity] } -function updateEntityType(projectId, entityTypeId) { +function listEntities(projectId, entityTypeId) { + // [START dialogflow_create_entity] // Imports the Dialogflow library const dialogflow = require('dialogflow'); - // Instantiates client + // Instantiates clients const entityTypesClient = new dialogflow.EntityTypesClient(); - // The path to the entity type to be updated. + // The path to the agent the entity types belong to. const entityTypePath = entityTypesClient.entityTypePath( projectId, entityTypeId ); - // UpdateEntityType does full snapshot update. For incremental update - // fetch the entity type first then modify it. - const getEntityTypeRequest = { + // The request. + const request = { name: entityTypePath, }; - entityTypesClient - .getEntityType(getEntityTypeRequest) - .then(responses => { - const entityType = responses[0]; - // Add a new entity foo to the entity type. - entityType.entities.push({value: 'foo', synonyms: ['foo']}); - const request = { - entityType: entityType, - }; - - return entityTypesClient.updateEntityType(request); - }) + // Call the client library to retrieve a list of all existing entity types. + return entityTypesClient + .getEntityType(request) .then(responses => { - console.log('Updated entity type:'); - logEntityType(responses[0]); + responses[0].entities.forEach(entity => { + console.log(`Entity value: ${entity.value}`); + console.log(`Entity synonyms: ${entity.synonyms}`); + }); + return responses[0]; }) .catch(err => { - console.error('Failed to update entity type', err); + console.error('Failed to list entity types:', err); }); + // [END dialogflow_create_entity] } -function logEntityType(entityType) { +function deleteEntity(projectId, entityTypeId, entityValue) { + // [START dialogflow_delete_entity] // Imports the Dialogflow library const dialogflow = require('dialogflow'); - // Instantiates client. + // Instantiates clients const entityTypesClient = new dialogflow.EntityTypesClient(); - console.log( - ' ID:', - entityTypesClient.matchEntityTypeFromEntityTypeName(entityType.name) - ); - console.log(' Display Name:', entityType.displayName); - console.log( - ' Auto expansion:', - entityType.autoExpansionMode === 'AUTO_EXPANSION_MODE_DEFAULT' + // The path to the agent the entity types belong to. + const entityTypePath = entityTypesClient.entityTypePath( + projectId, + entityTypeId ); - if (!entityType.entities) { - console.log(' No entity defined.'); - } else { - console.log(' Entities: '); - entityType.entities.forEach(entity => { - if (entityType.kind === 'KIND_MAP') { - console.log(` ${entity.value}: ${entity.synonyms.join(', ')}`); - } else { - console.log(` ${entity.value}`); - } + + const request = { + parent: entityTypePath, + entityValues: [entityValue], + }; + + // Call the client library to delete the entity type. + return entityTypesClient + .batchDeleteEntities(request) + .then(() => { + console.log(`Entity Value ${entityValue} deleted`); + }) + .catch(err => { + console.error(`Failed to delete entity value: ${entityValue}:`, err); }); - } - console.log(''); + // [END dialogflow_delete_entity] } // ///////////////////////////////////////////////////////////////////////////// // Operations for intents // ///////////////////////////////////////////////////////////////////////////// -function createIntents(projectId) { - // [START dialogflow_create_intent] +function listIntents(projectId) { + // [START dialogflow_list_intents] // Imports the Dialogflow library const dialogflow = require('dialogflow'); // Instantiates clients - const contextsClient = new dialogflow.ContextsClient(); const intentsClient = new dialogflow.IntentsClient(); - // The path to identify the agent that owns the created intent. - const agentPath = intentsClient.projectAgentPath(projectId); - - // Setup intents for ordering a pizza. - - // First of all, let's create an intent that triggers pizza order flow. - - // Output contexts for ordering pizza. They are used for matching follow-up - // intents. For pizza ordering intents, a "pizza" output context is used for - // hinting the conversation is about pizza ordering, not beer or something - // else. For the first intent, it returns responses asking users to provide - // size information, with a "size" output context for matching the intent - // asking for the size of the pizza. + // The path to identify the agent that owns the intents. + const projectAgentPath = intentsClient.projectAgentPath(projectId); - // Note that session ID is unknown here, using asterisk. - const pizzaOutputContexts = [ - { - name: contextsClient.contextPath( - projectId, - '*' /* sessionId */, - 'pizza_order' - ), - lifespanCount: 5, - }, - ]; - - // The result of the matched intent. - const pizzaResult = { - action: 'pizza', - parameters: [ - { - displayName: 'size', - value: '$size', - entityTypeDisplayName: '@size', - mandatory: true, - prompts: [ - 'What size pizza would you like to order?', - 'Would you like a large, medium, or small pizza?', - ], - }, - { - displayName: 'topping', - value: '$topping', - entityTypeDisplayName: '@topping', - mandatory: true, - prompts: ['What toppings would you like?'], - isList: true, - }, - { - displayName: 'address', - value: '$address', - // The API provides a built-in entity type @sys.address for addresses. - entityTypeDisplayName: '@sys.location', - mandatory: true, - prompts: ['What is the delivery address?'], - }, - ], - messages: [ - { - text: { - text: [ - 'No problem. Getting a $size pizza with $topping and delivering ' + - 'to $address.', - ], - }, - }, - { - text: { - text: [ - 'Reply "check" to place your order. Reply "cancel" to cancel ' + - 'your order. You can change your delivery address as well.', - ], - }, - }, - { - quickReplies: { - title: - 'No problem. Getting a $size pizza with $topping and ' + - 'delivering to $address.', - quickReplies: ['Place order', 'Cancel'], - }, - platform: 'PLATFORM_FACEBOOK', - }, - ], - outputContexts: pizzaOutputContexts, + const request = { + parent: projectAgentPath, }; - // The phrases for training the linguistic model. - const pizzaPhrases = [ - {type: 'EXAMPLE', parts: [{text: 'Order pizza'}]}, - {type: 'EXAMPLE', parts: [{text: 'Pizza'}]}, - { - type: 'EXAMPLE', - parts: [ - {text: 'Get me a '}, - {text: 'large', entityType: '@size', alias: 'size'}, - {text: ' '}, - {text: 'mushrooms', entityType: '@topping', alias: 'topping'}, - {text: ' for '}, - { - text: '1 1st st, New York, NY', - entityType: '@sys.location', - alias: 'address', - }, - ], - }, - { - type: 'EXAMPLE', - parts: [ - {text: "I'd like to order a "}, - {text: 'large', entityType: '@size', alias: 'size'}, - {text: ' pizza with '}, - {text: 'mushrooms', entityType: '@topping', alias: 'topping'}, - ], - }, - { - type: 'TEMPLATE', - parts: [{text: "I'd like a @size:size pizza"}], - }, - ]; + console.log(projectAgentPath); - // The intent to be created. - const pizzaIntent = Object.assign( - { - displayName: 'Pizza', - events: ['order_pizza'], - // Webhook is disabled because we are not ready to call the webhook yet. - webhookState: 'WEBHOOK_STATE_DISABLED', - trainingPhrases: pizzaPhrases, - mlEnabled: true, - priority: 500000, - }, - pizzaResult - ); + // Send the request for listing intents. + return intentsClient + .listIntents(request) + .then(responses => { + responses[0].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}` + ); - const pizzaRequest = { - parent: agentPath, - intent: pizzaIntent, - }; + console.log('Input contexts:'); + intent.inputContextNames.forEach(inputContextName => { + console.log(`\tName: ${inputContextName}`); + }); - // Create the pizza intent - intentsClient - .createIntent(pizzaRequest) - .then(responses => { - console.log('Created Pizza intent:'); - logIntent(responses[0]); + console.log('Output contexts:'); + intent.outputContexts.forEach(outputContext => { + console.log(`\tName: ${outputContext.name}`); + }); + }); + return responses[0]; }) .catch(err => { - console.error('ERROR:', err); + console.error('Failed to list intents:', err); }); + // [END dialogflow_list_intents] +} - // Create an intent to change the delivery address. This intent sets input - // contexts to make sure it's triggered in the conversation with the pizza - // intent created above. +function createIntent( + projectId, + displayName, + trainingPhrasesParts, + messageTexts +) { + // [START dialogflow_create_intent] + // Imports the Dialogflow library + const dialogflow = require('dialogflow'); - // The input contexts are the output contexts of the pizza intent. - const changeDeliveryAddressInputContexts = [ - contextsClient.contextPath(projectId, '*' /* sessionId */, 'pizza_order'), - ]; + // Instantiates the Intent Client + const intentsClient = new dialogflow.IntentsClient(); - // Renew the pizza_order intent. Without doing so the lifespan count of the - // pizza_order intent will decrease and eventually disappear if the user - // changes the delivery address a couple times. - const changeDeliveryAddressOutputContexts = [ - { - name: contextsClient.contextPath( - projectId, - '*' /* sessionId */, - 'pizza_order' - ), - lifespanCount: 5, - }, - ]; + // The path to identify the agent that owns the created intent. + const agentPath = intentsClient.projectAgentPath(projectId); - // This intent requires the $address parameter to be provided. The other - // parameters are collected from the pizza_order context. - const changeDeliveryAddressParameters = [ - { - displayName: 'address', - entityTypeDisplayName: '@sys.location', - mandatory: true, - prompts: ['What is new address?'], - }, - { - displayName: 'size', - value: '#pizza_order.size', - entityTypeDisplayName: '@size', - }, - { - displayName: 'topping', - value: '#pizza_order.topping', - entityTypeDisplayName: '@topping', - isList: true, - }, - ]; - - const changeDeliveryAddressResult = { - action: 'change-delivery-address', - parameters: changeDeliveryAddressParameters, - messages: [ - { - text: { - text: ['OK, the delivery address is changed to $address'], - }, - }, - {text: {text: ['You ordered a $size pizza with $topping.']}}, - { - text: { - text: [ - 'Reply "check" to place your order. Reply "cancel" to cancel ' + - 'your order. You can change your delivery address as well.', - ], - }, - }, - ], - outputContexts: changeDeliveryAddressOutputContexts, - }; + const trainingPhrases = []; - // The triggering phrases. One is an annotated example, the other is a - // template. - const changeDeliveryAddressPhrases = [ - { - type: 'EXAMPLE', - parts: [ - {text: 'Change address to '}, - { - text: '1 1st st, new york, ny', - entityType: '@sys.location', - alias: 'address', - }, - ], - }, - { + trainingPhrasesParts.forEach(trainingPhrasesPart => { + const part = { + text: trainingPhrasesPart, + }; + + // Here we create a new training phrase for each provided part. + const trainingPhrase = { type: 'EXAMPLE', - parts: [ - { - text: '1 1st st, new york, ny', - entityType: '@sys.location', - alias: 'address', - }, - ], - }, - ]; + parts: [part], + }; - const changeDeliveryAddressIntent = Object.assign( - { - displayName: 'ChangeDeliveryAddress', - webhookState: 'WEBHOOK_STATE_DISABLED', - trainingPhrases: changeDeliveryAddressPhrases, - inputContexts: changeDeliveryAddressInputContexts, - mlEnabled: true, - priority: 500000, - }, - changeDeliveryAddressResult - ); + trainingPhrases.push(trainingPhrase); + }); + + const messageText = { + text: messageTexts, + }; + + const message = { + text: messageText, + }; + + const intent = { + displayName: displayName, + trainingPhrases: trainingPhrases, + messages: [message], + }; - const changeDeliveryAddressRequest = { + const createIntentRequest = { parent: agentPath, - intent: changeDeliveryAddressIntent, + intent: intent, }; - // Create the size intent + // Create the intent intentsClient - .createIntent(changeDeliveryAddressRequest) + .createIntent(createIntentRequest) .then(responses => { - console.log('Created ChangeDeliveryAddress intent: '); - logIntent(responses[0]); + console.log(`Intent ${responses[0].name} created`); }) .catch(err => { console.error('ERROR:', err); }); + // [END dialogflow_create_intent] +} - // Finally, create two intents, one to place the order, and the other one to - // cancel it. - - const placeOrderInputContexts = [ - contextsClient.contextPath(projectId, '*' /* sessionId */, 'pizza_order'), - ]; - - // Collect all parameters from the "pizza_output". - const placeOrderParameters = [ - { - displayName: 'size', - value: '#pizza_order.size', - entityTypeDisplayName: '@size', - }, - { - displayName: 'topping', - value: '#pizza_order.topping', - entityTypeDisplayName: '@topping', - isList: true, - }, - { - displayName: 'address', - value: '#pizza_order.address', - entityTypeDisplayName: '@sys.location', - }, - ]; - - const placeOrderResult = { - action: 'pizza_confirm', - parameters: placeOrderParameters, - messages: [ - { - text: { - text: [ - 'Sure! Getting a $size pizza with $topping and shipping to $address.', - ], - }, - }, - ], - // Conclude the conversation by setting no output contexts and setting - // resetContexts to true. This clears all existing contexts. - outputContexts: [], - resetContexts: true, - }; +function deleteIntent(projectId, intentId) { + // [START dialogflow_delete_intent] + // Imports the Dialogflow library + const dialogflow = require('dialogflow'); - const placeOrderPhrases = [ - {type: 'EXAMPLE', parts: [{text: 'check'}]}, - {type: 'EXAMPLE', parts: [{text: 'confirm'}]}, - {type: 'EXAMPLE', parts: [{text: 'yes'}]}, - {type: 'EXAMPLE', parts: [{text: 'place order'}]}, - ]; + // Instantiates clients + const intentsClient = new dialogflow.IntentsClient(); - const placeOrderIntent = Object.assign( - { - displayName: 'PlaceOrder', - webhookState: 'WEBHOOK_STATE_ENABLED', - trainingPhrases: placeOrderPhrases, - inputContexts: placeOrderInputContexts, - mlEnabled: true, - priority: 500000, - }, - placeOrderResult - ); + const intentPath = intentsClient.intentPath(projectId, intentId); - const placeOrderRequest = { - parent: agentPath, - intent: placeOrderIntent, - }; + const request = {name: intentPath}; - intentsClient - .createIntent(placeOrderRequest) - .then(responses => { - console.log('Created PlaceOrder intent: '); - logIntent(responses[0]); - }) + // Send the request for deleting the intent. + return intentsClient + .deleteIntent(request) + .then(console.log(`Intent ${intentPath} deleted`)) .catch(err => { - console.error('ERROR:', err); + console.error(`Failed to delete intent ${intentPath}:`, err); }); + // [END dialogflow_delete_intent] +} - const cancelOrderInputContexts = [ - contextsClient.contextPath(projectId, '*' /* sessionId */, 'pizza_order'), - ]; +// ///////////////////////////////////////////////////////////////////////////// +// Operations for contexts +// ///////////////////////////////////////////////////////////////////////////// - const cancelOrderResult = { - action: 'cancel-order', - parameters: [], - messages: [{text: {text: ['Your order is canceled.']}}], - outputContexts: [], - resetContexts: true, - }; +function createContext(projectId, sessionId, contextId, lifespanCount) { + // [START dialogflow_create_context] + // Imports the Dialogflow library + const dialogflow = require('dialogflow'); - const cancelOrderPhrases = [ - {type: 'EXAMPLE', parts: [{text: 'cancel'}]}, - {type: 'EXAMPLE', parts: [{text: 'no'}]}, - {type: 'EXAMPLE', parts: [{text: 'cancel order'}]}, - {type: 'EXAMPLE', parts: [{text: "I don't want it any more"}]}, - ]; + // Instantiates clients + const contextsClient = new dialogflow.ContextsClient(); - const cancelOrderIntent = Object.assign( - { - displayName: 'CancelOrder', - webhookState: 'WEBHOOK_STATE_DISABLED', - trainingPhrases: cancelOrderPhrases, - inputContexts: cancelOrderInputContexts, - mlEnabled: true, - priority: 500000, - }, - cancelOrderResult + const sessionPath = contextsClient.sessionPath(projectId, sessionId); + const contextPath = contextsClient.contextPath( + projectId, + sessionId, + contextId ); - const cancelOrderRequest = { - parent: agentPath, - intent: cancelOrderIntent, + const createContextRequest = { + parent: sessionPath, + context: { + name: contextPath, + lifespanCount: lifespanCount, + }, }; - intentsClient - .createIntent(cancelOrderRequest) - .then(responses => { - console.log('Created Cancel Order intent: '); - logIntent(responses[0]); - }) - .catch(err => { - console.error('ERROR:', err); - }); - // [END dialogflow_create_intent] + contextsClient.createContext(createContextRequest).then(responses => { + console.log(`Created ${responses[0].name} context`); + }); + // [END dialogflow_create_context] } -function listIntents(projectId) { +function listContexts(projectId, sessionId) { + // [START dialogflow_list_contexts] // Imports the Dialogflow library const dialogflow = require('dialogflow'); // Instantiates clients - const intentsClient = new dialogflow.IntentsClient(); + const contextsClient = new dialogflow.ContextsClient(); - // The path to identify the agent that owns the intents. - const projectAgentPath = intentsClient.projectAgentPath(projectId); + // The path to identify the agent that owns the contexts. + const sessionPath = contextsClient.sessionPath(projectId, sessionId); const request = { - parent: projectAgentPath, + parent: sessionPath, }; - // Send the request for listing intents. - return intentsClient - .listIntents(request) + // Send the request for listing contexts. + return contextsClient + .listContexts(request) .then(responses => { + responses[0].forEach(context => { + console.log(`Context name: ${context.name}`); + console.log(`Lifespan count: ${context.lifespanCount}`); + console.log('Fields:'); + if (context.parameters !== null) { + context.parameters.fields.forEach(field => { + console.log(`\t${field.field}: ${field.value}`); + }); + } + }); return responses[0]; }) .catch(err => { - console.error('Failed to list intents:', err); + console.error('Failed to list contexts:', err); }); + // [END dialogflow_list_contexts] } -function showIntents(projectId) { - return listIntents(projectId).then(intents => { - return Promise.all( - intents.map(intent => { - return getIntent(intent); - }) - ); - }); -} - -function getIntent(intent) { +function deleteContext(projectId, sessionId, contextId) { + // [START dialogflow_delete_context] // Imports the Dialogflow library const dialogflow = require('dialogflow'); // Instantiates clients - const intentsClient = new dialogflow.IntentsClient(); + const contextsClient = new dialogflow.ContextsClient(); + + const contextPath = contextsClient.contextPath( + projectId, + sessionId, + contextId + ); const request = { - // By default training phrases are not returned. If you want training - // phrases included in the returned intent, uncomment the line below. - // - // intentView: 'INTENT_VIEW_FULL', - name: intent.name, + name: contextPath, }; - // Send the request for retrieving the intent. - return intentsClient - .getIntent(request) - .then(responses => { - console.log('Found intent:'); - logIntent(responses[0]); - }) - .catch(err => { - console.error(`Failed to get intent ${intent.displayName}`, err); - }); -} - -function clearIntents(projectId) { - // Send the request for listing intents. - return listIntents(projectId) - .then(intents => { - return Promise.all( - intents.map(intent => { - return deleteIntent(intent); - }) - ); - }) - .catch(err => { - console.error('Failed to list intents:', err); - }); -} - -function deleteIntent(intent) { - // [START dialogflow_delete_intent] - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const intentsClient = new dialogflow.IntentsClient(); - - const request = {name: intent.name}; - - // Send the request for retrieving the intent. - return intentsClient - .deleteIntent(request) - .then(() => { - console.log(`Intent ${intent.displayName} deleted`); - }) - .catch(err => { - console.error(`Failed to delete intent ${intent.displayName}:`, err); - }); - // [END dialogflow_delete_intent] -} - -function updateIntent(projectId, intentId) { - // [START dialogflow_update_intent] - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const intentsClient = new dialogflow.IntentsClient(); - - // The path to identify the intent to be deleted. - const intentPath = intentsClient.intentPath(projectId, intentId); - - // UpdateIntent does full snapshot updates. For incremental update - // fetch the intent first then modify it. - const getIntentRequest = { - name: intentPath, - // It's important to have INTENT_VIEW_FULL here, otherwise the training - // phrases are not returned and updating will remove all training phrases. - intentView: 'INTENT_VIEW_FULL', - }; - - intentsClient - .getIntent(getIntentRequest) - .then(responses => { - const intent = responses[0]; - // Add a new response message for telegram to the intent. - intent.messages.push({ - image: {imageUri: 'http://www.example.com/logo.png'}, - platform: 'PLATFORM_TELEGRAM', - }); - // And make sure telegram uses default messages as well. - if (intent.defaultResponsePlatforms.indexOf('PLATFORM_TELEGRAM') < 0) { - intent.defaultResponsePlatforms.push('PLATFORM_TELEGRAM'); - } - - // Now update the intent. - const updateIntentRequest = { - intent: intent, - }; - - return intentsClient.updateIntent(updateIntentRequest); - }) - .then(responses => { - console.log('Intent updated:'); - logIntent(responses[0]); - }) - .catch(err => { - console.error('ERROR:', err); - }); - // [END dialogflow_update_intent] -} - -function logIntent(intent) { - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const contextsClient = new dialogflow.ContextsClient(); - const intentsClient = new dialogflow.IntentsClient(); - - console.log(` ID:`, intentsClient.matchIntentFromIntentName(intent.name)); - console.log(` Display Name: ${intent.displayName}`); - const outputContexts = intent.outputContexts - .map(context => { - return contextsClient.matchContextFromContextName(context.name); - }) - .join(', '); - console.log(` Priority: ${intent.priority}`); - console.log(` Output contexts: ${outputContexts}`); - - console.log(` Action: ${intent.action}`); - console.log(` Parameters:`); - intent.parameters.forEach(parameter => { - console.log( - ` ${parameter.displayName}: ${parameter.entityTypeDisplayName}` - ); - }); - - console.log(` Responses:`); - intent.messages.forEach(message => { - const messageContent = JSON.stringify(message[message.message]); - console.log( - ` (${message.platform}) ${message.message}: ${messageContent}` - ); - }); - - const defaultResponsePlatforms = intent.defaultResponsePlatforms.join(', '); - console.log( - ` Platforms using default responses: ${defaultResponsePlatforms}` - ); - console.log(''); -} - -// ///////////////////////////////////////////////////////////////////////////// -// Operations for contexts -// ///////////////////////////////////////////////////////////////////////////// - -function createContext(projectId, sessionId) { - // [START dialogflow_create_context] - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const contextsClient = new dialogflow.ContextsClient(); - - const sessionPath = contextsClient.sessionPath(projectId, sessionId); - - // Create a pizza_order context with the same parameters as the Pizza intent - // created by createIntent(). - const pizzaContextPath = contextsClient.contextPath( - projectId, - sessionId, - 'pizza_order' - ); - const pizzaContextRequest = { - parent: sessionPath, - context: { - name: pizzaContextPath, - lifespanCount: 5, - parameters: structjson.jsonToStructProto({ - size: 'large', - topping: ['tuna', 'cheddar'], - address: { - 'street-address': '1600 Amphitheatre Pkwy', - city: 'Mountain View', - 'admin-area': 'California', - 'zip-code': '94043', - }, - }), - }, - }; - - contextsClient.createContext(pizzaContextRequest).then(responses => { - console.log('Created pizza_order context'); - logContext(responses[0]); - }); - // [END dialogflow_create_context] -} - -function listContexts(projectId, sessionId) { - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const contextsClient = new dialogflow.ContextsClient(); - - // The path to identify the agent that owns the contexts. - const sessionPath = contextsClient.sessionPath(projectId, sessionId); - - const request = { - parent: sessionPath, - }; - - // Send the request for listing contexts. - return contextsClient - .listContexts(request) - .then(responses => { - return responses[0]; - }) - .catch(err => { - console.error('Failed to list contexts:', err); - }); -} - -function showContexts(projectId, sessionId) { - return listContexts(projectId, sessionId).then(contexts => { - return Promise.all( - contexts.map(context => { - return getContext(context); - }) - ); - }); -} - -function getContext(context) { - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const contextsClient = new dialogflow.ContextsClient(); - - const request = { - name: context.name, - }; - - const contextId = contextsClient.matchContextFromContextName(context.name); - - // Send the request for retrieving the context. - return contextsClient - .getContext(request) - .then(responses => { - console.log('Found context:'); - logContext(responses[0]); - }) - .catch(err => { - console.error(`Failed to get context ${contextId}:`, err); - }); -} - -function clearContexts(projectId, sessionId) { - return listContexts(projectId, sessionId).then(contexts => { - return Promise.all( - contexts.map(context => { - return deleteContext(context); - }) - ); - }); -} - -function deleteContext(context) { - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const contextsClient = new dialogflow.ContextsClient(); - - const request = { - name: context.name, - }; - - const contextId = contextsClient.matchContextFromContextName(context.name); - // Send the request for retrieving the context. return contextsClient .deleteContext(request) .then(() => { - console.log(`Context ${contextId} deleted`); + console.log(`Context ${contextPath} deleted`); }) .catch(err => { console.error(`Failed to delete context ${contextId}`, err); }); -} - -function updateContext(projectId, sessionId, contextId) { - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const contextsClient = new dialogflow.ContextsClient(); - - // The path to identify the context to be deleted. - const contextPath = contextsClient.contextPath( - projectId, - sessionId, - contextId - ); - - // UpdateContext does full snapshot updates. For incremental update - // fetch the context first then modify it. - const getContextRequest = { - name: contextPath, - }; - - contextsClient - .getContext(getContextRequest) - .then(responses => { - const context = responses[0]; - // Add a new parameter value. - - const parametersJson = structjson.structProtoToJson(context.parameters); - parametersJson['foo'] = 'bar'; - context.parameters = structjson.jsonToStructProto(parametersJson); - - // Now update the context. - const updateContextRequest = { - context: context, - }; - - return contextsClient.updateContext(updateContextRequest); - }) - .then(responses => { - console.log('Context updated:'); - logContext(responses[0]); - }) - .catch(err => { - console.error('ERROR:', err); - }); -} - -function logContext(context) { - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const contextsClient = new dialogflow.ContextsClient(); - - console.log( - ` Name:`, - contextsClient.matchContextFromContextName(context.name) - ); - console.log(` Lifespan: ${context.lifespanCount}`); - console.log(` Parameters:`); - const parameters = structjson.structProtoToJson(context.parameters); - for (const k in parameters) { - console.log(` ${k}: ${parameters[k]}`); - } - console.log(''); + // [END dialogflow_delete_context] } // ///////////////////////////////////////////////////////////////////////////// // Operations for session entity type // ///////////////////////////////////////////////////////////////////////////// -function createSessionEntityType(projectId, sessionId) { +function createSessionEntityType( + projectId, + sessionId, + entityValues, + entityTypeDisplayName, + entityOverrideMode +) { // Imports the Dialogflow library const dialogflow = require('dialogflow'); // Instantiates clients const sessionEntityTypesClient = new dialogflow.SessionEntityTypesClient(); - const contextsClient = new dialogflow.ContextsClient(); - - const sessionPath = contextsClient.sessionPath(projectId, sessionId); - // Create a session entity type that overrides the @size entity type. - // - // NOTE: Unlike other resources, the resource name of the session entity type - // is the display name of the entity type, not the ID. - const sizeSessionEntityTypePath = sessionEntityTypesClient.sessionEntityTypePath( + const sessionPath = sessionEntityTypesClient.sessionPath( + projectId, + sessionId + ); + const sessionEntityTypePath = sessionEntityTypesClient.sessionEntityTypePath( projectId, sessionId, - 'size' + entityTypeDisplayName ); - const sizeSessionEntityTypeRequest = { - parent: sessionPath, - sessionEntityType: { - name: sizeSessionEntityTypePath, - entityOverrideMode: 'ENTITY_OVERRIDE_MODE_OVERRIDE', - entities: [ - {value: 'short', synonyms: ['short', 'small', 'petit']}, - {value: 'tall', synonyms: ['tall', 'medium']}, - {value: 'grande', synonyms: ['grande', 'large', 'big']}, - ], - }, - }; - sessionEntityTypesClient - .createSessionEntityType(sizeSessionEntityTypeRequest) - .then(responses => { - console.log('Overrode @size entity type:'); - logSessionEntityType(responses[0]); + // Here we use the entity value as the only synonym. + const entities = []; + entityValues.forEach(entityValue => { + entities.push({ + value: entityValue, + synonyms: [entityValue], }); + }); - // Create a session entity type that extends the @topping entity type. - const toppingSessionEntityTypePath = sessionEntityTypesClient.sessionEntityTypePath( - projectId, - sessionId, - 'topping' - ); - const toppingSessionEntityTypeRequest = { + const sessionEntityTypeRequest = { parent: sessionPath, sessionEntityType: { - name: toppingSessionEntityTypePath, - entityOverrideMode: 'ENTITY_OVERRIDE_MODE_SUPPLEMENT', - entities: [ - {value: 'feta', synonyms: ['feta']}, - {value: 'parmesan', synonyms: ['parmesan']}, - ], + name: sessionEntityTypePath, + entityOverrideMode: entityOverrideMode, + entities: entities, }, }; sessionEntityTypesClient - .createSessionEntityType(toppingSessionEntityTypeRequest) + .createSessionEntityType(sessionEntityTypeRequest) .then(responses => { - console.log('Extended @topping entity type:'); - logSessionEntityType(responses[0]); + console.log('SessionEntityType created:'); + console.log(responses[0]); }); } -function showSessionEntityTypes(projectId, sessionId) { - // There is no listSessionEntityTypes API, use listEntityTypes to get possible - // entity type names. - listEntityTypes(projectId).then(entityTypes => { - return Promise.all( - entityTypes.map(entityType => { - return getSessionEntityType( - projectId, - sessionId, - entityType.displayName - ); - }) - ); - }); -} - -function getSessionEntityType(projectId, sessionId, entityTypeName) { +function listSessionEntityTypes(projectId, sessionId) { // Imports the Dialogflow library const dialogflow = require('dialogflow'); // Instantiates clients const sessionEntityTypesClient = new dialogflow.SessionEntityTypesClient(); - - // The path to identify the sessionEntityType to be retrieved. - const sessionEntityTypePath = sessionEntityTypesClient.sessionEntityTypePath( + const sessionPath = sessionEntityTypesClient.sessionPath( projectId, - sessionId, - entityTypeName + sessionId ); const request = { - name: sessionEntityTypePath, + parent: sessionPath, }; // Send the request for retrieving the sessionEntityType. return sessionEntityTypesClient - .getSessionEntityType(request) + .listSessionEntityTypes(request) .then(responses => { - console.log('Found session entity type:'); - logSessionEntityType(responses[0]); + responses[0].forEach(sessionEntityType => { + console.log(`Session entity type name: ${sessionEntityType.name}`); + console.log( + `Number of entities: ${sessionEntityType.entities.length}\n` + ); + }); }) .catch(err => { - if (err.code === grpc.status.NOT_FOUND) { - console.log(`Session entity type ${entityTypeName} is not found.`); - } else { - console.error( - `Failed to get session entity type ${entityTypeName}:`, - err - ); - } + console.error( + `Failed to list session entity types for ${sessionId}:`, + err + ); }); } -function clearSessionEntityTypes(projectId, sessionId) { - // There is no listSessionEntityTypes API, use listEntityTypes to get possible - // entity type names. - listEntityTypes(projectId).then(entityTypes => { - return Promise.all( - entityTypes.map(entityType => { - return deleteSessionEntityType( - projectId, - sessionId, - entityType.displayName - ); - }) - ); - }); -} - -function deleteSessionEntityType(projectId, sessionId, entityTypeName) { +function deleteSessionEntityType(projectId, sessionId, entityTypeDisplayName) { // Imports the Dialogflow library const dialogflow = require('dialogflow'); @@ -1223,7 +549,7 @@ function deleteSessionEntityType(projectId, sessionId, entityTypeName) { const sessionEntityTypePath = sessionEntityTypesClient.sessionEntityTypePath( projectId, sessionId, - entityTypeName + entityTypeDisplayName ); const request = { @@ -1234,210 +560,16 @@ function deleteSessionEntityType(projectId, sessionId, entityTypeName) { return sessionEntityTypesClient .deleteSessionEntityType(request) .then(() => { - console.log(`Session entity type ${entityTypeName} deleted`); + console.log(`Session entity type ${entityTypeDisplayName} deleted`); }) .catch(err => { - if (err.code === grpc.status.NOT_FOUND) { - console.log( - `Cannot delete session entity type ${entityTypeName} because ` + - `it is not found.` - ); - } else { - console.error(`Failed to delete ${entityTypeName}:`, err); - } + console.error(`Failed to delete ${entityTypeDisplayName}:`, err); }); } -function updateSessionEntityType(projectId, sessionId, entityTypeName) { - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const sessionEntityTypesClient = new dialogflow.SessionEntityTypesClient(); - - // The path to identify the sessionEntityType to be deleted. - const sessionEntityTypePath = sessionEntityTypesClient.sessionEntityTypePath( - projectId, - sessionId, - entityTypeName - ); - - // Update the session entity type. - // - // Note: this overrides the existing entities of the session entity type being - // updated, even if entityOverrideMode is set to - // ENTITY_OVERRIDE_MODE_SUPPLEMENT. - const request = { - sessionEntityType: { - name: sessionEntityTypePath, - entityOverrideMode: 'ENTITY_OVERRIDE_MODE_SUPPLEMENT', - entities: [ - {value: 'foo', synonyms: ['foo']}, - {value: 'bar', synonyms: ['bar']}, - ], - }, - }; - sessionEntityTypesClient - .updateSessionEntityType(request) - .then(responses => { - console.log('Session entity type updated:'); - logSessionEntityType(responses[0]); - }) - .catch(err => { - console.error('ERROR:', err); - }); -} - -function logSessionEntityType(sessionEntityType) { - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates clients - const sessionEntityTypesClient = new dialogflow.SessionEntityTypesClient(); - - console.log( - ` Name:`, - sessionEntityTypesClient.matchEntityTypeFromSessionEntityTypeName( - sessionEntityType.name - ) - ); - console.log( - ` Entity override mode: ${sessionEntityType.entityOverrideMode}` - ); - console.log(` Entities:`); - sessionEntityType.entities.forEach(entity => { - console.log(` ${entity.value}: ${entity.synonyms.join(', ')}`); - }); - console.log(''); -} - -// ///////////////////////////////////////////////////////////////////////////// -// Operations for restoring agents -// ///////////////////////////////////////////////////////////////////////////// - -function restoreRoomAgent(projectId) { - const fs = require('fs'); - fs.readFile('./resources/RoomReservation.zip', function(err, data) { - if (err) { - console.error(err); - } - restoreAgent(projectId, data); - }); -} - -function restoreAgent(projectId, data) { - // Imports the Dialogflow library - const dialogflow = require('dialogflow'); - - // Instantiates agent client - const agentsClient = new dialogflow.AgentsClient(); - - const agentPath = agentsClient.projectPath(projectId); - - // construct restore agent request - const request = { - agentContent: data, - parent: agentPath, - }; - - agentsClient.restoreAgent(request).catch(err => { - console.error(err); - }); -} - // ///////////////////////////////////////////////////////////////////////////// // Command line interface. // ///////////////////////////////////////////////////////////////////////////// - -function setupAgent(projectId) { - clearAgent(projectId) - .then(() => createEntityTypes(projectId)) - .then(() => createIntents(projectId)); -} - -function clearAgent(projectId) { - return ( - clearIntents(projectId) - // Give api.ai some time to clean up the references to existing entity - // types. - .then(() => { - console.log('Waiting 10 seconds before deleting entity types.'); - return setTimeoutPromise(10000); - }) - .then(() => clearEntityTypes(projectId)) - ); -} - -function showAgent(projectId) { - showEntityTypes(projectId).then(() => showIntents(projectId)); -} - -function setupSession(projectId, sessionId) { - createContext(projectId, sessionId); - createSessionEntityType(projectId, sessionId); -} - -function showSession(projectId, sessionId) { - showContexts(projectId, sessionId).then(() => - showSessionEntityTypes(projectId, sessionId) - ); -} - -function clearSession(projectId, sessionId) { - clearContexts(projectId, sessionId).then(() => - clearSessionEntityTypes(projectId, sessionId) - ); -} - -function setTimeoutPromise(delayMillis) { - return new Promise(resolve => { - setTimeout(() => resolve(), delayMillis); - }); -} - -function verifyCommand(callback, force, projectId, arg2, arg3) { - if (force) { - callback(projectId, arg2, arg3); - return; - } - //add a special warning for these functions because they delete the agent - const deletionWarningFunctions = [setupAgent, clearAgent]; - // Prompt the user for confirmation - // This action may change their agent's behavior - let userConfirmationPrompt = - '\nWarning! This operation will alter the Dialogflow agent with the ' + - `project ID '${projectId}' for ALL users and developers.`; - if (deletionWarningFunctions.includes(callback)) { - userConfirmationPrompt += - '\nTHIS WILL DELETE ALL EXISTING INTENTS AND ENTITIES'; - } - userConfirmationPrompt += `\nAre you sure you want to continue?`; - - prompt.start(); - prompt.get( - { - properties: { - confirm: { - pattern: /^(yes|no|y|n)$/gi, - description: userConfirmationPrompt, - required: true, - default: 'yes/no', - }, - }, - }, - function(err, result) { - const input = result.confirm.toLowerCase(); - // If the user didn't say yes/y, abort - if (input !== 'y' && input !== 'yes') { - console.log('Operation aborted.'); - return; - } - // If the user says yes/y call intended function - callback(projectId, arg2, arg3); - } - ); -} - const cli = require(`yargs`) .demand(1) .options({ @@ -1459,89 +591,312 @@ const cli = require(`yargs`) .alias('force', ['f']) .describe('force', 'force operation without a prompt') .command( - `setup-agent`, - `Create entity types and intent for ordering pizzas.`, - {}, - opts => verifyCommand(setupAgent, opts.force, opts.projectId) + 'create-entity-type', + 'Create entity type', + { + displayName: { + alias: 'd', + string: true, + demandOption: true, + requiresArg: true, + description: 'Display Name', + }, + kind: { + alias: 'k', + demandOption: true, + requiresArg: true, + description: 'The kind of entity. KIND_MAP or KIND_LIST.', + }, + }, + opts => createEntityType(opts.projectId, opts.displayName, opts.kind) ) - .command( - `clear-agent`, - `Delete all intents and entity types from an agent.`, - {}, - opts => verifyCommand(clearAgent, opts.force, opts.projectId) + .command('list-entity-types', 'List entity types', {}, opts => + listEntityTypes(opts.projectId) ) .command( - `show-agent`, - `Show all intents and entity types from an agent.`, - {}, - opts => showAgent(opts.projectId) + 'delete-entity-type', + 'Delete entity type', + { + entityTypeId: { + alias: 'e', + string: true, + demandOption: true, + requiresArg: true, + description: 'Session Id', + }, + }, + opts => deleteEntityType(opts.projectId, opts.entityTypeId) ) .command( - `update-entity-type `, - `Update an entity type.`, - {}, + 'create-entity', + 'Create Entity', + { + entityTypeId: { + alias: 'e', + string: true, + demandOption: true, + requiresArg: true, + description: 'Entity Type Id', + }, + entityValue: { + alias: 'v', + demandOption: true, + requiresArg: true, + description: 'Entity Value', + }, + synonyms: { + alias: 's', + array: true, + demandOption: true, + requiresArg: true, + description: 'Synonyms', + }, + }, opts => - verifyCommand( - updateEntityType, - opts.force, + createEntity( opts.projectId, - opts.entityTypeId + opts.entityTypeId, + opts.entityValue, + opts.synonyms ) ) - .command(`update-intent `, `Update an intent.`, {}, opts => - verifyCommand(updateIntent, opts.force, opts.projectId, opts.intentId) - ) .command( - `setup-session `, - `Create contexts and session entity types for a session. It assumes ` + - `the agents is set up by setup-agent command.`, - {}, - opts => setupSession(opts.projectId, opts.sessionId) + 'list-entities', + 'List entities', + { + entityTypeId: { + alias: 'e', + string: true, + demandOption: true, + requiresArg: true, + description: 'Entity Type Id', + }, + }, + opts => listEntities(opts.projectId, opts.entityTypeId) ) .command( - `show-session `, - `Show all contexts and session entity types in a session.`, - {}, - opts => showSession(opts.projectId, opts.sessionId) + 'delete-entity', + 'Delete entity', + { + entityTypeId: { + alias: 'e', + string: true, + demandOption: true, + requiresArg: true, + description: 'Entity Type Id', + }, + entityValue: { + alias: 'v', + string: true, + demandOption: true, + requiresArg: true, + description: 'Entity Value', + }, + }, + opts => deleteEntity(opts.projectId, opts.entityTypeId, opts.entityValue) ) .command( - `clear-session `, - `Delete all contexts and session entity types.`, - {}, + 'create-context', + 'Create Context', + { + sessionId: { + alias: 's', + string: true, + demandOption: true, + requiresArg: true, + description: 'Session Id', + }, + contextId: { + alias: 'c', + string: true, + demandOption: true, + requiresArg: true, + description: 'Context Id', + }, + lifespanCount: { + alias: 'l', + demandOption: true, + requiresArg: true, + description: 'Lifespan Count', + }, + }, opts => - verifyCommand(clearSession, opts.force, opts.projectId, opts.sessionId) + createContext( + opts.projectId, + opts.sessionId, + opts.contextId, + opts.lifespanCount + ) + ) + .command( + 'list-contexts', + 'List Intents', + { + sessionId: { + alias: 's', + string: true, + demandOption: true, + requiresArg: true, + description: 'Session Id', + }, + }, + opts => listContexts(opts.projectId, opts.sessionId) + ) + .command( + 'delete-context', + 'Delete Context', + { + sessionId: { + alias: 's', + string: true, + demandOption: true, + requiresArg: true, + description: 'Session Id', + }, + contextId: { + alias: 'c', + string: true, + demandOption: true, + requiresArg: true, + description: 'Context Id', + }, + }, + opts => deleteContext(opts.projectId, opts.sessionId, opts.contextId) ) .command( - `update-context `, - `Update a context.`, - {}, + 'create-intent', + 'Create Intent', + { + displayName: { + alias: 'd', + string: true, + demandOption: true, + requiresArg: true, + description: 'Display Name', + }, + trainingPhrasesParts: { + alias: 't', + array: true, + string: true, + demandOption: true, + requiresArg: true, + description: 'Training Phrases', + }, + messageTexts: { + alias: 'm', + array: true, + string: true, + demandOption: true, + requiresArg: true, + description: 'Message Texts', + }, + }, opts => - verifyCommand( - updateContext, - opts.force, + createIntent( opts.projectId, - opts.sessionId, - opts.contextId + opts.displayName, + opts.trainingPhrasesParts, + opts.messageTexts ) ) + .command('list-intents', 'List Intent', {}, opts => + listIntents(opts.projectId) + ) .command( - `update-session-entity-type `, - `Update a session entity type.`, - {}, + '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 => - verifyCommand( - updateSessionEntityType, - opts.force, + createSessionEntityType( opts.projectId, opts.sessionId, - opts.entityTypeName + opts.entityValues, + opts.entityTypeDisplayName, + opts.entityOverrideMode ) ) .command( - `restore-room-agent`, - `Restore the room booking Dialogflow agent`, - {}, - opts => verifyCommand(restoreRoomAgent, opts.force, opts.projectId) + '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 + ) ) .example(`node $0 setup-agent`) .example(`node $0 show-agent`) diff --git a/dialogflow/system-test/detect.v2beta1.test.js b/dialogflow/system-test/detect.v2beta1.test.js index 9ad3a38f05..aab84adc8c 100644 --- a/dialogflow/system-test/detect.v2beta1.test.js +++ b/dialogflow/system-test/detect.v2beta1.test.js @@ -91,7 +91,6 @@ test.serial(`It should create a knowledge base`, async t => { }); test(`It should detect Intent with Model Selection`, async t => { - await runAsync(`node resource.js restore-room-agent -f`); const output = await runAsync(`${cmd} detectIntentwithModelSelection`); t.true( output.includes( diff --git a/dialogflow/system-test/resource_test.js b/dialogflow/system-test/resource_test.js index 8fbaec6799..d1a8a8cd8a 100644 --- a/dialogflow/system-test/resource_test.js +++ b/dialogflow/system-test/resource_test.js @@ -20,119 +20,166 @@ const tools = require(`@google-cloud/nodejs-repo-tools`); const cmd = 'node resource.js'; const sessionId = require('uuid/v1')(); +const contextName = 'fake_context_name'; +const displayName = 'fake_display_name'; +const entityName = 'fake_entity'; +const synonym1 = 'synonym_1'; +const synonym2 = 'synonym_2'; +const phrase1 = 'training_phrase_1'; +const phrase2 = 'training_phrase_2'; +const message1 = 'message_1'; +const message2 = 'message_2'; + +test.serial('Test creating / listing / deleting a context.', async t => { + let output = await tools.runAsync( + `${cmd} create-context -s ${sessionId} -c ${contextName} -l 3` + ); + t.true(output.includes(sessionId)); + t.true(output.includes(contextName)); -test.after('Remove all existing resources', async () => { - await tools.runAsync(`${cmd} clear-agent -f`); -}); + output = await tools.runAsync(`${cmd} list-contexts -s ${sessionId}`); + t.true(output.includes(sessionId)); + t.true(output.includes(contextName)); + t.true(output.includes('3')); + + output = await tools.runAsync( + `${cmd} delete-context -s ${sessionId} -c ${contextName}` + ); + t.true(output.includes(sessionId)); + t.true(output.includes(contextName)); -test.serial('setup-agent should create entity types and intents.', async t => { - const output = await tools.runAsync(`${cmd} setup-agent -f`); - t.true(output.includes('Created size entity type')); - t.true(output.includes('Created Pizza intent')); - t.true(output.includes('Created ChangeDeliveryAddress intent')); - t.true(output.includes('Created PlaceOrder intent')); - t.true(output.includes('Created Cancel Order intent')); + output = await tools.runAsync(`${cmd} list-contexts -s ${sessionId}`); + t.false(output.includes(sessionId)); + t.false(output.includes(contextName)); }); test.serial( - 'show-agent should show all created intents and entity types', + 'Test creating / listing / deleting a entity type and entity.', async t => { - const output = await tools.runAsync(`${cmd} show-agent -f`); - t.true(output.indexOf(' Display Name: Pizza') >= 0); - t.true(output.indexOf(' Display Name: ChangeDeliveryAddress') >= 0); - t.true(output.indexOf(' Display Name: PlaceOrder') >= 0); - t.true(output.indexOf(' Display Name: CancelOrder') >= 0); - t.true(output.indexOf(' Display Name: size') >= 0); - t.true(output.indexOf(' Display Name: topping') >= 0); - } -); + // Create the Entity Type + let output = await tools.runAsync( + `${cmd} create-entity-type -d ${displayName} -k KIND_MAP` + ); + t.true(output.includes('entityTypes')); -// ///////////////////////////////////////////////////////////////////////////// -// Context and session entity type operations. -// ///////////////////////////////////////////////////////////////////////////// + const entityTypeId = output.split(' ')[1].split('/')[4]; -test.serial( - 'setup-session should create contexts and session entity types', - async t => { - const output = await tools.runAsync(`${cmd} setup-session ${sessionId} -f`); - t.true(output.includes('Created pizza_order context')); - t.true(output.includes('Overrode @size entity type')); - t.true(output.includes('Extended @topping entity type')); - } -); + // List the Entity Type + output = await tools.runAsync(`${cmd} list-entity-types`); + t.true(output.includes(displayName)); + t.true(output.includes(entityTypeId)); -test.serial( - 'show-session should retrieve the created contexts and session entity types', - async t => { - const output = await tools.runAsync(`${cmd} show-session ${sessionId} -f`); - t.true(output.includes('Found context:\n Name: pizza_order')); - } -); + // Create an Entity for the Entity Type + output = await tools.runAsync( + `${cmd} create-entity -e ${entityTypeId} -v ${entityName} -s ${synonym1} -s ${synonym2}` + ); -test.serial( - 'update-session-entity-type should update session entity type @size', - async t => { - const output = await tools.runAsync( - `${cmd} update-session-entity-type ${sessionId} size -f` + // List the Entity + output = await tools.runAsync(`${cmd} list-entities -e ${entityTypeId}`); + t.true(output.includes(entityName)); + t.true(output.includes(synonym1)); + t.true(output.includes(synonym2)); + + // Delete the Entity + output = await tools.runAsync( + `${cmd} delete-entity -e ${entityTypeId} -v ${entityName}` ); - t.true(output.includes('Session entity')); - } -); + t.true(output.includes(entityName)); -test.serial('update-context should update context "pizza_order"', async t => { - const output = await tools.runAsync( - `${cmd} update-context ${sessionId} pizza_order -f` - ); - t.true(output.includes('Context updated')); - t.true(output.includes('foo: bar')); -}); + // Verify the Entity is Deleted + output = await tools.runAsync(`${cmd} list-entities -e ${entityTypeId}`); + t.false(output.includes(entityName)); + t.false(output.includes(synonym1)); + t.false(output.includes(synonym2)); -test.serial( - 'clear-session should delete contexts session entity types', - async t => { - const output = await tools.runAsync(`${cmd} clear-session ${sessionId} -f`); - t.true(output.includes('Context pizza_order deleted')); + // Delete the Entity Type + output = await tools.runAsync( + `${cmd} delete-entity-type -e ${entityTypeId}` + ); + t.true(output.includes(entityTypeId)); + + // Verify the Entity Type is Deleted + output = await tools.runAsync(`${cmd} list-entity-types`); + t.false(output.includes(displayName)); + t.false(output.includes(entityTypeId)); } ); -// ///////////////////////////////////////////////////////////////////////////// -// Other intent and entity type operations. -// ///////////////////////////////////////////////////////////////////////////// - -test.serial('update-entity-type should update entity type', async t => { - const showAgentOutput = await tools.runAsync(`${cmd} show-agent -f`); - const toppingEntityId = showAgentOutput.match( - /Found entity type:\n {2}ID: (.*)\n {2}Display Name: topping/ - )[1]; - const output = await tools.runAsync( - `${cmd} update-entity-type ${toppingEntityId} -f` +test.serial('Test creating / listing / deleting a intent.', async t => { + let output = await tools.runAsync( + `${cmd} create-intent -d ${displayName} -t ${phrase1} -t ${phrase2} -m ${message1} -m ${message2}` ); - t.truthy(output.includes('Updated entity type')); - t.truthy(output.includes('foo')); -}); + t.true(output.includes('intents')); + const intentId = output.split(' ')[1].split('/')[4]; -test.serial('update-intent should update intent "pizza"', async t => { - const showAgentOutput = await tools.runAsync(`${cmd} show-agent -f`); - const pizzaIntentId = showAgentOutput.match( - /Found intent:\n {2}ID: (.*)\n {2}Display Name: Pizza/ - )[1]; - const output = await tools.runAsync( - `${cmd} update-intent ${pizzaIntentId} -f` - ); - t.truthy(output.includes('Intent updated')); + output = await tools.runAsync(`${cmd} list-intents`); + t.true(output.includes(intentId)); + t.true(output.includes(displayName)); + + output = await tools.runAsync(`${cmd} delete-intent -i ${intentId}`); + t.true(output.includes(intentId)); + + output = await tools.runAsync(`${cmd} list-intents`); + t.false(output.includes(intentId)); + t.false(output.includes(displayName)); }); test.serial( - 'clear-agent should delete all intents and entity types', + 'Test creating / listing / deleting a session entity type', async t => { - const output = await tools.runAsync(`${cmd} clear-agent -f`); - t.true(output.includes('Intent Pizza deleted')); - t.true(output.includes('Intent ChangeDeliveryAddress deleted')); - t.true(output.includes('Intent PlaceOrder deleted')); - t.true(output.includes('Intent CancelOrder deleted')); + // Create the Entity Type + let output = await tools.runAsync( + `${cmd} create-entity-type -d ${displayName} -k KIND_MAP` + ); + t.true(output.includes('entityTypes')); + + const entityTypeId = output.split(' ')[1].split('/')[4]; + + // List the Entity Type + output = await tools.runAsync(`${cmd} list-entity-types`); + t.true(output.includes(displayName)); + t.true(output.includes(entityTypeId)); + + // Create a Session Entity Type + output = await tools.runAsync( + `${cmd} create-session-entity-type -s ${sessionId} -e ${synonym1} -e ${synonym2} -d ${displayName} -o ENTITY_OVERRIDE_MODE_OVERRIDE` + ); + t.true(output.includes(sessionId)); + t.true(output.includes(displayName)); + t.true(output.includes(synonym1)); + t.true(output.includes(synonym2)); + + // List the Session Entity Type + output = await tools.runAsync( + `${cmd} list-session-entity-types -s ${sessionId}` + ); + t.true(output.includes(sessionId)); + t.true(output.includes(displayName)); + t.true(output.includes('2')); + + // Delete the Session Entity Type + output = await tools.runAsync( + `${cmd} delete-session-entity-type -s ${sessionId} -d ${displayName}` + ); + t.true(output.includes(displayName)); + + // Verify the Session Entity Type is Deleted + output = await tools.runAsync( + `${cmd} list-session-entity-types -s ${sessionId}` + ); + t.false(output.includes(sessionId)); + t.false(output.includes(displayName)); + t.false(output.includes('2')); + + // Delete the Entity Type + output = await tools.runAsync( + `${cmd} delete-entity-type -e ${entityTypeId}` + ); + t.true(output.includes(entityTypeId)); + + // Verify the Entity Type is Deleted + output = await tools.runAsync(`${cmd} list-entity-types`); + t.false(output.includes(displayName)); + t.false(output.includes(entityTypeId)); } ); - -test.after.always('Setting up agent for other tests', async () => { - await tools.runAsync(`${cmd} restore-room-agent -f`); -});