/**
 * Copyright 2018 Google Inc. All Rights Reserved.
 *
 * 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.
 */ import * as Api from './api/v2' ; import * as ApiV1 from './api/v1' ; import * as ActionsApi from '../actionssdk/api/v2' ; import { Conversation , ConversationBaseOptions , ConversationOptionsInit , } from '../actionssdk' ; import { ProtoAny , JsonObject } from '../../common' ; import { Contexts , ContextValues , Parameters } from './context' ; import { Incoming } from './incoming' ; const CONV_DATA_CONTEXT = '_actions_on_google' ; const CONV_DATA_CONTEXT_LIFESPAN = 99 ; const SIMULATOR_WARNING = 'Cannot display response in Dialogflow simulator. ' + 'Please test on the Google Assistant simulator instead.' ; hidden export interface SystemIntent { intent : string ; data : ProtoAny < string , JsonObject > ; } hidden export interface GoogleAssistantResponse { expectUserResponse ? : boolean ; noInputPrompts ? : ActionsApi . GoogleActionsV2SimpleResponse [ ] ; isSsml ? : boolean ; richResponse ? : ActionsApi . GoogleActionsV2RichResponse ; systemIntent ? : SystemIntent ; userStorage ? : string ; speechBiasingHints ? : string [ ] ; } hidden export interface PayloadGoogle { google : GoogleAssistantResponse ; } public export interface DialogflowConversationOptions < TConvData , TUserStorage > extends ConversationBaseOptions < TConvData , TUserStorage > { public body ? : Api . GoogleCloudDialogflowV2WebhookRequest | ApiV1 . DialogflowV1WebhookRequest ; } const isV1 = ( body ) : body is ApiV1 . DialogflowV1WebhookRequest => ! ! ( body as ApiV1 . DialogflowV1WebhookRequest ) . result ; const isSimulator = ( body ) => { if ( isV1 ( body ) ) { return ! body . originalRequest ; } if ( ! body . originalDetectIntentRequest ) { return false ; } return ( Object . keys ( body . originalDetectIntentRequest . payload ! ) . length === 0 && ! ! body . responseId ) ; } ; const getRequest = ( body ) : ActionsApi . GoogleActionsV2AppRequest => { if ( isV1 ( body ) ) { const { originalRequest = { } } = body ; const { data = { } } = originalRequest ; return data ; } const { originalDetectIntentRequest = { } } = body ; const { payload = { } } = originalDetectIntentRequest ; return payload ; } ; const serializeData = < TConvData > ( data ) => JSON . stringify ( data ) ; const deserializeData = < TContexts extends Contexts , TConvData > ( contexts , defaultData ? ) : TConvData => { const context = contexts . get ( CONV_DATA_CONTEXT ) ; if ( context ) { const { data } = context . parameters ; if ( typeof data === 'string' ) { return JSON . parse ( data ) ; } } return Object . assign ( { } , defaultData ) as TConvData ; } ; public export class DialogflowConversation < TConvData = JsonObject , TUserStorage = JsonObject , TContexts extends Contexts = Contexts > extends Conversation < TUserStorage > { public body : Api . GoogleCloudDialogflowV2WebhookRequest | ApiV1 . DialogflowV1WebhookRequest ; example public action : string ; example public intent : string ; example public parameters : Parameters ; public contexts : ContextValues < TContexts > ; public incoming : Incoming ; example public query : string ; example public data : TConvData ; public version : number ; hidden _followup ? : Api . GoogleCloudDialogflowV2EventInput | ApiV1 . DialogflowV1FollowupEvent ; hidden _init : ConversationOptionsInit < TConvData , TUserStorage > ; public constructor ( options = { } ) { const { body = { } } = options ; super ( { request : getRequest ( body ) , headers : options . headers , init : options . init , ordersv3 : options . ordersv3 , } ) ; this . body = body ; if ( isV1 ( this . body ) ) { this . version = 1 ; const { result = { } } = this . body ; const { action = '' , parameters = { } , contexts , resolvedQuery = '' , metadata = { } , fulfillment , } = result ; const { intentName = '' } = metadata ; this . action = action ; this . intent = intentName ; this . parameters = parameters ; this . contexts = new ContextValues ( contexts ) ; this . incoming = new Incoming ( fulfillment ) ; this . query = resolvedQuery ; } else { this . version = 2 ; const { queryResult = { } } = this . body ; const { action = '' , parameters = { } , outputContexts , intent = { } , queryText = '' , fulfillmentMessages , } = queryResult ; const { displayName = '' } = intent ; this . action = action ; this . intent = displayName ; this . parameters = parameters ; this . contexts = new ContextValues ( outputContexts , this . body . session ) ; this . incoming = new Incoming ( fulfillmentMessages ) ; this . query = queryText ; } for ( const key in this . parameters ) { const value = this . parameters [ key ] ; if ( typeof value !== 'object' ) { this . parameters [ key ] = String ( value ) ; } } this . data = deserializeData ( this . contexts , this . _init . data ) ; } example param event param parameters param lang The language of this query.
     *     See  https *     for a list of the currently supported language codes.
     *     Note that queries in the same session do not necessarily need to specify the same language.
     *     By default, it is the languageCode sent with Dialogflow's queryResult.languageCode
     *  public followup ( event , parameters ? , lang ? ) { this . _responded = true ; if ( this . version === 1 ) { this . _followup = { name : event , data : parameters , } ; return this ; } const body = this . body as Api . GoogleCloudDialogflowV2WebhookRequest ; this . _followup = { name : event , parameters , languageCode : lang || body . queryResult ! . languageCode , } ; return this ; } public serialize ( ) { if ( this . _raw ) { return this . _raw ; } let payload ; if ( this . _followup ) { this . digested = true ; } else { const { richResponse , expectUserResponse , userStorage , expectedIntent , noInputPrompts , speechBiasingHints , } = this . response ( ) ; const google = { expectUserResponse , systemIntent : expectedIntent && { intent : expectedIntent . intent ! , data : expectedIntent . inputValueData as ProtoAny < string , JsonObject > , } , noInputPrompts , speechBiasingHints , } ; if ( richResponse . items ! . length ) { google . richResponse = richResponse ; } if ( userStorage ) { google . userStorage = userStorage ; } payload = { google } ; } const convDataDefault = deserializeData < TContexts , TConvData > ( this . contexts , this . _init . data ) ; const convDataIn = serializeData ( convDataDefault ) ; const convDataOut = serializeData ( this . data ) ; if ( convDataOut !== convDataIn ) { this . contexts . set ( CONV_DATA_CONTEXT , CONV_DATA_CONTEXT_LIFESPAN , { data : convDataOut , } ) ; } const simulator = isSimulator ( this . body ) ; if ( this . version === 1 ) { const response = { data : payload , followupEvent : this . _followup , } ; const contextOut = this . contexts . _serializeV1 ( ) ; if ( contextOut . length ) { response . contextOut = contextOut ; } if ( simulator && payload ) { const { richResponse = { } } = payload . google ; const { items = [ ] } = richResponse ; response . speech = SIMULATOR_WARNING ; if ( ! payload . google . systemIntent && items . length < 2 ) { for ( const { simpleResponse } of items ) { if ( simpleResponse ) { response . speech = simpleResponse . displayText || simpleResponse . textToSpeech ; break ; } } } } return response ; } const response = { payload , followupEventInput : this . _followup , } ; const outputContexts = this . contexts . _serialize ( ) ; if ( outputContexts . length ) { response . outputContexts = outputContexts ; } if ( simulator && payload ) { const { richResponse = { } } = payload . google ; const { items = [ ] } = richResponse ; response . fulfillmentText = SIMULATOR_WARNING ; if ( ! payload . google . systemIntent && items . length < 2 ) { for ( const { simpleResponse } of items ) { if ( simpleResponse ) { response . fulfillmentText = simpleResponse . displayText || simpleResponse . textToSpeech ; break ; } } } } return response ; } }