import { Global } from "../core/global" ; import { SkillContext , VirtualAlexa } from "virtual-alexa" ; import * as fs from "fs" ; import { BstStatistics , BstCommand } from "../statistics/bst-statistics" ; interface SavedSession { id : string ; attributes : { [ id ] : any ; } ; locale : string ; userId : string ; } /**
 * Programmatic interface for interacting with the Virtual Alexa.
 *
 */ export class BSTVirtualAlexa { public static DefaultIntentSchemaLocation = "speechAssets/IntentSchema.json" ; public static DefaultSampleUtterancesLocation = "speechAssets/SampleUtterances.txt" ; public static DefaultInteractionModelLocation = "models/en-US.json" ; static DefaultInteractionModel = { interactionModel : { languageModel : { invocationName : "" , intents : [ ] } } } ; private virtualAlexa : VirtualAlexa = null ; private interactionModelProvided : boolean = false ; private sampleUtterancesProvided : boolean = false ; private intentSchemaProvided : boolean = false ; private nodeId : string ; private static FileTypes = { InterationModel : "Interaction Model" , IntentSchema : "Intent Schema" , SampleUtterances : "Sample Utterances" } ; private saveSession ( ) { if ( Global . config ( ) ) { const session = this . virtualAlexa . context ( ) . session ( ) ; if ( ! session ) { Global . config ( ) . deleteSession ( ) ; return ; } const savedSession = { id : session . id ( ) , attributes : session . attributes ( ) , locale : this . locale , userId : this . userId } ; Global . config ( ) . saveSession ( savedSession ) ; } } public deleteSession ( ) { Global . config ( ) . deleteSession ( ) ; } private loadSession ( ) { if ( Global . config ( ) ) { const savedSession = Global . config ( ) . loadSession ( ) as SavedSession ; if ( savedSession ) { this . virtualAlexa . context ( ) . session ( ) . setID ( savedSession . id ) ; this . virtualAlexa . context ( ) . session ( ) . updateAttributes ( savedSession . attributes ) ; } } } param skillURL param interactionModel The path to the interaction model file - defaults to  BSTAlexa . DefaultInteractionModelLocation .
     *  param intentSchemaFile The path to the intent schema file - defaults to  BSTAlexa . DefaultIntentSchemaLocation .
     *  param sampleUtterancesFile The path to the samples utterances file - defaults to  BSTAlexa . DefaultSampleUtterancesLocation .
     *  param applicationID public constructor ( private skillURL , private interactionModel ? , private intentSchemaFile ? , private sampleUtterancesFile ? , private applicationID ? , private locale ? , private userId ? ) { if ( ( intentSchemaFile || sampleUtterancesFile ) && interactionModel ) { console . error ( "The Interaction Model and Intent Schema Files should not both be specified. It should be one or the other." ) ; throw new Error ( "The Interaction Model and Intent Schema Files should not both be specified. It should be one or the other." ) ; } if ( ! this . interactionModel ) { this . interactionModel = BSTVirtualAlexa . DefaultInteractionModelLocation ; } else { this . interactionModelProvided = true ; } if ( ! this . intentSchemaFile ) { this . intentSchemaFile = BSTVirtualAlexa . DefaultIntentSchemaLocation ; } else { this . intentSchemaProvided = true ; } if ( ! this . sampleUtterancesFile ) { this . sampleUtterancesFile = BSTVirtualAlexa . DefaultSampleUtterancesLocation ; } else { this . sampleUtterancesProvided = true ; } if ( Global . config ( ) ) { if ( this . applicationID ) { Global . config ( ) . updateApplicationID ( this . applicationID ) ; } else { this . applicationID = Global . config ( ) . applicationID ( ) ; } } } /**
     * Returns internal virtual alexa context
     */ public context ( ) { return this . virtualAlexa . context ( ) ; } private validateFile ( file , fileType ) { if ( ! fs . existsSync ( file ) ) { console . error ( "Error loading " + fileType ) ; console . error ( "Cause: '" + this . interactionModel + "' doesn't exist" ) ; throw new Error ( "Error loading " + fileType + ", file not found" ) ; } } private validateJsonFiles ( fileLocation , fileType ) { const fileContent = fs . readFileSync ( fileLocation ) ; try { JSON . parse ( fileContent . toString ( ) ) ; } catch ( error ) { console . error ( "Error loading '" + fileType + "', incorrect JSON" ) ; console . error ( "Cause: " , error . message ) ; throw new Error ( "Error loading '" + fileType + "', incorrect JSON" ) ; } } private validateFilesAndBuild ( createdEmptyInteractionModelIfNeeded ) { const builder = VirtualAlexa . Builder ( ) . applicationID ( this . applicationID ) . skillURL ( this . skillURL ) ; let usingInteractionModel = false ; if ( this . locale ) { builder . locale ( this . locale ) ; if ( ! this . interactionModelProvided ) { this . interactionModel = this . interactionModel . replace ( "en-US" , this . locale ) ; } } if ( ! ( this . interactionModelProvided || this . intentSchemaProvided ) ) { if ( fs . existsSync ( this . interactionModel ) ) { usingInteractionModel = true ; } else if ( ! ( fs . existsSync ( this . intentSchemaFile ) && fs . existsSync ( this . sampleUtterancesFile ) ) && ! createdEmptyInteractionModelIfNeeded ) { console . error ( "Error loading Interaction model, no file provided and none found in default locations" ) ; throw new Error ( "Error loading Interaction model, no file provided and none found in default locations" ) ; } } else { if ( this . interactionModelProvided ) { this . validateFile ( this . interactionModel , BSTVirtualAlexa . FileTypes . InterationModel ) ; usingInteractionModel = true ; } else { if ( ! fs . existsSync ( this . intentSchemaFile ) ) { this . validateFile ( this . intentSchemaFile , BSTVirtualAlexa . FileTypes . IntentSchema ) ; } if ( ! fs . existsSync ( this . sampleUtterancesFile ) ) { this . validateFile ( this . sampleUtterancesFile , BSTVirtualAlexa . FileTypes . SampleUtterances ) ; } } } if ( usingInteractionModel ) { this . validateJsonFiles ( this . interactionModel , BSTVirtualAlexa . FileTypes . InterationModel ) ; builder . interactionModelFile ( this . interactionModel ) ; } else if ( createdEmptyInteractionModelIfNeeded ) { builder . interactionModel ( BSTVirtualAlexa . DefaultInteractionModel ) ; } else { this . validateJsonFiles ( this . intentSchemaFile , BSTVirtualAlexa . FileTypes . IntentSchema ) ; builder . intentSchemaFile ( this . intentSchemaFile ) . sampleUtterancesFile ( this . sampleUtterancesFile ) ; } return builder . create ( ) ; } /**
     * Start the emulator
     */ public start ( createdEmptyInteractionModelIfNeeded ? ) { this . virtualAlexa = this . validateFilesAndBuild ( createdEmptyInteractionModelIfNeeded ) ; const globalConfig = Global . config ( ) ; if ( globalConfig && globalConfig . configuration && globalConfig . configuration . secretKey ) { this . nodeId = globalConfig . configuration . secretKey ; } } param phrase param callback returns public spoken ( phrase , callback ? ) { let request ; this . virtualAlexa . filter ( ( generatedRequest ) => { request = generatedRequest ; } ) ; this . loadSession ( ) ; this . virtualAlexa . utter ( phrase ) . then ( ( payload ) => { this . saveSession ( ) ; if ( callback !== undefined && callback !== null ) { callback ( null , payload , request ) ; } } ) . catch ( error => { callback ( error , null , request ) ; } ) ; BstStatistics . instance ( ) . record ( BstCommand . utter , undefined , this . nodeId , Global . version ( ) ) ; return this ; } param intentName param slots param callback returns public intended ( intentName , slots ? , callback ? ) { let request ; this . virtualAlexa . filter ( ( generatedRequest ) => { request = generatedRequest ; } ) ; this . loadSession ( ) ; this . virtualAlexa . intend ( intentName , slots ) . then ( ( payload ) => { this . saveSession ( ) ; if ( callback !== undefined && callback !== null ) { callback ( null , payload , request ) ; } } ) . catch ( error => { callback ( error , null , request ) ; } ) ; BstStatistics . instance ( ) . record ( BstCommand . intend , undefined , this . nodeId , Global . version ( ) ) ; return this ; } param callback returns public launched ( callback ? ) { let request ; this . virtualAlexa . filter ( ( generatedRequest ) => { request = generatedRequest ; } ) ; this . virtualAlexa . launch ( ) . then ( payload => { this . saveSession ( ) ; callback ( null , payload , request ) ; } ) . catch ( error => { callback ( error , null , request ) ; } ) ; BstStatistics . instance ( ) . record ( BstCommand . launch , undefined , this . nodeId , Global . version ( ) ) ; return this ; } }