diff --git a/deploy/admin.gbapp/dialogs/AdminDialog.ts b/deploy/admin.gbapp/dialogs/AdminDialog.ts index c6d94414..f302eef7 100644 --- a/deploy/admin.gbapp/dialogs/AdminDialog.ts +++ b/deploy/admin.gbapp/dialogs/AdminDialog.ts @@ -32,111 +32,111 @@ "use strict"; - const UrlJoin = require("url-join"); import { AzureSearch } from "pragmatismo-io-framework"; -import { Prompts, Session, UniversalBot } from 'botbuilder'; +const { DialogSet, TextPrompt, NumberPrompt } = require('botbuilder-dialogs'); +const { createTextPrompt, createNumberPrompt } = require('botbuilder-prompts'); import { GBMinInstance } from "botlib"; import { IGBDialog } from "botlib"; import { GBDeployer } from '../../core.gbapp/services/GBDeployer'; import { GBImporter } from '../../core.gbapp/services/GBImporter'; import { GBConfigService } from '../../core.gbapp/services/GBConfigService'; import { KBService } from './../../kb.gbapp/services/KBService'; +import { BotAdapter } from "botbuilder"; export class AdminDialog extends IGBDialog { - static setup(bot: UniversalBot, min: GBMinInstance) { + static setup(bot: BotAdapter, min: GBMinInstance) { let importer = new GBImporter(min.core); let deployer = new GBDeployer(min.core, importer); - bot - .dialog("/admin", [ - (session: Session, args) => { - Prompts.text(session, "Please, authenticate:"); - if (args == undefined || args.firstRun) { - } + min.dialogs.add("/admin", [ + async (dc, args) => { + const prompt = "Please, authenticate:"; + await dc.prompt('textPrompt', prompt); }, - (session: Session, results) => { - var text = results.response; + async (dc, value) => { + var text = value.response; + const user = min.userState.get(dc.context); + if ( - !session.privateConversationData.authenticated || + !user.authenticated || text === GBConfigService.get("ADMIN_PASS") ) { - session.privateConversationData.authenticated = true; - session.send( + user.authenticated = true; + dc.context.sendActivity( "Welcome to Pragmatismo.io GeneralBots Administration." ); - Prompts.text(session, "Which task do you wanna run now?"); + await dc.prompt('textPrompt', "Which task do you wanna run now?"); } else { - session.endDialog(); + dc.endAll(); } }, - function (session: Session, results) { - var text = results.response; + async (dc, value) => { + var text = value; + const user = min.userState.get(dc.context); + if (text === "quit") { - session.privateConversationData.authenticated = false; - session.replaceDialog("/"); + user.authenticated = false; + dc.replace("/"); } else if (text === "sync") { min.core.syncDatabaseStructure(() => { }); - session.send("Sync started..."); - session.replaceDialog("/admin", { + dc.context.sendActivity("Sync started..."); + dc.replace("/admin", { firstRun: false }); } else if (text.split(" ")[0] === "rebuildIndex") { - AdminDialog.rebuildIndexCommand(min, session, () => - session.replaceDialog("/admin", { + AdminDialog.rebuildIndexCommand(min, dc, () => + dc.replace("/admin", { firstRun: false }) ); } else if (text.split(" ")[0] === "deployPackage") { - AdminDialog.deployPackageCommand(text, session, deployer, min, () => - session.replaceDialog("/admin", { + AdminDialog.deployPackageCommand(text, dc, deployer, min, () => + dc.replace("/admin", { firstRun: false }) ); } else if (text.split(" ")[0] === "redeployPackage") { - AdminDialog.undeployPackageCommand(text, min, session, () => { - AdminDialog.deployPackageCommand(text, session, deployer, min, () => { - session.send("Redeploy done."); - session.replaceDialog("/admin", { + AdminDialog.undeployPackageCommand(text, min, dc, () => { + AdminDialog.deployPackageCommand(text, dc, deployer, min, () => { + dc.context.sendActivity("Redeploy done."); + dc.replace("/admin", { firstRun: false }); }); }); } else if (text.split(" ")[0] === "undeployPackage") { - AdminDialog.undeployPackageCommand(text, min, session, () => - session.replaceDialog("/admin", { + AdminDialog.undeployPackageCommand(text, min, dc, () => + dc.replace("/admin", { firstRun: false }) ); } else if (text.split(" ")[0] === "applyPackage") { - session.send("Applying in progress..."); + dc.context.sendActivity("Applying in progress..."); min.core.loadInstance(text.split(" ")[1], (item, err) => { - session.send("Applying done..."); - session.replaceDialog("/"); + dc.context.sendActivity("Applying done..."); + dc.replace("/"); }); - session.replaceDialog("/admin", { + dc.replace("/admin", { firstRun: false }); } } ]) - .triggerAction({ - matches: /^(admin)/i - }); } - static undeployPackageCommand(text: any, min: GBMinInstance, session: Session, cb) { + static undeployPackageCommand(text: any, min: GBMinInstance, dc, cb) { let packageName = text.split(" ")[1]; let importer = new GBImporter(min.core); let deployer = new GBDeployer(min.core, importer); - session.send(`Undeploying package ${packageName}...`); + dc.context.sendActivity(`Undeploying package ${packageName}...`); deployer.undeployPackageFromLocalPath( min.instance, UrlJoin("deploy", packageName), (data, err) => { - session.send(`Package ${packageName} undeployed...`); + dc.context.sendActivity(`Package ${packageName} undeployed...`); cb(); } ); @@ -144,38 +144,38 @@ export class AdminDialog extends IGBDialog { static deployPackageCommand( text: string, - session: Session, + dc, deployer: GBDeployer, min: GBMinInstance, cb ) { let packageName = text.split(" ")[1]; - session.send(`Deploying package ${packageName}... (It may take a few seconds)`); + dc.context.sendActivity(`Deploying package ${packageName}... (It may take a few seconds)`); - // TODO: Find packages in all posible locations. + // TODO: Find packages in all possible locations. let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH"); deployer.deployPackageFromLocalPath( UrlJoin(additionalPath, packageName), (data, err) => { - session.send(`Package ${packageName} deployed... Please run rebuildIndex command.`); + dc.context.sendActivity(`Package ${packageName} deployed... Please run rebuildIndex command.`); } ); } - static rebuildIndexCommand(min: GBMinInstance, session: Session, cb) { + static rebuildIndexCommand(min: GBMinInstance, dc, cb) { let search = new AzureSearch( min.instance.searchKey, min.instance.searchHost, min.instance.searchIndex, min.instance.searchIndexer ); - session.send("Rebuilding index..."); + dc.context.sendActivity("Rebuilding index..."); search.deleteIndex((data, err) => { let kbService = new KBService(); search.createIndex(kbService.getSearchSchema(min.instance.searchIndex), "gb", (data, err) => { - session.send("Index rebuilt."); + dc.context.sendActivity("Index rebuilt."); }); }); } diff --git a/deploy/admin.gbapp/dialogs/UploadPackageDialog.ts b/deploy/admin.gbapp/dialogs/UploadPackageDialog.ts deleted file mode 100644 index a89a52b2..00000000 --- a/deploy/admin.gbapp/dialogs/UploadPackageDialog.ts +++ /dev/null @@ -1,189 +0,0 @@ -/*****************************************************************************\ -| ( )_ _ | -| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | -| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ | -| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) | -| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | -| | | ( )_) | | -| (_) \___/' | -| | -| General Bots Copyright (c) Pragmatismo.io. All rights reserved. | -| Licensed under the AGPL-3.0. | -| | -| According to our dual licensing model, this program can be used either | -| under the terms of the GNU Affero General Public License, version 3, | -| or under a proprietary license. | -| | -| The texts of the GNU Affero General Public License with an additional | -| permission and of our proprietary license can be found at and | -| in the LICENSE file you have received along with this program. | -| | -| This program is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | -| GNU Affero General Public License for more details. | -| | -| "General Bots" is a registered trademark of Pragmatismo.io. | -| The licensing of the program under the AGPLv3 does not imply a | -| trademark license. Therefore any rights, title and interest in | -| our trademarks remain entirely with us. | -| | -\*****************************************************************************/ - -"use strict"; - -import { IGBDialog } from "botlib"; -import { Prompts, UniversalBot, Session, ListStyle } from "botbuilder"; -import { GBMinInstance } from "botlib"; -var fs = require("fs"); -var request = require("request"); -var mkdirp = require("mkdirp"); -var builder = require("botbuilder"); -const logger = require('../base/winston'); - -export class AskDialog extends IGBDialog { - static setup(bot: UniversalBot, min: GBMinInstance) { - bot.dialog("/attachFile", [ - function(session, args, next) { - logger.debug("/attachFile/F1: Start"); - if (session.privateConversationData.JWToken === undefined) { - logger.error("/attachFile/F1: Undefined JWToken"); - session.endConversation( - "Unable to store your attachments. Sorry for the inconvenience, please try again." - ); - } else { - if (session.privateConversationData.userRequest.text.length === 0) { - if ( - session.privateConversationData.userRequest.attachments.length === - 1 - ) { - var txt = - "I received your attachment. Please let me know how should I handle it."; - } else { - var txt = - "I received your attachments. Please let me know how should I handle them."; - } - var msg = new builder.Message(session) - .textFormat("markdown") - .text(txt); - builder.Prompts.text(session, msg); - } else { - next(); - } - } - }, - - function(session, args, next) { - logger.debug("/attachFile/F2: Start"); - if (!(args.response === null) && !(args.response === undefined)) { - session.privateConversationData.userRequest.text = args.response; - } - - var mkdirName = - "work" - - mkdirp(mkdirName, function(err) { - if (err) { - logger.error( - "/attachFile/F2: unable to create folder. Error-> " + err - ); - session.endConversation( - "Unable to store your attachments. Sorry for the inconvenience, please try again." - ); - } else { - if (!mkdirName.endsWith("/")) { - mkdirName = mkdirName + "/"; - } - session.privateConversationData.attachmentsToWrite = - session.privateConversationData.userRequest.attachments.length - - 1; - writeFileRequest(session, mkdirName); - } - }); - } - ]); - - function writeFileRequest(session, mkdirName) { - var options = { - url: - session.privateConversationData.userRequest.attachments[ - session.privateConversationData.attachmentsToWrite - ].contentUrl, - method: "GET", - headers: { - "Content-type": - session.privateConversationData.userRequest.attachments[ - session.privateConversationData.attachmentsToWrite - ].contentType - } - }; - // if ( - // session.message.address.channelId === "skype" || - // session.message.address.channelId === "msteams" - // ) { - // options.headers.Authorization = - // "Bearer " + session.privateConversationData.JWToken; - // } - - request(options, function(err, response, body) { - if (err) { - logger.error(err); - } else { - logger.trace(response.statusCode); - - var fileName = - session.privateConversationData.userRequest.attachments[ - session.privateConversationData.attachmentsToWrite - ].name; - if (fs.existsSync(mkdirName + fileName)) { - var fileType = fileName.substr(fileName.lastIndexOf(".")); //e.g. '.pdf' - var fileSubName = fileName.substr( - 0, - fileName.length - fileType.length - ); //'name' if original fileName is 'name.pdf' - var j = 1; - while ( - fs.existsSync(mkdirName + fileSubName + "(" + j + ")" + fileType) - ) { - j += 1; - } - fileName = fileSubName + "(" + j + ")" + fileType; - } - session.privateConversationData.userRequest.attachments[ - session.privateConversationData.attachmentsToWrite - ] = { - name: fileName, - contentUrl: mkdirName, - contentType: - session.privateConversationData.userRequest.attachments[ - session.privateConversationData.attachmentsToWrite - ].contentType - }; - fs.writeFile( - mkdirName + fileName, - body, - { encoding: "binary" }, - function(err) { - //{encoding: 'binary' , flag: 'wx'} - if (err) { - logger.error( - "/attachFile/F2: unable to save file. Error-> " + err - ); - session.endConversation( - "Unable to store your attachments. Sorry for the inconvenience, please try again." - ); - } else { - session.privateConversationData.attachmentsToWrite -= 1; - if (session.privateConversationData.attachmentsToWrite < 0) { - session.beginDialog("/textRequest"); - } else { - writeFileRequest(session, mkdirName); - } - } - } - ); - } - }); - } - } -} diff --git a/deploy/admin.gbapp/index.ts b/deploy/admin.gbapp/index.ts index 94c2890e..fb02df40 100644 --- a/deploy/admin.gbapp/index.ts +++ b/deploy/admin.gbapp/index.ts @@ -35,7 +35,7 @@ const UrlJoin = require("url-join"); import { AdminDialog } from './dialogs/AdminDialog'; import { GBMinInstance, IGBPackage } from "botlib"; -import { Session } from 'botbuilder'; + import { Sequelize } from 'sequelize-typescript'; import { IGBCoreService } from 'botlib'; @@ -53,7 +53,7 @@ export class GBAdminPackage implements IGBPackage { unloadBot(min: GBMinInstance): void { } - onNewSession(min: GBMinInstance, session: Session): void { + onNewSession(min: GBMinInstance, dc: any): void { } } diff --git a/deploy/analytics.gblib/index.ts b/deploy/analytics.gblib/index.ts index c58afd26..9e8c77a4 100644 --- a/deploy/analytics.gblib/index.ts +++ b/deploy/analytics.gblib/index.ts @@ -37,7 +37,7 @@ const UrlJoin = require("url-join"); import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"; -import { Session } from 'botbuilder'; + import { Sequelize } from "sequelize-typescript"; export class GBAnalyticsPackage implements IGBPackage { @@ -56,7 +56,7 @@ export class GBAnalyticsPackage implements IGBPackage { unloadBot(min: GBMinInstance): void { } - onNewSession(min: GBMinInstance, session: Session): void { + onNewSession(min: GBMinInstance, dc: any): void { } } diff --git a/deploy/console.gblib/index.ts b/deploy/console.gblib/index.ts index 871b6663..b5e46453 100644 --- a/deploy/console.gblib/index.ts +++ b/deploy/console.gblib/index.ts @@ -36,7 +36,7 @@ const UrlJoin = require("url-join"); import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"; -import { Session } from 'botbuilder'; + import { Sequelize } from "sequelize-typescript"; import { ConsoleDirectLine } from "./services/ConsoleDirectLine"; @@ -59,7 +59,7 @@ export class GBConsolePackage implements IGBPackage { unloadBot(min: GBMinInstance): void { } - onNewSession(min: GBMinInstance, session: Session): void { + onNewSession(min: GBMinInstance, dc: any): void { } } diff --git a/deploy/core.gbapp/dialogs/WelcomeDialog.ts b/deploy/core.gbapp/dialogs/WelcomeDialog.ts index 7453866b..5ce66378 100644 --- a/deploy/core.gbapp/dialogs/WelcomeDialog.ts +++ b/deploy/core.gbapp/dialogs/WelcomeDialog.ts @@ -36,39 +36,40 @@ const WaitUntil = require("wait-until"); import { GBCoreService } from "../services/GBCoreService"; import { IGBDialog } from "botlib"; import { GBConversationalService } from "../services/GBConversationalService"; -import { UniversalBot, Session, Prompts } from "botbuilder"; import { GBMinInstance } from "botlib"; +import { BotAdapter } from "botbuilder"; export class WelcomeDialog extends IGBDialog { - static setup(bot: UniversalBot, min: GBMinInstance) { + static setup(bot: BotAdapter, min: GBMinInstance) { - bot.dialog("/", [ - function (session, args, next) { - if (!session.userData.once) { - session.userData.once = true; + min.dialogs.add("/", [ + + async (dc, args) => { + + const user = min.userState.get(dc.context); + + if (!user.once) { + user.once = true; var a = new Date(); const date = a.getHours(); var msg = date < 12 ? "bom dia" : date < 18 ? "boa tarde" : "boa noite"; - - session.sendTyping(); - let msgs = [`Oi, ${msg}.`, `Oi!`, `Olá, ${msg}`, `Olá!`]; - session.endDialog(msgs); + + let messages = [`Oi, ${msg}.`, `Oi!`, `Olá, ${msg}`, `Olá!`]; + dc.end(messages); } - - if (session.message && session.message.text != "") { - session.replaceDialog("/answer", { query: session.message.text }); - return; - } + // V4: if (dc.context.message && dc.message.text != "") { + // dc.replace("/answer", { query: dc.message.text }); + // return; + // } + // let userName = dc.message.user.name; + // let displayName = dc.message.user.name; - let userName = session.message.user.name; - let displayName = session.message.user.name; - - if (args) { - userName = args.userName; - displayName = args.displayName; - } + // if (args) { + // userName = args.userName; + // displayName = args.displayName; + // } } ]); diff --git a/deploy/core.gbapp/dialogs/WhoAmIDialog.ts b/deploy/core.gbapp/dialogs/WhoAmIDialog.ts index 358f8943..4e90cb86 100644 --- a/deploy/core.gbapp/dialogs/WhoAmIDialog.ts +++ b/deploy/core.gbapp/dialogs/WhoAmIDialog.ts @@ -35,26 +35,25 @@ import { GBConversationalService } from "./../services/GBConversationalService"; import { GBCoreService } from "../services/GBCoreService"; import { IGBDialog } from "botlib"; -import { UniversalBot, Session, Prompts } from "botbuilder"; import { GBMinInstance } from "botlib"; +import { BotAdapter } from "botbuilder"; export class WhoAmIDialog extends IGBDialog { - static setup(bot: UniversalBot, min: GBMinInstance) { - bot.dialog("/whoAmI", [ - function(session, args) { - session.sendTyping(); - session.send(`${min.instance.description}`); + static setup(bot: BotAdapter, min: GBMinInstance) { + min.dialogs.add("/whoAmI", [ + async (dc, args) => { + dc.context.sendActivity(`${min.instance.description}`); if (min.instance.whoAmIVideo){ - session.send(`Vou te mostrar um vídeo. Por favor, aguarde...`); - min.conversationalService.sendEvent(session, "play", { + dc.context.sendActivity(`Vou te mostrar um vídeo. Por favor, aguarde...`); + min.conversationalService.sendEvent(dc, "play", { playerType: "video", data: min.instance.whoAmIVideo.trim() }); } - session.replaceDialog('/ask', {isReturning: true}); + dc.replace('/ask', {isReturning: true}); } ]); } diff --git a/deploy/core.gbapp/index.ts b/deploy/core.gbapp/index.ts index c4f4c7c1..1ab52eeb 100644 --- a/deploy/core.gbapp/index.ts +++ b/deploy/core.gbapp/index.ts @@ -35,7 +35,7 @@ const UrlJoin = require("url-join"); import { GBMinInstance, IGBPackage } from "botlib"; -import { Session } from 'botbuilder'; + import { WelcomeDialog } from "./dialogs/WelcomeDialog"; import { WhoAmIDialog } from "./dialogs/WhoAmIDialog"; import { IGBCoreService} from "botlib"; @@ -66,7 +66,7 @@ export class GBCorePackage implements IGBPackage { unloadBot(min: GBMinInstance): void { } - onNewSession(min: GBMinInstance, session: Session): void { + onNewSession(min: GBMinInstance, dc: any): void { } } diff --git a/deploy/core.gbapp/models/GBModel.ts b/deploy/core.gbapp/models/GBModel.ts index a32feb19..5f86cc1e 100644 --- a/deploy/core.gbapp/models/GBModel.ts +++ b/deploy/core.gbapp/models/GBModel.ts @@ -111,6 +111,12 @@ export class GuaribasInstance extends Model implements IGBInst @Column kb: string; + @Column + nlpAppId: string; + + @Column + nlpSubscriptionKey: string; + @Column @Column({ type: DataType.STRING(512) }) nlpServerUrl: string; diff --git a/deploy/core.gbapp/services/GBConversationalService.ts b/deploy/core.gbapp/services/GBConversationalService.ts index 118755d0..2ef90289 100644 --- a/deploy/core.gbapp/services/GBConversationalService.ts +++ b/deploy/core.gbapp/services/GBConversationalService.ts @@ -38,14 +38,11 @@ const logger = require("../../../src/logger"); import { GBConfigService } from "./GBConfigService"; import { GBCoreService } from "./GBCoreService"; - -import { Session, Message, LuisRecognizer } from "botbuilder"; - import { GBService, GBServiceCallback, IGBConversationalService } from "botlib"; import { GBError } from "botlib"; import { GBERROR_TYPE } from "botlib"; import { GBMinInstance } from "botlib"; - +import { LuisRecognizer } from "botbuilder-ai"; export class GBConversationalService implements IGBConversationalService { @@ -55,73 +52,61 @@ export class GBConversationalService implements IGBConversationalService { this.coreService = coreService; } - sendEvent(session: Session, name: string, value: any) { + sendEvent(dc: any, name: string, value: any) { var msg = new gBuilder.Message(); msg.data.type = "event"; msg.data.name = name; msg.data.value = value; - session.send(msg); + dc.context.sendActivity(msg); } - runNLP( - session: Session, + async runNLP( + dc: any, min: GBMinInstance, text: string, cb: GBServiceCallback ) { - LuisRecognizer.recognize( - text, - min.instance.nlpServerUrl, - (err, intents, entities) => { - if (err) { - cb(null, new GBError(err, GBERROR_TYPE.nlpGeneralError)); - return; + + const model = new LuisRecognizer({ + appId: min.instance.nlpAppId, + subscriptionKey: min.instance.nlpSubscriptionKey, + serviceEndpoint: min.instance.nlpServerUrl + }); + + await model.recognize(dc).then(res => { + + // Resolve intents returned from LUIS + let topIntent = LuisRecognizer.topIntent(res); + + if (topIntent) { + var intent = topIntent; + var entity = + res.entities && res.entities.length > 0 + ? res.entities[0].entity.toUpperCase() + : null; + logger.trace( + "luis: intent: [" + intent + "] entity: [" + entity + "]" + ); + + try { + dc.replace("/" + intent); + } catch (error) { + logger.trace("error: intent: [" + intent + "] error: [" + error + "]"); + + dc.context.sendActivity("Desculpe-me, não encontrei nada a respeito..."); + dc.replace("/ask", { isReturning: true }); } - if (intents && intents.length > 0) { - var intent = intents[0].intent; - var entity = - entities && entities.length > 0 - ? entities[0].entity.toUpperCase() - : null; - logger.trace( - "luis: intent: [" + intent + "] entity: [" + entity + "]" - ); - - // PACKAGE: Send to packages. - - if (intent === "Student.CheckAttendance") { - session.replaceDialog("/belagua-check-attendance", { entities: entities }); - } - else if (intent === 'User.Authenticate') { - session.replaceDialog("/belagua-user-login", { entities: entities }); - } - else if (intent === "PerguntarSobreTermo") { - session.send( - "Vou mostrar um menu para ajudar você a formular sua pergunta..." - ); - session.replaceDialog("/menu"); - } else if (intent === "ShowSubjectMenu") { - session.replaceDialog("/menu"); - } else { - try { - session.replaceDialog("/" + intent); - } catch (error) { - logger.trace("error: intent: [" + intent + "] error: [" + error + "]"); - session.sendTyping(); - session.send("Desculpe-me, não encontrei nada a respeito..."); - session.replaceDialog("/ask", {isReturning: true}); - } - } - - cb({ intent, entities }, null); - } else { - session.sendTyping(); - session.send("Lamento, não achei nada a respeito..."); - session.replaceDialog("/ask", {isReturning: true}); - cb(null, null); - } + cb({ intent, entities: res.entities }, null); + } else { + + dc.context.sendActivity("Lamento, não achei nada a respeito..."); + dc.replace("/ask", { isReturning: true }); + cb(null, null); } - ); + } + ).catch(err => { + cb(null, new GBError(err, GBERROR_TYPE.nlpGeneralError)); + }); } } diff --git a/deploy/core.gbapp/services/GBCoreService.ts b/deploy/core.gbapp/services/GBCoreService.ts index c6f87b6e..dc83517f 100644 --- a/deploy/core.gbapp/services/GBCoreService.ts +++ b/deploy/core.gbapp/services/GBCoreService.ts @@ -45,7 +45,7 @@ import { Sequelize } from "sequelize-typescript"; import { Promise } from "bluebird"; import { GBConfigService } from "./GBConfigService"; import { DataTypeUUIDv1 } from "sequelize"; -import { UniversalBot } from "botbuilder"; + import { GBServiceCallback, IGBInstance, IGBCoreService } from 'botlib'; import { GuaribasInstance } from "../models/GBModel"; diff --git a/deploy/core.gbapp/services/GBDeployer.ts b/deploy/core.gbapp/services/GBDeployer.ts index cb613a2a..32564d93 100644 --- a/deploy/core.gbapp/services/GBDeployer.ts +++ b/deploy/core.gbapp/services/GBDeployer.ts @@ -51,7 +51,7 @@ import { Promise } from "bluebird"; import { GBConfigService } from "./GBConfigService"; import { DataTypeUUIDv1 } from "sequelize"; import { GBError, GBERROR_TYPE } from "botlib"; -import { UniversalBot } from "botbuilder"; + import { GBConversationalService } from "./GBConversationalService"; import { GuaribasPackage } from '../models/GBModel'; diff --git a/deploy/core.gbapp/services/GBMinService.ts b/deploy/core.gbapp/services/GBMinService.ts index 3fb96975..93ad656e 100644 --- a/deploy/core.gbapp/services/GBMinService.ts +++ b/deploy/core.gbapp/services/GBMinService.ts @@ -42,8 +42,9 @@ const WaitUntil = require("wait-until"); const Walk = require("fs-walk"); const express = require("express"); -import { UniversalBot } from "botbuilder"; -import { Session, MemoryBotStorage, Message } from "botbuilder"; +import { BotFrameworkAdapter, BotStateSet, ConversationState, MemoryStorage, UserState } from "botbuilder"; +import { LanguageTranslator, LocaleConverter } from "botbuilder-ai"; + import { GBCoreService } from "./GBCoreService"; import { GBConversationalService } from "./GBConversationalService"; import { GBConfigService } from "./GBConfigService"; @@ -70,8 +71,9 @@ export class GBMinService { deployFolder = "deploy"; corePackage = "core.gbai"; + /** - * Static iniatialization of minimal instance. + * Static initialization of minimal instance. * * @param core Basic database services to identify instance, for example. * @param cb Returns the loaded instance. @@ -164,17 +166,32 @@ export class GBMinService { }); }); + // Build bot adapter. + + let adapter = new BotFrameworkAdapter({ + appId: instance.marketplaceId, + appPassword: instance.marketplacePassword + }); + const storage = new MemoryStorage(); + const conversationState = new ConversationState(storage); + const userState = new UserState(storage); + adapter.use(new BotStateSet(conversationState, userState)); + // The minimal bot is built here. let min = new GBMinInstance(); min.botId = instance.botId; + min.bot = adapter; + min.userState = userState; min.core = _this_.core; min.conversationalService = _this_.conversationalService; + + _this_.core.loadInstance(min.botId, (data, err) => { min.instance = data; - // Call the loadBot event for all packages. + // Call the loadBot context.activity for all packages. appPackages.forEach(e => { e.sysPackages = new Array(); @@ -199,10 +216,6 @@ export class GBMinService { }); - let connector = new gBuilder.ChatConnector({ - appId: instance.marketplaceId, - appPassword: instance.marketplacePassword - }); // Serves individual URL for each bot conversational interface... @@ -210,7 +223,81 @@ export class GBMinService { logger.trace( `GeneralBots(${instance.engineName}) listening on: ${url}.` ); - server.post(url, connector.listen()); + server.post('/api/messages/', (req, res) => { + + adapter.processActivity(req, res, async (context) => { + + if (context.activity.type === 'message') { + // Create dialog context and continue executing the "current" dialog, if any. + const state = conversationState.get(context); + const dc = min.dialogs.createContext(context, state); + await dc.continue(); + + // Check to see if anyone replied. If not then start echo dialog + if (!context.responded) { + await dc.begin('echo'); + } + + // context.activity.type === "conversationUpdate" && + // context.activity.membersAdded.length > 0 + + // // if (context.activity.address.channelId != "directline") { + // // dc.begin("/"); + // // } + // // else { + // // next(); + // // } + + if (context.activity.name === "whoAmI") { + dc.begin("/whoAmI"); + } else if (context.activity.name === "showSubjects") { + dc.begin("/menu"); + } else if (context.activity.name === "giveFeedback") { + dc.begin("/feedback", { + fromMenu: true + }); + } else if (context.activity.name === "showFAQ") { + dc.begin("/faq"); + } else if (context.activity.name === "ask") { + dc.begin("/answer", { + // TODO: query: context.activity.data, + fromFaq: true + }); + } else if (context.activity.name === "quality") { + dc.begin("/quality", { + // TODO: score: context.activity.data + }); + } else { + await dc.continue(); + } + + const user = min.userState.get(dc.context); + if (!user.loaded) { + setTimeout( + () => { + min.conversationalService.sendEvent( + dc, + "loadInstance", + min.instance // TODO: Send a new thiner object. + ) + }, + 500 + ); + user.loaded = true; + user.subjects = []; + } + + appPackages.forEach(e => { + e.onNewSession(min, dc); + }); + + logger.trace( + `[RCV]: ChannelID: ${context.activity.channelId}, ConversationID: ${context.activity.conversation.id} + Type: ${context.activity.type}, Name: ${context.activity.name}, Text: ${context.activity.text}.` + ); + } + }); + }); // Serves individual URL for each bot user interface. @@ -221,102 +308,20 @@ export class GBMinService { ); logger.trace(`Bot UI ${uiPackage} acessible at: ${uiUrl}.`); - - // Prepares bot service. - - let inMemoryStorage = new MemoryBotStorage(); - - min.bot = new gBuilder.UniversalBot(connector, { - storage: inMemoryStorage - }); - - // Setups handlers. - - min.bot.use({ - - botbuilder: (session, next) => { - - if (!session.privateConversationData.loaded) { - setTimeout( - () => { - min.conversationalService.sendEvent( - session, - "loadInstance", - min.instance // TODO: Send a new thiner object. - ) - }, - 500 - ); - session.privateConversationData.loaded = true; - session.userData.subjects = []; - } - - appPackages.forEach(e => { - e.onNewSession(min, session); - }); - - next(); - }, - receive: function (event: any, next) { - logger.trace( - `[RCV]: ChannelID: ${event.address.channelId}, ConversationID: ${event.address.conversation.id} - Type: ${event.type}, Name: ${event.name}, Text: ${event.text}.` - ); - - // PACKAGE: Provide loop here. - - if ( - event.type === "conversationUpdate" && - event.membersAdded.length > 0 - // TODO: Is it really Necessary? !event.membersAdded[0].id.startsWith('general-bot-9672a8d3') //DEMO: min.botId) //TODO: Check entire collection. - ) { - - if (event.address.channelId != "directline") { - min.bot.beginDialog(event.address, "/"); - } - else { - next(); - } - } else if (event.name === "whoAmI") { - min.bot.beginDialog(event.address, "/whoAmI"); - } else if (event.name === "showSubjects") { - min.bot.beginDialog(event.address, "/menu"); - } else if (event.name === "giveFeedback") { - min.bot.beginDialog(event.address, "/feedback", { - fromMenu: true - }); - } else if (event.name === "showFAQ") { - min.bot.beginDialog(event.address, "/faq"); - } else if (event.name === "ask") { - min.bot.beginDialog(event.address, "/answer", { - query: event.data, - fromFaq: true - }); - } else if (event.name === "quality") { - min.bot.beginDialog(event.address, "/quality", { - score: event.data - }); - } else { - next(); - } - }, - send: function (event, next) { - logger.trace( - `[SND]: ChannelID: ${event.address.channelId}, ConversationID: ${event.address.conversation}, - Type: ${event.type} `); - this.core.createMessage( - this.min.conversation, - this.min.conversation.startedBy, - event.source, - (data, err) => { - logger.trace(event.source); - } - ); - next(); - } - }); - + // send: function (context.activity, next) { + // logger.trace( + // `[SND]: ChannelID: ${context.activity.address.channelId}, ConversationID: ${context.activity.address.conversation}, + // Type: ${context.activity.type} `); + // this.core.createMessage( + // this.min.conversation, + // this.min.conversation.startedBy, + // context.activity.source, + // (data, err) => { + // logger.trace(context.activity.source); + // } + // ); + // next(); // Specialized load for each min instance. diff --git a/deploy/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts b/deploy/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts index c08942a8..e2c86b33 100644 --- a/deploy/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts +++ b/deploy/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts @@ -32,69 +32,69 @@ "use strict"; -import { UniversalBot, Session, Prompts, ListStyle } from "botbuilder"; + import { CSService } from '../services/CSService'; import { AzureText } from "pragmatismo-io-framework"; import { GBMinInstance } from "botlib"; -import { IGBDialog } from "botlib"; +import { IGBDialog } from "botlib"; +import { BotAdapter } from 'botbuilder'; export class FeedbackDialog extends IGBDialog { - static setup(bot: UniversalBot, min: GBMinInstance) { - + static setup(bot: BotAdapter, min: GBMinInstance) { + const service = new CSService(); - bot.dialog("/feedbackNumber", [ - function(session, args) { - session.sendTyping(); - let msgs = [ + min.dialogs.add("/feedbackNumber", [ + async (dc, args) => { + + let messages = [ "O que achou do meu atendimento, de 1 a 5?", "Qual a nota do meu atendimento?", "Como define meu atendimento numa escala de 1 a 5?" ]; - Prompts.choice(session, msgs, "1|2|3|4|5", { - listStyle: ListStyle.button - }); + await dc.prompt('choicePrompt', messages[0], ['1', '2', '3', '4', ' 5']); }, - function(session, results) { - let rate = results.response.entity; - service.updateConversationRate(session.userData.conversation, rate, item => { - let msgs = ["Obrigado!", "Obrigado por responder."]; - session.send(msgs); + async (dc, value) => { + let rate = value.entity; + const user = min.userState.get(dc.context); + service.updateConversationRate(user.conversation, rate, item => { + let messages = ["Obrigado!", "Obrigado por responder."]; + dc.context.sendActivity(messages[0]); // TODO: Handle rnd. }); } ]); - bot.dialog("/feedback", [ - function(session, args) { + min.dialogs.add("/feedback", [ + async (dc, args) => { if (args && args.fromMenu) { - let msgs = [ + let messages = [ "Sugestões melhoram muito minha qualidade...", "Obrigado pela sua iniciativa de sugestão." ]; - session.send(msgs); + dc.context.sendActivity(messages[0]); // TODO: Handle rnd. } - session.sendTyping(); - let msgs = [ + + let messages = [ "O que achou do meu atendimento?", "Como foi meu atendimento?", "Gostaria de dizer algo sobre meu atendimento?" ]; - Prompts.text(session, msgs); + await dc.prompt('textPrompt', messages[0]); }, - function(session, results) { + async (dc, value) => { AzureText.getSentiment( min.instance.textAnalyticsKey, - results.response, + value, (err, rate) => { if (!err && rate > 0) { - session.send("Bom saber que você gostou. Conte comigo."); + dc.context.sendActivity("Bom saber que você gostou. Conte comigo."); } else { - session.send( + dc.context.sendActivity( "Vamos registrar sua questão, obrigado pela sinceridade." ); } - session.replaceDialog('/ask', {isReturning: true}); + dc.replace('/ask', { isReturning: true }); } ); } diff --git a/deploy/customer-satisfaction.gbapp/dialogs/QualityDialog.ts b/deploy/customer-satisfaction.gbapp/dialogs/QualityDialog.ts index 14e1e13d..cee6e1dc 100644 --- a/deploy/customer-satisfaction.gbapp/dialogs/QualityDialog.ts +++ b/deploy/customer-satisfaction.gbapp/dialogs/QualityDialog.ts @@ -33,23 +33,25 @@ "use strict"; import { IGBDialog } from "botlib"; -import { UniversalBot, Session, Prompts, ListStyle } from "botbuilder"; + import { GBMinInstance } from "botlib"; import { CSService } from "../services/CSService"; +import { BotAdapter } from "botbuilder"; const logger = require("../../../src/logger"); export class QualityDialog extends IGBDialog { - static setup(bot: UniversalBot, min: GBMinInstance) { + static setup(bot: BotAdapter, min: GBMinInstance) { const service = new CSService(); - bot.dialog("/quality", [ - (session, args) => { + min.dialogs.add("/quality", [ + async (dc, args) => { + const user = min.userState.get(dc.context); var score = args.score; setTimeout( - () => min.conversationalService.sendEvent(session, "stop", null), + () => min.conversationalService.sendEvent(dc, "stop", null), 400 ); @@ -59,25 +61,25 @@ export class QualityDialog extends IGBDialog { "Lamento... Vamos tentar novamente!", "Desculpe-me. Por favor, tente escrever de outra forma?" ]; - session.send(msg); + dc.context.sendActivity(msg[0]); } else { let msg = [ "Ótimo, obrigado por contribuir com sua resposta.", "Certo, obrigado pela informação.", "Obrigado pela contribuição." ]; - session.send(msg); + dc.context.sendActivity(msg[0]); service.insertQuestionAlternate( min.instance.instanceId, - session.userData.lastQuestion, - session.userData.lastQuestionId, + user.lastQuestion, + user.lastQuestionId, (data, err) => { logger.trace("QuestionAlternate inserted."); } ); - session.replaceDialog('/ask', {isReturning: true}); + dc.replace('/ask', {isReturning: true}); } } ]); diff --git a/deploy/customer-satisfaction.gbapp/index.ts b/deploy/customer-satisfaction.gbapp/index.ts index 3981ca5d..7e28941a 100644 --- a/deploy/customer-satisfaction.gbapp/index.ts +++ b/deploy/customer-satisfaction.gbapp/index.ts @@ -37,7 +37,7 @@ import { GuaribasQuestionAlternate } from './models/index'; import { QualityDialog } from './dialogs/QualityDialog'; import { FeedbackDialog } from './dialogs/FeedbackDialog'; import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"; -import { Session } from 'botbuilder'; + import { Sequelize } from 'sequelize-typescript'; export class GBCustomerSatisfactionPackage implements IGBPackage { @@ -57,7 +57,7 @@ export class GBCustomerSatisfactionPackage implements IGBPackage { unloadBot(min: GBMinInstance): void { } - onNewSession(min: GBMinInstance, session: Session): void { + onNewSession(min: GBMinInstance, dc: any): void { } } diff --git a/deploy/default.gbui/src/GBUIApp.js b/deploy/default.gbui/src/GBUIApp.js index f8d7186b..b12c5264 100644 --- a/deploy/default.gbui/src/GBUIApp.js +++ b/deploy/default.gbui/src/GBUIApp.js @@ -43,8 +43,6 @@ import { SpeechRecognizer } from "botframework-webchat/CognitiveServices"; import { SpeechSynthesizer } from "botframework-webchat/CognitiveServices"; import { SynthesisGender } from "botframework-webchat/CognitiveServices"; import { Chat } from "botframework-webchat"; -import { BotChat } from "botframework-webchat"; -import { Speech } from "botframework-webchat/botchat"; import GBPowerBIPlayer from "./players/GBPowerBIPlayer.js"; class GBUIApp extends React.Component { diff --git a/deploy/kb.gbapp/dialogs/AskDialog.ts b/deploy/kb.gbapp/dialogs/AskDialog.ts index 4b408ea6..8a6d3e6c 100644 --- a/deploy/kb.gbapp/dialogs/AskDialog.ts +++ b/deploy/kb.gbapp/dialogs/AskDialog.ts @@ -32,38 +32,39 @@ "use strict"; -import { Prompts, UniversalBot, Session, ListStyle } from "botbuilder"; import { IGBDialog } from "botlib"; import { AzureText } from "pragmatismo-io-framework"; import { GBMinInstance } from "botlib"; import { KBService } from './../services/KBService'; +import { BotAdapter } from "botbuilder"; const logger = require("../../../src/logger"); export class AskDialog extends IGBDialog { - static setup(bot: UniversalBot, min: GBMinInstance) { + static setup(bot: BotAdapter, min: GBMinInstance) { const service = new KBService(); - bot.dialog("/answer", [ - (session, args) => { - + min.dialogs.add("/answer", [ + async (dc, args) => { + const user = min.userState.get(dc.context); + let text = ""; if (args && args.query) { text = args.query; } else if (args && args.fromFaq) { - let msgs = [ + let messages = [ `Ótima escolha, procurando resposta para sua questão...`, `Pesquisando sobre o termo...`, `Aguarde, por favor, enquanto acho sua resposta...` ]; - session.sendTyping(); - session.send(msgs); + + dc.context.sendActivity(messages[0]); // TODO: Handle rnd. } if (text === "") { - session.replaceDialog("/ask"); + dc.replace("/ask"); } else { AzureText.getSpelledText( min.instance.spellcheckerKey, @@ -73,25 +74,25 @@ export class AskDialog extends IGBDialog { logger.trace("Spelled Text: " + data); text = data; } - session.userData.lastQuestion = data; + user.lastQuestion = data; service.ask( min.instance, text, min.instance.searchScore, - session.userData.subjects, + user.subjects, resultsA => { - min.conversationalService.sendEvent(session, "stop", null); + min.conversationalService.sendEvent(dc, "stop", null); if (resultsA && resultsA.answer) { - session.userData.isAsking = false; + user.isAsking = false; service.sendAnswer(min.conversationalService, - session, + dc, resultsA.answer ); - session.userData.lastQuestionId = resultsA.questionId; + user.lastQuestionId = resultsA.questionId; - session.replaceDialog("/ask", { isReturning: true }); + dc.replace("/ask", { isReturning: true }); } else { //if (min.isAsking) { // Second time with no filter. @@ -103,47 +104,49 @@ export class AskDialog extends IGBDialog { null, resultsB => { if (resultsB && resultsB.answer) { - session.userData.isAsking = false; + const user = min.userState.get(dc.context); - if (session.userData.subjects.length > 0) { + user.isAsking = false; + + if (user.subjects.length > 0) { let subjectText = `${KBService.getSubjectItemsSeparatedBySpaces( - session.userData.subjects + user.subjects )}`; - let msgs = [ + let messages = [ `Respondendo nao apenas sobre ${subjectText}... `, `Respondendo de modo mais abrangente...`, `Vou te responder de modo mais abrangente... Não apenas sobre ${subjectText}` ]; - session.send(msgs); + dc.context.sendActivity(messages[0]); // TODO: Handle rnd. } - session.userData.isAsking = false; + user.isAsking = false; service.sendAnswer(min.conversationalService, - session, + dc, resultsB.answer ); - session.replaceDialog("/ask", { isReturning: true }); + dc.replace("/ask", { isReturning: true }); - session.userData.lastQuestionId = resultsB.questionId; + user.lastQuestionId = resultsB.questionId; } else { min.conversationalService.runNLP( - session, + dc, min, text, (data, error) => { if (!data) { - let msgs = [ + let messages = [ "Desculpe-me, não encontrei nada a respeito.", "Lamento... Não encontrei nada sobre isso. Vamos tentar novamente?", "Desculpe-me, não achei nada parecido. Poderia tentar escrever de outra forma?" ]; - session.send(msgs); - session.replaceDialog("/ask", { isReturning: true }); + dc.context.sendActivity(messages[0]); // TODO: Handle rnd. + dc.replace("/ask", { isReturning: true }); } } ); @@ -160,36 +163,34 @@ export class AskDialog extends IGBDialog { ]); bot - .dialog("/ask", [ - (session, args) => { - session.userData.isAsking = true; - let text = []; - if (session.userData.subjects.length > 0) { - text = [ - `Faça sua pergunta...`, - `Pode perguntar sobre o assunto em questão... `, - `Qual a pergunta?` - ]; - } - - if (args && args.isReturning) { - text = [ - "Sobre o que mais posso ajudar?", - "Então, posso ajudar em algo a mais?", - "Deseja fazer outra pergunta?" - ]; - } - if (text.length > 0) { - Prompts.text(session, text); - } - }, - (session, results) => { - session.replaceDialog("/answer", { query: results.response }); + min.dialogs.add("/ask", [ + async (dc, args) => { + const user = min.userState.get(dc.context); + user.isAsking = true; + let text = []; + if (user.subjects.length > 0) { + text = [ + `Faça sua pergunta...`, + `Pode perguntar sobre o assunto em questão... `, + `Qual a pergunta?` + ]; } - ]) - .triggerAction({ - matches: /^(bing|google)/i - }); - bot.beginDialogAction("ask", "/ask"); + + if (args && args.isReturning) { + text = [ + "Sobre o que mais posso ajudar?", + "Então, posso ajudar em algo a mais?", + "Deseja fazer outra pergunta?" + ]; + } + if (text.length > 0) { + await dc.prompt('textPrompt', text[0]); + } + }, + async (dc, value) => { + dc.endAll(); + dc.begin("/answer", { query: value }); + } + ]); } } diff --git a/deploy/kb.gbapp/dialogs/FaqDialog.ts b/deploy/kb.gbapp/dialogs/FaqDialog.ts index 983bd81b..370ee333 100644 --- a/deploy/kb.gbapp/dialogs/FaqDialog.ts +++ b/deploy/kb.gbapp/dialogs/FaqDialog.ts @@ -34,38 +34,35 @@ import { KBService } from './../services/KBService'; import { IGBDialog } from "botlib"; -import { Prompts, UniversalBot, Session, ListStyle } from "botbuilder"; +import { BotAdapter } from "botbuilder"; import { GBMinInstance } from "botlib"; export class FaqDialog extends IGBDialog { - static setup(bot: UniversalBot, min: GBMinInstance) { + static setup(bot: BotAdapter, min: GBMinInstance) { const service = new KBService(); - bot - .dialog("/faq", [ - (session, args) => { - service.getFaqBySubjectArray("faq", null, (data, err) => { - if (data) { - min.conversationalService.sendEvent(session, "play", { - playerType: "bullet", - data: data.slice(0, 10) - }); + min.dialogs.add("/faq", [ + async (dc, args) => { + service.getFaqBySubjectArray("faq", null, (data, err) => { + if (data) { + min.conversationalService.sendEvent(dc, "play", { + playerType: "bullet", + data: data.slice(0, 10) + }); - let msgs = [ - "Veja algumas perguntas mais frequentes logo na tela. Clique numa delas para eu responder.", - "Você pode clicar em alguma destas perguntas da tela que eu te respondo de imediato.", - "Veja a lista que eu preparei logo aí na tela..." - ]; + let messages = [ + "Veja algumas perguntas mais frequentes logo na tela. Clique numa delas para eu responder.", + "Você pode clicar em alguma destas perguntas da tela que eu te respondo de imediato.", + "Veja a lista que eu preparei logo aí na tela..." + ]; + + dc.context.sendActivity(messages[0]); // TODO: RND messages. + dc.endAll(); + } + }); + } + ]); - session.endDialog(msgs); - } - }); - } - ]) - .triggerAction({ - matches: /^(faq|perguntas frequentes)/i - }); - bot.beginDialogAction("faq", "/faq"); } } diff --git a/deploy/kb.gbapp/dialogs/MenuDialog.ts b/deploy/kb.gbapp/dialogs/MenuDialog.ts index 556a3d94..d79f95c6 100644 --- a/deploy/kb.gbapp/dialogs/MenuDialog.ts +++ b/deploy/kb.gbapp/dialogs/MenuDialog.ts @@ -29,20 +29,19 @@ | our trademarks remain entirely with us. | | | \*****************************************************************************/ - - "use strict"; - + +"use strict"; + import { Length } from "sequelize-typescript"; import { - UniversalBot, - Session, - Message, - AttachmentLayout, CardAction, HeroCard, - CardImage + CardImage, + BotAdapter, + CardFactory, + MessageFactory } from "botbuilder"; -import { IGBDialog } from "botlib"; +import { IGBDialog } from "botlib"; import { GBMinInstance } from "botlib"; import { AzureText } from "pragmatismo-io-framework"; import { GuaribasSubject } from '../models'; @@ -53,135 +52,136 @@ const WaitUntil = require("wait-until"); export class MenuDialog extends IGBDialog { - static setup(bot: UniversalBot, min: GBMinInstance) { + static setup(bot: BotAdapter, min: GBMinInstance) { var service = new KBService(); bot - .dialog("/menu", [ - (session, args) => { - var rootSubjectId = null; - var botId = min.botId; + min.dialogs.add("/menu", [ + async (dc, args) => { + var rootSubjectId = null; + var botId = min.botId; - var msg = session.message; - if (msg.attachments && msg.attachments.length > 0) { - var attachment = msg.attachments[0]; + // var msg = dc.message; TODO: message from Where in V4? + // if (msg.attachments && msg.attachments.length > 0) { + // var attachment = msg.attachments[0]; + // } + + + if (args && args.data) { + var subject = JSON.parse(args.data); // ? + + if (subject.to) { + let dialog = subject.to.split(":")[1]; + dc.replace("/" + dialog); + dc.end(); + return; } + const user = min.userState.get(dc.context); + user.subjects.push(subject); + rootSubjectId = subject.subjectId; - if (args && args.data) { - var subject = JSON.parse(args.data); // ? + if (user.subjects.length > 0) { - if (subject.to) { - let dialog = subject.to.split(":")[1]; - session.replaceDialog("/" + dialog); - session.endDialog(); - return; - } - - session.userData.subjects.push(subject); - rootSubjectId = subject.subjectId; - - if (session.userData.subjects.length > 0) { - - service.getFaqBySubjectArray( - "menu", - session.userData.subjects, - (data, err) => { - min.conversationalService.sendEvent(session, "play", { - playerType: "bullet", - data: data.slice(0, 6) - }); - } - ); - } - } else { - session.userData.subjects = []; - session.sendTyping(); - WaitUntil() - .interval(2000) - .times(1) - .condition(function(cb) { - return false; - }) - .done(function(result) { - let msgs = [ - "Aqui estão algumas categorias de assuntos...", - "Selecionando o assunto você pode me ajudar a encontrar a resposta certa...", - "Você pode selecionar algum dos assuntos abaixo e perguntar algo..." - ]; - session.send(msgs); - }); - - session.userData.isAsking = false; - } - - service.getSubjectItems( - min.instance.instanceId, - rootSubjectId, - data => { - var msg = new Message(session); - msg.attachmentLayout(AttachmentLayout.carousel); - var attachments = []; - - data.forEach(function(item: GuaribasSubject) { - var subject = item; - var button = CardAction.dialogAction( - session, - "menuAction", - JSON.stringify({ - title: subject.title, - subjectId: subject.subjectId, - to: subject.to - }), - "Selecionar" - ); - var card = new HeroCard(session) - .title(subject.title) - .text(subject.description) - .images([ - CardImage.create( - session, - UrlJoin( - "/kb", - min.instance.kb, - "subjects", - subject.internalId + ".png" // TODO: or fallback to subject.png - ) - ) - ]) // Using public dir of ui. - .buttons([button]); - attachments.push(card); - }); - - if (attachments.length == 0) { - if (session.userData.subjects && session.userData.subjects.length > 0) { - session.send( - `Vamos pesquisar sobre ${KBService.getFormattedSubjectItems( - session.userData.subjects - )}?` - ); - } - - session.replaceDialog("/ask", {}); - } else { - msg.attachments(attachments); - session.send(msg); + service.getFaqBySubjectArray( + "menu", + user.subjects, + (data, err) => { + min.conversationalService.sendEvent(dc, "play", { + playerType: "bullet", + data: data.slice(0, 6) + }); } - } - ); - - session.userData.isAsking = true; - }, - function(session, results) { - var text = results.response; - if (AzureText.isIntentNo(text)) { - session.replaceDialog("/feedback"); - } else { - session.replaceDialog("/ask"); + ); } - } - ]); + } else { + const user = min.userState.get(dc.context); + user.subjects = []; - bot.beginDialogAction("menuAction", "/menu"); + WaitUntil() + .interval(2000) + .times(1) + .condition(function (cb) { + return false; + }) + .done(function (result) { + let messages = [ + "Aqui estão algumas categorias de assuntos...", + "Selecionando o assunto você pode me ajudar a encontrar a resposta certa...", + "Você pode selecionar algum dos assuntos abaixo e perguntar algo..." + ]; + dc.context.sendActivity(messages[0]); // TODO: Handle rnd. + }); + + user.isAsking = false; + } + + const msg = MessageFactory.text('Greetings from example message'); + var attachments = []; + + service.getSubjectItems( + min.instance.instanceId, + rootSubjectId, + data => { + + msg.attachmentLayout='carousel'; + + + data.forEach(function (item: GuaribasSubject) { + + var subject = item; + + var card = CardFactory.heroCard( + subject.title, + CardFactory.images([UrlJoin( + "/kb", + min.instance.kb, + "subjects", + subject.internalId + ".png" // TODO: or fallback to subject.png + )]), + CardFactory.actions([ + { + type: 'postBack', + title: 'Selecionar', + value: JSON.stringify({ + title: subject.title, + subjectId: subject.subjectId, + to: subject.to + }) + }])); + + attachments.push(card); + + }); + + if (attachments.length == 0) { + const user = min.userState.get(dc.context); + if (user.subjects && user.subjects.length > 0) { + dc.context.sendActivity( + `Vamos pesquisar sobre ${KBService.getFormattedSubjectItems( + user.subjects + )}?` + ); + } + + dc.replace("/ask", {}); + } else { + msg.attachments = attachments; + dc.context.sendActivity(msg); + } + } + ); + const user = min.userState.get(dc.context); + user.isAsking = true; + }, + async (dc, value) => { + var text = value; + if (AzureText.isIntentNo(text)) { + dc.replace("/feedback"); + } else { + dc.replace("/ask"); + } + } + ]); } } diff --git a/deploy/kb.gbapp/index.ts b/deploy/kb.gbapp/index.ts index 39fe4311..35884d57 100644 --- a/deploy/kb.gbapp/index.ts +++ b/deploy/kb.gbapp/index.ts @@ -36,7 +36,7 @@ const UrlJoin = require("url-join"); import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from './models/index'; import { GBMinInstance, IGBPackage } from "botlib"; -import { Session } from 'botbuilder'; + import { AskDialog } from "./dialogs/AskDialog"; import { FaqDialog } from "./dialogs/FaqDialog"; import { MenuDialog } from "./dialogs/MenuDialog"; @@ -68,7 +68,7 @@ export class GBKBPackage implements IGBPackage { unloadBot(min: GBMinInstance): void { } - onNewSession(min: GBMinInstance, session: Session): void { + onNewSession(min: GBMinInstance, dc: any): void { } } diff --git a/deploy/kb.gbapp/services/KBService.ts b/deploy/kb.gbapp/services/KBService.ts index a54eb041..4b98f4ae 100644 --- a/deploy/kb.gbapp/services/KBService.ts +++ b/deploy/kb.gbapp/services/KBService.ts @@ -39,11 +39,6 @@ const UrlJoin = require("url-join"); const Walk = require("fs-walk"); const WaitUntil = require("wait-until"); const marked = require("marked"); - - - - - import { Sequelize } from "sequelize-typescript"; import { GBConfigService } from './../../core.gbapp/services/GBConfigService'; import { GuaribasQuestion, GuaribasAnswer, GuaribasSubject } from "../models"; @@ -52,7 +47,7 @@ import { AzureSearch } from "pragmatismo-io-framework"; import { GBCoreService } from 'deploy/core.gbapp/services/GBCoreService'; import { GBDeployer } from "../../core.gbapp/services/GBDeployer"; import { GBConversationalService } from "../../core.gbapp/services/GBConversationalService"; -import { Session } from "botbuilder"; + import { GuaribasPackage } from "../../core.gbapp/models/GBModel"; export class KBService { @@ -449,20 +444,20 @@ export class KBService { }).pipe(parser); } - sendAnswer(conversationalService: IGBConversationalService, session: Session, answer: GuaribasAnswer) { + sendAnswer(conversationalService: IGBConversationalService, dc: any, answer: GuaribasAnswer) { if (answer.content.endsWith('.mp4')) { - conversationalService.sendEvent(session, "play", { + conversationalService.sendEvent(dc, "play", { playerType: "video", data: answer.content }); - } else if (answer.content.length > 140 && session.message.source != "directline") { - let msgs = [ + } else if (answer.content.length > 140 && dc.message.source != "directline") { + let messages = [ "Vou te responder na tela para melhor visualização...", "A resposta está na tela...", "Veja a resposta na tela..." ]; - session.send(msgs); + dc.context.sendActivity(messages[0]); // TODO: Handle rnd. var html = answer.content; if (answer.format === ".md") { marked.setOptions({ @@ -478,10 +473,10 @@ export class KBService { }); html = marked(answer.content); } - conversationalService.sendEvent(session, "play", { playerType: "markdown", data: html }); + conversationalService.sendEvent(dc, "play", { playerType: "markdown", data: html }); } else { - session.send(answer.content); - conversationalService.sendEvent(session, "stop", null); + dc.context.sendActivity(answer.content); + conversationalService.sendEvent(dc, "stop", null); } } diff --git a/deploy/security.gblib/index.ts b/deploy/security.gblib/index.ts index 78b071b9..b5c53a65 100644 --- a/deploy/security.gblib/index.ts +++ b/deploy/security.gblib/index.ts @@ -36,7 +36,7 @@ const UrlJoin = require("url-join"); import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"; -import { Session } from 'botbuilder'; + import { Sequelize } from "sequelize-typescript"; import { GuaribasUser, GuaribasGroup, GuaribasUserGroup } from "./models"; @@ -61,7 +61,7 @@ export class GBSecurityPackage implements IGBPackage { unloadBot(min: GBMinInstance): void { } - onNewSession(min: GBMinInstance, session: Session): void { + onNewSession(min: GBMinInstance, dc: any): void { } } diff --git a/deploy/whatsapp.gblib/index.ts b/deploy/whatsapp.gblib/index.ts index 47d8ea94..cb033669 100644 --- a/deploy/whatsapp.gblib/index.ts +++ b/deploy/whatsapp.gblib/index.ts @@ -36,7 +36,7 @@ const UrlJoin = require("url-join"); import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"; -import { Session } from 'botbuilder'; + import { Sequelize } from "sequelize-typescript"; import { WhatsappDirectLine } from "./services/WhatsappDirectLine"; @@ -66,7 +66,7 @@ export class GBWhatsappPackage implements IGBPackage { unloadBot(min: GBMinInstance): void { } - onNewSession(min: GBMinInstance, session: Session): void { + onNewSession(min: GBMinInstance, dc: any): void { } } diff --git a/package.json b/package.json index a98cf89e..6157e3c3 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,12 @@ "dependencies": { "async": "^2.6.1", "body-parser": "^1.18.3", - "botbuilder": "^3.15.0", + "botbuilder": "^4.0.0-preview1.2", + "botbuilder-ai": "^4.0.0-preview1.2", + "botbuilder-azure": "^4.0.0-preview1.2", + "botbuilder-choices": "^4.0.0-preview1.2", + "botbuilder-dialogs": "^4.0.0-preview1.2", + "botbuilder-prompts": "^4.0.0-preview1.2", "botlib": "^0.0.28", "chokidar": "^2.0.3", "csv-parse": "^2.4.0", diff --git a/src/app.ts b/src/app.ts index 65be40f8..f6799b42 100644 --- a/src/app.ts +++ b/src/app.ts @@ -37,7 +37,7 @@ const UrlJoin = require("url-join"); const logger = require("./logger"); const express = require("express"); const bodyParser = require("body-parser"); -import { UniversalBot } from "botbuilder"; + import { Sequelize } from "sequelize-typescript"; import { GBConfigService } from "../deploy/core.gbapp/services/GBConfigService"; import { GBConversationalService } from "../deploy/core.gbapp/services/GBConversationalService";