// tslint:disable
/*
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. 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. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file 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.
*/
// tslint:enable
import { Component, Input, Output, EventEmitter, OnInit, ChangeDetectorRef } from '@angular/core';
import { AmplifyService } from '../../../providers/amplify.service';
import { ConsoleLogger as Logger } from '@aws-amplify/core';
import { isUndefined } from 'util';
require('./aws-lex-audio.js')
const logger = new Logger('ChatBot');
const template = `
`;
declare var LexAudio: any;
let STATES = {
INITIAL: { MESSAGE: 'Type your message or click 🎤', ICON: '🎤' },
LISTENING: { MESSAGE: 'Listening... click 🔴 again to cancel', ICON: '🔴' },
SENDING: { MESSAGE: 'Please wait...', ICON: '🔊' },
SPEAKING: { MESSAGE: 'Speaking...', ICON: '...' }
};
const defaultVoiceConfig = {
silenceDetectionConfig: {
time: 2000,
amplitude: 0.2
}
}
@Component({
selector: 'amplify-interactions-core',
template: template
})
export class ChatbotComponentCore {
errorMessage: string;
amplifyService: AmplifyService;
inputText: string = "";
botName: string;
chatTitle: string;
clearComplete: boolean = false;
messages: any = [];
completions: any = {};
currentVoiceState: string = STATES.INITIAL.MESSAGE;
inputDisabled: boolean = false;
micText: string = STATES.INITIAL.ICON;
voiceConfig: any = defaultVoiceConfig;
continueConversation: boolean = false;
micButtonDisabled: boolean = false;
audioInput: any;
lexResponse: any;
conversationModeOn: boolean = false;
ref: ChangeDetectorRef;
voiceEnabled: boolean = false;
textEnabled: boolean = true;
audioControl: any;
@Output()
complete: EventEmitter = new EventEmitter();
constructor(ref: ChangeDetectorRef, amplifyService: AmplifyService) {
this.amplifyService = amplifyService;
this.ref = ref;
this.continueConversation = false;
}
@Input()
set data(data: any) {
this.botName = data.bot;
this.chatTitle = data.title;
this.clearComplete = data.clearComplete;
this.conversationModeOn = isUndefined(data.conversationModeOn) ? false : data.conversationModeOn;
this.voiceEnabled = isUndefined(data.voiceEnabled) ? false : data.voiceEnabled;
this.textEnabled = isUndefined(data.textEnabled) ? true : data.textEnabled;
this.voiceConfig = data.voiceConfig || this.voiceConfig;
this.performOnComplete = this.performOnComplete.bind(this);
this.amplifyService.interactions().onComplete(this.botName, this.performOnComplete);
if (!this.textEnabled && this.voiceEnabled) {
this.currentVoiceState = "Click the mic button"
STATES.INITIAL.MESSAGE = "Click the mic button"
}
if (!this.voiceEnabled && this.textEnabled) {
this.currentVoiceState = "Type a message"
STATES.INITIAL.MESSAGE = "Type a message"
}
if (this.voiceEnabled) {
this.audioControl = new LexAudio.audioControl();
}
}
@Input()
set bot(botName: string) {
this.botName = botName;
this.performOnComplete = this.performOnComplete.bind(this);
this.amplifyService.interactions().onComplete(botName, this.performOnComplete);
}
@Input()
set title(title: string) {
this.chatTitle = title;
}
@Input()
set clearOnComplete(clearComplete: boolean) {
this.clearComplete = clearComplete;
}
performOnComplete(evt) {
this.complete.emit(evt);
if (this.clearComplete) {
this.messages = [];
}
}
onInputChange(value: string) {
this.inputText = value;
}
onSubmit(e) {
if (!this.inputText) {
return;
}
let message = {
'me': this.inputText,
'meSentTime': new Date().toLocaleTimeString(),
'bot': '',
'botSentTime': ''
};
this.amplifyService.interactions().send(this.botName, this.inputText)
.then((response: any) => {
this.inputText = "";
message.bot = response.message;
message.botSentTime = new Date().toLocaleTimeString();
this.messages.push(message);
})
.catch((error) => logger.error(error));
}
onSilenceHandler = () => {
if (!this.continueConversation) {
return;
}
this.audioControl.exportWAV((blob) => {
this.currentVoiceState = STATES.SENDING.MESSAGE;
this.audioInput = blob;
this.micText = STATES.SENDING.ICON;
this.micButtonDisabled = true;
this.lexResponseHandler();
});
this.ref.detectChanges();
}
reset() {
this.audioControl.clear();
this.inputText = '';
this.currentVoiceState = STATES.INITIAL.MESSAGE;
this.inputDisabled = false;
this.micText = STATES.INITIAL.ICON;
this.continueConversation = false;
this.micButtonDisabled = false;
this.ref.detectChanges();
}
onError(error) {
logger.error(error)
}
async lexResponseHandler() {
if (!this.continueConversation) {
return;
}
const interactionsMessage = {
content: this.audioInput,
options: {
messageType: 'voice'
}
};
const response = await this.amplifyService.interactions().send(this.botName, interactionsMessage);
this.lexResponse = response;
this.currentVoiceState = STATES.SPEAKING.MESSAGE;
this.micText = STATES.SPEAKING.ICON;
this.micButtonDisabled = true;
let message = {
'me': this.lexResponse.inputTranscript,
'meSentTime': new Date().toLocaleTimeString(),
'bot': '',
'botSentTime': ''
};
this.inputText = "";
message.bot = this.lexResponse.message;
message.botSentTime = new Date().toLocaleTimeString();
this.messages.push(message);
this.doneSpeakingHandler();
this.ref.detectChanges();
}
doneSpeakingHandler() {
if (!this.continueConversation) {
return;
}
if (this.lexResponse.contentType === 'audio/mpeg') {
this.audioControl.play(this.lexResponse.audioStream, () => {
if (this.lexResponse.dialogState === 'ReadyForFulfillment' ||
this.lexResponse.dialogState === 'Fulfilled' ||
this.lexResponse.dialogState === 'Failed' ||
!this.conversationModeOn) {
this.inputDisabled = false;
this.currentVoiceState = STATES.INITIAL.MESSAGE;
this.micText = STATES.INITIAL.ICON;
this.micButtonDisabled = false;
this.continueConversation = false;
this.ref.detectChanges();
} else {
this.currentVoiceState = STATES.LISTENING.MESSAGE;
this.micText = STATES.LISTENING.ICON;
this.micButtonDisabled = false;
this.audioControl.startRecording(this.onSilenceHandler, null, this.voiceConfig.silenceDetectionConfig);
this.ref.detectChanges();
}
});
} else {
this.inputDisabled = false;
this.currentVoiceState = STATES.INITIAL.MESSAGE;
this.micText = STATES.INITIAL.ICON;
this.micButtonDisabled = false;
this.continueConversation = false;
this.ref.detectChanges();
}
}
async micButtonHandler() {
if (this.continueConversation) {
this.reset();
this.ref.detectChanges();
} else {
this.inputDisabled = true;
this.continueConversation = true;
this.currentVoiceState = STATES.LISTENING.MESSAGE;
this.micText = STATES.LISTENING.ICON;
this.micButtonDisabled = false;
this.audioControl.startRecording(this.onSilenceHandler, null, this.voiceConfig.silenceDetectionConfig);
this.ref.detectChanges();
}
}
}