UNPKG

angular-chat-widget-rasa

Version:

A chatbot widget that is able to connect to a rasa chatbot using SocketIO

501 lines (490 loc) 20.6 kB
import { CommonModule } from '@angular/common'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { Subject } from 'rxjs'; import { animate, style, transition, trigger } from '@angular/animations'; import io from 'socket.io-client'; import { Observable } from 'rxjs/Observable'; import { Component, Input, Injectable, EventEmitter, Output, ViewChild, ViewEncapsulation, HostListener, NgModule, defineInjectable } from '@angular/core'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ChatAvatarComponent = /** @class */ (function () { function ChatAvatarComponent() { } ChatAvatarComponent.decorators = [ { type: Component, args: [{ selector: 'chat-avatar', template: "\n <img [attr.src]=\"image\" class=\"avatar\" />\n ", styles: ["\n .avatar {\n height: 30px;\n width: 30px;\n border-radius: 50%;\n float: left;\n margin-right: 10px;\n }\n "] }] } ]; ChatAvatarComponent.propDecorators = { image: [{ type: Input }] }; return ChatAvatarComponent; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ var fadeInOut = trigger('fadeInOut', [ transition(':enter', [ style({ opacity: 0 }), animate(250) ]), transition('* => void', [ animate(250, style({ opacity: 0, })) ]) ]); /** @type {?} */ var fadeIn = trigger('fadeIn', [ transition(':enter', [ style({ opacity: 0 }), animate(500) ]), transition(':leave', [ style({ opacity: 0 }), animate(1) ]), ]); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ChatService = /** @class */ (function () { function ChatService() { var _this = this; this.getMessages = (/** * @return {?} */ function () { return Observable.create((/** * @param {?} observer * @return {?} */ function (observer) { _this.socket.on('bot_uttered', (/** * @param {?} message * @return {?} */ function (message) { observer.next(message); })); })); }); } /** * @param {?} url * @return {?} */ ChatService.prototype.connect = /** * @param {?} url * @return {?} */ function (url) { var _this = this; this.socket = io(url); this.socket.on('connect', (/** * @return {?} */ function () { _this.socket.emit('session_request', { 'session_id': _this.socket.id }); })); this.socket.on('session_confirm', (/** * @param {?} remote_id * @return {?} */ function (remote_id) { })); this.socket.on('connect_error', (/** * @param {?} error * @return {?} */ function (error) { console.log(error); })); this.socket.on('error', (/** * @param {?} error * @return {?} */ function (error) { console.log(error); })); this.socket.on('disconnect', (/** * @param {?} reason * @return {?} */ function (reason) { console.log(reason); })); }; /** * @param {?} message * @return {?} */ ChatService.prototype.sendMessage = /** * @param {?} message * @return {?} */ function (message) { this.socket.emit('user_uttered', { 'message': message }); }; ChatService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; /** @nocollapse */ ChatService.ctorParameters = function () { return []; }; /** @nocollapse */ ChatService.ngInjectableDef = defineInjectable({ factory: function ChatService_Factory() { return new ChatService(); }, token: ChatService, providedIn: "root" }); return ChatService; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ChatWidgetComponent = /** @class */ (function () { function ChatWidgetComponent(chatService) { this.theme = 'blue'; this.botName = 'Bot'; this.botAvatar = "https://cdn.dribbble.com/users/275794/screenshots/3128598/gbot_800.png"; this.userAvatar = "https://storage.proboards.com/6172192/images/gKhXFw_5W0SD4nwuMev1.png"; this.url = 'http://localhost:5002'; this.startingMessage = 'Hi, how can we help you?'; this.opened = true; this._visible = false; this.focus = new Subject(); this.messages = []; this.chatService = chatService; this.chatService.connect(this.url); } Object.defineProperty(ChatWidgetComponent.prototype, "visible", { get: /** * @return {?} */ function () { return this._visible; }, set: /** * @param {?} visible * @return {?} */ function (visible) { var _this = this; this._visible = visible; if (this._visible) { setTimeout((/** * @return {?} */ function () { _this.scrollToBottom(); _this.focusMessage(); }), 0); } }, enumerable: true, configurable: true }); /** * @param {?} from * @param {?} text * @param {?} type * @return {?} */ ChatWidgetComponent.prototype.addMessage = /** * @param {?} from * @param {?} text * @param {?} type * @return {?} */ function (from, text, type) { this.messages.unshift({ from: from, text: text, type: type, date: new Date().getTime(), }); this.scrollToBottom(); }; /** * @return {?} */ ChatWidgetComponent.prototype.scrollToBottom = /** * @return {?} */ function () { if (this.bottom !== undefined) { this.bottom.nativeElement.scrollIntoView(); } }; /** * @return {?} */ ChatWidgetComponent.prototype.focusMessage = /** * @return {?} */ function () { this.focus.next(true); }; /** * @return {?} */ ChatWidgetComponent.prototype.ngOnInit = /** * @return {?} */ function () { var _this = this; this.client = { name: 'Guest User', status: 'online', avatar: this.userAvatar, }; this.operator = { name: this.botName, status: 'online', avatar: this.botAvatar, }; if (this.opened) { setTimeout((/** * @return {?} */ function () { return _this.visible = true; }), 1000); } setTimeout((/** * @return {?} */ function () { _this.addMessage(_this.operator, _this.startingMessage, 'received'); }), 1500); this.chatService .getMessages() .subscribe((/** * @param {?} message * @return {?} */ function (message) { setTimeout((/** * @return {?} */ function () { _this.addMessage(_this.operator, message.text, 'received'); }), 1000); })); }; /** * @return {?} */ ChatWidgetComponent.prototype.toggleChat = /** * @return {?} */ function () { this.visible = !this.visible; }; /** * @param {?} __0 * @return {?} */ ChatWidgetComponent.prototype.sendMessage = /** * @param {?} __0 * @return {?} */ function (_a) { var message = _a.message; if (message.trim() === '') { return; } this.addMessage(this.client, message, 'sent'); this.chatService.sendMessage(message); }; /** * @param {?} event * @return {?} */ ChatWidgetComponent.prototype.handleKeyboardEvent = /** * @param {?} event * @return {?} */ function (event) { if (event.key === '/') { this.focusMessage(); } if (event.key === '?' && !this._visible) { this.toggleChat(); } }; ChatWidgetComponent.decorators = [ { type: Component, args: [{ selector: 'chat-widget', template: "<div class=\"wrapper {{theme}}\">\n <div class=\"chat-box\" *ngIf=\"visible\" [@fadeInOut]=\"visible\">\n <div class=\"chat-box-header\">\n <div class=\"\">\n <div class=\"operator-status\">\n {{operator.status}}\n <span class=\"operator-status-online\">\u25CF</span>\n <button class=\"chat-button-header\" (click)=\"toggleChat()\">\u2715</button>\n </div>\n <chat-avatar [image]=\"operator.avatar\"></chat-avatar>\n <h3 class=\"operator-name\">\n {{operator.name}}\n </h3>\n </div>\n </div>\n <div class=\"chat-box-main\">\n <div class=\"chat-message-bottom\" #bottom></div>\n <ng-container *ngFor=\"let message of messages\">\n <div class=\"chat-message\" [class.chat-message-received]=\"message.type === 'received'\"\n [@fadeIn]\n [class.chat-message-sent]=\"message.type === 'sent'\">\n <div >\n <chat-avatar [image]=\"message.from.avatar\" class=\"chat-message-from-avatar\"></chat-avatar>\n <div class=\"chat-message-text\">\n {{message.text}}\n </div>\n </div>\n <div class=\"chat-message-date\">\n {{message.date | date: 'short'}}\n </div>\n </div>\n </ng-container>\n </div>\n <div class=\"chat-box-footer\">\n <chat-input (send)=\"sendMessage($event)\" (dismiss)=\"toggleChat()\" [focus]=\"focus\"></chat-input>\n </div>\n </div>\n <button class=\"chat-button\" (click)=\"toggleChat()\">\n <span [@fadeIn] *ngIf=\"visible\">\u2715</span>\n <span [@fadeIn] *ngIf=\"!visible\">?</span>\n </button>\n</div>\n", animations: [fadeInOut, fadeIn], styles: ["*{box-sizing:border-box;position:relative;font-family:\"Open Sans\",\"Helvetica Neue\",sans-serif}.wrapper{position:absolute;top:0;bottom:0;height:100vh;width:100vw}.chat-button{z-index:1;width:60px;height:60px;position:absolute;bottom:20px;right:40px;box-shadow:0 5px 40px rgba(0,0,0,.16);background:#1976d2;border-radius:50%;border:none;outline:0;color:#fff;font-size:32px}.chat-button-header{z-index:1;font-weight:700;color:#fff;border:1px solid #fff;background-color:inherit;padding:5px 9px;margin-left:5px}.chat-button:focus{border:2px solid #fff}.chat-box{z-index:2;position:absolute;left:0;height:100vh;width:100vw;margin:0;display:flex;flex-direction:column;box-shadow:0 5px 40px rgba(0,0,0,.16);background:#1976d2}.chat-box-hidden{display:none}.chat-box-header{padding:10px;color:#fff}.chat-box-main{flex:1;width:100%;background:#f5f5f5;display:flex;flex-direction:column-reverse;overflow:auto}.chat-box-footer{color:#fff;height:50px}.operator-name{margin:0;padding:1px}.operator-status{float:right;padding:4px}.operator-status span{margin-left:4px}.operator-status-online{color:#7cfc00}.operator-status-offline{color:red}.operator-avatar{height:30px;width:30px;border-radius:50%;float:left;margin-right:10px}.chat-message{display:block;width:auto;margin:5px;align-self:flex-start;flex-direction:row;max-width:80%;word-wrap:break-word}.chat-message-date{font-size:11px;color:#8d898d;padding:5px}.chat-message-from-avatar{height:35px;width:35px;border-radius:50%}.chat-message-text{margin-left:10px;padding:10px;border-radius:3px}.chat-message-received{margin-right:50px}.chat-message-received .chat-message-text{background:#b9d6f2;margin-left:50px;border-bottom-left-radius:0}.chat-message-received .chat-message-text:before{position:absolute;content:\" \";left:-10px;bottom:0;border-right:10px solid #b9d6f2;border-top:10px solid transparent;z-index:0}.chat-message-received .chat-message-date{margin-left:50px}.chat-message-received .chat-message-from-avatar{position:absolute;left:0;bottom:-15px}.chat-message-sent{align-self:flex-end}.chat-message-sent .chat-message-from{float:right}.chat-message-sent .chat-message-text{background:#84dccf;margin-right:50px;border-bottom-right-radius:0}.chat-message-sent .chat-message-text:after{position:absolute;content:\" \";right:-10px;bottom:0;border-left:10px solid #84dccf;border-top:10px solid transparent;z-index:0}.chat-message-sent .chat-message-date{text-align:right;padding-right:50px}.chat-message-sent .chat-message-from-avatar{position:absolute;right:0;bottom:-15px}.blue .chat-box,.blue .chat-button{background:#1976d2}.grey .chat-box,.grey .chat-button{background:#454549}.red .chat-box,.red .chat-button{background:#dd0031}@media (min-width:576px){.wrapper{top:auto;right:0;width:300px}.chat-button{display:block}.chat-button-header{display:none}.chat-box{top:auto;left:auto;bottom:100px;right:40px;height:60vh;width:300px;border-radius:10px}}@media (min-width:768px){.chat-box{height:70vh}}@media (min-width:992px){.chat-box{height:80vh}}"] }] } ]; /** @nocollapse */ ChatWidgetComponent.ctorParameters = function () { return [ { type: ChatService } ]; }; ChatWidgetComponent.propDecorators = { bottom: [{ type: ViewChild, args: ['bottom',] }], theme: [{ type: Input }], botName: [{ type: Input }], botAvatar: [{ type: Input }], userAvatar: [{ type: Input }], url: [{ type: Input }], startingMessage: [{ type: Input }], opened: [{ type: Input }], visible: [{ type: Input }], handleKeyboardEvent: [{ type: HostListener, args: ['document:keypress', ['$event'],] }] }; return ChatWidgetComponent; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ChatInputComponent = /** @class */ (function () { function ChatInputComponent() { this.buttonText = '↩︎'; this.focus = new EventEmitter(); this.send = new EventEmitter(); this.dismiss = new EventEmitter(); } /** * @return {?} */ ChatInputComponent.prototype.ngOnInit = /** * @return {?} */ function () { var _this = this; this.focus.subscribe((/** * @return {?} */ function () { return _this.focusMessage(); })); }; /** * @return {?} */ ChatInputComponent.prototype.focusMessage = /** * @return {?} */ function () { this.message.nativeElement.focus(); }; /** * @return {?} */ ChatInputComponent.prototype.getMessage = /** * @return {?} */ function () { return this.message.nativeElement.value; }; /** * @return {?} */ ChatInputComponent.prototype.clearMessage = /** * @return {?} */ function () { this.message.nativeElement.value = ''; }; /** * @return {?} */ ChatInputComponent.prototype.onSubmit = /** * @return {?} */ function () { /** @type {?} */ var message = this.getMessage(); if (message.trim() === '') { return; } this.send.emit({ message: message }); this.clearMessage(); this.focusMessage(); }; ChatInputComponent.decorators = [ { type: Component, args: [{ selector: 'chat-input', template: "\n <textarea type=\"text\" class=\"chat-input-text\" placeholder=\"Type message...\"\n #message (keydown.enter)=\"onSubmit()\" (keyup.enter)=\"message.value = ''\" (keyup.escape)=\"dismiss.emit()\"></textarea>\n <button type=\"submit\" class=\"chat-input-submit\" (click)=\"onSubmit()\">\n {{buttonText}}\n </button>\n ", encapsulation: ViewEncapsulation.None, styles: [".chat-input-text{margin:14px 0 0 14px;height:25px;width:70%;border:0;resize:none;border:none;overflow:auto;outline:0;box-shadow:none;font-size:14px;background-color:inherit;color:inherit}.chat-input-text::-webkit-input-placeholder{color:inherit}.chat-input-text::-moz-placeholder{color:inherit}.chat-input-text::-ms-input-placeholder{color:inherit}.chat-input-submit{margin:14px 12px;float:right;background-color:inherit;color:inherit;font-size:24px;border:0;outline:0}"] }] } ]; ChatInputComponent.propDecorators = { buttonText: [{ type: Input }], focus: [{ type: Input }], send: [{ type: Output }], dismiss: [{ type: Output }], message: [{ type: ViewChild, args: ['message',] }] }; return ChatInputComponent; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ChatConfigComponent = /** @class */ (function () { function ChatConfigComponent() { this.text = 'Select theme'; this.themeChange = new EventEmitter(); this.themes = ['blue', 'grey', 'red']; } /** * @param {?} theme * @return {?} */ ChatConfigComponent.prototype.setTheme = /** * @param {?} theme * @return {?} */ function (theme) { this.theme = theme; this.themeChange.emit(this.theme); }; ChatConfigComponent.decorators = [ { type: Component, args: [{ selector: 'chat-config', template: "\n <div class=\"chat-config\">\n {{text}}\n <button *ngFor=\"let item of themes\"\n class=\"btn\" [class.btn-active]=\"item === theme\"\n (click)=\"setTheme(item)\">\n {{item}}\n </button>\n </div>\n ", styles: ["\n .chat-config {\n padding: 20px;\n }\n .btn {\n padding: 5px;\n margin: 0px 2px;\n border: 1px solid #dedede;\n outline: none;\n }\n .btn-active {\n border: 1px solid #a0a0a0;\n }\n .btn:focus {\n border: 1px solid #333;\n }\n "] }] } ]; ChatConfigComponent.propDecorators = { theme: [{ type: Input }], text: [{ type: Input }], themeChange: [{ type: Output }] }; return ChatConfigComponent; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ChatbotRasaModule = /** @class */ (function () { function ChatbotRasaModule() { } ChatbotRasaModule.decorators = [ { type: NgModule, args: [{ imports: [CommonModule, BrowserAnimationsModule], declarations: [ChatAvatarComponent, ChatWidgetComponent, ChatInputComponent, ChatConfigComponent], exports: [ChatWidgetComponent, ChatConfigComponent], entryComponents: [ChatWidgetComponent, ChatConfigComponent], providers: [ChatService] },] } ]; return ChatbotRasaModule; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { ChatbotRasaModule, fadeIn as ɵd, fadeInOut as ɵc, ChatAvatarComponent as ɵa, ChatConfigComponent as ɵg, ChatInputComponent as ɵf, ChatWidgetComponent as ɵb, ChatService as ɵe }; //# sourceMappingURL=angular-chat-widget-rasa.js.map