diff --git a/.gitignore b/.gitignore index 6c556d19..9a4c83bc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ node_modules /guaribas.sqlite /guaribas.log /work -/docs \ No newline at end of file +/docs +/.env diff --git a/deploy/admin.gbapp/dialogs/AdminDialog.ts b/deploy/admin.gbapp/dialogs/AdminDialog.ts index 5756f6f2..0ba4decf 100644 --- a/deploy/admin.gbapp/dialogs/AdminDialog.ts +++ b/deploy/admin.gbapp/dialogs/AdminDialog.ts @@ -1,4 +1,3 @@ -import { KBService } from './../../kb.gbapp/services/KBService'; /*****************************************************************************\ | ( )_ _ | | _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | @@ -34,6 +33,7 @@ import { KBService } from './../../kb.gbapp/services/KBService'; "use strict"; +import { UrlJoin } from "urljoin"; import { AzureSearch } from "pragmatismo-io-framework"; import { Prompts, Session, UniversalBot } from 'botbuilder'; import { GBMinInstance } from "botlib"; @@ -41,8 +41,8 @@ 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'; -const UrlJoin = require("url-join"); export class AdminDialog extends IGBDialog { static setup(bot: UniversalBot, min: GBMinInstance) { diff --git a/deploy/admin.gbapp/dialogs/UploadPackageDialog.ts b/deploy/admin.gbapp/dialogs/UploadPackageDialog.ts index 4d043de1..a89a52b2 100644 --- a/deploy/admin.gbapp/dialogs/UploadPackageDialog.ts +++ b/deploy/admin.gbapp/dialogs/UploadPackageDialog.ts @@ -34,7 +34,6 @@ import { IGBDialog } from "botlib"; import { Prompts, UniversalBot, Session, ListStyle } from "botbuilder"; -import UrlJoin from "url-join"; import { GBMinInstance } from "botlib"; var fs = require("fs"); var request = require("request"); diff --git a/deploy/core.gbapp/dialogs/WelcomeDialog.ts b/deploy/core.gbapp/dialogs/WelcomeDialog.ts index 4920b206..80e09ed8 100644 --- a/deploy/core.gbapp/dialogs/WelcomeDialog.ts +++ b/deploy/core.gbapp/dialogs/WelcomeDialog.ts @@ -33,7 +33,6 @@ "use strict"; const WaitUntil = require("wait-until"); -import UrlJoin from "url-join"; import { GBCoreService } from "../services/GBCoreService"; import { IGBDialog } from "botlib"; import { GBConversationalService } from "../services/GBConversationalService"; @@ -42,6 +41,7 @@ import { GBMinInstance } from "botlib"; export class WelcomeDialog extends IGBDialog { static setup(bot: UniversalBot, min: GBMinInstance) { + bot.dialog("/", [ function (session, args, next) { if (!session.userData.once) { diff --git a/deploy/core.gbapp/dialogs/WhoAmIDialog.ts b/deploy/core.gbapp/dialogs/WhoAmIDialog.ts index 7b983749..358f8943 100644 --- a/deploy/core.gbapp/dialogs/WhoAmIDialog.ts +++ b/deploy/core.gbapp/dialogs/WhoAmIDialog.ts @@ -36,7 +36,6 @@ import { GBConversationalService } from "./../services/GBConversationalService"; import { GBCoreService } from "../services/GBCoreService"; import { IGBDialog } from "botlib"; import { UniversalBot, Session, Prompts } from "botbuilder"; -import UrlJoin from "url-join"; import { GBMinInstance } from "botlib"; diff --git a/deploy/core.gbapp/models/GBModel.ts b/deploy/core.gbapp/models/GBModel.ts index 79dcca91..9f831a68 100644 --- a/deploy/core.gbapp/models/GBModel.ts +++ b/deploy/core.gbapp/models/GBModel.ts @@ -91,6 +91,10 @@ export class GuaribasInstance extends Model implements IGBInst @Column webchatKey: string; + @Column whatsappKey: string; + + @Column spellCheckerKey: string; + @Column theme: string; @Column ui: string; diff --git a/deploy/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts b/deploy/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts index 50ee5b4e..c08942a8 100644 --- a/deploy/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts +++ b/deploy/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts @@ -33,7 +33,6 @@ "use strict"; import { UniversalBot, Session, Prompts, ListStyle } from "botbuilder"; -import UrlJoin from "url-join"; import { CSService } from '../services/CSService'; import { AzureText } from "pragmatismo-io-framework"; import { GBMinInstance } from "botlib"; diff --git a/deploy/customer-satisfaction.gbapp/dialogs/QualityDialog.ts b/deploy/customer-satisfaction.gbapp/dialogs/QualityDialog.ts index 477a27c1..14e1e13d 100644 --- a/deploy/customer-satisfaction.gbapp/dialogs/QualityDialog.ts +++ b/deploy/customer-satisfaction.gbapp/dialogs/QualityDialog.ts @@ -34,7 +34,6 @@ import { IGBDialog } from "botlib"; import { UniversalBot, Session, Prompts, ListStyle } from "botbuilder"; -import UrlJoin from "url-join"; import { GBMinInstance } from "botlib"; import { CSService } from "../services/CSService"; const logger = require("../../../src/logger"); diff --git a/deploy/customer-satisfaction.gbapp/services/CSService.ts b/deploy/customer-satisfaction.gbapp/services/CSService.ts index 3e1c1bb4..4079bd37 100644 --- a/deploy/customer-satisfaction.gbapp/services/CSService.ts +++ b/deploy/customer-satisfaction.gbapp/services/CSService.ts @@ -42,7 +42,6 @@ const Walk = require("fs-walk"); const WaitUntil = require("wait-until"); import { GBServiceCallback } from "botlib"; -import { UrlJoin } from 'url-join'; import { GBDeployer } from "../../core.gbapp/services/GBDeployer"; import { GuaribasQuestionAlternate } from '../models'; import { GuaribasConversation } from '../../analytics.gblib/models'; diff --git a/deploy/kb.gbapp/dialogs/AskDialog.ts b/deploy/kb.gbapp/dialogs/AskDialog.ts index 6a37a947..d0908867 100644 --- a/deploy/kb.gbapp/dialogs/AskDialog.ts +++ b/deploy/kb.gbapp/dialogs/AskDialog.ts @@ -69,14 +69,13 @@ export class AskDialog extends IGBDialog { session.replaceDialog("/menu"); } else { AzureText.getSpelledText( - "1f1653cd23e941ce869af73bdf9ef272", + min.instance.spellCheckerKey, text, (data, err) => { if (data != text) { logger.trace("Spelled Text: " + data); text = data; } - session.userData.lastQuestion = data; service.ask( diff --git a/deploy/kb.gbapp/dialogs/FaqDialog.ts b/deploy/kb.gbapp/dialogs/FaqDialog.ts index 4b70017a..dcdfffa2 100644 --- a/deploy/kb.gbapp/dialogs/FaqDialog.ts +++ b/deploy/kb.gbapp/dialogs/FaqDialog.ts @@ -35,7 +35,7 @@ import { KBService } from './../services/KBService'; import { IGBDialog } from "botlib"; import { Prompts, UniversalBot, Session, ListStyle } from "botbuilder"; -import UrlJoin from "url-join"; +import UrlJoin from "urljoin"; import { GBMinInstance } from "botlib"; export class FaqDialog extends IGBDialog { diff --git a/deploy/kb.gbapp/dialogs/MenuDialog.ts b/deploy/kb.gbapp/dialogs/MenuDialog.ts index b2f454c0..63784e34 100644 --- a/deploy/kb.gbapp/dialogs/MenuDialog.ts +++ b/deploy/kb.gbapp/dialogs/MenuDialog.ts @@ -42,7 +42,6 @@ import { HeroCard, CardImage } from "botbuilder"; -import UrlJoin from "url-join"; import { IGBDialog } from "botlib"; import { GBMinInstance } from "botlib"; import { AzureText } from "pragmatismo-io-framework"; diff --git a/deploy/whatsapp.gblib/services/directline.ts b/deploy/whatsapp.gblib/services/directline.ts new file mode 100644 index 00000000..915c5b0e --- /dev/null +++ b/deploy/whatsapp.gblib/services/directline.ts @@ -0,0 +1,186 @@ +/*****************************************************************************\ +| ( )_ _ | +| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | +| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ | +| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) | +| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | +| | | ( )_) | | +| (_) \___/' | +| | +| 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. | +| | +\*****************************************************************************/ + +const Path = require("path"); +const Fs = require("fs"); +const _ = require("lodash"); +const Parse = require("csv-parse"); +const Async = require("async"); +const UrlJoin = require("url-join"); +const Walk = require("fs-walk"); +const logger = require("../../../src/logger"); +const Swagger = require('swagger-client'); +const open = require('open'); +const rp = require('request-promise'); +import { GBServiceCallback, GBService, IGBInstance } from "botlib"; + +export class WhatsappDirectLine extends GBService { + + pollInterval = 1000; + directLineSecret = ''; + directLineClientName = 'DirectLineClient'; + directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json'; + + constructor(directLineSecret) { + super(); + + this.directLineSecret = directLineSecret; + + let directLineClient = rp(this.directLineSpecUrl) + .then(function (spec) { + return new Swagger({ + spec: JSON.parse(spec.trim()), + usePromise: true + }); + }) + .then(function (client) { + client.clientAuthorizations.add('AuthorizationBotConnector', + new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' + this.directLineSecret, 'header')); + return client; + }) + .catch(function (err) { + console.error('Error initializing DirectLine client', err); + }); + + directLineClient.then(function (client) { + client.Conversations.Conversations_StartConversation() // create conversation + .then(function (response) { + return response.obj.conversationId; + }) // obtain id + .then(function (conversationId) { + this.sendMessagesFromConsole(client, conversationId); // start watching console input for sending new messages to bot + this.pollMessages(client, conversationId); // start polling messages from bot + }) + .catch(function (err) { + console.error('Error starting conversation', err); + }); + }); + } + + sendMessagesFromConsole(client, conversationId) { + var stdin = process.openStdin(); + process.stdout.write('Command> '); + stdin.addListener('data', function (e) { + var input = e.toString().trim(); + if (input) { + // exit + if (input.toLowerCase() === 'exit') { + return process.exit(); + } + + // send message + client.Conversations.Conversations_PostActivity( + { + conversationId: conversationId, + activity: { + textFormat: 'plain', + text: input, + type: 'message', + from: { + id: this.directLineClientName, + name: this.directLineClientName + } + } + }).catch(function (err) { + console.error('Error sending message:', err); + }); + + process.stdout.write('Command> '); + } + }); + } + + /** Poll Messages from conversation using DirectLine client */ + pollMessages(client, conversationId) { + console.log('Starting polling message for conversationId: ' + conversationId); + var watermark = null; + setInterval(function () { + client.Conversations.Conversations_GetActivities({ conversationId: conversationId, watermark: watermark }) + .then(function (response) { + watermark = response.obj.watermark; // use watermark so subsequent requests skip old messages + return response.obj.activities; + }) + .then(this.printMessages); + }, this.pollInterval); + } + + printMessages(activities) { + if (activities && activities.length) { + // ignore own messages + activities = activities.filter(function (m) { return m.from.id !== this.directLineClientName }); + + if (activities.length) { + + // print other messages + activities.forEach(this.printMessage); + + process.stdout.write('Command> '); + } + } + } + + printMessage(activity) { + if (activity.text) { + console.log(activity.text); + } + + if (activity.attachments) { + activity.attachments.forEach(function (attachment) { + switch (attachment.contentType) { + case "application/vnd.microsoft.card.hero": + this.renderHeroCard(attachment); + break; + + case "image/png": + console.log('Opening the requested image ' + attachment.contentUrl); + open(attachment.contentUrl); + break; + } + }); + } + } + + renderHeroCard(attachment) { + var width = 70; + var contentLine = function (content) { + return ' '.repeat((width - content.length) / 2) + + content + + ' '.repeat((width - content.length) / 2); + } + + console.log('/' + '*'.repeat(width + 1)); + console.log('*' + contentLine(attachment.content.title) + '*'); + console.log('*' + ' '.repeat(width) + '*'); + console.log('*' + contentLine(attachment.content.text) + '*'); + console.log('*'.repeat(width + 1) + '/'); + } +} \ No newline at end of file diff --git a/package.json b/package.json index 62f40b51..e3a17217 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,10 @@ { "name": "botserver", - "version": "0.0.18", - "description": "General Bots Community Edition open-core server.", - "author": "me@rodrigorodriguez.com", + "version": "0.0.19", + "description": "General Bot Community Edition open-core server.", + "contributors": [ + "Rodrigo Rodriguez " + ], "license": "AGPL-3.0", "main": "./src/app.ts", "preferGlobal": "true", @@ -26,12 +28,13 @@ "@types/azure": "^0.9.19", "@types/chai": "4.0.4", "@types/mocha": "2.2.43", + "@types/url-join": "^0.8.2", "async": "^1.5.2", "botbuilder": "^3.14.0", "botlib": "0.0.12", "chai": "^4.1.2", "chokidar": "^2.0.2", - "csv-parse": "^2.2.0", + "csv-parse": "^2.4.0", "dotenv-extended": "^1.0.4", "express": "^4.16.2", "fs-extra": "^5.0.0",