diff --git a/deploy/admin.gbapp/dialogs/AdminDialog.ts b/deploy/admin.gbapp/dialogs/AdminDialog.ts index 8549c9690..00573f5c1 100644 --- a/deploy/admin.gbapp/dialogs/AdminDialog.ts +++ b/deploy/admin.gbapp/dialogs/AdminDialog.ts @@ -107,7 +107,7 @@ export class AdminDialog extends IGBDialog { let importer = new GBImporter(min.core); let deployer = new GBDeployer(min.core, importer); - min.dialogs.add("/admin", [ + min.dialogs.add("/adminRat", [ async dc => { await AdminDialog.refreshAdminToken(min, dc); // await dc.context.sendActivity( @@ -137,7 +137,7 @@ export class AdminDialog extends IGBDialog { } ]); - min.dialogs.add("/admin1", [ + min.dialogs.add("/admin", [ async (dc, args) => { const prompt = "Please, authenticate:"; await dc.prompt("textPrompt", prompt); diff --git a/deploy/core.gbapp/services/GBMinService.ts b/deploy/core.gbapp/services/GBMinService.ts index 81e7fd8f7..6a6822a19 100644 --- a/deploy/core.gbapp/services/GBMinService.ts +++ b/deploy/core.gbapp/services/GBMinService.ts @@ -291,9 +291,9 @@ export class GBMinService { } logger.info( - `[RCV]: ${context.activity.type}, ChannelID: ${ + `[User]: ${context.activity.type}, ChannelID: ${ context.activity.channelId - }, Name: ${context.activity.name}, Text: ${context.activity.text}.` + } Text: ${context.activity.text}.` ) if ( context.activity.type === "conversationUpdate" && @@ -358,9 +358,9 @@ export class GBMinService { }) } else if (context.activity.name === "showFAQ") { await dc.begin("/faq") - } else if (context.activity.name === "ask") { - await dc.begin("/answer", { - query: (context.activity as any).data, + } else if (context.activity.name === "answerEvent") { + await dc.begin("/answerEvent", { + questionId: (context.activity as any).data, fromFaq: true }) @@ -374,7 +374,7 @@ export class GBMinService { } } } catch (error) { - let msg = `Error in main activity: ${error.message}` + let msg = `Error in main activity: ${error.message} ${error.stack? error.stack:""}` logger.error(msg) } }) diff --git a/deploy/default.gbui/src/GBUIApp.js b/deploy/default.gbui/src/GBUIApp.js index 4787ee095..ce94b96da 100644 --- a/deploy/default.gbui/src/GBUIApp.js +++ b/deploy/default.gbui/src/GBUIApp.js @@ -57,9 +57,11 @@ class GBUIApp extends React.Component { token: null, instanceClient: null }; + window.user = this.getUser() } sendToken(token) { + setTimeout(() => { window.botConnection .postActivity({ @@ -69,7 +71,7 @@ class GBUIApp extends React.Component { locale: "en-us", textFormat: "plain", timestamp: new Date().toISOString(), - from: { id: "webUser", name: "You" } + from: this.getUser() }) .subscribe(() => { window.userAgentApplication.logout(); @@ -86,10 +88,11 @@ class GBUIApp extends React.Component { locale: "en-us", textFormat: "plain", timestamp: new Date().toISOString(), - from: { id: "webUser", name: "You" } + from: this.getUser() }) .subscribe(console.log("EVENT SENT TO Guaribas.")); } + getUser() { return { id: "webUser@gb", name: "You" }; } diff --git a/deploy/default.gbui/src/components/SidebarMenu.js b/deploy/default.gbui/src/components/SidebarMenu.js index 42dfd8985..fda919d27 100644 --- a/deploy/default.gbui/src/components/SidebarMenu.js +++ b/deploy/default.gbui/src/components/SidebarMenu.js @@ -41,7 +41,7 @@ class SideBarMenu extends React.Component { locale: "en-us", textFormat: "plain", timestamp: new Date().toISOString(), - from: { id: "webUser", name: "You" } + from: window.user }) .subscribe(console.log("success")); } diff --git a/deploy/default.gbui/src/players/GBBulletPlayer.js b/deploy/default.gbui/src/players/GBBulletPlayer.js index 2e4fd1189..46cabc347 100644 --- a/deploy/default.gbui/src/players/GBBulletPlayer.js +++ b/deploy/default.gbui/src/players/GBBulletPlayer.js @@ -39,12 +39,12 @@ class RenderItem extends Component { window.botConnection .postActivity({ type: "event", - name: "ask", - data: item.content, + name: "answerEvent", + data: item.questionId, locale: "en-us", textFormat: "plain", timestamp: new Date().toISOString(), - from: { id: "webUser", name: "You" } + from: window.user }) .subscribe(console.log("success")); },400); diff --git a/deploy/default.gbui/src/players/GBMarkdownPlayer.js b/deploy/default.gbui/src/players/GBMarkdownPlayer.js index 556440adf..40d4d8137 100644 --- a/deploy/default.gbui/src/players/GBMarkdownPlayer.js +++ b/deploy/default.gbui/src/players/GBMarkdownPlayer.js @@ -33,6 +33,7 @@ import React, { Component } from "react"; class GBMarkdownPlayer extends Component { + send(value) { setTimeout(() => { window.botConnection @@ -49,15 +50,35 @@ class GBMarkdownPlayer extends Component { }, 400); } + sendAnswer(text) { + setTimeout(() => { + window.botConnection + .postActivity({ + type: "event", + name: "answerEvent", + data: text, + locale: "en-us", + textFormat: "plain", + timestamp: new Date().toISOString(), + from: window.user + }) + .subscribe(console.log("success")); + }, 400); + + } + + constructor() { super(); this.state = { - content: "" + content: "", + prevId: 0, + nextId: 0 }; } play(data) { - this.setState({ content: data }); + this.setState({ content: data.content, prevId: data.prevId, nextId: data.nextId }); } stop() { @@ -78,7 +99,7 @@ class GBMarkdownPlayer extends Component { render() { - var quality = + var quality =
(this.quality = i)}>Is the answer OK?    @@ -91,18 +112,34 @@ class GBMarkdownPlayer extends Component {
; - if (this.state.content === "") { - quality = ""; - } + var next = "", prev = ""; + + if (this.state.content === "") { + quality = ""; + } + + if (this.state.prevId) { + prev = this.sendAnswer(this.state.prevId)}> + Back + + } + if (this.state.nextId) { + next = this.sendAnswer(this.state.nextId)}> + Next + + } return (
(this.playerText = i)} className="media-player">
+
{prev}      {next}
-
- {quality} +
+ {quality} ); } diff --git a/deploy/kb.gbapp/dialogs/AskDialog.ts b/deploy/kb.gbapp/dialogs/AskDialog.ts index 38751e1fd..9777d845f 100644 --- a/deploy/kb.gbapp/dialogs/AskDialog.ts +++ b/deploy/kb.gbapp/dialogs/AskDialog.ts @@ -39,6 +39,7 @@ import { KBService } from "./../services/KBService"; import { BotAdapter } from "botbuilder"; import { Messages } from "../strings"; import { LuisRecognizer } from "botbuilder-ai"; +import { GuaribasQuestion } from "../models"; const logger = require("../../../src/logger"); @@ -58,6 +59,24 @@ export class AskDialog extends IGBDialog { serviceEndpoint: min.instance.nlpServerUrl }); + min.dialogs.add("/answerEvent", [ + async (dc, args) => { + + if (args && args.questionId) { + + let question = await service.getQuestionById(min.instance.instanceId, args.questionId); + let answer = await service.getAnswerById(min.instance.instanceId, question.answerId) + + // Sends the answer to all outputs, including projector. + + await service.sendAnswer( + min.conversationalService, + dc, + answer + ); + } + }]) + min.dialogs.add("/answer", [ async (dc, args) => { // Initialize values. diff --git a/deploy/kb.gbapp/dialogs/MenuDialog.ts b/deploy/kb.gbapp/dialogs/MenuDialog.ts index d978c9957..13b81b5a5 100644 --- a/deploy/kb.gbapp/dialogs/MenuDialog.ts +++ b/deploy/kb.gbapp/dialogs/MenuDialog.ts @@ -84,7 +84,7 @@ export class MenuDialog extends IGBDialog { ) await min.conversationalService.sendEvent(dc, "play", { playerType: "bullet", - data: data.slice(0, 6) + data: data.slice(0, 10) }) } } else { @@ -109,12 +109,13 @@ export class MenuDialog extends IGBDialog { var subject = item var card = CardFactory.heroCard( subject.title, + subject.description, CardFactory.images([ UrlJoin( "/kb", min.instance.kb, "subjects", - subject.internalId + ".png" // TODO: or fallback to subject.png + "subject.png" ) ]), CardFactory.actions([ @@ -123,7 +124,9 @@ export class MenuDialog extends IGBDialog { title: Messages[locale].menu_select, value: JSON.stringify({ title: subject.title, + description: subject.description, subjectId: subject.subjectId, + internalId: subject.internalId, to: subject.to }) } diff --git a/deploy/kb.gbapp/models/index.ts b/deploy/kb.gbapp/models/index.ts index f730e8aeb..b69bea388 100644 --- a/deploy/kb.gbapp/models/index.ts +++ b/deploy/kb.gbapp/models/index.ts @@ -54,7 +54,8 @@ import { DataType, IsUUID, PrimaryKey, - AutoIncrement + AutoIncrement, + HasOne } from "sequelize-typescript" import { GuaribasUser } from "../../security.gblib/models" @@ -71,6 +72,7 @@ export class GuaribasSubject extends Model { @Column title: string + @Column(DataType.STRING(512)) @Column description: string @Column from: string @@ -201,6 +203,20 @@ export class GuaribasAnswer extends Model { @HasMany(() => GuaribasQuestion) questions: GuaribasQuestion[] + @HasOne(() => GuaribasQuestion) + prev: GuaribasQuestion + + @HasOne(() => GuaribasQuestion) + next: GuaribasQuestion + + @ForeignKey(() => GuaribasQuestion) + @Column + nextId: number + + @ForeignKey(() => GuaribasQuestion) + @Column + prevId: number + @ForeignKey(() => GuaribasInstance) @Column instanceId: number diff --git a/deploy/kb.gbapp/services/KBService.ts b/deploy/kb.gbapp/services/KBService.ts index 1403d8399..aff32b26f 100644 --- a/deploy/kb.gbapp/services/KBService.ts +++ b/deploy/kb.gbapp/services/KBService.ts @@ -63,23 +63,28 @@ export class KBService { this.sequelize = sequelize } + async getQuestionById( + instanceId: number, + questionId: number + ): Promise { + return GuaribasQuestion.findOne({ + where: { + instanceId: instanceId, + questionId: questionId + } + }) + } + async getAnswerById( instanceId: number, answerId: number ): Promise { - return new Promise( - (resolve, reject) => { - GuaribasAnswer.findAll({ - where: { - instanceId: instanceId, - answerId: answerId - } - }).then((item: GuaribasAnswer[]) => { - resolve(item[0]) - }).error((reason) => { - reject(reason) - }) - }) + return GuaribasAnswer.findOne({ + where: { + instanceId: instanceId, + answerId: answerId + } + }) } async getAnswerByText( @@ -291,7 +296,7 @@ export class KBService { static getSubjectItemsSeparatedBySpaces(subjects: GuaribasSubject[]) { let out = [] subjects.forEach(subject => { - out.push(subject.title) + out.push(subject.internalId) }) return out.join(" ") } @@ -300,66 +305,37 @@ export class KBService { instanceId: number, parentId: number ): Promise { - return new Promise( - (resolve, reject) => { - var where = { parentSubjectId: parentId, instanceId: instanceId } - GuaribasSubject.findAll({ - where: where - }) - .then((values: GuaribasSubject[]) => { - resolve(values) - }) - .error(reason => { - reject(reason) - }) - }) + var where = { parentSubjectId: parentId, instanceId: instanceId } + return GuaribasSubject.findAll({ + where: where + }) } async getFaqBySubjectArray(from: string, subjects: any): Promise { - return new Promise( - (resolve, reject) => { + let where = { + from: from + } - let where = { - from: from - } + if (subjects) { + if (subjects[0]) { + where["subject1"] = subjects[0].internalId + } - if (subjects) { - if (subjects[0]) { - where["subject1"] = subjects[0].title - } + if (subjects[1]) { + where["subject2"] = subjects[1].internalId + } - if (subjects[1]) { - where["subject2"] = subjects[1].title - } + if (subjects[2]) { + where["subject3"] = subjects[2].internalId + } - if (subjects[2]) { - where["subject3"] = subjects[2].title - } - - if (subjects[3]) { - where["subject4"] = subjects[3].title - } - } - GuaribasQuestion.findAll({ - where: where - }) - .then((items: GuaribasQuestion[]) => { - if (!items) items = [] - if (items.length == 0) { - resolve([]) - } else { - resolve(items) - } - }) - .catch(reason => { - if (reason.message.indexOf("no such table: IGBInstance") != -1) { - resolve([]) - } else { - reject(reason) - logger.info(`GuaribasServiceError: ${reason}`) - } - }) - }) + if (subjects[3]) { + where["subject4"] = subjects[3].internalId + } + } + return await GuaribasQuestion.findAll({ + where: where + }) } async importKbTabularFile( @@ -373,6 +349,9 @@ export class KBService { delimiter: "\t" } + let lastQuestion: GuaribasQuestion; + let lastAnswer: GuaribasAnswer; + let data = await parse(file, opts) return asyncPromise.eachSeries(data, async line => { @@ -428,9 +407,11 @@ export class KBService { instanceId: instanceId, content: answer, format: format, - packageId: packageId + packageId: packageId, + prevId: lastQuestion ? lastQuestion.questionId : 0, }) - await GuaribasQuestion.create({ + + let question1 = await GuaribasQuestion.create({ from: from, to: to, subject1: subject1, @@ -443,7 +424,13 @@ export class KBService { packageId: packageId }) - return Promise.resolve(question) + if (lastAnswer && lastQuestion) { + await lastAnswer.updateAttributes({ nextId: lastQuestion.questionId }) + } + lastAnswer = answer1 + lastQuestion = question1 + + return Promise.resolve(lastQuestion) } else { @@ -465,7 +452,7 @@ export class KBService { } else if (answer.content.length > 140 && dc.context._activity.channelId === "webchat") { const locale = dc.context.activity.locale; - + await dc.context.sendActivity(Messages[locale].will_answer_projector) // TODO: Handle rnd. var html = answer.content @@ -483,7 +470,13 @@ export class KBService { }) html = marked(answer.content) } - await conversationalService.sendEvent(dc, "play", { playerType: "markdown", data: html }) + await conversationalService.sendEvent(dc, "play", + { + playerType: "markdown", data: { + content: html, answer: answer, + prevId: answer.prevId, nextId: answer.nextId + } + }) } else { await dc.context.sendActivity(answer.content) await conversationalService.sendEvent(dc, "stop", null) @@ -560,10 +553,8 @@ export class KBService { else { return Promise.resolve(item) } - }) } - return doIt(subjects.children, null) } @@ -603,11 +594,11 @@ export class KBService { ) let instance = await core.loadInstance(packageObject.botId) - logger.info(`[GBDeployer] Beginning importing: ${localPath}`) + logger.info(`[GBDeployer] Importing: ${localPath}`) let p = await deployer.deployPackageToStorage( instance.instanceId, packageName) await this.importKbPackage(localPath, p, instance) - logger.info(`[GBDeployer] Finished importing ${localPath}`) + logger.info(`[GBDeployer] Finished import of ${localPath}`) } }