Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Wechaty | 15,477 | 70 | 58 | 2 months ago | 1,526 | May 15, 2022 | 282 | apache-2.0 | TypeScript | |
Conversational RPA SDK for Chatbot Makers | ||||||||||
Chat | 10,034 | 1 | a day ago | 136 | September 06, 2022 | 33 | gpl-3.0 | Go | ||
Instant messaging platform. Backend in Go. Clients: Swift iOS, Java Android, JS webapp, scriptable command line; chatbots | ||||||||||
Venom | 4,576 | 6 | 6 days ago | 114 | August 15, 2022 | 21 | apache-2.0 | JavaScript | ||
Venom is the most complete javascript library for Whatsapp, 100% Open Source. | ||||||||||
Wa Automate Nodejs | 2,701 | 7 | 2 days ago | 533 | September 18, 2022 | 79 | other | TypeScript | ||
💬 🤖 The most reliable WhatsApp tool for chatbots with advanced features. Be sure to 🌟 this repository for updates! | ||||||||||
Whatsapp Chatgpt | 2,164 | a day ago | 29 | TypeScript | ||||||
ChatGPT + DALL-E + WhatsApp = AI Assistant :rocket: :robot: | ||||||||||
Wppconnect | 1,134 | a day ago | 73 | July 11, 2022 | 30 | other | TypeScript | |||
WPPConnect is an open source project developed by the JavaScript community with the aim of exporting functions from WhatsApp Web to the node, which can be used to support the creation of any interaction, such as customer service, media sending, intelligence recognition based on phrases artificial and many other things, use your imagination | ||||||||||
Sulla | 1,126 | 1 | 18 days ago | 26 | February 17, 2021 | 94 | mit | JavaScript | ||
👩🏻🔬 Javascript Whatsapp api library for chatbots | ||||||||||
Python Wechaty | 1,042 | 4 | 3 days ago | 81 | July 06, 2022 | 127 | apache-2.0 | Python | ||
Python Wechaty is a Conversational RPA SDK for Chatbot Makers written in Python | ||||||||||
Facebook Messenger Bot | 669 | 6 months ago | 30 | mit | Python | |||||
Facebook chatbot that I trained to talk like me using Seq2Seq | ||||||||||
Me_bot | 618 | 2 years ago | 6 | Jupyter Notebook | ||||||
Build a bot that speaks like you! |
Attention: This version is NOT STABLE yet!!! NOT USE YET!!!
With this node.js micro framework using Venom Bot under the hood, you can easily create a WhatsApp Chatbot 🤖 . You will only need to edit your conversation flow in a single file.
Requirements: docker
Build and Run with Dockerfile
$ docker build -t wchatbot .
$ docker run --name wchatbot -p 3000:3000 -v /your_project_absolute_path/src:/wchatbot/src wchatbot
or Build and Run with Docker Compose
$ docker-compose build
$ docker-compose up
Visit http://localhost:3000 and play with your chatbot!
Requirements: nodejs (Latest maintenance LTS version), yarn (or npm), pm2, chrome/chromium
Use an nginx reverse proxy to publicly expose the http control panel (configuration example).
$ yarn install
Launch the chatbot and the http control panel
$ yarn start
$ yarn http-ctrl:start
Visit http://localhost:3000 and play with your chatbot!
Requirements: nodejs (Latest maintenance LTS version), yarn (or npm), chrome/chromium
$ yarn install
Launch the chatbot and the http control panel
$ yarn http-ctrl:dev:detach
$ yarn dev
Visit http://localhost:3000 and play with your chatbot!
Edit ./src/config.js
file
export const chatbotOptions = {
httpCtrl: {
port: 3000, // httpCtrl port (http://localhost:3000/)
username: "admin", // httpCtrl auth login
password: "chatbot",
},
};
export const venomOptions = {
...
puppeteerOptions: { // Will be passed to puppeteer.launch.
args: ["--no-sandbox"] // Use --no-sandbox with Docker
},
...
};
Chatbot Controls
$ docker exec wchatbot yarn start
$ docker exec wchatbot yarn stop
$ docker exec wchatbot yarn restart
$ docker exec wchatbot yarn reload
HTTP Control Panel Controls
$ docker exec wchatbot yarn http-ctrl:start
$ docker exec wchatbot yarn http-ctrl:stop
$ docker exec wchatbot yarn http-ctrl:restart
$ docker exec wchatbot yarn http-ctrl:reload
Chatbot Controls
$ yarn start
$ yarn stop
$ yarn restart
$ yarn reload
HTTP Control Panel Controls
$ yarn http-ctrl:start
$ yarn http-ctrl:stop
$ yarn http-ctrl:restart
$ yarn http-ctrl:reload
Direct in your OS without Docker
Chatbot
$ yarn dev
$ yarn dev:detach
Launch HTTP Control Panel
$ yarn http-ctrl:dev
$ yarn http-ctrl:dev:detach
Sessions and auth tokens are write in ./tokens
folder.
Logs are write in ./logs
folder.
Attention: console.log
and http-ctrl-console.log
only write in ./logs
folder with yarn dev:detach
and yarn http-ctrl:dev:detach
otherwise managed by pm2
.
Chatbot
$ docker exec wchatbot yarn log
HTTP Control Panel
$ docker exec wchatbot yarn http-ctrl:log
Conversations
$ docker exec wchatbot yarn conversations
Chatbot
$ yarn log
HTTP Control Panel
$ yarn http-ctrl:log
Conversations
$ yarn conversations
Chatbot
$ yarn log:dev
HTTP Control Panel
$ yarn log:http-ctrl:dev
Conversations
$ yarn conversations
Edit ./src/conversations/conversation.js
file.
The conversation flow is an array of ordered reply objects.
A reply is only triggered if its parent
(can be an integer or an array)
is equal to the id
of the previous reply.
To indicate that a reply is the end of the conversation add the following property:
Property | Type | Description |
---|---|---|
end |
Boolean | The end of the conversation |
A reply necessarily needs the following properties:
Property | Type | Description |
---|---|---|
id |
Integer | Reply id is used to link with parent
|
parent |
Integer | Id of the reply parent or ids array [2, 3] . If it has no parent it is 0 by default |
pattern |
RegExp | Regular expression to match in lower case |
message |
String | Reply text message |
Example
[
{
id: 1,
parent: 0,
pattern: /.*/, // Match with all text
message: "Hi I am a Chatbot!",
}
]
Property | Type | Description |
---|---|---|
id |
Integer | Reply id is used to link with parent
|
parent |
Integer | Id of the reply parent or ids array [2, 3] . If it has no parent it is 0 by default |
pattern |
RegExp | Regular expression to match in lower case |
message |
String | Reply text message |
description |
String | Reply text subtitle |
buttons |
Array | Button object, look at the example |
Example
[
{
id: 1,
parent: 0,
pattern: /.*/,
message: "Hello!",
description: "Can I help with something?",
buttons: buttons([
"Website",
"LinkedIn",
"Github",
]),
}
]
Attention: Does not work with Business account.
Property | Type | Description |
---|---|---|
id |
Integer | Reply id is used to link with parent
|
parent |
Integer | Id of the reply parent or ids array [2, 3] . If it has no parent it is 0 by default |
pattern |
RegExp | Regular expression to match in lower case |
message |
String | Reply text message |
description |
String | Reply text subtitle |
button |
String | List button text |
list |
Array | List object, look at the example |
Example
[
{
id: 1,
parent: 0,
pattern: /other country/,
message: "Choice one country",
description: "Choice one option!",
button: "Countries list",
list: list([
"Argentina",
"Belize",
"Bolivia",
]),
},
]
Property | Type | Description |
---|---|---|
id |
Integer | Reply id is used to link with parent
|
parent |
Integer | Id of the reply parent or ids array [2, 3] . If it has no parent it is 0 by default |
pattern |
RegExp | Regular expression to match in lower case |
message |
String | Reply text message |
link |
String | URL of generated link preview |
Example
[
{
id: 2,
parent: 1, // Relation with id: 1
pattern: /github/,
message: "Check my Github repositories!",
link: "https://github.com/jfadev",
}
]
Property | Type | Description |
---|---|---|
id |
Integer | Reply id is used to link with parent
|
parent |
Integer | Id of the reply parent or ids array [2, 3] . If it has no parent it is 0 by default |
pattern |
RegExp | Regular expression to match in lower case |
image |
Path / Object | Path or Object returned by remoteImg() funtion |
Example
[
{
id: 1,
parent: 0,
pattern: /.*/, // Match all
image: remoteImg("https://remote-server.com/menu.jpg"),
// image: "./images/menu.jpg",
}
]
Property | Type | Description |
---|---|---|
id |
Integer | Reply id is used to link with parent
|
parent |
Integer | Id of the reply parent or ids array [2, 3] . If it has no parent it is 0 by default |
pattern |
RegExp | Regular expression to match in lower case |
audio |
Path / Object | Path or Object returned by remoteAudio() funtion. |
Example
[
{
id: 1,
parent: 0,
pattern: /.*/, // Match all
audio: remoteAudio("https://remote-server.com/audio.mp3"),
// audio: "./audios/audio.mp3",
}
]
Property | Type | Description |
---|---|---|
id |
Integer | Reply id is used to link with parent
|
parent |
Integer | Id of the reply parent or ids array [2, 3] . If it has no parent it is 0 by default |
pattern |
RegExp | Regular expression to match in lower case |
message |
String | Reply text message |
forward |
String | Number where the message is forwarded |
Example
[
{
id: 1,
parent: 0,
pattern: /forward/,
message: "Text to forward",
forward: "[email protected]", // forward this message to this number
}
]
Helper | Return | Description |
---|---|---|
buttons(buttonTexts) |
Array | Generate buttons |
remoteTxt(url) |
String | Return a remote TXT file |
remoteJson(url) |
JSON | Return a remote JSON file |
remoteImg(url) |
Object | Return a remote Image file |
remoteAudio(url) |
Object | Return a remote Audio file |
list(listRows) |
Array | Generate list |
inp(id, parents) |
String | Return input string by reply id. Use in beforeReply, afterReply and beforeForward |
Property | Type | Description |
---|---|---|
beforeReply(from, input, output, parents, media) |
Function | Inject custom code before a reply |
afterReply(from, input, parents, media) |
Function | Inject custom code after a reply |
beforeForward(from, forward, input, parents, media) |
Function | Inject custom code before a forward |
Property | Type | Description |
---|---|---|
goTo(from, input, output, parents, media) |
Function | Should return the reply id where to jump |
With the control panel you can log in, start, stop or restart the bot and monitor the logs.
Set your username
and password
to access your control panel in file ./src/config.js
export const chatbotOptions = {
httpCtrl: {
port: 3000, // httpCtrl port (http://localhost:3000/)
username: "admin",
password: "chatbot"
}
};
Use an nginx reverse proxy to publicly expose the http control panel (configuration example).
Edit your file ./src/conversations/conversation.js
and create your custom conversation workflow.
import { buttons } from "../helpers";
/**
* Chatbot conversation flow
* Example 1
*/
export default [
{
id: 1,
parent: 0,
pattern: /hello|hi|howdy|good day|good morning|hey|hi-ya|how are you|how goes it|howdy\-do/,
message: "Hello! Thank you for contacting me, I am a Chatbot 🤖 , we will gladly assist you.",
description: "Can I help with something?",
buttons: buttons([
"Website",
"Linkedin",
"Github",
"Donate",
"Leave a Message",
]),
},
{
id: 2,
parent: 1, // Relation with id: 1
pattern: /website/,
message: "Visit my website and learn more about me!",
link: "https://jordifernandes.com/",
end: true,
},
{
id: 3,
parent: 1, // Relation with id: 1
pattern: /linkedin/,
message: "Visit my LinkedIn profile!",
link: "https://www.linkedin.com/in/jfadev",
end: true,
},
{
id: 4,
parent: 1, // Relation with id: 1
pattern: /github/,
message: "Check my Github repositories!",
link: "https://github.com/jfadev",
end: true,
},
{
id: 5,
parent: 1, // Relation with id: 1
pattern: /donate/,
message: "A tip is always good!",
link: "https://jordifernandes.com/donate/",
end: true,
},
{
id: 6,
parent: 1, // Relation with id: 1
pattern: /leave a message/,
message: "Write your message, I will contact you as soon as possible!",
},
{
id: 7,
parent: 6, // Relation with id: 6
pattern: /.*/, // Match with all text
message: "Thank you very much, your message will be sent to Jordi! Sincerely the Chatbot 🤖 !",
end: true,
},
];
import { buttons, remoteTxt, remoteJson } from "../helpers";
const customEndpoint = "https://jordifernandes.com/examples/chatbot";
/**
* Chatbot conversation flow
* Example 2
*/
export default [
{
id: 1,
parent: 0,
pattern: /.*/,
message: "Hello! I am a Delivery Chatbot.",
description: "Choice one option!",
buttons: buttons([
"See today's menu?",
"Order directly!",
"Talk to a human!",
]),
},
{
id: 2,
parent: 1, // Relation with id: 1
pattern: /menu/,
message: remoteTxt(`${customEndpoint}/menu.txt`),
// message: remoteJson(`${customEndpoint}/menu.json`)[0].message,
end: true,
},
{
id: 3,
parent: 1, // Relation with id: 1
pattern: /order/,
message: "Make a order!",
link: `${customEndpoint}/delivery-order.php`,
end: true,
},
{
id: 4,
parent: 1, // Relation with id: 1
pattern: /human/,
message: "Please call the following WhatsApp number: +1 206 555 0100",
end: true,
},
];
import fetch from "sync-fetch";
import { remoteImg } from "../helpers";
const customEndpoint = "https://jordifernandes.com/examples/chatbot";
/**
* Chatbot conversation flow
* Example 3
*/
export default [
{
id: 1,
parent: 0,
pattern: /.*/, // Match all
message: "Hello! I am a Delivery Chatbot. Send a menu item number!",
},
{
id: 2,
parent: 0, // Same parent (send reply id=1 and id=2)
pattern: /.*/, // Match all
image: remoteImg(`${customEndpoint}/menu.jpg`),
},
{
id: 3,
parent: 1, // Relation with id: 1
pattern: /\d+/, // Match any number
message: "You are choice item number $input. How many units do you want?", // Inject input value ($input) in message
},
{
id: 4,
parent: 2, // Relation with id: 2
pattern: /\d+/, // Match any number
message: "You are choice $input units. How many units do you want?",
// Inject custom code or overwrite output 'message' property before reply
beforeReply(from, input, output, parents) {
// Example check external api and overwrite output 'message'
const response = fetch(
`${customEndpoint}/delivery-check-stock.php/?item=${input}&qty=${parents.pop()}`
).json();
return response.stock === 0
? "Item number $input is not available in this moment!"
: output;
},
end: true,
},
];
import { remoteImg } from "../helpers";
const customEndpoint = "https://jordifernandes.com/examples/chatbot";
/**
* Chatbot conversation flow
* Example 4
*/
export default [
{
id: 1,
parent: 0,
pattern: /.*/, // Match all
message: "Image local and remote! Send [local] or [remote]",
},
{
id: 2,
parent: 1,
pattern: /local/,
image: "./images/image1.jpg",
end: true,
},
{
id: 3,
parent: 1,
pattern: /remote/,
image: remoteImg(`${customEndpoint}/image1.jpg`),
end: true,
},
];
import { remoteImg } from "../helpers";
const customEndpoint = "https://jordifernandes.com/examples/chatbot";
/**
* Chatbot conversation flow
* Example 5
*/
export default [
{
id: 1,
parent: 0,
pattern: /.*/, // Match all
message: "Audio local and remote! Send [local] or [remote]",
},
{
id: 2,
parent: 1,
pattern: /local/,
audio: "./audios/audio1.mp3",
end: true,
},
{
id: 3,
parent: 1,
pattern: /remote/,
audio: remoteAudio(`${customEndpoint}/audio1.mp3`),
end: true,
},
];
import fetch from "sync-fetch";
const customEndpoint = "https://jordifernandes.com/examples/chatbot";
/**
* Chatbot conversation flow
* Example 6
*/
export default [
{
id: 1,
parent: 0,
pattern: /.*/, // Match all
message: "",
// Inject custom code or overwrite output 'message' property before reply
beforeReply(from, input, output, parents) {
// Get reply from external api and overwrite output 'message'
const response = fetch(`${customEndpoint}/ai-reply.php/?input=${input}`).json();
return response.message;
},
end: true,
},
];
import fetch from "sync-fetch";
const customEndpoint = "https://jordifernandes.com/examples/chatbot";
/**
* Chatbot conversation flow
* Example 7
*/
export default [
{
id: 1,
parent: 0,
pattern: /.*/, // Match all
message: "Hello!",
// Inject custom code after reply
afterReply(from, input, parents) {
// Send WhatApp number to external api
const response = fetch(`${customEndpoint}/number-lead.php/`, {
method: "POST",
body: JSON.stringify({ number: from }),
headers: { "Content-Type": "application/json" },
}).json();
console.log('response:', response);
},
end: true,
},
];
import { buttons, inp } from "../helpers";
/**
* Chatbot conversation flow
* Example 8
*/
export default [
{
id: 1,
parent: 0,
pattern: /.*/,
message: "Choice one option",
description: "choice option:",
buttons: buttons(["Option 1", "Option 2"]),
},
{
id: 2,
parent: 1,
pattern: /.*/,
message: "We have received your request. Thanks.\n\n",
beforeReply(from, input, output, parents) {
output += `Your option: ${inp(2, parents)}`;
return output;
},
forward: "[email protected]", // default number or empty
beforeForward(from, forward, input, parents) { // Overwrite forward number
switch (inp(2, parents)) { // Access to replies inputs by id
case "option 1":
forward = "[email protected]";
break;
case "option 2":
forward = "[email protected]";
break;
default:
forward = "[email protected]";
break;
}
return forward;
},
end: true,
},
];
/**
* Chatbot conversation flow
* Example 9
*/
export default [
{
id: 1,
parent: 0,
pattern: /.*/, // Match all
message: "",
// Inject custom code or overwrite output 'message' property before reply
beforeReply(from, input, output, parents, media) {
if (media) {
console.log("media buffer", media.buffer);
return `You send file with .${media.extension} extension!`;
} else {
return "Send a picture please!";
}
},
end: true,
},
];
doc/examples/conversation10.js
import { promises as fs } from "fs";
/**
* Chatbot conversation flow
* Example 10
*/
export default [
{
id: 1,
parent: 0,
pattern: /\b(?!photo\b)\w+/, // different to photo
message: `Write "photo" for starting.`,
},
{
id: 2,
parent: [0, 1],
pattern: /photo/,
message: `Hi I'm a Chatbot, send a photo(s)`,
},
{
id: 3,
parent: 2,
pattern: /\b(?!finalize\b)\w+/, // different to finalize
message: "",
async beforeReply(from, input, output, parents, media) {
const uniqId = (new Date()).getTime();
// Download media
if (media) {
const dirName = "./downloads";
const fileName = `${uniqId}.${media.extension}`;
const filePath = `${dirName}/${fileName}`;
await fs.mkdir(dirName, { recursive: true });
await fs.writeFile(filePath, await media.buffer);
return `Photo download successfully! Send another or write "finalize".`;
} else {
return `Try send again or write "finalize".`;
}
},
goTo(from, input, output, parents, media) {
return 3; // return to id = 3
},
},
{
id: 4,
parent: 2,
pattern: /finalize/,
message: "Thank's you!",
end: true,
},
];
Edit ./src/main.js
file.
import { session } from "./core";
import info from "./conversations/info";
import delivery from "./conversations/delivery";
session("chatbotSession", info);
session("chatbotSession", delivery);
Edit ./src/main.js
file.
import { session } from "./core";
import commercial from "./conversations/commercial";
import delivery from "./conversations/delivery";
session("commercial_1", commercial);
session("commercial_2", commercial);
session("delivery", delivery);
Edit ./src/httpCtrl.js
file.
import { httpCtrl } from "./core";
httpCtrl("commercial_1", 3000);
httpCtrl("commercial_2", 3001);
httpCtrl("delivery", 3002);
Edit ./src/main.js
file.
import { session } from "./core";
import conversation from "./conversations/conversation";
// Run conversation flow and return a Venom client
const chatbot = await session("chatbotSession", conversation);
Edit ./src/main.js
file.
import schedule from "node-schedule"; // Add node-schedule in your project
import { session, log } from "./core";
import { jobsOptions } from "./config";
import conversation from "./conversations/conversation";
// Run conversation flow and return a Venom client
const chatbot = await session("chatbotSession", conversation);
const job1 = schedule.scheduleJob(
jobsOptions.job1.rule, // "*/15 * * * *"
async () => {
// custom logic example
await chatbot.sendText("[email protected]", "test");
}
);
Unit tests writes with jest
$ yarn test
Test you conversation flow array structure with conversation.test.js file as example.
$ yarn test src/conversations/conversation
Attention: Do not log in to whatsapp web with the same account that the chatbot uses. This will make the chatbot unable to hear the messages.
Attention: You need a whatsapp account for the chatbot and a different account to be able to talk to it.
Attention: Does not work with WhatsApp multi-device (beta). Disable it on your device.
https://jordifernandes.com/donate/
Pull requests are welcome :)