-
Medium: https://medium.com/@sanchezcarlosjr/how-to-create-a-bot-on-whatsapp-476a61ce3c15
-
Ana email bot: hola@sanchezcarlosjr.com
-
Ana whatsapp bot: https://x.sanchezcarlosjr.com/whatsapp
Last active
July 20, 2020 21:27
-
-
Save sanchezcarlosjr/2387ce3fa902848a4f436c23e1f67130 to your computer and use it in GitHub Desktop.
How to create a bot on Whatsapp?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as dialogflow from '@google-cloud/dialogflow'; | |
import { uuid } from 'uuidv4'; | |
import { NaturalProcessorLanguage } from '../domain/NaturalProcessorLanguage'; | |
import * as protos from '@google-cloud/dialogflow/build/protos/protos'; | |
export class Dialogflow implements NaturalProcessorLanguage { | |
private responses: | |
[protos.google.cloud.dialogflow.v2.IDetectIntentResponse, | |
protos.google.cloud.dialogflow.v2.IDetectIntentRequest | undefined, {} | undefined]; | |
async detectIntent(text: string, sessionId: string = uuid()): Promise<string> { | |
if (text.length > 250) { | |
return new Promise((resolve) => resolve('Be shorter in your request')); | |
} | |
const sessionClient = new dialogflow.SessionsClient(); | |
const sessionPath = sessionClient.projectAgentSessionPath('project-id ', sessionId); | |
this.responses = await sessionClient.detectIntent({ | |
session: sessionPath, | |
queryInput: { | |
text: { | |
text, | |
languageCode: 'en-US' | |
}, | |
}, | |
}); | |
return this.responses[0].queryResult.fulfillmentText; | |
} | |
getMedia(): string { | |
if (this.responses[0].queryResult.fulfillmentText === 'Listen to how I am!') { | |
return 'https://firebasestorage.googleapis.com/v0/b/arsus-production.appspot.com/o/assets%2FWhatsApp%20Ptt%202020-07-17%20at%205.14.18%20PM.ogg?alt=media&token=b0de767c-e6b5-49d8-b916-275244ff3ed6'; | |
} | |
return ''; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface NaturalProcessorLanguage { | |
detectIntent(text: string, sessionId?: string): Promise<string>; | |
getMedia(): string; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "arsus-server", | |
"scripts": { | |
"build": "tsc", | |
"start": "npm run shell", | |
"test": "npm run test:unit", | |
"test:unit": "mocha -r ts-node/register tests/**/*.spec.ts --timeout 100000", | |
"test:features": "cucumber-js -p default", | |
"deploy": "firebase deploy --only functions" | |
}, | |
"main": "lib/index.js", | |
"dependencies": { | |
"@google-cloud/dialogflow": "^2.0.0", | |
"@google-cloud/vision": "^2.1.0", | |
"@sendgrid/mail": "^7.2.0", | |
"actions-on-google": "^2.12.0", | |
"dialogflow-fulfillment": "^0.6.1", | |
"express": "^4.17.1", | |
"firebase": "^7.15.1", | |
"firebase-admin": "^8.12.1", | |
"firebase-functions": "^3.7.0", | |
"twilio": "^3.48.0", | |
"uuidv4": "^6.1.1" | |
}, | |
"devDependencies": { | |
"@firebase/firestore-types": "^1.11.0", | |
"@types/actions-on-google": "^2.0.1", | |
"@types/chai": "^4.2.11", | |
"@types/cucumber": "^6.0.1", | |
"@types/express": "^4.17.6", | |
"@types/faker": "^4.1.12", | |
"@types/jest": "^26.0.0", | |
"@types/mocha": "^7.0.2", | |
"@types/node": "^14.0.13", | |
"@types/request-promise": "^4.1.46", | |
"@types/sinon": "^9.0.4", | |
"@types/stripe": "^7.13.23", | |
"@types/supertest": "^2.0.9", | |
"chai": "^4.2.0", | |
"chai-as-promised": "^7.1.1", | |
"cucumber": "^6.0.5", | |
"faker": "^4.1.0", | |
"firebase-functions-test": "^0.2.1", | |
"mocha": "^8.0.1", | |
"sinon": "^9.0.2", | |
"supertest": "^4.0.2", | |
"ts-jest": "^26.1.0", | |
"ts-node": "^8.10.2", | |
"tslint": "^6.1.2", | |
"typescript": "^3.9.5" | |
}, | |
"engines": { | |
"node": "10" | |
}, | |
"private": true | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { https } from 'firebase-functions'; | |
import { Response } from 'express'; | |
import { Dialogflow } from '../../../../contexts/email/infraestructure/Dialogflow'; | |
import * as functions from 'firebase-functions'; | |
import { WhatsappCreator } from '../../../../contexts/blog/bot/application/WhatsappCreator'; | |
export interface BodyTwilio { | |
SmsMessageSid: string; | |
NumMedia: string; | |
SmsSid: string; | |
SmsStatus: string; | |
Body: string; | |
To: string; | |
NumSegments: string; | |
MessageSid: string; | |
AccountSid: string; | |
From: string; | |
ApiVersion: string; | |
} | |
export const SMS = functions | |
.runWith({ | |
timeoutSeconds: 20, | |
memory: '2GB' | |
}) | |
.https.onRequest(async (request: https.Request, response: Response) => { | |
const body: BodyTwilio = request.body; | |
const whatsappCreator = new WhatsappCreator(new Dialogflow()); | |
const xml: string = await whatsappCreator.create(body.Body, body.From); | |
response.setHeader('Content-Type', 'text/xml'); | |
return response.send(xml); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
{ | |
"compilerOptions": { | |
"module": "commonjs", | |
"noImplicitReturns": true, | |
"noUnusedLocals": true, | |
"outDir": "lib", | |
"sourceMap": true, | |
"strict": true, | |
"target": "es2015", | |
"strictNullChecks": false, | |
"skipLibCheck": true | |
}, | |
"lib": ["esnext.asynciterable", "es2015", "dom"], | |
"compileOnSave": true, | |
"include": ["src/*"], | |
"exclude": ["node_modules", "**/*.spec.ts"] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"extends": ["tslint:recommended", "tslint-config-prettier"], | |
"rules": { | |
"array-type": false, | |
"arrow-parens": false, | |
"deprecation": { | |
"severity": "warn" | |
}, | |
"import-blacklist": [true, "rxjs/Rx"], | |
"max-line-length": [true, 120], | |
"member-access": false, | |
"member-ordering": [ | |
true, | |
{ | |
"order": [ | |
"public-static-field", | |
"protected-static-field", | |
"private-static-field", | |
"public-instance-field", | |
"protected-instance-field", | |
"private-instance-field", | |
"constructor", | |
"public-static-method", | |
"protected-static-method", | |
"private-static-method", | |
"public-instance-method", | |
"protected-instance-method", | |
"private-instance-method" | |
] | |
} | |
], | |
"interface-name": false, | |
"max-classes-per-file": false, | |
"no-consecutive-blank-lines": false, | |
"no-console": [true, "debug", "time", "timeEnd", "trace"], | |
"no-duplicate-variable": [true, "check-parameters"], | |
"no-empty": false, | |
"no-inferrable-types": [true, "ignore-params"], | |
"no-non-null-assertion": true, | |
"no-redundant-jsdoc": true, | |
"no-switch-case-fall-through": true, | |
"no-unnecessary-initializer": true, | |
"object-literal-sort-keys": false, | |
"quotemark": [true, "single"], | |
"typedef": [true, "parameter", "property-declaration"], | |
"variable-name": false, | |
"no-var-requires": false, | |
"object-literal-key-quotes": false, | |
"ordered-imports": false, | |
"trailing-comma": false, | |
"no-conflicting-lifecycle": true, | |
"no-output-native": true, | |
"directive-selector": [true, "attribute", "app", "camelCase"], | |
"component-selector": [true, "element", "page", "app", "kebab-case"], | |
"template-banana-in-box": true, | |
"template-no-negated-async": true, | |
"no-output-on-prefix": true, | |
"no-inputs-metadata-property": true, | |
"no-outputs-metadata-property": true, | |
"no-host-metadata-property": true, | |
"no-input-rename": true, | |
"no-output-rename": true, | |
"use-lifecycle-interface": true, | |
"use-pipe-transform-interface": true, | |
"component-class-suffix": true, | |
"contextual-lifecycle": true, | |
"directive-class-suffix": true | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { expect } from 'chai'; | |
import * as mocha from 'mocha'; | |
import { WhatsappCreator } from '../../../src/contexts/blog/bot/application/WhatsappCreator'; | |
import sinon = require('sinon'); | |
mocha.describe('Whatsapp', () => { | |
it.only('should return a string', async () => { | |
const dialogflow = sinon.createStubInstance(Dialogflow); | |
const body = 'ABC'; | |
dialogflow.detectIntent.returns(new Promise((resolve) => resolve(body))); | |
const whatsapp = new WhatsappCreator(dialogflow); | |
const response = await whatsapp.create('a'); | |
const xml = `<?xml version="1.0" encoding="UTF-8"?><Response><Message><Body>${body}</Body></Message></Response>`; | |
expect(response).to.equal(xml); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { NaturalProcessorLanguage } from '../../../email/domain/NaturalProcessorLanguage'; | |
const MessagingResponse = require('twilio').twiml.MessagingResponse; | |
export class WhatsappCreator { | |
private twiml = new MessagingResponse(); | |
private message = this.twiml.message(); | |
constructor(private naturalProcessorLanguage: NaturalProcessorLanguage) { | |
} | |
async create(text: string, sessionId: string): Promise<string> { | |
const fulfillmentText = await this.naturalProcessorLanguage.detectIntent(text, sessionId); | |
this.message.body(fulfillmentText); | |
this.setMedia(this.naturalProcessorLanguage.getMedia()); | |
return this.twiml.toString(); | |
} | |
private setMedia(media: string) { | |
if (media) { | |
this.message.media(media); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment