docker-compose.yml

TYPEBOT + WHATSAP SEM VPS
100% Grátis

TYPEBOT SEM VPS + NOVA API
 
1- INSTALAR UBUNTU WINDOWS STORE
2- PREPARA UBUNTU
3- PREPARAR DOCKER-COMPOSE.YML
a. docker-compose up -d
b. hostname -I
4- CONSTRUIR A API (GIT e NODE)
a. criar pasta e arquivos
b. npm install
c. node botzdg_typebot_api2

Ativar Ubuntu no Windows (WSL)

				
					1- Abra o PowerShell como Administrador: Clique com o botão direito no menu Iniciar e escolha "Windows PowerShell (Admin)".

2- Habilite o recurso WSL: No PowerShell, execute o seguinte comando:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

3- Reinicie o Computador:

4- Instale uma Distribuição do Linux

5- Atualize para WSL 2 (Opcional):
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

				
			

Ubuntu

				
					sudo apt update && sudo apt upgrade
sudo apt-add-repository universe
sudo apt install python2-minimal

curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs
node -v
npm -v

sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
sudo apt update
sudo apt install docker-ce
sudo systemctl status docker
sudo apt install docker-compose
sudo usermod -aG docker ${USER}
dockerd &
				
			

docker-compose.yml

				
					version: '3.3'
services:
  typebot-db:
    image: postgres:13
    restart: always
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=typebot
      - POSTGRES_PASSWORD=typebot
  typebot-builder:
    ports:
      - 3001:3000
    image: baptistearno/typebot-builder:latest
    restart: always
    depends_on:
      - typebot-db
    environment:
      - DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
      - NEXTAUTH_URL=http://172.22.63.118:3001
      - NEXT_PUBLIC_VIEWER_URL=http://172.22.63.118:3002

      - ENCRYPTION_SECRET=9bd08a339fb03237e02cb5ce0f430675

      - ADMIN_EMAIL=email@gmail.com
      
      - SMTP_HOST=smtp.gmail.com
      - SMTP_USERNAME=email@gmail.com
      - SMTP_PASSWORD=senha
      - NEXT_PUBLIC_SMTP_FROM='Suporte Typebot' <email@gmail.com>

      - S3_ACCESS_KEY=minio
      - S3_SECRET_KEY=minio123
      - S3_BUCKET=typebot
      - S3_ENDPOINT=storagezdg.comunidadezdg.com.br
  typebot-viewer:
    ports:
      - 3002:3000
    image: baptistearno/typebot-viewer:latest
    restart: always
    environment:
      - DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
      - NEXT_PUBLIC_VIEWER_URL=http://172.22.63.118:3002
      - NEXTAUTH_URL=http://172.22.63.118:3001
      - ENCRYPTION_SECRET=9bd08a339fb03237e02cb5ce0f430675

      - S3_ACCESS_KEY=minio
      - S3_SECRET_KEY=minio123
      - S3_BUCKET=typebot
      - S3_ENDPOINT=storagezdg.comunidadezdg.com.br
  mail:
    image: bytemark/smtp
    restart: always
  minio:
    labels:
      virtual.host: 'storagezdg.comunidadezdg.com.br'
      virtual.port: '9000'
      virtual.tls-email: 'email@gmail.com'
    image: minio/minio
    command: server /data
    ports:
      - '9000:9000'
    environment:
      MINIO_ROOT_USER: minio
      MINIO_ROOT_PASSWORD: minio123
    volumes:
      - s3_data:/data
  createbuckets:
    image: minio/mc
    depends_on:
      - minio
    entrypoint: >
      /bin/sh -c "
      sleep 10;
      /usr/bin/mc config host add minio http://minio:9000 minio minio123;
      /usr/bin/mc mb minio/typebot;
      /usr/bin/mc anonymous set public minio/typebot/public;
      exit 0;
      "
volumes:
  db_data:
  s3_data:


				
			

index.html

				
					<!DOCTYPE html>
<html>
<head>
	<title>WPP API by Pedrinho da NASA</title>
</head>
<body>

	<div id="app">
		<h1>WPP API</h1>
		<h3>Entre agora para comunidade ZDG: <a href="https://comunidadezdg.com.br/">clique aqui</a></h3>
		<p>ZDG MOD</p>
		<img decoding="async" src="" alt="QR Code" id="qrcode">
		<h3>Logs:</h3>
		<ul class="logs"></ul>
	</div>

	<script type="rocketlazyloadscript" data-minify="1" src="https://comunidadezdg.com.br/wp-content/cache/min/1/ajax/libs/jquery/3.5.1/jquery.min.js?ver=1733159882" crossorigin="anonymous" defer></script>
	<script type="rocketlazyloadscript" data-minify="1" src="https://comunidadezdg.com.br/wp-content/cache/min/1/ajax/libs/socket.io/2.3.0/socket.io.js?ver=1733159882" crossorigin="anonymous" defer></script>
	<script type="rocketlazyloadscript">window.addEventListener('DOMContentLoaded', function() {
		$(document).ready(function() {
			var socket = io();

			socket.on('message', function(msg) {
				$('.logs').append($('<li>').text(msg));
			});

			socket.on('qr', function(src) {
				$('#qrcode').attr('src', src);
				$('#qrcode').show();
			});

			socket.on('ready', function(data) {
				$('#qrcode').hide();
			});

			socket.on('authenticated', function(data) {
				$('#qrcode').hide();
			});
		});
	});</script>
<script>class RocketElementorAnimation{constructor(){this.deviceMode=document.createElement("span"),this.deviceMode.id="elementor-device-mode",this.deviceMode.setAttribute("class","elementor-screen-only"),document.body.appendChild(this.deviceMode)}_detectAnimations(){let t=getComputedStyle(this.deviceMode,":after").content.replace(/"/g,"");this.animationSettingKeys=this._listAnimationSettingsKeys(t),document.querySelectorAll(".elementor-invisible[data-settings]").forEach(t=>{const e=t.getBoundingClientRect();if(e.bottom>=0&&e.top<=window.innerHeight)try{this._animateElement(t)}catch(t){}})}_animateElement(t){const e=JSON.parse(t.dataset.settings),i=e._animation_delay||e.animation_delay||0,n=e[this.animationSettingKeys.find(t=>e[t])];if("none"===n)return void t.classList.remove("elementor-invisible");t.classList.remove(n),this.currentAnimation&&t.classList.remove(this.currentAnimation),this.currentAnimation=n;let s=setTimeout(()=>{t.classList.remove("elementor-invisible"),t.classList.add("animated",n),this._removeAnimationSettings(t,e)},i);window.addEventListener("rocket-startLoading",function(){clearTimeout(s)})}_listAnimationSettingsKeys(t="mobile"){const e=[""];switch(t){case"mobile":e.unshift("_mobile");case"tablet":e.unshift("_tablet");case"desktop":e.unshift("_desktop")}const i=[];return["animation","_animation"].forEach(t=>{e.forEach(e=>{i.push(t+e)})}),i}_removeAnimationSettings(t,e){this._listAnimationSettingsKeys().forEach(t=>delete e[t]),t.dataset.settings=JSON.stringify(e)}static run(){const t=new RocketElementorAnimation;requestAnimationFrame(t._detectAnimations.bind(t))}}document.addEventListener("DOMContentLoaded",RocketElementorAnimation.run);</script></body>
</html>

				
			

package.json

				
					{"name":"bot-zdg","version":"1.0.0","description":"bot-zdg: based on Whatsapp API","main":"app.js","scripts":{"start":"node .\botzdg_typebot_stop.js","start:dev":"nodemon app.js","test":"echo \"Error: no test specified\" && exit 1"},"keywords":["whatsapp-api","node.js"],"author":"Pedro","license":"MIT","dependencies":{"axios":"^1.5.0","express":"^4.17.1","express-fileupload":"^1.2.0","express-validator":"^6.9.2","http":"0.0.1-security","qrcode":"^1.4.4","qrcode-terminal":"^0.12.0","socket.io":"2.3.0","whatsapp-web.js":"^1.23.0"},"devDependencies":{"nodemon":"^2.0.19"}}
				
			

botzdg_typebot_api2.js

				
					const { Client, LocalAuth, MessageMedia } = require('whatsapp-web.js');
const express = require('express');
const socketIO = require('socket.io');
const qrcode = require('qrcode');
const http = require('http');
const fileUpload = require('express-fileupload');
const port = 8000;
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const url = 'http://172.22.63.118:3002/api/v1/';
const typebot = 'zdg';
const dirBot = './typebot';

if (!fs.existsSync(dirBot)){
    fs.mkdirSync(dirBot)
}

app.use(express.json());
app.use(express.urlencoded({
  extended: true
}));
app.use(fileUpload({
  debug: true
}));
app.use("/", express.static(__dirname + "/"))
app.get('/', (req, res) => {
  res.sendFile('index.html', {
    root: __dirname
  });
});

const client = new Client({
  authStrategy: new LocalAuth({ clientId: 'typebot' }),
  puppeteer: { headless: true,
    executablePath: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-dev-shm-usage',
      '--disable-accelerated-2d-canvas',
      '--no-first-run',
      '--no-zygote',
      '--single-process', // <- this one doesn't works in Windows
      '--disable-gpu'
    ] }
});

client.initialize();

io.on('connection', function(socket) {
  socket.emit('message', '© BOT-ZDG - Iniciado');
  socket.emit('qr', './icon.svg');

client.on('qr', (qr) => {
    console.log('QR RECEIVED', qr);
    qrcode.toDataURL(qr, (err, url) => {
      socket.emit('qr', url);
      socket.emit('message', '© BOT-ZDG QRCode recebido, aponte a câmera  seu celular!');
    });
});

client.on('ready', async () => {
    socket.emit('ready', '© BOT-ZDG Dispositivo pronto!');
    socket.emit('message', '© BOT-ZDG Dispositivo pronto!');
    socket.emit('qr', './check.svg')	
    console.log('© BOT-ZDG Dispositivo pronto');
});

client.on('authenticated', () => {
    socket.emit('authenticated', '© BOT-ZDG Autenticado!');
    socket.emit('message', '© BOT-ZDG Autenticado!');
    console.log('© BOT-ZDG Autenticado');
});

client.on('auth_failure', function() {
    socket.emit('message', '© BOT-ZDG Falha na autenticação, reiniciando...');
    console.error('© BOT-ZDG Falha na autenticação');
});

client.on('change_state', state => {
  console.log('© BOT-ZDG Status de conexão: ', state );
});

client.on('disconnected', (reason) => {
  socket.emit('message', '© BOT-ZDG Cliente desconectado!');
  console.log('© BOT-ZDG Cliente desconectado', reason);
  client.initialize();
});
});

function deleteDirectory(dirPath) {
  if (fs.existsSync(dirPath)) {
    const files = fs.readdirSync(dirPath);
    files.forEach((file) => {
      const filePath = path.join(dirPath, file);
      if (fs.statSync(filePath).isDirectory()) {
        deleteDirectory(filePath);
      } else {
        fs.unlinkSync(filePath);
      }
    });
    try {
      fs.rmdirSync(dirPath);
      console.log(`Diretório ${dirPath} deletado com sucesso.`);
    } catch (error) {
      console.error(`Erro ao deletar diretório ${dirPath}:`, error);
    }
  } else {
    console.log(`O diretório ${dirPath} não existe.`);
  }
}

async function readWriteFileJson(sessionId, from) {
  let dataFile = [];
  fs.writeFileSync("./typebot/" + from + "/typebot.json", JSON.stringify(dataFile));
  var data = fs.readFileSync("./typebot/" + from + "/typebot.json");
  var myObject = JSON.parse(data);
  let newData = {
    id: sessionId,
  };
  await myObject.push(newData);
  fs.writeFileSync("./typebot/" + from + "/typebot.json", JSON.stringify(myObject));
}

async function createSession(data){
  let config = {
    method: 'post',
    maxBodyLength: Infinity,
    url: `${url}typebots/${typebot}/startChat`,
    headers: { 
      'Content-Type': 'application/json', 
      'Accept': 'application/json'
    }
  };

  const response = await axios.request(config);
  console.log('createSession' + response.data)
    const dirFrom = './typebot/' + data.from.replace(/\D/g,'');
    if (!fs.existsSync(dirFrom)){
      fs.mkdirSync(dirFrom);
      await readWriteFileJson(response.data.sessionId, data.from.replace(/\D/g,''));
    }
  return response.data
}

async function continueSession(data, msg){
  let dataMessage = JSON.stringify({
    "message": msg
  });

  let config = {
    method: 'post',
    maxBodyLength: Infinity,
    url: `${url}sessions/${data}/continueChat`,
    headers: { 
      'Content-Type': 'application/json', 
      'Accept': 'application/json'
    },
    data : dataMessage
  };

  const response = await axios.request(config);
  console.log('continueSession', response.data)
  return response.data
}

const timer = ms => new Promise(res => setTimeout(res, ms))
function randomIntFromInterval(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min)
}
const rndInt = randomIntFromInterval(1, 3)

client.on('message', async msg => {
  const dirFrom = './typebot/' + msg.from.replace(/\D/g,'');
  if (msg.body === 'sair'){
    await deleteDirectory(dirFrom)
    await client.sendMessage(msg.from, 'Atendimento automático reiniciado.')
  }
  if (msg.body !== 'sair'){
    if (!fs.existsSync(dirFrom)){
      const session = await createSession(msg);
      const messages = session.messages
      for (const message of messages){
        if (message.type === 'text') {
          let formattedText = '';
          for (const richText of message.content.richText){
            for (const element of richText.children){
              let text = '';
              if (element.text) {
                  text = element.text;
              }
              if (element.bold) {
                  text = `*${text}*`;
              }
              if (element.italic) {
                  text = `_${text}_`;
              }
              if (element.underline) {
                  text = `~${text}~`;
              }
              formattedText += text;          
            }
            formattedText += '\n';
          }
          formattedText = formattedText.replace(/\n$/, '');
          await client.sendMessage(msg.from, formattedText);
          await timer(rndInt * 1000)
        }
        if (message.type === 'image' || message.type === 'video') {
          try{
            const media = await MessageMedia.fromUrl(message.content.url)
            await client.sendMessage(msg.from, media, {caption: 'Comunidade ZDG'})
            await timer(rndInt * 1000)
          }catch(e){}
        }
        if (message.type === 'audio') {
          try{
            const media = await MessageMedia.fromUrl(message.content.url)
            await client.sendMessage(msg.from, media, {sendAudioAsVoice: true})
            await timer(rndInt * 1000)
          }catch(e){}
        }
      }
      const input = session.input
      if (input) {
        if (input.type === 'choice input') {
          let formattedText = '';
          const items = input.items;
          for (const item of items) {
            formattedText += `▶️ ${item.content}\n`;
          }
          formattedText = formattedText.replace(/\n$/, '');
          await client.sendMessage(msg.from, formattedText);
          await timer(rndInt * 1000)
        }
      }
    }
    else {
      const from = msg.from.replace(/\D/g,'');
      const sessionId = fs.readFileSync("./typebot/" + from + "/typebot.json","utf8").split(':')[1].replace(/\W/g, '');
      const session = await continueSession(sessionId, msg.body);
      const messages = session.messages
      for (const message of messages){
        if (message.type === 'text') {
          let formattedText = '';
          for (const richText of message.content.richText){
            for (const element of richText.children){
              let text = '';
              if (element.text) {
                  text = element.text;
              }
              if (element.bold) {
                  text = `*${text}*`;
              }
              if (element.italic) {
                  text = `_${text}_`;
              }
              if (element.underline) {
                  text = `~${text}~`;
              }
              formattedText += text;          
            }
            formattedText += '\n';
          }
          formattedText = formattedText.replace(/\n$/, '');
          await client.sendMessage(msg.from, formattedText);
          await timer(rndInt * 1000)
        }
        if (message.type === 'image' || message.type === 'video') {
          try{
            const media = await MessageMedia.fromUrl(message.content.url)
            await client.sendMessage(msg.from, media, {caption: 'Comunidade ZDG'})
            await timer(rndInt * 1000)
          }catch(e){}
        }
        if (message.type === 'audio') {
          try{
            const media = await MessageMedia.fromUrl(message.content.url)
            await client.sendMessage(msg.from, media, {sendAudioAsVoice: true})
            await timer(rndInt * 1000)
          }catch(e){}
        }
      }
      const input = session.input
      if (input) {
        if (input.type === 'choice input') {
          let formattedText = '';
          const items = input.items;
          for (const item of items) {
            formattedText += `▶️ ${item.content}\n`;
          }
          formattedText = formattedText.replace(/\n$/, '');
          await client.sendMessage(msg.from, formattedText);
          await timer(rndInt * 1000)
        }
      }
    }
  }
});
   
server.listen(port, function() {
  console.log('App running on *: ' + port);
});

				
			

Um poderoso sistema de blocos integrado ao whatsapp do seu negócio

 

🔗 Conector API para WhatsApp

🧩Blocos de bolha (texto, áudio, vídeo e imagens) – usados para exibir informações ao usuário.

🧩 Blocos de entrada – usados para solicitar entrada do usuário. Isso interromperá a conversa e o usuário fornecerá informações.

🧩Os blocos lógicos – usados para realizar operações em segundo plano. Eles não são visíveis para os usuários.

🧩 Os blocos de integração – usados para acionar operações de serviços externos.

Conheça alguns dos alunos da melhor comunidade de marketing de conversa do Brasil

E entenda porque tanta gente está economizando tempo e ganhando dinheiro explorando robôs e automações, mesmo sem nunca antes ter tido contato com uma API.

"O Pedrinho pega na nossa mão. Se eu consegui, você também consegue."

"Eu sou desenvolvedor de sistemas, e venho utilizando as soluções do Pedrinho para integrar nos meus sistemas, e o ganho de tempo é excepcional."

"O Pedrinho tem uma didática excelente e com o curso dele, consegui colocar minha API para rodar 24 horas e estou fazendo vendas todos os dias."

"A estratégia mais eficiente e totalmente escalável."

Comunidade ZDG © 2023 | CNPJ: 35.617.749/0001-67 | Razão Social: BIANCA SANT ANA PEREIRA 10398514607
Rua Alaor Ferreira da Fonseca, 295, CEP 37.136-132, Alfenas – MG | Tel: (35) 9 8875-4197 | E-mail: [email protected] | Política de Privacidade | Termos de Uso
Art. 49 do Código de Defesa do Consumidor | GARANTIA TOTAL DE 7 DIAS | Este produto não garante a obtenção de resultados. Qualquer referência ao desempenho de uma estratégia não deve ser interpretada como uma garantia de resultados.