diff --git a/CHANGELOG.md b/CHANGELOG.md index 059dd781..427a412b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# 1.5.1 (homolog) + +### Feature + +* Added listening_from_me option in Set Typebot +* Added variables options in Start Typebot +* Added webhooks for typebot events +* Added ChamaAI integration +* Added webhook to send errors + +### Fixed + +* Fix looping connection messages in chatwoot + # 1.5.0 (2023-08-18 12:47) ### Feature diff --git a/Docker/.env.example b/Docker/.env.example index bf21a71c..88be79fe 100644 --- a/Docker/.env.example +++ b/Docker/.env.example @@ -81,11 +81,19 @@ WEBHOOK_EVENTS_CONNECTION_UPDATE=true WEBHOOK_EVENTS_CALL=true # This event fires every time a new token is requested via the refresh route WEBHOOK_EVENTS_NEW_JWT_TOKEN=false +# This events is used with Typebot +WEBHOOK_EVENTS_TYPEBOT_START=false +WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false +# This event is used with Chama AI +WEBHOOK_EVENTS_CHAMA_AI_ACTION=false +# This event is used to send errors +WEBHOOK_EVENTS_ERRORS=false +WEBHOOK_EVENTS_ERRORS_WEBHOOK= # Name that will be displayed on smartphone connection CONFIG_SESSION_PHONE_CLIENT=EvolutionAPI -# Browser Name = chrome | firefox | edge | opera | safari -CONFIG_SESSION_PHONE_NAME=chrome +# Browser Name = Chrome | Firefox | Edge | Opera | Safari +CONFIG_SESSION_PHONE_NAME=Chrome # Set qrcode display limit QRCODE_LIMIT=30 diff --git a/Docker/docker-compose.yaml b/Docker/docker-compose.yaml new file mode 100644 index 00000000..cbc55c12 --- /dev/null +++ b/Docker/docker-compose.yaml @@ -0,0 +1,22 @@ +version: '3.3' + +services: + + api: + container_name: evolution_api + image: davidsongomes/evolution-api + restart: always + ports: + - 8080:8080 + volumes: + - evolution_instances:/evolution/instances + - evolution_store:/evolution/store + env_file: + - .env + command: ['node', './dist/src/main.js'] + expose: + - 8080 + +volumes: + evolution_instances: + evolution_store: \ No newline at end of file diff --git a/Docker/evolution-api-all-services/.env b/Docker/evolution-api-all-services/.env new file mode 100644 index 00000000..555ba7bc --- /dev/null +++ b/Docker/evolution-api-all-services/.env @@ -0,0 +1,109 @@ +# Server URL - Set your application url +SERVER_URL='http://localhost:8080' + +# Cors - * for all or set separate by commas - ex.: 'yourdomain1.com, yourdomain2.com' +CORS_ORIGIN='*' +CORS_METHODS='POST,GET,PUT,DELETE' +CORS_CREDENTIALS=true + +# Determine the logs to be displayed +LOG_LEVEL='ERROR,WARN,DEBUG,INFO,LOG,VERBOSE,DARK,WEBHOOKS' +LOG_COLOR=true +# Log Baileys - "fatal" | "error" | "warn" | "info" | "debug" | "trace" +LOG_BAILEYS=error + +# Determine how long the instance should be deleted from memory in case of no connection. +# Default time: 5 minutes +# If you don't even want an expiration, enter the value false +DEL_INSTANCE=false + +# Temporary data storage +STORE_MESSAGES=true +STORE_MESSAGE_UP=true +STORE_CONTACTS=true +STORE_CHATS=true + +# Set Store Interval in Seconds (7200 = 2h) +CLEAN_STORE_CLEANING_INTERVAL=7200 +CLEAN_STORE_MESSAGES=true +CLEAN_STORE_MESSAGE_UP=true +CLEAN_STORE_CONTACTS=true +CLEAN_STORE_CHATS=true + +# Permanent data storage +DATABASE_ENABLED=true +DATABASE_CONNECTION_URI=mongodb://root:root@mongodb:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true +DATABASE_CONNECTION_DB_PREFIX_NAME=evolution + +# Choose the data you want to save in the application's database or store +DATABASE_SAVE_DATA_INSTANCE=false +DATABASE_SAVE_DATA_NEW_MESSAGE=false +DATABASE_SAVE_MESSAGE_UPDATE=false +DATABASE_SAVE_DATA_CONTACTS=false +DATABASE_SAVE_DATA_CHATS=false + +REDIS_ENABLED=true +REDIS_URI=redis://redis:6379 +REDIS_PREFIX_KEY=evolution + +# Global Webhook Settings +# Each instance's Webhook URL and events will be requested at the time it is created +## Define a global webhook that will listen for enabled events from all instances +WEBHOOK_GLOBAL_URL='' +WEBHOOK_GLOBAL_ENABLED=false +# With this option activated, you work with a url per webhook event, respecting the global url and the name of each event +WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false +## Set the events you want to hear +WEBHOOK_EVENTS_APPLICATION_STARTUP=false +WEBHOOK_EVENTS_QRCODE_UPDATED=true +WEBHOOK_EVENTS_MESSAGES_SET=true +WEBHOOK_EVENTS_MESSAGES_UPSERT=true +WEBHOOK_EVENTS_MESSAGES_UPDATE=true +WEBHOOK_EVENTS_MESSAGES_DELETE=true +WEBHOOK_EVENTS_SEND_MESSAGE=true +WEBHOOK_EVENTS_CONTACTS_SET=true +WEBHOOK_EVENTS_CONTACTS_UPSERT=true +WEBHOOK_EVENTS_CONTACTS_UPDATE=true +WEBHOOK_EVENTS_PRESENCE_UPDATE=true +WEBHOOK_EVENTS_CHATS_SET=true +WEBHOOK_EVENTS_CHATS_UPSERT=true +WEBHOOK_EVENTS_CHATS_UPDATE=true +WEBHOOK_EVENTS_CHATS_DELETE=true +WEBHOOK_EVENTS_GROUPS_UPSERT=true +WEBHOOK_EVENTS_GROUPS_UPDATE=true +WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true +WEBHOOK_EVENTS_CONNECTION_UPDATE=true +# This event fires every time a new token is requested via the refresh route +WEBHOOK_EVENTS_NEW_JWT_TOKEN=false + +# Name that will be displayed on smartphone connection +CONFIG_SESSION_PHONE_CLIENT='Evolution API' +# Browser Name = chrome | firefox | edge | opera | safari +CONFIG_SESSION_PHONE_NAME=chrome + +# Set qrcode display limit +QRCODE_LIMIT=30 + +# Defines an authentication type for the api +# We recommend using the apikey because it will allow you to use a custom token, +# if you use jwt, a random token will be generated and may be expired and you will have to generate a new token +# jwt or 'apikey' +AUTHENTICATION_TYPE='apikey' +## Define a global apikey to access all instances. +### OBS: This key must be inserted in the request header to create an instance. +AUTHENTICATION_API_KEY='B6D711FCDE4D4FD5936544120E713976' +AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true +## Set the secret key to encrypt and decrypt your token and its expiration time +# seconds - 3600s ===1h | zero (0) - never expires +AUTHENTICATION_JWT_EXPIRIN_IN=0 +AUTHENTICATION_JWT_SECRET='L0YWtjb2w554WFqPG' +# Set the instance name and webhook url to create an instance in init the application +# With this option activated, you work with a url per webhook event, respecting the local url and the name of each event +# container or server +AUTHENTICATION_INSTANCE_MODE=server +# if you are using container mode, set the container name and the webhook url to default instance +AUTHENTICATION_INSTANCE_NAME=evolution +AUTHENTICATION_INSTANCE_WEBHOOK_URL='' +AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID=1 +AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN=123456 +AUTHENTICATION_INSTANCE_CHATWOOT_URL='' \ No newline at end of file diff --git a/Docker/evolution-api-all-services/docker-compose.yaml b/Docker/evolution-api-all-services/docker-compose.yaml new file mode 100644 index 00000000..1fe01975 --- /dev/null +++ b/Docker/evolution-api-all-services/docker-compose.yaml @@ -0,0 +1,91 @@ +version: '3.3' + +services: + + mongodb: + container_name: mongodb + image: mongo + restart: on-failure + ports: + - 27017:27017 + environment: + - MONGO_INITDB_ROOT_USERNAME=root + - MONGO_INITDB_ROOT_PASSWORD=root + - PUID=1000 + - PGID=1000 + volumes: + - evolution_mongodb_data:/data/db + - evolution_mongodb_configdb:/data/configdb + expose: + - 27017 + + mongo-express: + container_name: mongodb-express + image: mongo-express + restart: on-failure + ports: + - 8081:8081 + depends_on: + - mongodb + environment: + ME_CONFIG_BASICAUTH_USERNAME: root + ME_CONFIG_BASICAUTH_PASSWORD: root + ME_CONFIG_MONGODB_SERVER: mongodb + ME_CONFIG_MONGODB_ADMINUSERNAME: root + ME_CONFIG_MONGODB_ADMINPASSWORD: root + links: + - mongodb + + redis: + container_name: redis + image: redis:latest + restart: on-failure + ports: + - 6379:6379 + command: > + redis-server + --port 6379 + --appendonly yes + volumes: + - evolution_redis:/data + + rebrow: + container_name: rebrow + image: marian/rebrow + restart: on-failure + depends_on: + - redis + ports: + - 5001:5001 + links: + - redis + + api: + container_name: evolution_api + image: davidsongomes/evolution-api + restart: always + depends_on: + - mongodb + - redis + ports: + - 8080:8080 + volumes: + - evolution_instances:/evolution/instances + - evolution_store:/evolution/store + env_file: + - .env + command: ['node', './dist/src/main.js'] + expose: + - 8080 + +volumes: + evolution_mongodb_data: + evolution_mongodb_configdb: + evolution_redis: + evolution_instances: + evolution_store: + +networks: + evolution-net: + external: true + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index c9975782..df4b3176 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM node:16.18-alpine -LABEL version="1.5.0" description="Api to control whatsapp features through http requests." +LABEL version="1.5.1" description="Api to control whatsapp features through http requests." LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes" LABEL contact="contato@agenciadgcode.com" @@ -84,8 +84,16 @@ ENV WEBHOOK_EVENTS_CALL=true ENV WEBHOOK_EVENTS_NEW_JWT_TOKEN=false +ENV WEBHOOK_EVENTS_TYPEBOT_START=false +ENV WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false + +ENV WEBHOOK_EVENTS_CHAMA_AI_ACTION=false + +ENV WEBHOOK_EVENTS_ERRORS=false +ENV WEBHOOK_EVENTS_ERRORS_WEBHOOK= + ENV CONFIG_SESSION_PHONE_CLIENT=EvolutionAPI -ENV CONFIG_SESSION_PHONE_NAME=chrome +ENV CONFIG_SESSION_PHONE_NAME=Chrome ENV QRCODE_LIMIT=30 ENV QRCODE_COLOR=#198754 diff --git a/Extras/typebot/typebot-example.json b/Extras/typebot/typebot-example.json index 93ababc4..c45cd509 100644 --- a/Extras/typebot/typebot-example.json +++ b/Extras/typebot/typebot-example.json @@ -1 +1 @@ -{"id":"l27ft2bq9a7tke15i7m64d9o","version":"3","createdAt":"2023-08-04T17:27:18.072Z","updatedAt":"2023-08-11T21:38:15.669Z","icon":null,"name":"[Dgcode] [whatsapp] Pesquisa Satisfacao","folderId":"cll1fzkfy0008pa65kgz3tm86","groups":[{"id":"c76ucoughhenpernmadu7ibg","title":"Start","blocks":[{"id":"qn40kjwtw1he3l1bujt3bnje","type":"start","label":"Start","groupId":"c76ucoughhenpernmadu7ibg","outgoingEdgeId":"aovnigvk665gzhyzg7bxhvn0"}],"graphCoordinates":{"x":-126.43,"y":220.29}},{"id":"nog2woqmvhssnnjlcpwd41k5","title":"Apresentação","blocks":[{"id":"potdr8jwrn6mnkjipynqjmhh","type":"Set variable","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"type":"Random ID","variableId":"vsu5or5sxes9lyuhsgcl3cuyd"}},{"id":"jp1v0u6lucs72qn8h2y0krll","type":"Google Sheets","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"action":"Insert a row","sheetId":"0","cellsToInsert":[{"id":"e7h6q8pa9q9p2xv4owpfkwa4","value":"{{ID}}","column":"ID"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"}},{"id":"mcpyoq8x28bnwp23g7h1dbc1","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Olá! Bem-vindo(a) à nossa "},{"bold":true,"text":"pesquisa de satisfação"},{"text":"."}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"o0731ch0epj2vm2c5aoxyvw1","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Meu nome é "},{"bold":true,"text":"🤖 Mike"},{"text":", estou aqui para ouvir sua opinião e experiência com nossos serviços."}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"hgqbj5kmosz64cb435xqh0am","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Sua opinião é fundamental para nos ajudar a melhorar!"}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"cbvgdo0jknjyzmvwe6o614ni","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Vamos começar?"}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"nmhkn4jod3evk08tbq5vw3s3","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Qual o seu nome?"}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"o8ijci5gdfsp6fpv07kwh8br","type":"text input","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Digite o seu nome"},"variableId":"vo40px5r6wg9vhs9fixd45kzn"}},{"id":"etbdi8paer56f82p6xc379um","type":"Google Sheets","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{name}}","column":"Nome"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"},"outgoingEdgeId":"hqxrso204tkg5p71o96hduaz"}],"graphCoordinates":{"x":771.26,"y":213}},{"id":"j5co2kcotxafuxhzlj7u0qnn","title":"Qual seu email?","blocks":[{"id":"he1367t9ssao735kidd86mna","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Muito bem {{name}}, agora me informe seu endereço de email?"}]}]},"groupId":"j5co2kcotxafuxhzlj7u0qnn"},{"id":"qb8nwfs52g168tmnvp257b44","type":"email input","groupId":"j5co2kcotxafuxhzlj7u0qnn","options":{"labels":{"button":"Enviar","placeholder":"Digite o seu email"},"variableId":"vr75l1drc5uoxvisje0hio5ph","retryMessageContent":"Email incorreto!"}},{"id":"m0tqedan6l1j5jr6fb9wfdm7","type":"Google Sheets","groupId":"j5co2kcotxafuxhzlj7u0qnn","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{email}}","column":"Email"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"},"outgoingEdgeId":"ghbmp8sjr88b30phgi89qkjl"}],"graphCoordinates":{"x":1236.92,"y":204.84}},{"id":"wtd0o382phaji7i7u2n8pody","title":"Pergunta 1","blocks":[{"id":"zr69lw3bcmmkgahqq8og7shw","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Em uma escala de 0 a 10, qual é o seu nível de satisfação geral com os serviços que nossa empresa fornece?"}]}]},"groupId":"wtd0o382phaji7i7u2n8pody"},{"id":"ku0zpu43cbbnd7y0ai71ptde","type":"rating input","groupId":"wtd0o382phaji7i7u2n8pody","options":{"labels":{"button":"Send"},"length":10,"buttonType":"Numbers","customIcon":{"isEnabled":false},"variableId":"vbfl3sqze2wzicn9l1n9ckjs4"}},{"id":"l2s8irgrtrxfwy97v2gclajy","type":"Google Sheets","groupId":"wtd0o382phaji7i7u2n8pody","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question1}}","column":"Pergunta 1"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"},"outgoingEdgeId":"d2m2uo2gvnqzqw7m3hqp78zk"}],"graphCoordinates":{"x":1692.4,"y":194.19}},{"id":"ylerbfc1l2o62j68g8ghegxt","title":"Pergunta 2","blocks":[{"id":"l19jgtpln9al473dudr0gbzn","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Em uma escala de 0 a 10, em que medida nossa empresa atendeu às suas expectativas em termos de qualidade do serviço prestado?"}]}]},"groupId":"ylerbfc1l2o62j68g8ghegxt"},{"id":"kfxuc6p58cdzy1xcyp4i4ra7","type":"rating input","groupId":"ylerbfc1l2o62j68g8ghegxt","options":{"labels":{"button":"Send"},"length":10,"buttonType":"Numbers","customIcon":{"isEnabled":false},"variableId":"vkgl2bfdbyms1dyc1s6efx678"}},{"id":"v6vdddy19ncfhrkeettwr123","type":"Google Sheets","groupId":"ylerbfc1l2o62j68g8ghegxt","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question2}}","column":"Pergunta 2"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"},"outgoingEdgeId":"oylxp0jgu571sjsgqevol5yi"}],"graphCoordinates":{"x":2156.14,"y":190.76}},{"id":"lbieknd0qp42pogsby5l82ww","title":"Pergunta 3","blocks":[{"id":"y43s12dnoxh772c9o3pmnhxf","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Você teve alguma dificuldade em se comunicar com nossa equipe de suporte ao cliente?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"lbieknd0qp42pogsby5l82ww"},{"id":"fb6ckchqp8vx9ypig07we6q4","type":"text input","groupId":"lbieknd0qp42pogsby5l82ww","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Responda com uma das opções"},"variableId":"vzhsu0uc4suqoz38kv3q891ma"}},{"id":"rj84ja6d3mgouspwhrkeadz7","type":"Google Sheets","groupId":"lbieknd0qp42pogsby5l82ww","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question3}}","column":"Pergunta 3"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"}},{"id":"b538q1mt18l6oddo397nh1m4","type":"Condition","items":[{"id":"dwhc3ptqvktlgfvl17xg79s5","type":1,"blockId":"b538q1mt18l6oddo397nh1m4","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vzhsu0uc4suqoz38kv3q891ma","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"w6ao5pi6wt0966tobkned56m"},{"id":"cod3tkt16ry8ixm5u7rwxzm9","type":1,"blockId":"b538q1mt18l6oddo397nh1m4","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vzhsu0uc4suqoz38kv3q891ma","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"wlfmh2g3j5avj75sa9q6rsab"}],"groupId":"lbieknd0qp42pogsby5l82ww","outgoingEdgeId":"ehcwqdrkc4025pui2y1s9390"}],"graphCoordinates":{"x":2605.34,"y":189.93}},{"id":"qzhp25b9f2lvt4yeniqvjkav","title":"Pergunta 4","blocks":[{"id":"pos7njae2r35r29kcbyxtz2j","type":"text","content":{"richText":[{"type":"p","children":[{"text":"{{name}}, por favor, descreva o problema para que possamos melhorar."}]}]},"groupId":"qzhp25b9f2lvt4yeniqvjkav"},{"id":"ce2eodve0e4f2rubk4wv5jf1","type":"text input","groupId":"qzhp25b9f2lvt4yeniqvjkav","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Descreva o problema"},"variableId":"vd6fm2i9shcdjz8bhhwbsdh6t"}},{"id":"e75om4ccho8uob245t2wethw","type":"Google Sheets","groupId":"qzhp25b9f2lvt4yeniqvjkav","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question4}}","column":"Pergunta 4"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"},"outgoingEdgeId":"fe7xrdj315gebr22f0eylupl"}],"graphCoordinates":{"x":3041.23,"y":187.11}},{"id":"c8kh8eee1m3wyy372v4n6m1i","title":"Pergunta 5","blocks":[{"id":"txqi87lwinpa0p5of0xmqxu6","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Em uma escala de 0 a 10, como você avalia a capacidade da nossa empresa de cumprir os prazos acordados?"}]}]},"groupId":"c8kh8eee1m3wyy372v4n6m1i"},{"id":"mg2tmcmwnx3tap0hs4b7e0la","type":"rating input","groupId":"c8kh8eee1m3wyy372v4n6m1i","options":{"labels":{"button":"Enviar"},"length":10,"buttonType":"Numbers","customIcon":{"isEnabled":false},"variableId":"vz6lvahwo15dosvckdtkxduly"}},{"id":"cciytmy1bulw32j24ndbq39r","type":"Google Sheets","groupId":"c8kh8eee1m3wyy372v4n6m1i","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question5}}","column":"Pergunta 5"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"},"outgoingEdgeId":"dlfg76etmcqs3sgxplnisbf1"}],"graphCoordinates":{"x":3501.8,"y":179.58}},{"id":"tn8bcyughy9dsxhmjngrosvj","title":"Pergunta 6","blocks":[{"id":"aema350m33n9dljopcsxn8q5","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Você recomendaria nossos serviços para outras pessoas ou empresas?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"tn8bcyughy9dsxhmjngrosvj"},{"id":"wk4bkxbxcfu9skrzn8p8077u","type":"text input","groupId":"tn8bcyughy9dsxhmjngrosvj","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Responda com uma das opções"},"variableId":"vndjnalmnb3ez9beeon5tzrgq"}},{"id":"uucahcq4zwadysop7n9ktbms","type":"Google Sheets","groupId":"tn8bcyughy9dsxhmjngrosvj","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question6}}","column":"Pergunta 6"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"}},{"id":"n3j2dxaalkljl020o0o61ef9","type":"Condition","items":[{"id":"ifhm8cj8lsulhrarnfda2oal","type":1,"blockId":"n3j2dxaalkljl020o0o61ef9","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vndjnalmnb3ez9beeon5tzrgq","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"yu9762ttf5jn3bmhd6uzrsv8"},{"id":"gxp6j3ouga4r0t8364tn8axs","type":1,"blockId":"n3j2dxaalkljl020o0o61ef9","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vndjnalmnb3ez9beeon5tzrgq","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"ji1y2o1hldhemto0ymwou09c"}],"groupId":"tn8bcyughy9dsxhmjngrosvj","outgoingEdgeId":"d3u83fikqplfy9ntva3sm7eg"}],"graphCoordinates":{"x":3926.41,"y":186.15}},{"id":"nzkhdw3hdv550aepsxvk2a0u","title":"Pergunta 7","blocks":[{"id":"io90onrpfrokejgkps94r3dj","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Que pena {{name}}, por gentileza, nos conte o motivo?"}]}]},"groupId":"nzkhdw3hdv550aepsxvk2a0u"},{"id":"dj7dbgyjqk0a5u3jn6kzykb2","type":"text input","groupId":"nzkhdw3hdv550aepsxvk2a0u","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Digite o motivo"},"variableId":"vept0w6tr0w7eyyi52hgq1r3c"}},{"id":"i10wbfctp4dzroie3310rra0","type":"Google Sheets","groupId":"nzkhdw3hdv550aepsxvk2a0u","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question7}}","column":"Pergunta 7"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"},"outgoingEdgeId":"vu3k1pxfilhmz59malpqvj1u"}],"graphCoordinates":{"x":4352.64,"y":194.04}},{"id":"jdz9w8vrz09vefk4wqrf0vwl","title":"Pergunta 8","blocks":[{"id":"hndzyb58fqxudykajr22skla","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Existe alguma sugestão que você gostaria de nos dar para melhorar nossos serviços?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"jdz9w8vrz09vefk4wqrf0vwl"},{"id":"ol9l8fdb3q65auykrn383q6d","type":"text input","groupId":"jdz9w8vrz09vefk4wqrf0vwl","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Responda com uma das opções"},"variableId":"vy5it60mewmth7mayzhlgmzf0"}},{"id":"qhxod01c7mdlfrxr5cy0xgoj","type":"Google Sheets","groupId":"jdz9w8vrz09vefk4wqrf0vwl","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question8}}","column":"Pergunta 8"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"}},{"id":"zderh9hqjkpuz58p79szfa1i","type":"Condition","items":[{"id":"lur26nqa8dv7m4jmmljpyyf1","type":1,"blockId":"zderh9hqjkpuz58p79szfa1i","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vy5it60mewmth7mayzhlgmzf0","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"x2fzu1uuukp9cgmdzecp7mgk"},{"id":"aoj7e49zimwxng4o7bd6u00s","type":1,"blockId":"zderh9hqjkpuz58p79szfa1i","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vy5it60mewmth7mayzhlgmzf0","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"mb1fg83gijikrafud2ml6zbn"}],"groupId":"jdz9w8vrz09vefk4wqrf0vwl","outgoingEdgeId":"amyrx4i2rm3cjksym5zvwd50"}],"graphCoordinates":{"x":4768.69,"y":201.49}},{"id":"c4k1ftb4rbynkb01ulwuh4qh","title":"Pergunta 9","blocks":[{"id":"jqn5de3i29ygjyf6usbj117t","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Qual seria a sua sugestão?"}]}]},"groupId":"c4k1ftb4rbynkb01ulwuh4qh"},{"id":"wfucksh3yaeq21l7mnlnsx75","type":"text input","groupId":"c4k1ftb4rbynkb01ulwuh4qh","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Deixe sua sugestão"},"variableId":"vhygxyvhu5l6r2uws1cbthmxm"}},{"id":"kt1w6r6mucelx2odhnka5td1","type":"Google Sheets","groupId":"c4k1ftb4rbynkb01ulwuh4qh","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question9}}","column":"Pergunta 9"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"},"outgoingEdgeId":"imbs12h9gb2dpmrb19yvx71u"}],"graphCoordinates":{"x":5233.77,"y":205.27}},{"id":"vvyooiddvdbon0t21bvzdr7q","title":"Finalização","blocks":[{"id":"efk089lhks1ev4khy38caner","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Então {{name}}, agradecemos muito por dedicar um tempo para nos fornecer seu feedback."}]}]},"groupId":"vvyooiddvdbon0t21bvzdr7q"},{"id":"pvu3g8vpqdi3aecu2u0in2d0","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Sua opinião é muito importante para nós, e trabalharemos arduamente para melhorar ainda mais nossos serviços!"}]}]},"groupId":"vvyooiddvdbon0t21bvzdr7q"},{"id":"wqe9r1ivjf0ikubqichufzsg","type":"Webhook","groupId":"vvyooiddvdbon0t21bvzdr7q","options":{"isCustomBody":true,"isAdvancedConfig":true,"variablesForTest":[],"responseVariableMapping":[]},"webhookId":"i3g1959ev6fl9s61ir8hn1we"}],"graphCoordinates":{"x":7067.06,"y":231.55}},{"id":"ffm0s2y4head3auw808hwfnx","title":"Retorna Pergunta 3","blocks":[{"id":"ox70407atqtf1kwrszis4cix","type":"Set variable","groupId":"ffm0s2y4head3auw808hwfnx","options":{"type":"Empty","variableId":"vzhsu0uc4suqoz38kv3q891ma"}},{"id":"bcwkrcxtsc8drzwynb2igu0g","type":"Jump","groupId":"ffm0s2y4head3auw808hwfnx","options":{"groupId":"lbieknd0qp42pogsby5l82ww"}}],"graphCoordinates":{"x":3031.03,"y":754.83}},{"id":"cf8r0wx0sgw6c9v79ebja1tj","title":"Retorna Pergunta 6","blocks":[{"id":"e02yfpbpj298m1q9y4tb905i","type":"Set variable","groupId":"cf8r0wx0sgw6c9v79ebja1tj","options":{"type":"Empty","variableId":"vndjnalmnb3ez9beeon5tzrgq"}},{"id":"wjfe41oxiik0jgwcye7sczeu","type":"Jump","groupId":"cf8r0wx0sgw6c9v79ebja1tj","options":{"groupId":"tn8bcyughy9dsxhmjngrosvj"}}],"graphCoordinates":{"x":4360.16,"y":732.74}},{"id":"b7zfnwcxvu28s98ii03isdae","title":"Retorna Pergunta 8","blocks":[{"id":"j1xmpy60ggf162ej9a0rti4f","type":"Set variable","groupId":"b7zfnwcxvu28s98ii03isdae","options":{"type":"Empty","variableId":"vy5it60mewmth7mayzhlgmzf0"}},{"id":"lk06yb9dvrctn2u9tx35n12c","type":"Jump","groupId":"b7zfnwcxvu28s98ii03isdae","options":{"groupId":"jdz9w8vrz09vefk4wqrf0vwl"}}],"graphCoordinates":{"x":5213.21,"y":778}},{"id":"z0idhsnqisrd695z0j1tnqvw","title":"Retorna Pergunta 10","blocks":[{"id":"gs96ig682082mj4igcjjuh76","type":"Set variable","groupId":"z0idhsnqisrd695z0j1tnqvw","options":{"type":"Empty","variableId":"vx6p4ivk4mnssvbhl30c5zng9"}},{"id":"tihlp1xm8mvpdm3d0dqkwwx6","type":"Jump","groupId":"z0idhsnqisrd695z0j1tnqvw","options":{"groupId":"cs5kjnrcsh4bjiuvwf99agho"}}],"graphCoordinates":{"x":6100.86,"y":819.65}},{"id":"qsrkmfsr04kayulair47gmn0","title":"Gera QRCODE pix","blocks":[{"id":"qs1uxqm8jqla9uui43ofms65","type":"Webhook","groupId":"qsrkmfsr04kayulair47gmn0","options":{"isCustomBody":true,"isAdvancedConfig":true,"variablesForTest":[],"responseVariableMapping":[{"id":"gcia6kdba4yydt14klsg8h6x","bodyPath":"data.qrcode_base64","variableId":"vamn8ortov9nk1y04vczo375h"}]},"webhookId":"ajx8mv7trd50mbv2uj6fr3x5"},{"id":"sz447ty7t4vreto9bf07h52i","type":"Set variable","groupId":"qsrkmfsr04kayulair47gmn0","options":{"type":"Custom","variableId":"vamn8ortov9nk1y04vczo375h","expressionToEvaluate":"if({{remoteJid}}){\n return {{qrcode}}.replace('data:image/png;base64,', ''); \n}else{\n return {{qrcode}}\n}\n"}},{"id":"c3wp5ic2wx9emj6kkii42xpj","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Aqui está qrcode para sua contribuição de R$ {{question11}}, caso tenha dificuldade na leitura utilize a nossa chave:"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"Telefone: 7499879409"}]},{"type":"p","children":[{"text":"Em nome de: Davidson Oliveira Gomes"}]}]},"groupId":"qsrkmfsr04kayulair47gmn0"},{"id":"jncggap4fivalzgntw3bfaom","type":"image","content":{"url":"{{qrcode}}"},"groupId":"qsrkmfsr04kayulair47gmn0"},{"id":"chiz9utw18jvui4c2r0vsiqp","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Muito obrigado pela sua contribuição!"}]}]},"groupId":"qsrkmfsr04kayulair47gmn0","outgoingEdgeId":"cwlt91vwhr7gvgx0qx2mnxtr"}],"graphCoordinates":{"x":6607.75,"y":229.53}},{"id":"cs5kjnrcsh4bjiuvwf99agho","title":"Pergunta 10","blocks":[{"id":"axpk3aoauusbiy8av70fc2fo","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Gostaria de fazer uma contribuição?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"cs5kjnrcsh4bjiuvwf99agho"},{"id":"q136n37ja1g5dyhdeisur4rg","type":"text input","groupId":"cs5kjnrcsh4bjiuvwf99agho","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Deixe sua resposta"},"variableId":"vx6p4ivk4mnssvbhl30c5zng9"}},{"id":"m3sx9dam0ngbyni52l5b8b34","type":"Google Sheets","groupId":"cs5kjnrcsh4bjiuvwf99agho","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question10}}","column":"Pergunta 10"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"}},{"id":"xza6e0p4hgkfz1wvwcjss48s","type":"Condition","items":[{"id":"m5mvt5ecw81eevl428n56aji","type":1,"blockId":"xza6e0p4hgkfz1wvwcjss48s","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vx6p4ivk4mnssvbhl30c5zng9","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"fe1wk4fc1xzt7mefasb2qzqz"},{"id":"bpcidulg0g7v8pwh3w9my880","type":1,"blockId":"xza6e0p4hgkfz1wvwcjss48s","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vx6p4ivk4mnssvbhl30c5zng9","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"xg1zkpvob8ilx2r8p0kv604d"}],"groupId":"cs5kjnrcsh4bjiuvwf99agho","outgoingEdgeId":"o746eh96sq2j7juionfql73t"}],"graphCoordinates":{"x":5708.94,"y":210.9}},{"id":"tq60r6azxrmn17b4y7mjovf5","title":"Pergunta 11","blocks":[{"id":"o5fspfge731wt6m781nzjsll","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Muito bem {{name}}, quanto você deseja contribuir?"}]}]},"groupId":"tq60r6azxrmn17b4y7mjovf5"},{"id":"khncvmg5fcjsmu8tlmf8in6m","type":"number input","groupId":"tq60r6azxrmn17b4y7mjovf5","options":{"max":5000,"min":1,"step":1,"labels":{"button":"Enviar","placeholder":"Digite um numero"},"variableId":"vhoqah2c0blbx92bfmd4gjnyx"}},{"id":"xcd54kvlpao5si54yuvle8y8","type":"Google Sheets","groupId":"tq60r6azxrmn17b4y7mjovf5","options":{"action":"Update a row","filter":{"comparisons":[{"id":"w2o1z5ire06bqcg8b53kzct8","value":"{{ID}}","column":"ID","comparisonOperator":"Equal to"}],"logicalOperator":"AND"},"sheetId":"0","cellsToUpsert":[{"id":"cn2vxka7p4a590r61ia7kwzg","value":"{{question11}}","column":"Pergunta 11"}],"credentialsId":"clkvo2r8h0003mk664r70mype","spreadsheetId":"1qFqRjMIJXc6BLoJSqrpIw-aF3pVjVav64lQo-SBmoBs"},"outgoingEdgeId":"t1r05l9c3n3n377bdt8adu2x"}],"graphCoordinates":{"x":6158.94,"y":224.91}},{"id":"h0svx6gyzgjsclr9hbpo04v6","title":"Configurações Iniciais","blocks":[{"id":"na4zglpatkg8ejqcap8lcv69","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vp1ask55v2r58ukom5lek5hej","expressionToEvaluate":"https://8338-2804-910-16a-ff01-bd73-9d18-5395-c820.ngrok-free.app"}},{"id":"t2bdxy8x8fsn29yijk02ti43","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vtsldvs2u8ui93tktazy77djw","expressionToEvaluate":"8EAA51D7-F658-409D-9C9C-0A68DDC783DD1"}},{"id":"rt5h0lk6jaoh5hzag0s5hidd","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vkg1qlinovziltaloqhso2cw7","expressionToEvaluate":"https://pix.dgcode.com.br"}},{"id":"mh758b8y8288t56s6wz73mht","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vpjyy2e2ha6mu5x10q0nowuz3","expressionToEvaluate":"Davidson Oliveira Gomes"}},{"id":"ri9kv80djsej7r51m8xfjhuk","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vicsm3nkvhssvfhgss2xce2ad","expressionToEvaluate":"Telefone"}},{"id":"ye4teva02mnxph0rvfszdnsn","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vlmflx32cjlz457h0uzdi706g","expressionToEvaluate":"74999879409"}},{"id":"hfz4hqzfe6wgje96ezb5kann","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"veesfw943copg17w2qzdln9be","expressionToEvaluate":"Irece"}},{"id":"nd3yk369k7j73kws6exos0jw","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vavwvk4wgst506zdioplg4u8p","expressionToEvaluate":"TypeBot"},"outgoingEdgeId":"mb90csrzzep8qz2opcxmw736"}],"graphCoordinates":{"x":312.08,"y":218.28}}],"variables":[{"id":"vo40px5r6wg9vhs9fixd45kzn","name":"name"},{"id":"vr75l1drc5uoxvisje0hio5ph","name":"email"},{"id":"vzhsu0uc4suqoz38kv3q891ma","name":"question3"},{"id":"vbfl3sqze2wzicn9l1n9ckjs4","name":"question1"},{"id":"vkgl2bfdbyms1dyc1s6efx678","name":"question2"},{"id":"vd6fm2i9shcdjz8bhhwbsdh6t","name":"question4"},{"id":"vz6lvahwo15dosvckdtkxduly","name":"question5"},{"id":"vndjnalmnb3ez9beeon5tzrgq","name":"question6"},{"id":"vept0w6tr0w7eyyi52hgq1r3c","name":"question7"},{"id":"vy5it60mewmth7mayzhlgmzf0","name":"question8"},{"id":"vhygxyvhu5l6r2uws1cbthmxm","name":"question9"},{"id":"vrdwfo2lpoei2fzlzazh4pp61","name":"pushName"},{"id":"vz1uq7t77aivpi5crwy6ifact","name":"remoteJid"},{"id":"vsu5or5sxes9lyuhsgcl3cuyd","name":"ID"},{"id":"vamn8ortov9nk1y04vczo375h","name":"qrcode"},{"id":"vx6p4ivk4mnssvbhl30c5zng9","name":"question10"},{"id":"vhoqah2c0blbx92bfmd4gjnyx","name":"question11"},{"id":"vpjyy2e2ha6mu5x10q0nowuz3","name":"me"},{"id":"vicsm3nkvhssvfhgss2xce2ad","name":"typePIX"},{"id":"vavwvk4wgst506zdioplg4u8p","name":"reference"},{"id":"vlmflx32cjlz457h0uzdi706g","name":"keyPIX"},{"id":"vkg1qlinovziltaloqhso2cw7","name":"apiURL"},{"id":"veesfw943copg17w2qzdln9be","name":"city"},{"id":"vp1ask55v2r58ukom5lek5hej","name":"evolutionURL"},{"id":"vtsldvs2u8ui93tktazy77djw","name":"evolutionToken"}],"edges":[{"id":"w6ao5pi6wt0966tobkned56m","to":{"groupId":"qzhp25b9f2lvt4yeniqvjkav"},"from":{"itemId":"dwhc3ptqvktlgfvl17xg79s5","blockId":"b538q1mt18l6oddo397nh1m4","groupId":"lbieknd0qp42pogsby5l82ww"}},{"id":"wlfmh2g3j5avj75sa9q6rsab","to":{"groupId":"tn8bcyughy9dsxhmjngrosvj"},"from":{"itemId":"cod3tkt16ry8ixm5u7rwxzm9","blockId":"b538q1mt18l6oddo397nh1m4","groupId":"lbieknd0qp42pogsby5l82ww"}},{"id":"yu9762ttf5jn3bmhd6uzrsv8","to":{"groupId":"jdz9w8vrz09vefk4wqrf0vwl"},"from":{"itemId":"ifhm8cj8lsulhrarnfda2oal","blockId":"n3j2dxaalkljl020o0o61ef9","groupId":"tn8bcyughy9dsxhmjngrosvj"}},{"id":"ji1y2o1hldhemto0ymwou09c","to":{"groupId":"nzkhdw3hdv550aepsxvk2a0u"},"from":{"itemId":"gxp6j3ouga4r0t8364tn8axs","blockId":"n3j2dxaalkljl020o0o61ef9","groupId":"tn8bcyughy9dsxhmjngrosvj"}},{"id":"x2fzu1uuukp9cgmdzecp7mgk","to":{"groupId":"c4k1ftb4rbynkb01ulwuh4qh"},"from":{"itemId":"lur26nqa8dv7m4jmmljpyyf1","blockId":"zderh9hqjkpuz58p79szfa1i","groupId":"jdz9w8vrz09vefk4wqrf0vwl"}},{"id":"d3u83fikqplfy9ntva3sm7eg","to":{"groupId":"cf8r0wx0sgw6c9v79ebja1tj"},"from":{"blockId":"n3j2dxaalkljl020o0o61ef9","groupId":"tn8bcyughy9dsxhmjngrosvj"}},{"id":"ehcwqdrkc4025pui2y1s9390","to":{"groupId":"ffm0s2y4head3auw808hwfnx"},"from":{"blockId":"b538q1mt18l6oddo397nh1m4","groupId":"lbieknd0qp42pogsby5l82ww"}},{"id":"hqxrso204tkg5p71o96hduaz","to":{"groupId":"j5co2kcotxafuxhzlj7u0qnn"},"from":{"blockId":"etbdi8paer56f82p6xc379um","groupId":"nog2woqmvhssnnjlcpwd41k5"}},{"id":"ghbmp8sjr88b30phgi89qkjl","to":{"groupId":"wtd0o382phaji7i7u2n8pody"},"from":{"blockId":"m0tqedan6l1j5jr6fb9wfdm7","groupId":"j5co2kcotxafuxhzlj7u0qnn"}},{"id":"d2m2uo2gvnqzqw7m3hqp78zk","to":{"groupId":"ylerbfc1l2o62j68g8ghegxt"},"from":{"blockId":"l2s8irgrtrxfwy97v2gclajy","groupId":"wtd0o382phaji7i7u2n8pody"}},{"id":"oylxp0jgu571sjsgqevol5yi","to":{"groupId":"lbieknd0qp42pogsby5l82ww"},"from":{"blockId":"v6vdddy19ncfhrkeettwr123","groupId":"ylerbfc1l2o62j68g8ghegxt"}},{"id":"fe7xrdj315gebr22f0eylupl","to":{"groupId":"c8kh8eee1m3wyy372v4n6m1i"},"from":{"blockId":"e75om4ccho8uob245t2wethw","groupId":"qzhp25b9f2lvt4yeniqvjkav"}},{"id":"dlfg76etmcqs3sgxplnisbf1","to":{"groupId":"tn8bcyughy9dsxhmjngrosvj"},"from":{"blockId":"cciytmy1bulw32j24ndbq39r","groupId":"c8kh8eee1m3wyy372v4n6m1i"}},{"id":"vu3k1pxfilhmz59malpqvj1u","to":{"groupId":"jdz9w8vrz09vefk4wqrf0vwl"},"from":{"blockId":"i10wbfctp4dzroie3310rra0","groupId":"nzkhdw3hdv550aepsxvk2a0u"}},{"id":"imbs12h9gb2dpmrb19yvx71u","to":{"groupId":"cs5kjnrcsh4bjiuvwf99agho"},"from":{"blockId":"kt1w6r6mucelx2odhnka5td1","groupId":"c4k1ftb4rbynkb01ulwuh4qh"}},{"id":"mb1fg83gijikrafud2ml6zbn","to":{"groupId":"cs5kjnrcsh4bjiuvwf99agho"},"from":{"itemId":"aoj7e49zimwxng4o7bd6u00s","blockId":"zderh9hqjkpuz58p79szfa1i","groupId":"jdz9w8vrz09vefk4wqrf0vwl"}},{"id":"amyrx4i2rm3cjksym5zvwd50","to":{"groupId":"b7zfnwcxvu28s98ii03isdae"},"from":{"blockId":"zderh9hqjkpuz58p79szfa1i","groupId":"jdz9w8vrz09vefk4wqrf0vwl"}},{"id":"o746eh96sq2j7juionfql73t","to":{"groupId":"z0idhsnqisrd695z0j1tnqvw"},"from":{"blockId":"xza6e0p4hgkfz1wvwcjss48s","groupId":"cs5kjnrcsh4bjiuvwf99agho"}},{"id":"fe1wk4fc1xzt7mefasb2qzqz","to":{"groupId":"tq60r6azxrmn17b4y7mjovf5"},"from":{"itemId":"m5mvt5ecw81eevl428n56aji","blockId":"xza6e0p4hgkfz1wvwcjss48s","groupId":"cs5kjnrcsh4bjiuvwf99agho"}},{"id":"xg1zkpvob8ilx2r8p0kv604d","to":{"groupId":"vvyooiddvdbon0t21bvzdr7q"},"from":{"itemId":"bpcidulg0g7v8pwh3w9my880","blockId":"xza6e0p4hgkfz1wvwcjss48s","groupId":"cs5kjnrcsh4bjiuvwf99agho"}},{"id":"t1r05l9c3n3n377bdt8adu2x","to":{"groupId":"qsrkmfsr04kayulair47gmn0"},"from":{"blockId":"xcd54kvlpao5si54yuvle8y8","groupId":"tq60r6azxrmn17b4y7mjovf5"}},{"id":"cwlt91vwhr7gvgx0qx2mnxtr","to":{"groupId":"vvyooiddvdbon0t21bvzdr7q"},"from":{"blockId":"chiz9utw18jvui4c2r0vsiqp","groupId":"qsrkmfsr04kayulair47gmn0"}},{"id":"aovnigvk665gzhyzg7bxhvn0","to":{"groupId":"h0svx6gyzgjsclr9hbpo04v6"},"from":{"blockId":"qn40kjwtw1he3l1bujt3bnje","groupId":"c76ucoughhenpernmadu7ibg"}},{"id":"mb90csrzzep8qz2opcxmw736","to":{"groupId":"nog2woqmvhssnnjlcpwd41k5"},"from":{"blockId":"nd3yk369k7j73kws6exos0jw","groupId":"h0svx6gyzgjsclr9hbpo04v6"}}],"theme":{"chat":{"inputs":{"color":"#ffffff","backgroundColor":"#1e293b","placeholderColor":"#9095A0"},"buttons":{"color":"#ffffff","backgroundColor":"#1a5fff"},"roundness":"large","hostAvatar":{"isEnabled":true},"guestAvatar":{"isEnabled":false},"hostBubbles":{"color":"#ffffff","backgroundColor":"#1e293b"},"guestBubbles":{"color":"#FFFFFF","backgroundColor":"#FF8E21"}},"general":{"font":"Open Sans","background":{"type":"Color","content":"#171923"}}},"selectedThemeTemplateId":"typebot-dark","settings":{"general":{"isBrandingEnabled":false},"metadata":{"imageUrl":"https://i.imgur.com/48TjKBb.jpg","description":"Sua opinião é fundamental para nos ajudar a melhorar!"},"typingEmulation":{"speed":300,"enabled":true,"maxDelay":1.5}},"publicId":"dgcode-pesquisa-satisfacao-whatsapp-7m64d9o","customDomain":null,"workspaceId":"clktt8c1y0001qa66zyg5tt23","resultsTablePreferences":null,"isArchived":false,"isClosed":false} \ No newline at end of file +{"id":"l27ft2bq9a7tke15i7m64d9o","version":"3","createdAt":"2023-08-04T17:27:18.072Z","updatedAt":"2023-08-20T13:35:33.073Z","icon":null,"name":"[Dgcode] [whatsapp] Pesquisa Satisfacao","folderId":"cll1fzkfy0008pa65kgz3tm86","groups":[{"id":"c76ucoughhenpernmadu7ibg","title":"Start","blocks":[{"id":"qn40kjwtw1he3l1bujt3bnje","type":"start","label":"Start","groupId":"c76ucoughhenpernmadu7ibg","outgoingEdgeId":"aovnigvk665gzhyzg7bxhvn0"}],"graphCoordinates":{"x":-126.43,"y":220.29}},{"id":"nog2woqmvhssnnjlcpwd41k5","title":"Apresentação","blocks":[{"id":"potdr8jwrn6mnkjipynqjmhh","type":"Set variable","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"type":"Random ID","variableId":"vsu5or5sxes9lyuhsgcl3cuyd"}},{"id":"mcpyoq8x28bnwp23g7h1dbc1","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Olá! {{pushName}} Bem-vindo(a) à nossa "},{"bold":true,"text":"pesquisa de satisfação"},{"text":"."}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"o0731ch0epj2vm2c5aoxyvw1","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Meu nome é "},{"bold":true,"text":"🤖 Mike"},{"text":", estou aqui para ouvir sua opinião e experiência com nossos serviços."}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"twx683ok814enh3bwlaexe0t","type":"Wait","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"secondsToWaitFor":"5"}},{"id":"hgqbj5kmosz64cb435xqh0am","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Sua opinião é fundamental para nos ajudar a melhorar!"}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"cbvgdo0jknjyzmvwe6o614ni","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Vamos começar?"}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"vpj58atr9o534tjhhu0l0t0b","type":"Wait","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"secondsToWaitFor":"5"}},{"id":"nmhkn4jod3evk08tbq5vw3s3","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Qual o seu nome?"}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"o8ijci5gdfsp6fpv07kwh8br","type":"text input","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Digite o seu nome"},"variableId":"vo40px5r6wg9vhs9fixd45kzn"},"outgoingEdgeId":"vwx6ofz1ur8maxcbw8fk66x9"}],"graphCoordinates":{"x":771.26,"y":213}},{"id":"j5co2kcotxafuxhzlj7u0qnn","title":"Qual seu email?","blocks":[{"id":"he1367t9ssao735kidd86mna","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Muito bem {{name}}, agora me informe seu endereço de email?"}]}]},"groupId":"j5co2kcotxafuxhzlj7u0qnn"},{"id":"qb8nwfs52g168tmnvp257b44","type":"email input","groupId":"j5co2kcotxafuxhzlj7u0qnn","options":{"labels":{"button":"Enviar","placeholder":"Digite o seu email"},"variableId":"vr75l1drc5uoxvisje0hio5ph","retryMessageContent":"Email incorreto!"},"outgoingEdgeId":"v53mvhejcapb4a1zq98swq5b"}],"graphCoordinates":{"x":1236.92,"y":204.84}},{"id":"wtd0o382phaji7i7u2n8pody","title":"Pergunta 1","blocks":[{"id":"zr69lw3bcmmkgahqq8og7shw","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Em uma escala de 0 a 10, qual é o seu nível de satisfação geral com os serviços que nossa empresa fornece?"}]}]},"groupId":"wtd0o382phaji7i7u2n8pody"},{"id":"ku0zpu43cbbnd7y0ai71ptde","type":"rating input","groupId":"wtd0o382phaji7i7u2n8pody","options":{"labels":{"button":"Send"},"length":10,"buttonType":"Numbers","customIcon":{"isEnabled":false},"variableId":"vbfl3sqze2wzicn9l1n9ckjs4"},"outgoingEdgeId":"ed1x8zan90zvrpo9xk9moroe"}],"graphCoordinates":{"x":1692.4,"y":194.19}},{"id":"ylerbfc1l2o62j68g8ghegxt","title":"Pergunta 2","blocks":[{"id":"l19jgtpln9al473dudr0gbzn","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Em uma escala de 0 a 10, em que medida nossa empresa atendeu às suas expectativas em termos de qualidade do serviço prestado?"}]}]},"groupId":"ylerbfc1l2o62j68g8ghegxt"},{"id":"kfxuc6p58cdzy1xcyp4i4ra7","type":"rating input","groupId":"ylerbfc1l2o62j68g8ghegxt","options":{"labels":{"button":"Send"},"length":10,"buttonType":"Numbers","customIcon":{"isEnabled":false},"variableId":"vkgl2bfdbyms1dyc1s6efx678"},"outgoingEdgeId":"iy61ajcfl6ubbj7zghxeu6f7"}],"graphCoordinates":{"x":2156.14,"y":190.76}},{"id":"lbieknd0qp42pogsby5l82ww","title":"Pergunta 3","blocks":[{"id":"y43s12dnoxh772c9o3pmnhxf","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Você teve alguma dificuldade em se comunicar com nossa equipe de suporte ao cliente?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"lbieknd0qp42pogsby5l82ww"},{"id":"fb6ckchqp8vx9ypig07we6q4","type":"text input","groupId":"lbieknd0qp42pogsby5l82ww","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Responda com uma das opções"},"variableId":"vzhsu0uc4suqoz38kv3q891ma"}},{"id":"b538q1mt18l6oddo397nh1m4","type":"Condition","items":[{"id":"dwhc3ptqvktlgfvl17xg79s5","type":1,"blockId":"b538q1mt18l6oddo397nh1m4","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vzhsu0uc4suqoz38kv3q891ma","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"w6ao5pi6wt0966tobkned56m"},{"id":"cod3tkt16ry8ixm5u7rwxzm9","type":1,"blockId":"b538q1mt18l6oddo397nh1m4","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vzhsu0uc4suqoz38kv3q891ma","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"wlfmh2g3j5avj75sa9q6rsab"}],"groupId":"lbieknd0qp42pogsby5l82ww","outgoingEdgeId":"ehcwqdrkc4025pui2y1s9390"}],"graphCoordinates":{"x":2605.34,"y":189.93}},{"id":"qzhp25b9f2lvt4yeniqvjkav","title":"Pergunta 4","blocks":[{"id":"pos7njae2r35r29kcbyxtz2j","type":"text","content":{"richText":[{"type":"p","children":[{"text":"{{name}}, por favor, descreva o problema para que possamos melhorar."}]}]},"groupId":"qzhp25b9f2lvt4yeniqvjkav"},{"id":"ce2eodve0e4f2rubk4wv5jf1","type":"text input","groupId":"qzhp25b9f2lvt4yeniqvjkav","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Descreva o problema"},"variableId":"vd6fm2i9shcdjz8bhhwbsdh6t"},"outgoingEdgeId":"i11xudmpsb1tbsss7qoge6cm"}],"graphCoordinates":{"x":3041.23,"y":187.11}},{"id":"c8kh8eee1m3wyy372v4n6m1i","title":"Pergunta 5","blocks":[{"id":"txqi87lwinpa0p5of0xmqxu6","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Em uma escala de 0 a 10, como você avalia a capacidade da nossa empresa de cumprir os prazos acordados?"}]}]},"groupId":"c8kh8eee1m3wyy372v4n6m1i"},{"id":"mg2tmcmwnx3tap0hs4b7e0la","type":"rating input","groupId":"c8kh8eee1m3wyy372v4n6m1i","options":{"labels":{"button":"Enviar"},"length":10,"buttonType":"Numbers","customIcon":{"isEnabled":false},"variableId":"vz6lvahwo15dosvckdtkxduly"},"outgoingEdgeId":"c9nrzzcxt8w4dgk2sfez53n5"}],"graphCoordinates":{"x":3501.8,"y":179.58}},{"id":"tn8bcyughy9dsxhmjngrosvj","title":"Pergunta 6","blocks":[{"id":"aema350m33n9dljopcsxn8q5","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Você recomendaria nossos serviços para outras pessoas ou empresas?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"tn8bcyughy9dsxhmjngrosvj"},{"id":"wk4bkxbxcfu9skrzn8p8077u","type":"text input","groupId":"tn8bcyughy9dsxhmjngrosvj","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Responda com uma das opções"},"variableId":"vndjnalmnb3ez9beeon5tzrgq"}},{"id":"n3j2dxaalkljl020o0o61ef9","type":"Condition","items":[{"id":"ifhm8cj8lsulhrarnfda2oal","type":1,"blockId":"n3j2dxaalkljl020o0o61ef9","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vndjnalmnb3ez9beeon5tzrgq","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"yu9762ttf5jn3bmhd6uzrsv8"},{"id":"gxp6j3ouga4r0t8364tn8axs","type":1,"blockId":"n3j2dxaalkljl020o0o61ef9","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vndjnalmnb3ez9beeon5tzrgq","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"ji1y2o1hldhemto0ymwou09c"}],"groupId":"tn8bcyughy9dsxhmjngrosvj","outgoingEdgeId":"d3u83fikqplfy9ntva3sm7eg"}],"graphCoordinates":{"x":3926.41,"y":186.15}},{"id":"nzkhdw3hdv550aepsxvk2a0u","title":"Pergunta 7","blocks":[{"id":"io90onrpfrokejgkps94r3dj","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Que pena {{name}}, por gentileza, nos conte o motivo?"}]}]},"groupId":"nzkhdw3hdv550aepsxvk2a0u"},{"id":"dj7dbgyjqk0a5u3jn6kzykb2","type":"text input","groupId":"nzkhdw3hdv550aepsxvk2a0u","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Digite o motivo"},"variableId":"vept0w6tr0w7eyyi52hgq1r3c"},"outgoingEdgeId":"k7vrrf5cfxopvmhsbf35bt3m"}],"graphCoordinates":{"x":4352.64,"y":194.04}},{"id":"jdz9w8vrz09vefk4wqrf0vwl","title":"Pergunta 8","blocks":[{"id":"hndzyb58fqxudykajr22skla","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Existe alguma sugestão que você gostaria de nos dar para melhorar nossos serviços?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"jdz9w8vrz09vefk4wqrf0vwl"},{"id":"ol9l8fdb3q65auykrn383q6d","type":"text input","groupId":"jdz9w8vrz09vefk4wqrf0vwl","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Responda com uma das opções"},"variableId":"vy5it60mewmth7mayzhlgmzf0"}},{"id":"zderh9hqjkpuz58p79szfa1i","type":"Condition","items":[{"id":"lur26nqa8dv7m4jmmljpyyf1","type":1,"blockId":"zderh9hqjkpuz58p79szfa1i","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vy5it60mewmth7mayzhlgmzf0","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"x2fzu1uuukp9cgmdzecp7mgk"},{"id":"aoj7e49zimwxng4o7bd6u00s","type":1,"blockId":"zderh9hqjkpuz58p79szfa1i","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vy5it60mewmth7mayzhlgmzf0","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"mb1fg83gijikrafud2ml6zbn"}],"groupId":"jdz9w8vrz09vefk4wqrf0vwl","outgoingEdgeId":"amyrx4i2rm3cjksym5zvwd50"}],"graphCoordinates":{"x":4768.69,"y":201.49}},{"id":"c4k1ftb4rbynkb01ulwuh4qh","title":"Pergunta 9","blocks":[{"id":"jqn5de3i29ygjyf6usbj117t","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Qual seria a sua sugestão?"}]}]},"groupId":"c4k1ftb4rbynkb01ulwuh4qh"},{"id":"wfucksh3yaeq21l7mnlnsx75","type":"text input","groupId":"c4k1ftb4rbynkb01ulwuh4qh","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Deixe sua sugestão"},"variableId":"vhygxyvhu5l6r2uws1cbthmxm"},"outgoingEdgeId":"u8c55of7l95fnz25gf7swt1m"}],"graphCoordinates":{"x":5233.77,"y":205.27}},{"id":"vvyooiddvdbon0t21bvzdr7q","title":"Finalização","blocks":[{"id":"efk089lhks1ev4khy38caner","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Então {{name}}, agradecemos muito por dedicar um tempo para nos fornecer seu feedback."}]}]},"groupId":"vvyooiddvdbon0t21bvzdr7q"},{"id":"pvu3g8vpqdi3aecu2u0in2d0","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Sua opinião é muito importante para nós, e trabalharemos arduamente para melhorar ainda mais nossos serviços!"}]}]},"groupId":"vvyooiddvdbon0t21bvzdr7q"},{"id":"wqe9r1ivjf0ikubqichufzsg","type":"Webhook","groupId":"vvyooiddvdbon0t21bvzdr7q","options":{"isCustomBody":true,"isAdvancedConfig":true,"variablesForTest":[],"responseVariableMapping":[]},"webhookId":"i3g1959ev6fl9s61ir8hn1we"}],"graphCoordinates":{"x":7067.06,"y":231.55}},{"id":"ffm0s2y4head3auw808hwfnx","title":"Retorna Pergunta 3","blocks":[{"id":"ox70407atqtf1kwrszis4cix","type":"Set variable","groupId":"ffm0s2y4head3auw808hwfnx","options":{"type":"Empty","variableId":"vzhsu0uc4suqoz38kv3q891ma"}},{"id":"bcwkrcxtsc8drzwynb2igu0g","type":"Jump","groupId":"ffm0s2y4head3auw808hwfnx","options":{"groupId":"lbieknd0qp42pogsby5l82ww"}}],"graphCoordinates":{"x":3040.8,"y":772.28}},{"id":"cf8r0wx0sgw6c9v79ebja1tj","title":"Retorna Pergunta 6","blocks":[{"id":"e02yfpbpj298m1q9y4tb905i","type":"Set variable","groupId":"cf8r0wx0sgw6c9v79ebja1tj","options":{"type":"Empty","variableId":"vndjnalmnb3ez9beeon5tzrgq"}},{"id":"wjfe41oxiik0jgwcye7sczeu","type":"Jump","groupId":"cf8r0wx0sgw6c9v79ebja1tj","options":{"groupId":"tn8bcyughy9dsxhmjngrosvj"}}],"graphCoordinates":{"x":4360.16,"y":732.74}},{"id":"b7zfnwcxvu28s98ii03isdae","title":"Retorna Pergunta 8","blocks":[{"id":"j1xmpy60ggf162ej9a0rti4f","type":"Set variable","groupId":"b7zfnwcxvu28s98ii03isdae","options":{"type":"Empty","variableId":"vy5it60mewmth7mayzhlgmzf0"}},{"id":"lk06yb9dvrctn2u9tx35n12c","type":"Jump","groupId":"b7zfnwcxvu28s98ii03isdae","options":{"groupId":"jdz9w8vrz09vefk4wqrf0vwl"}}],"graphCoordinates":{"x":5213.21,"y":778}},{"id":"z0idhsnqisrd695z0j1tnqvw","title":"Retorna Pergunta 10","blocks":[{"id":"gs96ig682082mj4igcjjuh76","type":"Set variable","groupId":"z0idhsnqisrd695z0j1tnqvw","options":{"type":"Empty","variableId":"vx6p4ivk4mnssvbhl30c5zng9"}},{"id":"tihlp1xm8mvpdm3d0dqkwwx6","type":"Jump","groupId":"z0idhsnqisrd695z0j1tnqvw","options":{"groupId":"cs5kjnrcsh4bjiuvwf99agho"}}],"graphCoordinates":{"x":6100.86,"y":819.65}},{"id":"qsrkmfsr04kayulair47gmn0","title":"Gera QRCODE pix","blocks":[{"id":"qs1uxqm8jqla9uui43ofms65","type":"Webhook","groupId":"qsrkmfsr04kayulair47gmn0","options":{"isCustomBody":true,"isAdvancedConfig":true,"variablesForTest":[],"responseVariableMapping":[{"id":"gcia6kdba4yydt14klsg8h6x","bodyPath":"data.qrcode_base64","variableId":"vamn8ortov9nk1y04vczo375h"}]},"webhookId":"ajx8mv7trd50mbv2uj6fr3x5"},{"id":"sz447ty7t4vreto9bf07h52i","type":"Set variable","groupId":"qsrkmfsr04kayulair47gmn0","options":{"type":"Custom","variableId":"vamn8ortov9nk1y04vczo375h","expressionToEvaluate":"if({{remoteJid}}){\n return {{qrcode}}.replace('data:image/png;base64,', ''); \n}else{\n return {{qrcode}}\n}\n"}},{"id":"c3wp5ic2wx9emj6kkii42xpj","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Aqui está qrcode para sua contribuição de R$ {{question11}}, caso tenha dificuldade na leitura utilize a nossa chave:"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"Telefone: 7499879409"}]},{"type":"p","children":[{"text":"Em nome de: Davidson Oliveira Gomes"}]}]},"groupId":"qsrkmfsr04kayulair47gmn0"},{"id":"jncggap4fivalzgntw3bfaom","type":"image","content":{"url":"{{qrcode}}"},"groupId":"qsrkmfsr04kayulair47gmn0"},{"id":"chiz9utw18jvui4c2r0vsiqp","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Muito obrigado pela sua contribuição!"}]}]},"groupId":"qsrkmfsr04kayulair47gmn0","outgoingEdgeId":"cwlt91vwhr7gvgx0qx2mnxtr"}],"graphCoordinates":{"x":6607.75,"y":229.53}},{"id":"cs5kjnrcsh4bjiuvwf99agho","title":"Pergunta 10","blocks":[{"id":"axpk3aoauusbiy8av70fc2fo","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Gostaria de fazer uma contribuição?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"cs5kjnrcsh4bjiuvwf99agho"},{"id":"q136n37ja1g5dyhdeisur4rg","type":"text input","groupId":"cs5kjnrcsh4bjiuvwf99agho","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Deixe sua resposta"},"variableId":"vx6p4ivk4mnssvbhl30c5zng9"}},{"id":"xza6e0p4hgkfz1wvwcjss48s","type":"Condition","items":[{"id":"m5mvt5ecw81eevl428n56aji","type":1,"blockId":"xza6e0p4hgkfz1wvwcjss48s","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vx6p4ivk4mnssvbhl30c5zng9","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"fe1wk4fc1xzt7mefasb2qzqz"},{"id":"bpcidulg0g7v8pwh3w9my880","type":1,"blockId":"xza6e0p4hgkfz1wvwcjss48s","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vx6p4ivk4mnssvbhl30c5zng9","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"xg1zkpvob8ilx2r8p0kv604d"}],"groupId":"cs5kjnrcsh4bjiuvwf99agho","outgoingEdgeId":"o746eh96sq2j7juionfql73t"}],"graphCoordinates":{"x":5708.94,"y":210.9}},{"id":"tq60r6azxrmn17b4y7mjovf5","title":"Pergunta 11","blocks":[{"id":"o5fspfge731wt6m781nzjsll","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Muito bem {{name}}, quanto você deseja contribuir?"}]}]},"groupId":"tq60r6azxrmn17b4y7mjovf5"},{"id":"khncvmg5fcjsmu8tlmf8in6m","type":"number input","groupId":"tq60r6azxrmn17b4y7mjovf5","options":{"max":5000,"min":1,"step":1,"labels":{"button":"Enviar","placeholder":"Digite um numero"},"variableId":"vhoqah2c0blbx92bfmd4gjnyx"},"outgoingEdgeId":"ns2kch8n15uklzwf8kn4m0lb"}],"graphCoordinates":{"x":6158.94,"y":224.91}},{"id":"h0svx6gyzgjsclr9hbpo04v6","title":"Configurações Iniciais","blocks":[{"id":"na4zglpatkg8ejqcap8lcv69","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vp1ask55v2r58ukom5lek5hej","expressionToEvaluate":"https://d715-45-39-187-135.ngrok-free.app"}},{"id":"t2bdxy8x8fsn29yijk02ti43","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vtsldvs2u8ui93tktazy77djw","expressionToEvaluate":"0f1c6e17-5a6a-4989-8c12-a7e7350870fe"}},{"id":"rt5h0lk6jaoh5hzag0s5hidd","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vkg1qlinovziltaloqhso2cw7","expressionToEvaluate":"https://pix.dgcode.com.br"}},{"id":"mh758b8y8288t56s6wz73mht","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vpjyy2e2ha6mu5x10q0nowuz3","expressionToEvaluate":"Davidson Oliveira Gomes"}},{"id":"ri9kv80djsej7r51m8xfjhuk","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vicsm3nkvhssvfhgss2xce2ad","expressionToEvaluate":"Telefone"}},{"id":"ye4teva02mnxph0rvfszdnsn","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vlmflx32cjlz457h0uzdi706g","expressionToEvaluate":"74999879409"}},{"id":"hfz4hqzfe6wgje96ezb5kann","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"veesfw943copg17w2qzdln9be","expressionToEvaluate":"Irece"}},{"id":"nd3yk369k7j73kws6exos0jw","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vavwvk4wgst506zdioplg4u8p","expressionToEvaluate":"TypeBot"},"outgoingEdgeId":"mb90csrzzep8qz2opcxmw736"}],"graphCoordinates":{"x":312.08,"y":218.28}}],"variables":[{"id":"vo40px5r6wg9vhs9fixd45kzn","name":"name"},{"id":"vr75l1drc5uoxvisje0hio5ph","name":"email"},{"id":"vzhsu0uc4suqoz38kv3q891ma","name":"question3"},{"id":"vbfl3sqze2wzicn9l1n9ckjs4","name":"question1"},{"id":"vkgl2bfdbyms1dyc1s6efx678","name":"question2"},{"id":"vd6fm2i9shcdjz8bhhwbsdh6t","name":"question4"},{"id":"vz6lvahwo15dosvckdtkxduly","name":"question5"},{"id":"vndjnalmnb3ez9beeon5tzrgq","name":"question6"},{"id":"vept0w6tr0w7eyyi52hgq1r3c","name":"question7"},{"id":"vy5it60mewmth7mayzhlgmzf0","name":"question8"},{"id":"vhygxyvhu5l6r2uws1cbthmxm","name":"question9"},{"id":"vrdwfo2lpoei2fzlzazh4pp61","name":"pushName"},{"id":"vz1uq7t77aivpi5crwy6ifact","name":"remoteJid"},{"id":"vsu5or5sxes9lyuhsgcl3cuyd","name":"ID"},{"id":"vamn8ortov9nk1y04vczo375h","name":"qrcode"},{"id":"vx6p4ivk4mnssvbhl30c5zng9","name":"question10"},{"id":"vhoqah2c0blbx92bfmd4gjnyx","name":"question11"},{"id":"vpjyy2e2ha6mu5x10q0nowuz3","name":"me"},{"id":"vicsm3nkvhssvfhgss2xce2ad","name":"typePIX"},{"id":"vavwvk4wgst506zdioplg4u8p","name":"reference"},{"id":"vlmflx32cjlz457h0uzdi706g","name":"keyPIX"},{"id":"vkg1qlinovziltaloqhso2cw7","name":"apiURL"},{"id":"veesfw943copg17w2qzdln9be","name":"city"},{"id":"vp1ask55v2r58ukom5lek5hej","name":"evolutionURL"},{"id":"vtsldvs2u8ui93tktazy77djw","name":"evolutionToken"},{"id":"vpoyfwgfw4tbt4l4iy4homfoq","name":"instanceName"}],"edges":[{"id":"w6ao5pi6wt0966tobkned56m","to":{"groupId":"qzhp25b9f2lvt4yeniqvjkav"},"from":{"itemId":"dwhc3ptqvktlgfvl17xg79s5","blockId":"b538q1mt18l6oddo397nh1m4","groupId":"lbieknd0qp42pogsby5l82ww"}},{"id":"wlfmh2g3j5avj75sa9q6rsab","to":{"groupId":"tn8bcyughy9dsxhmjngrosvj"},"from":{"itemId":"cod3tkt16ry8ixm5u7rwxzm9","blockId":"b538q1mt18l6oddo397nh1m4","groupId":"lbieknd0qp42pogsby5l82ww"}},{"id":"yu9762ttf5jn3bmhd6uzrsv8","to":{"groupId":"jdz9w8vrz09vefk4wqrf0vwl"},"from":{"itemId":"ifhm8cj8lsulhrarnfda2oal","blockId":"n3j2dxaalkljl020o0o61ef9","groupId":"tn8bcyughy9dsxhmjngrosvj"}},{"id":"ji1y2o1hldhemto0ymwou09c","to":{"groupId":"nzkhdw3hdv550aepsxvk2a0u"},"from":{"itemId":"gxp6j3ouga4r0t8364tn8axs","blockId":"n3j2dxaalkljl020o0o61ef9","groupId":"tn8bcyughy9dsxhmjngrosvj"}},{"id":"x2fzu1uuukp9cgmdzecp7mgk","to":{"groupId":"c4k1ftb4rbynkb01ulwuh4qh"},"from":{"itemId":"lur26nqa8dv7m4jmmljpyyf1","blockId":"zderh9hqjkpuz58p79szfa1i","groupId":"jdz9w8vrz09vefk4wqrf0vwl"}},{"id":"d3u83fikqplfy9ntva3sm7eg","to":{"groupId":"cf8r0wx0sgw6c9v79ebja1tj"},"from":{"blockId":"n3j2dxaalkljl020o0o61ef9","groupId":"tn8bcyughy9dsxhmjngrosvj"}},{"id":"ehcwqdrkc4025pui2y1s9390","to":{"groupId":"ffm0s2y4head3auw808hwfnx"},"from":{"blockId":"b538q1mt18l6oddo397nh1m4","groupId":"lbieknd0qp42pogsby5l82ww"}},{"id":"mb1fg83gijikrafud2ml6zbn","to":{"groupId":"cs5kjnrcsh4bjiuvwf99agho"},"from":{"itemId":"aoj7e49zimwxng4o7bd6u00s","blockId":"zderh9hqjkpuz58p79szfa1i","groupId":"jdz9w8vrz09vefk4wqrf0vwl"}},{"id":"amyrx4i2rm3cjksym5zvwd50","to":{"groupId":"b7zfnwcxvu28s98ii03isdae"},"from":{"blockId":"zderh9hqjkpuz58p79szfa1i","groupId":"jdz9w8vrz09vefk4wqrf0vwl"}},{"id":"o746eh96sq2j7juionfql73t","to":{"groupId":"z0idhsnqisrd695z0j1tnqvw"},"from":{"blockId":"xza6e0p4hgkfz1wvwcjss48s","groupId":"cs5kjnrcsh4bjiuvwf99agho"}},{"id":"fe1wk4fc1xzt7mefasb2qzqz","to":{"groupId":"tq60r6azxrmn17b4y7mjovf5"},"from":{"itemId":"m5mvt5ecw81eevl428n56aji","blockId":"xza6e0p4hgkfz1wvwcjss48s","groupId":"cs5kjnrcsh4bjiuvwf99agho"}},{"id":"xg1zkpvob8ilx2r8p0kv604d","to":{"groupId":"vvyooiddvdbon0t21bvzdr7q"},"from":{"itemId":"bpcidulg0g7v8pwh3w9my880","blockId":"xza6e0p4hgkfz1wvwcjss48s","groupId":"cs5kjnrcsh4bjiuvwf99agho"}},{"id":"cwlt91vwhr7gvgx0qx2mnxtr","to":{"groupId":"vvyooiddvdbon0t21bvzdr7q"},"from":{"blockId":"chiz9utw18jvui4c2r0vsiqp","groupId":"qsrkmfsr04kayulair47gmn0"}},{"id":"aovnigvk665gzhyzg7bxhvn0","to":{"groupId":"h0svx6gyzgjsclr9hbpo04v6"},"from":{"blockId":"qn40kjwtw1he3l1bujt3bnje","groupId":"c76ucoughhenpernmadu7ibg"}},{"id":"mb90csrzzep8qz2opcxmw736","to":{"groupId":"nog2woqmvhssnnjlcpwd41k5"},"from":{"blockId":"nd3yk369k7j73kws6exos0jw","groupId":"h0svx6gyzgjsclr9hbpo04v6"}},{"id":"vwx6ofz1ur8maxcbw8fk66x9","to":{"groupId":"j5co2kcotxafuxhzlj7u0qnn"},"from":{"blockId":"o8ijci5gdfsp6fpv07kwh8br","groupId":"nog2woqmvhssnnjlcpwd41k5"}},{"id":"v53mvhejcapb4a1zq98swq5b","to":{"groupId":"wtd0o382phaji7i7u2n8pody"},"from":{"blockId":"qb8nwfs52g168tmnvp257b44","groupId":"j5co2kcotxafuxhzlj7u0qnn"}},{"id":"ed1x8zan90zvrpo9xk9moroe","to":{"groupId":"ylerbfc1l2o62j68g8ghegxt"},"from":{"blockId":"ku0zpu43cbbnd7y0ai71ptde","groupId":"wtd0o382phaji7i7u2n8pody"}},{"id":"iy61ajcfl6ubbj7zghxeu6f7","to":{"groupId":"lbieknd0qp42pogsby5l82ww"},"from":{"blockId":"kfxuc6p58cdzy1xcyp4i4ra7","groupId":"ylerbfc1l2o62j68g8ghegxt"}},{"id":"i11xudmpsb1tbsss7qoge6cm","to":{"groupId":"c8kh8eee1m3wyy372v4n6m1i"},"from":{"blockId":"ce2eodve0e4f2rubk4wv5jf1","groupId":"qzhp25b9f2lvt4yeniqvjkav"}},{"id":"c9nrzzcxt8w4dgk2sfez53n5","to":{"groupId":"tn8bcyughy9dsxhmjngrosvj"},"from":{"blockId":"mg2tmcmwnx3tap0hs4b7e0la","groupId":"c8kh8eee1m3wyy372v4n6m1i"}},{"id":"k7vrrf5cfxopvmhsbf35bt3m","to":{"groupId":"jdz9w8vrz09vefk4wqrf0vwl"},"from":{"blockId":"dj7dbgyjqk0a5u3jn6kzykb2","groupId":"nzkhdw3hdv550aepsxvk2a0u"}},{"id":"u8c55of7l95fnz25gf7swt1m","to":{"groupId":"cs5kjnrcsh4bjiuvwf99agho"},"from":{"blockId":"wfucksh3yaeq21l7mnlnsx75","groupId":"c4k1ftb4rbynkb01ulwuh4qh"}},{"id":"ns2kch8n15uklzwf8kn4m0lb","to":{"groupId":"qsrkmfsr04kayulair47gmn0"},"from":{"blockId":"khncvmg5fcjsmu8tlmf8in6m","groupId":"tq60r6azxrmn17b4y7mjovf5"}}],"theme":{"chat":{"inputs":{"color":"#ffffff","backgroundColor":"#1e293b","placeholderColor":"#9095A0"},"buttons":{"color":"#ffffff","backgroundColor":"#1a5fff"},"roundness":"large","hostAvatar":{"isEnabled":true},"guestAvatar":{"isEnabled":false},"hostBubbles":{"color":"#ffffff","backgroundColor":"#1e293b"},"guestBubbles":{"color":"#FFFFFF","backgroundColor":"#FF8E21"}},"general":{"font":"Open Sans","background":{"type":"Color","content":"#171923"}}},"selectedThemeTemplateId":"typebot-dark","settings":{"general":{"isBrandingEnabled":false},"metadata":{"imageUrl":"https://i.imgur.com/48TjKBb.jpg","description":"Sua opinião é fundamental para nos ajudar a melhorar!"},"typingEmulation":{"speed":300,"enabled":true,"maxDelay":1.5}},"publicId":"dgcode-pesquisa-satisfacao-whatsapp-7m64d9o","customDomain":null,"workspaceId":"clktt8c1y0001qa66zyg5tt23","resultsTablePreferences":null,"isArchived":false,"isClosed":false} \ No newline at end of file diff --git a/package.json b/package.json index 6f92aaf3..275e2b41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "evolution-api", - "version": "1.5.0", + "version": "1.5.1", "description": "Rest api for communication with WhatsApp", "main": "./dist/src/main.js", "scripts": { @@ -69,6 +69,7 @@ "mongoose": "^6.10.5", "node-cache": "^5.1.2", "node-mime-types": "^1.1.0", + "node-windows": "^1.0.0-beta.8", "pino": "^8.11.0", "proxy-agent": "^6.3.0", "qrcode": "^1.5.1", @@ -76,6 +77,7 @@ "redis": "^4.6.5", "sharp": "^0.30.7", "socket.io": "^4.7.1", + "socks-proxy-agent": "^8.0.1", "uuid": "^9.0.0" }, "devDependencies": { @@ -86,6 +88,7 @@ "@types/jsonwebtoken": "^8.5.9", "@types/mime-types": "^2.1.1", "@types/node": "^18.15.11", + "@types/node-windows": "^0.1.2", "@types/qrcode": "^1.5.0", "@types/qrcode-terminal": "^0.12.0", "@types/uuid": "^8.3.4", diff --git a/src/config/env.config.ts b/src/config/env.config.ts index 9c63b893..e4995aab 100644 --- a/src/config/env.config.ts +++ b/src/config/env.config.ts @@ -92,6 +92,11 @@ export type EventsWebhook = { GROUP_PARTICIPANTS_UPDATE: boolean; CALL: boolean; NEW_JWT_TOKEN: boolean; + TYPEBOT_START: boolean; + TYPEBOT_CHANGE_STATUS: boolean; + CHAMA_AI_ACTION: boolean; + ERRORS: boolean; + ERRORS_WEBHOOK: string; }; export type ApiKey = { KEY: string }; @@ -166,17 +171,17 @@ export class ConfigService { return { SERVER: { TYPE: process.env.SERVER_TYPE as 'http' | 'https', - PORT: Number.parseInt(process.env.SERVER_PORT), + PORT: Number.parseInt(process.env.SERVER_PORT) || 8080, URL: process.env.SERVER_URL, }, CORS: { - ORIGIN: process.env.CORS_ORIGIN.split(','), - METHODS: process.env.CORS_METHODS.split(',') as HttpMethods[], + ORIGIN: process.env.CORS_ORIGIN.split(',') || ['*'], + METHODS: (process.env.CORS_METHODS.split(',') as HttpMethods[]) || ['POST', 'GET', 'PUT', 'DELETE'], CREDENTIALS: process.env?.CORS_CREDENTIALS === 'true', }, SSL_CONF: { - PRIVKEY: process.env?.SSL_CONF_PRIVKEY, - FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN, + PRIVKEY: process.env?.SSL_CONF_PRIVKEY || '', + FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN || '', }, STORE: { MESSAGES: process.env?.STORE_MESSAGES === 'true', @@ -195,8 +200,8 @@ export class ConfigService { }, DATABASE: { CONNECTION: { - URI: process.env.DATABASE_CONNECTION_URI, - DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME, + URI: process.env.DATABASE_CONNECTION_URI || '', + DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME || 'evolution', }, ENABLED: process.env?.DATABASE_ENABLED === 'true', SAVE_DATA: { @@ -209,27 +214,36 @@ export class ConfigService { }, REDIS: { ENABLED: process.env?.REDIS_ENABLED === 'true', - URI: process.env.REDIS_URI, - PREFIX_KEY: process.env.REDIS_PREFIX_KEY, + URI: process.env.REDIS_URI || '', + PREFIX_KEY: process.env.REDIS_PREFIX_KEY || 'evolution', }, RABBITMQ: { ENABLED: process.env?.RABBITMQ_ENABLED === 'true', - URI: process.env.RABBITMQ_URI, + URI: process.env.RABBITMQ_URI || '', }, WEBSOCKET: { ENABLED: process.env?.WEBSOCKET_ENABLED === 'true', }, LOG: { - LEVEL: process.env?.LOG_LEVEL.split(',') as LogLevel[], + LEVEL: (process.env?.LOG_LEVEL.split(',') as LogLevel[]) || [ + 'ERROR', + 'WARN', + 'DEBUG', + 'INFO', + 'LOG', + 'VERBOSE', + 'DARK', + 'WEBHOOKS', + ], COLOR: process.env?.LOG_COLOR === 'true', BAILEYS: (process.env?.LOG_BAILEYS as LogBaileys) || 'error', }, - DEL_INSTANCE: process.env?.DEL_INSTANCE === 'true' - ? 5 + DEL_INSTANCE: isBooleanString(process.env?.DEL_INSTANCE) + ? process.env.DEL_INSTANCE === 'true' : Number.parseInt(process.env.DEL_INSTANCE) || false, WEBHOOK: { GLOBAL: { - URL: process.env?.WEBHOOK_GLOBAL_URL, + URL: process.env?.WEBHOOK_GLOBAL_URL || '', ENABLED: process.env?.WEBHOOK_GLOBAL_ENABLED === 'true', WEBHOOK_BY_EVENTS: process.env?.WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS === 'true', }, @@ -255,27 +269,32 @@ export class ConfigService { GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true', CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true', NEW_JWT_TOKEN: process.env?.WEBHOOK_EVENTS_NEW_JWT_TOKEN === 'true', + TYPEBOT_START: process.env?.WEBHOOK_EVENTS_TYPEBOT_START === 'true', + TYPEBOT_CHANGE_STATUS: process.env?.WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS === 'true', + CHAMA_AI_ACTION: process.env?.WEBHOOK_EVENTS_CHAMA_AI_ACTION === 'true', + ERRORS: process.env?.WEBHOOK_EVENTS_ERRORS === 'true', + ERRORS_WEBHOOK: process.env?.WEBHOOK_EVENTS_ERRORS_WEBHOOK || '', }, }, CONFIG_SESSION_PHONE: { CLIENT: process.env?.CONFIG_SESSION_PHONE_CLIENT || 'Evolution API', - NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'chrome', + NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'Chrome', }, QRCODE: { LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30, COLOR: process.env.QRCODE_COLOR || '#198754', }, AUTHENTICATION: { - TYPE: process.env.AUTHENTICATION_TYPE as 'jwt', + TYPE: process.env.AUTHENTICATION_TYPE as 'apikey', API_KEY: { - KEY: process.env.AUTHENTICATION_API_KEY, + KEY: process.env.AUTHENTICATION_API_KEY || 'BQYHJGJHJ', }, EXPOSE_IN_FETCH_INSTANCES: process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true', JWT: { EXPIRIN_IN: Number.isInteger(process.env?.AUTHENTICATION_JWT_EXPIRIN_IN) ? Number.parseInt(process.env.AUTHENTICATION_JWT_EXPIRIN_IN) : 3600, - SECRET: process.env.AUTHENTICATION_JWT_SECRET, + SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`', }, }, }; diff --git a/src/config/error.config.ts b/src/config/error.config.ts index 6449d52e..7a6717da 100644 --- a/src/config/error.config.ts +++ b/src/config/error.config.ts @@ -8,6 +8,7 @@ export function onUnexpectedError() { stderr: process.stderr.fd, error, }); + process.exit(1); }); process.on('unhandledRejection', (error, origin) => { @@ -17,5 +18,6 @@ export function onUnexpectedError() { stderr: process.stderr.fd, error, }); + process.exit(1); }); } diff --git a/src/dev-env.yml b/src/dev-env.yml index 235ec1b7..e670f1ec 100644 --- a/src/dev-env.yml +++ b/src/dev-env.yml @@ -83,7 +83,7 @@ RABBITMQ: ENABLED: false URI: "amqp://guest:guest@localhost:5672" -WEBSOCKET: +WEBSOCKET: ENABLED: false # Global Webhook Settings @@ -120,16 +120,24 @@ WEBHOOK: CALL: true # This event fires every time a new token is requested via the refresh route NEW_JWT_TOKEN: false + # This events is used with Typebot + TYPEBOT_START: false + TYPEBOT_CHANGE_STATUS: false + # This event is used with Chama AI + CHAMA_AI_ACTION: false + # This event is used to send errors to the webhook + ERRORS: false + ERRORS_WEBHOOK: CONFIG_SESSION_PHONE: # Name that will be displayed on smartphone connection CLIENT: "Evolution API" - NAME: chrome # chrome | firefox | edge | opera | safari + NAME: Chrome # Chrome | Firefox | Edge | Opera | Safari # Set qrcode display limit QRCODE: LIMIT: 30 - COLOR: '#198754' + COLOR: "#198754" # Defines an authentication type for the api # We recommend using the apikey because it will allow you to use a custom token, @@ -145,4 +153,4 @@ AUTHENTICATION: # Set the secret key to encrypt and decrypt your token and its expiration time. JWT: EXPIRIN_IN: 0 # seconds - 3600s === 1h | zero (0) - never expires - SECRET: L=0YWt]b2w[WF>#>:&E` \ No newline at end of file + SECRET: L=0YWt]b2w[WF>#>:&E` diff --git a/src/libs/amqp.server.ts b/src/libs/amqp.server.ts index cc0f13b5..18b82c52 100644 --- a/src/libs/amqp.server.ts +++ b/src/libs/amqp.server.ts @@ -41,3 +41,33 @@ export const initAMQP = () => { export const getAMQP = (): amqp.Channel | null => { return amqpChannel; }; + +export const initQueues = (instanceName: string, events: string[]) => { + if (!events || !events.length) return; + + const queues = events.map((event) => { + return `${event.replace(/_/g, '.').toLowerCase()}`; + }); + + queues.forEach((event) => { + const amqp = getAMQP(); + const exchangeName = instanceName ?? 'evolution_exchange'; + + amqp.assertExchange(exchangeName, 'topic', { + durable: true, + autoDelete: false, + }); + + const queueName = `${instanceName}.${event}`; + + amqp.assertQueue(queueName, { + durable: true, + autoDelete: false, + arguments: { + 'x-queue-type': 'quorum', + }, + }); + + amqp.bindQueue(queueName, exchangeName, event); + }); +}; diff --git a/src/libs/redis.client.ts b/src/libs/redis.client.ts index dffeb949..f03513ba 100644 --- a/src/libs/redis.client.ts +++ b/src/libs/redis.client.ts @@ -5,6 +5,10 @@ import { Redis } from '../config/env.config'; import { Logger } from '../config/logger.config'; export class RedisCache { + async disconnect() { + await this.client.disconnect(); + this.statusConnection = false; + } constructor() { this.logger.verbose('instance created'); process.on('beforeExit', async () => { diff --git a/src/main.ts b/src/main.ts index 75dd95b3..167909b1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,11 +1,12 @@ import 'express-async-errors'; +import axios from 'axios'; import compression from 'compression'; import cors from 'cors'; import express, { json, NextFunction, Request, Response, urlencoded } from 'express'; import { join } from 'path'; -import { configService, Cors, HttpServer, Rabbitmq } from './config/env.config'; +import { configService, Cors, HttpServer, Rabbitmq, Webhook } from './config/env.config'; import { onUnexpectedError } from './config/error.config'; import { Logger } from './config/logger.config'; import { ROOT_DIR } from './config/path.config'; @@ -47,11 +48,41 @@ function bootstrap() { app.set('views', join(ROOT_DIR, 'views')); app.use(express.static(join(ROOT_DIR, 'public'))); + app.use('/store', express.static(join(ROOT_DIR, 'store'))); + app.use('/', router); app.use( (err: Error, req: Request, res: Response, next: NextFunction) => { if (err) { + const webhook = configService.get('WEBHOOK'); + + if (webhook.EVENTS.ERRORS_WEBHOOK && webhook.EVENTS.ERRORS_WEBHOOK != '' && webhook.EVENTS.ERRORS) { + const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds + const localISOTime = new Date(Date.now() - tzoffset).toISOString(); + const now = localISOTime; + + const errorData = { + event: 'error', + data: { + error: err['error'] || 'Internal Server Error', + message: err['message'] || 'Internal Server Error', + status: err['status'] || 500, + response: { + message: err['message'] || 'Internal Server Error', + }, + }, + date_time: now, + }; + + logger.error(errorData); + + const baseURL = webhook.EVENTS.ERRORS_WEBHOOK; + const httpService = axios.create({ baseURL }); + + httpService.post('', errorData); + } + return res.status(err['status'] || 500).json({ status: err['status'] || 500, error: err['error'] || 'Internal Server Error', diff --git a/src/validate/validate.schema.ts b/src/validate/validate.schema.ts index bce05660..b8a4c0ad 100644 --- a/src/validate/validate.schema.ts +++ b/src/validate/validate.schema.ts @@ -55,6 +55,9 @@ export const instanceNameSchema: JSONSchema7 = { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ], }, }, @@ -856,6 +859,9 @@ export const webhookSchema: JSONSchema7 = { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ], }, }, @@ -927,6 +933,9 @@ export const websocketSchema: JSONSchema7 = { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ], }, }, @@ -967,6 +976,9 @@ export const rabbitmqSchema: JSONSchema7 = { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ], }, }, @@ -985,9 +997,10 @@ export const typebotSchema: JSONSchema7 = { expire: { type: 'integer' }, delay_message: { type: 'integer' }, unknown_message: { type: 'string' }, + listening_from_me: { type: 'boolean', enum: [true, false] }, }, - required: ['enabled', 'url', 'typebot', 'expire'], - ...isNotEmpty('enabled', 'url', 'typebot', 'expire'), + required: ['enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'], + ...isNotEmpty('enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'), }; export const typebotStatusSchema: JSONSchema7 = { @@ -1023,3 +1036,17 @@ export const proxySchema: JSONSchema7 = { required: ['enabled', 'proxy'], ...isNotEmpty('enabled', 'proxy'), }; + +export const chamaaiSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean', enum: [true, false] }, + url: { type: 'string' }, + token: { type: 'string' }, + waNumber: { type: 'string' }, + answerByAudio: { type: 'boolean', enum: [true, false] }, + }, + required: ['enabled', 'url', 'token', 'waNumber', 'answerByAudio'], + ...isNotEmpty('enabled', 'url', 'token', 'waNumber', 'answerByAudio'), +}; diff --git a/src/whatsapp/controllers/chamaai.controller.ts b/src/whatsapp/controllers/chamaai.controller.ts new file mode 100644 index 00000000..e9cafb50 --- /dev/null +++ b/src/whatsapp/controllers/chamaai.controller.ts @@ -0,0 +1,29 @@ +import { Logger } from '../../config/logger.config'; +import { ChamaaiDto } from '../dto/chamaai.dto'; +import { InstanceDto } from '../dto/instance.dto'; +import { ChamaaiService } from '../services/chamaai.service'; + +const logger = new Logger('ChamaaiController'); + +export class ChamaaiController { + constructor(private readonly chamaaiService: ChamaaiService) {} + + public async createChamaai(instance: InstanceDto, data: ChamaaiDto) { + logger.verbose('requested createChamaai from ' + instance.instanceName + ' instance'); + + if (!data.enabled) { + logger.verbose('chamaai disabled'); + data.url = ''; + data.token = ''; + data.waNumber = ''; + data.answerByAudio = false; + } + + return this.chamaaiService.create(instance, data); + } + + public async findChamaai(instance: InstanceDto) { + logger.verbose('requested findChamaai from ' + instance.instanceName + ' instance'); + return this.chamaaiService.find(instance); + } +} diff --git a/src/whatsapp/controllers/instance.controller.ts b/src/whatsapp/controllers/instance.controller.ts index 2a904761..8d0e21ca 100644 --- a/src/whatsapp/controllers/instance.controller.ts +++ b/src/whatsapp/controllers/instance.controller.ts @@ -67,6 +67,7 @@ export class InstanceController { typebot_keyword_finish, typebot_delay_message, typebot_unknown_message, + typebot_listening_from_me, }: InstanceDto) { try { this.logger.verbose('requested createInstance from ' + instanceName + ' instance'); @@ -126,6 +127,9 @@ export class InstanceController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ]; } else { newEvents = events; @@ -172,9 +176,12 @@ export class InstanceController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ]; } else { - newEvents = events; + newEvents = websocket_events; } this.websocketService.create(instance, { enabled: true, @@ -216,9 +223,12 @@ export class InstanceController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ]; } else { - newEvents = events; + newEvents = rabbitmq_events; } this.rabbitmqService.create(instance, { enabled: true, @@ -247,6 +257,7 @@ export class InstanceController { keyword_finish: typebot_keyword_finish, delay_message: typebot_delay_message, unknown_message: typebot_unknown_message, + listening_from_me: typebot_listening_from_me, }); } catch (error) { this.logger.log(error); @@ -304,6 +315,7 @@ export class InstanceController { keyword_finish: typebot_keyword_finish, delay_message: typebot_delay_message, unknown_message: typebot_unknown_message, + listening_from_me: typebot_listening_from_me, }, settings, qrcode: getQrcode, @@ -396,6 +408,7 @@ export class InstanceController { keyword_finish: typebot_keyword_finish, delay_message: typebot_delay_message, unknown_message: typebot_unknown_message, + listening_from_me: typebot_listening_from_me, }, settings, chatwoot: { @@ -482,12 +495,13 @@ export class InstanceController { } public async fetchInstances({ instanceName }: InstanceDto) { - this.logger.verbose('requested fetchInstances from ' + instanceName + ' instance'); if (instanceName) { + this.logger.verbose('requested fetchInstances from ' + instanceName + ' instance'); this.logger.verbose('instanceName: ' + instanceName); return this.waMonitor.instanceInfo(instanceName); } + this.logger.verbose('requested fetchInstances (all instances)'); return this.waMonitor.instanceInfo(); } diff --git a/src/whatsapp/controllers/rabbitmq.controller.ts b/src/whatsapp/controllers/rabbitmq.controller.ts index 4efd1c3f..8d33ce84 100644 --- a/src/whatsapp/controllers/rabbitmq.controller.ts +++ b/src/whatsapp/controllers/rabbitmq.controller.ts @@ -40,6 +40,9 @@ export class RabbitmqController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ]; } diff --git a/src/whatsapp/controllers/webhook.controller.ts b/src/whatsapp/controllers/webhook.controller.ts index 5515b8cc..8201f1b5 100644 --- a/src/whatsapp/controllers/webhook.controller.ts +++ b/src/whatsapp/controllers/webhook.controller.ts @@ -48,6 +48,9 @@ export class WebhookController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ]; } diff --git a/src/whatsapp/controllers/websocket.controller.ts b/src/whatsapp/controllers/websocket.controller.ts index fb6bea0f..5771027a 100644 --- a/src/whatsapp/controllers/websocket.controller.ts +++ b/src/whatsapp/controllers/websocket.controller.ts @@ -40,6 +40,9 @@ export class WebsocketController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ]; } diff --git a/src/whatsapp/dto/chamaai.dto.ts b/src/whatsapp/dto/chamaai.dto.ts new file mode 100644 index 00000000..2c71a07d --- /dev/null +++ b/src/whatsapp/dto/chamaai.dto.ts @@ -0,0 +1,7 @@ +export class ChamaaiDto { + enabled: boolean; + url: string; + token: string; + waNumber: string; + answerByAudio: boolean; +} diff --git a/src/whatsapp/dto/instance.dto.ts b/src/whatsapp/dto/instance.dto.ts index cffe0303..7807d1a5 100644 --- a/src/whatsapp/dto/instance.dto.ts +++ b/src/whatsapp/dto/instance.dto.ts @@ -28,6 +28,7 @@ export class InstanceDto { typebot_keyword_finish?: string; typebot_delay_message?: number; typebot_unknown_message?: string; + typebot_listening_from_me?: boolean; proxy_enabled?: boolean; proxy_proxy?: string; } diff --git a/src/whatsapp/dto/typebot.dto.ts b/src/whatsapp/dto/typebot.dto.ts index cda5ae58..6e9c6111 100644 --- a/src/whatsapp/dto/typebot.dto.ts +++ b/src/whatsapp/dto/typebot.dto.ts @@ -14,5 +14,6 @@ export class TypebotDto { keyword_finish?: string; delay_message?: number; unknown_message?: string; + listening_from_me?: boolean; sessions?: Session[]; } diff --git a/src/whatsapp/guards/auth.guard.ts b/src/whatsapp/guards/auth.guard.ts index 72148885..a72ebfff 100644 --- a/src/whatsapp/guards/auth.guard.ts +++ b/src/whatsapp/guards/auth.guard.ts @@ -55,7 +55,7 @@ async function jwtGuard(req: Request, res: Response, next: NextFunction) { } } -async function apikey(req: Request, res: Response, next: NextFunction) { +async function apikey(req: Request, _: Response, next: NextFunction) { const env = configService.get('AUTHENTICATION').API_KEY; const key = req.get('apikey'); diff --git a/src/whatsapp/guards/instance.guard.ts b/src/whatsapp/guards/instance.guard.ts index 144f4d40..e5b7ebe0 100644 --- a/src/whatsapp/guards/instance.guard.ts +++ b/src/whatsapp/guards/instance.guard.ts @@ -4,31 +4,40 @@ import { join } from 'path'; import { configService, Database, Redis } from '../../config/env.config'; import { INSTANCE_DIR } from '../../config/path.config'; -import { BadRequestException, ForbiddenException, NotFoundException } from '../../exceptions'; +import { + BadRequestException, + ForbiddenException, + InternalServerErrorException, + NotFoundException, +} from '../../exceptions'; import { dbserver } from '../../libs/db.connect'; import { InstanceDto } from '../dto/instance.dto'; import { cache, waMonitor } from '../whatsapp.module'; async function getInstance(instanceName: string) { - const db = configService.get('DATABASE'); - const redisConf = configService.get('REDIS'); + try { + const db = configService.get('DATABASE'); + const redisConf = configService.get('REDIS'); - const exists = !!waMonitor.waInstances[instanceName]; + const exists = !!waMonitor.waInstances[instanceName]; - if (redisConf.ENABLED) { - const keyExists = await cache.keyExists(); - return exists || keyExists; + if (redisConf.ENABLED) { + const keyExists = await cache.keyExists(); + return exists || keyExists; + } + + if (db.ENABLED) { + const collection = dbserver + .getClient() + .db(db.CONNECTION.DB_PREFIX_NAME + '-instances') + .collection(instanceName); + return exists || (await collection.find({}).toArray()).length > 0; + } + + return exists || existsSync(join(INSTANCE_DIR, instanceName)); + } catch (error) { + throw new InternalServerErrorException(error?.toString()); } - - if (db.ENABLED) { - const collection = dbserver - .getClient() - .db(db.CONNECTION.DB_PREFIX_NAME + '-instances') - .collection(instanceName); - return exists || (await collection.find({}).toArray()).length > 0; - } - - return exists || existsSync(join(INSTANCE_DIR, instanceName)); } export async function instanceExistsGuard(req: Request, _: Response, next: NextFunction) { diff --git a/src/whatsapp/models/chamaai.model.ts b/src/whatsapp/models/chamaai.model.ts new file mode 100644 index 00000000..d3d10aff --- /dev/null +++ b/src/whatsapp/models/chamaai.model.ts @@ -0,0 +1,24 @@ +import { Schema } from 'mongoose'; + +import { dbserver } from '../../libs/db.connect'; + +export class ChamaaiRaw { + _id?: string; + enabled?: boolean; + url?: string; + token?: string; + waNumber?: string; + answerByAudio?: boolean; +} + +const chamaaiSchema = new Schema({ + _id: { type: String, _id: true }, + enabled: { type: Boolean, required: true }, + url: { type: String, required: true }, + token: { type: String, required: true }, + waNumber: { type: String, required: true }, + answerByAudio: { type: Boolean, required: true }, +}); + +export const ChamaaiModel = dbserver?.model(ChamaaiRaw.name, chamaaiSchema, 'chamaai'); +export type IChamaaiModel = typeof ChamaaiModel; diff --git a/src/whatsapp/models/index.ts b/src/whatsapp/models/index.ts index 5d71911d..e79093f9 100644 --- a/src/whatsapp/models/index.ts +++ b/src/whatsapp/models/index.ts @@ -1,4 +1,5 @@ export * from './auth.model'; +export * from './chamaai.model'; export * from './chat.model'; export * from './chatwoot.model'; export * from './contact.model'; diff --git a/src/whatsapp/models/typebot.model.ts b/src/whatsapp/models/typebot.model.ts index 5b005294..28135ebd 100644 --- a/src/whatsapp/models/typebot.model.ts +++ b/src/whatsapp/models/typebot.model.ts @@ -19,6 +19,7 @@ export class TypebotRaw { keyword_finish?: string; delay_message?: number; unknown_message?: string; + listening_from_me?: boolean; sessions?: Session[]; } @@ -31,6 +32,7 @@ const typebotSchema = new Schema({ keyword_finish: { type: String, required: true }, delay_message: { type: Number, required: true }, unknown_message: { type: String, required: true }, + listening_from_me: { type: Boolean, required: true }, sessions: [ { remoteJid: { type: String, required: true }, diff --git a/src/whatsapp/repository/chamaai.repository.ts b/src/whatsapp/repository/chamaai.repository.ts new file mode 100644 index 00000000..a2009f41 --- /dev/null +++ b/src/whatsapp/repository/chamaai.repository.ts @@ -0,0 +1,62 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; + +import { ConfigService } from '../../config/env.config'; +import { Logger } from '../../config/logger.config'; +import { IInsert, Repository } from '../abstract/abstract.repository'; +import { ChamaaiRaw, IChamaaiModel } from '../models'; + +export class ChamaaiRepository extends Repository { + constructor(private readonly chamaaiModel: IChamaaiModel, private readonly configService: ConfigService) { + super(configService); + } + + private readonly logger = new Logger('ChamaaiRepository'); + + public async create(data: ChamaaiRaw, instance: string): Promise { + try { + this.logger.verbose('creating chamaai'); + if (this.dbSettings.ENABLED) { + this.logger.verbose('saving chamaai to db'); + const insert = await this.chamaaiModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); + + this.logger.verbose('chamaai saved to db: ' + insert.modifiedCount + ' chamaai'); + return { insertCount: insert.modifiedCount }; + } + + this.logger.verbose('saving chamaai to store'); + + this.writeStore({ + path: join(this.storePath, 'chamaai'), + fileName: instance, + data, + }); + + this.logger.verbose('chamaai saved to store in path: ' + join(this.storePath, 'chamaai') + '/' + instance); + + this.logger.verbose('chamaai created'); + return { insertCount: 1 }; + } catch (error) { + return error; + } + } + + public async find(instance: string): Promise { + try { + this.logger.verbose('finding chamaai'); + if (this.dbSettings.ENABLED) { + this.logger.verbose('finding chamaai in db'); + return await this.chamaaiModel.findOne({ _id: instance }); + } + + this.logger.verbose('finding chamaai in store'); + return JSON.parse( + readFileSync(join(this.storePath, 'chamaai', instance + '.json'), { + encoding: 'utf-8', + }), + ) as ChamaaiRaw; + } catch (error) { + return {}; + } + } +} diff --git a/src/whatsapp/repository/repository.manager.ts b/src/whatsapp/repository/repository.manager.ts index 2cd4931e..1c16fdef 100644 --- a/src/whatsapp/repository/repository.manager.ts +++ b/src/whatsapp/repository/repository.manager.ts @@ -5,6 +5,7 @@ import { join } from 'path'; import { Auth, ConfigService, Database } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { AuthRepository } from './auth.repository'; +import { ChamaaiRepository } from './chamaai.repository'; import { ChatRepository } from './chat.repository'; import { ChatwootRepository } from './chatwoot.repository'; import { ContactRepository } from './contact.repository'; @@ -29,6 +30,7 @@ export class RepositoryBroker { public readonly rabbitmq: RabbitmqRepository, public readonly typebot: TypebotRepository, public readonly proxy: ProxyRepository, + public readonly chamaai: ChamaaiRepository, public readonly auth: AuthRepository, private configService: ConfigService, dbServer?: MongoClient, @@ -63,6 +65,7 @@ export class RepositoryBroker { const rabbitmqDir = join(storePath, 'rabbitmq'); const typebotDir = join(storePath, 'typebot'); const proxyDir = join(storePath, 'proxy'); + const chamaaiDir = join(storePath, 'chamaai'); const tempDir = join(storePath, 'temp'); if (!fs.existsSync(authDir)) { @@ -113,6 +116,10 @@ export class RepositoryBroker { this.logger.verbose('creating proxy dir: ' + proxyDir); fs.mkdirSync(proxyDir, { recursive: true }); } + if (!fs.existsSync(chamaaiDir)) { + this.logger.verbose('creating chamaai dir: ' + chamaaiDir); + fs.mkdirSync(chamaaiDir, { recursive: true }); + } if (!fs.existsSync(tempDir)) { this.logger.verbose('creating temp dir: ' + tempDir); fs.mkdirSync(tempDir, { recursive: true }); diff --git a/src/whatsapp/routers/chamaai.router.ts b/src/whatsapp/routers/chamaai.router.ts new file mode 100644 index 00000000..e8021306 --- /dev/null +++ b/src/whatsapp/routers/chamaai.router.ts @@ -0,0 +1,52 @@ +import { RequestHandler, Router } from 'express'; + +import { Logger } from '../../config/logger.config'; +import { chamaaiSchema, instanceNameSchema } from '../../validate/validate.schema'; +import { RouterBroker } from '../abstract/abstract.router'; +import { ChamaaiDto } from '../dto/chamaai.dto'; +import { InstanceDto } from '../dto/instance.dto'; +import { chamaaiController } from '../whatsapp.module'; +import { HttpStatus } from './index.router'; + +const logger = new Logger('ChamaaiRouter'); + +export class ChamaaiRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('set'), ...guards, async (req, res) => { + logger.verbose('request received in setChamaai'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: chamaaiSchema, + ClassRef: ChamaaiDto, + execute: (instance, data) => chamaaiController.createChamaai(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + logger.verbose('request received in findChamaai'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: instanceNameSchema, + ClassRef: InstanceDto, + execute: (instance) => chamaaiController.findChamaai(instance), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router = Router(); +} diff --git a/src/whatsapp/routers/index.router.ts b/src/whatsapp/routers/index.router.ts index a84e815d..f67c936a 100644 --- a/src/whatsapp/routers/index.router.ts +++ b/src/whatsapp/routers/index.router.ts @@ -4,6 +4,7 @@ import fs from 'fs'; import { Auth, configService } from '../../config/env.config'; import { authGuard } from '../guards/auth.guard'; import { instanceExistsGuard, instanceLoggedGuard } from '../guards/instance.guard'; +import { ChamaaiRouter } from './chamaai.router'; import { ChatRouter } from './chat.router'; import { ChatwootRouter } from './chatwoot.router'; import { GroupRouter } from './group.router'; @@ -52,6 +53,7 @@ router .use('/websocket', new WebsocketRouter(...guards).router) .use('/rabbitmq', new RabbitmqRouter(...guards).router) .use('/typebot', new TypebotRouter(...guards).router) - .use('/proxy', new ProxyRouter(...guards).router); + .use('/proxy', new ProxyRouter(...guards).router) + .use('/chamaai', new ChamaaiRouter(...guards).router); export { HttpStatus, router }; diff --git a/src/whatsapp/services/chamaai.service.ts b/src/whatsapp/services/chamaai.service.ts new file mode 100644 index 00000000..ad2a42ad --- /dev/null +++ b/src/whatsapp/services/chamaai.service.ts @@ -0,0 +1,230 @@ +import axios from 'axios'; +import { writeFileSync } from 'fs'; +import path from 'path'; + +import { ConfigService, HttpServer } from '../../config/env.config'; +import { Logger } from '../../config/logger.config'; +import { ChamaaiDto } from '../dto/chamaai.dto'; +import { InstanceDto } from '../dto/instance.dto'; +import { ChamaaiRaw } from '../models'; +import { Events } from '../types/wa.types'; +import { WAMonitoringService } from './monitor.service'; + +export class ChamaaiService { + constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {} + + private readonly logger = new Logger(ChamaaiService.name); + + public create(instance: InstanceDto, data: ChamaaiDto) { + this.logger.verbose('create chamaai: ' + instance.instanceName); + this.waMonitor.waInstances[instance.instanceName].setChamaai(data); + + return { chamaai: { ...instance, chamaai: data } }; + } + + public async find(instance: InstanceDto): Promise { + try { + this.logger.verbose('find chamaai: ' + instance.instanceName); + const result = await this.waMonitor.waInstances[instance.instanceName].findChamaai(); + + if (Object.keys(result).length === 0) { + throw new Error('Chamaai not found'); + } + + return result; + } catch (error) { + return { enabled: false, url: '', token: '', waNumber: '', answerByAudio: false }; + } + } + + private getTypeMessage(msg: any) { + this.logger.verbose('get type message'); + + const types = { + conversation: msg.conversation, + extendedTextMessage: msg.extendedTextMessage?.text, + }; + + this.logger.verbose('type message: ' + types); + + return types; + } + + private getMessageContent(types: any) { + this.logger.verbose('get message content'); + const typeKey = Object.keys(types).find((key) => types[key] !== undefined); + + const result = typeKey ? types[typeKey] : undefined; + + this.logger.verbose('message content: ' + result); + + return result; + } + + private getConversationMessage(msg: any) { + this.logger.verbose('get conversation message'); + + const types = this.getTypeMessage(msg); + + const messageContent = this.getMessageContent(types); + + this.logger.verbose('conversation message: ' + messageContent); + + return messageContent; + } + + private calculateTypingTime(text: string) { + const wordsPerMinute = 100; + + const wordCount = text.split(' ').length; + const typingTimeInMinutes = wordCount / wordsPerMinute; + const typingTimeInMilliseconds = typingTimeInMinutes * 60; + return typingTimeInMilliseconds; + } + + private convertToMilliseconds(count: number) { + const averageCharactersPerSecond = 15; + const characterCount = count; + const speakingTimeInSeconds = characterCount / averageCharactersPerSecond; + return speakingTimeInSeconds; + } + + private getRegexPatterns() { + const patternsToCheck = [ + '.*atend.*humano.*', + '.*falar.*com.*um.*humano.*', + '.*fala.*humano.*', + '.*atend.*humano.*', + '.*fala.*atend.*', + '.*preciso.*ajuda.*', + '.*quero.*suporte.*', + '.*preciso.*assiste.*', + '.*ajuda.*atend.*', + '.*chama.*atendente.*', + '.*suporte.*urgente.*', + '.*atend.*por.*favor.*', + '.*quero.*falar.*com.*alguém.*', + '.*falar.*com.*um.*humano.*', + '.*transfer.*humano.*', + '.*transfer.*atend.*', + '.*equipe.*humano.*', + '.*suporte.*humano.*', + ]; + + const regexPatterns = patternsToCheck.map((pattern) => new RegExp(pattern, 'iu')); + return regexPatterns; + } + + public async sendChamaai(instance: InstanceDto, remoteJid: string, msg: any) { + const content = this.getConversationMessage(msg.message); + const msgType = msg.messageType; + const find = await this.find(instance); + const url = find.url; + const token = find.token; + const waNumber = find.waNumber; + const answerByAudio = find.answerByAudio; + + if (!content && msgType !== 'audioMessage') { + return; + } + + let data; + let endpoint; + + if (msgType === 'audioMessage') { + const downloadBase64 = await this.waMonitor.waInstances[instance.instanceName].getBase64FromMediaMessage({ + message: { + ...msg, + }, + }); + + const random = Math.random().toString(36).substring(7); + const nameFile = `${random}.ogg`; + + const fileData = Buffer.from(downloadBase64.base64, 'base64'); + + const fileName = `${path.join( + this.waMonitor.waInstances[instance.instanceName].storePath, + 'temp', + `${nameFile}`, + )}`; + + writeFileSync(fileName, fileData, 'utf8'); + + const urlServer = this.configService.get('SERVER').URL; + + const url = `${urlServer}/store/temp/${nameFile}`; + + data = { + waNumber: waNumber, + audioUrl: url, + queryNumber: remoteJid.split('@')[0], + answerByAudio: answerByAudio, + }; + endpoint = 'processMessageAudio'; + } else { + data = { + waNumber: waNumber, + question: content, + queryNumber: remoteJid.split('@')[0], + answerByAudio: answerByAudio, + }; + endpoint = 'processMessageText'; + } + + const request = await axios.post(`${url}/${endpoint}`, data, { + headers: { + Authorization: `${token}`, + }, + }); + + const answer = request.data?.answer; + + const type = request.data?.type; + + const characterCount = request.data?.characterCount; + + if (answer) { + if (type === 'text') { + this.waMonitor.waInstances[instance.instanceName].textMessage({ + number: remoteJid.split('@')[0], + options: { + delay: this.calculateTypingTime(answer) * 1000 || 1000, + presence: 'composing', + linkPreview: false, + quoted: { + key: msg.key, + message: msg.message, + }, + }, + textMessage: { + text: answer, + }, + }); + } + + if (type === 'audio') { + this.waMonitor.waInstances[instance.instanceName].audioWhatsapp({ + number: remoteJid.split('@')[0], + options: { + delay: characterCount ? this.convertToMilliseconds(characterCount) * 1000 || 1000 : 1000, + presence: 'recording', + encoding: true, + }, + audioMessage: { + audio: answer, + }, + }); + } + + if (this.getRegexPatterns().some((pattern) => pattern.test(answer))) { + this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.CHAMA_AI_ACTION, { + remoteJid: remoteJid, + message: msg, + answer: answer, + action: 'transfer', + }); + } + } + } +} diff --git a/src/whatsapp/services/chatwoot.service.ts b/src/whatsapp/services/chatwoot.service.ts index 4dc9215c..abe48150 100644 --- a/src/whatsapp/services/chatwoot.service.ts +++ b/src/whatsapp/services/chatwoot.service.ts @@ -1444,16 +1444,16 @@ export class ChatwootService { await this.createBotMessage(instance, msgStatus, 'incoming'); } - if (event === 'connection.update') { - this.logger.verbose('event connection.update'); + // if (event === 'connection.update') { + // this.logger.verbose('event connection.update'); - if (body.status === 'open') { - const msgConnection = `🚀 Connection successfully established!`; + // if (body.status === 'open') { + // const msgConnection = `🚀 Connection successfully established!`; - this.logger.verbose('send message to chatwoot'); - await this.createBotMessage(instance, msgConnection, 'incoming'); - } - } + // this.logger.verbose('send message to chatwoot'); + // await this.createBotMessage(instance, msgConnection, 'incoming'); + // } + // } if (event === 'qrcode.updated') { this.logger.verbose('event qrcode.updated'); diff --git a/src/whatsapp/services/monitor.service.ts b/src/whatsapp/services/monitor.service.ts index 039a5f29..69aae5aa 100644 --- a/src/whatsapp/services/monitor.service.ts +++ b/src/whatsapp/services/monitor.service.ts @@ -115,7 +115,7 @@ export class WAMonitoringService { if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; + instanceData.instance['apikey'] = (await this.repository.auth.find(key))?.apikey; instanceData.instance['chatwoot'] = chatwoot; } @@ -134,7 +134,7 @@ export class WAMonitoringService { if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; + instanceData.instance['apikey'] = (await this.repository.auth.find(key))?.apikey; instanceData.instance['chatwoot'] = chatwoot; } @@ -161,8 +161,7 @@ export class WAMonitoringService { }); this.logger.verbose('instance files deleted: ' + name); }); - // } else if (this.redis.ENABLED) { - } else { + } else if (!this.redis.ENABLED) { const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); for await (const dirent of dir) { if (dirent.isDirectory()) { @@ -200,6 +199,7 @@ export class WAMonitoringService { this.logger.verbose('cleaning up instance in redis: ' + instanceName); this.cache.reference = instanceName; await this.cache.delAll(); + this.cache.disconnect(); return; } @@ -220,6 +220,11 @@ export class WAMonitoringService { execSync(`rm -rf ${join(STORE_DIR, 'auth', 'apikey', instanceName + '.json')}`); execSync(`rm -rf ${join(STORE_DIR, 'webhook', instanceName + '.json')}`); execSync(`rm -rf ${join(STORE_DIR, 'chatwoot', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'chamaai', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'proxy', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'rabbitmq', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'typebot', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'websocket', instanceName + '*')}`); execSync(`rm -rf ${join(STORE_DIR, 'settings', instanceName + '*')}`); return; @@ -263,6 +268,7 @@ export class WAMonitoringService { } else { this.logger.verbose('no instance keys found'); } + this.cache.disconnect(); return; } diff --git a/src/whatsapp/services/rabbitmq.service.ts b/src/whatsapp/services/rabbitmq.service.ts index 383ad07a..a377595b 100644 --- a/src/whatsapp/services/rabbitmq.service.ts +++ b/src/whatsapp/services/rabbitmq.service.ts @@ -1,4 +1,5 @@ import { Logger } from '../../config/logger.config'; +import { initQueues } from '../../libs/amqp.server'; import { InstanceDto } from '../dto/instance.dto'; import { RabbitmqDto } from '../dto/rabbitmq.dto'; import { RabbitmqRaw } from '../models'; @@ -13,6 +14,7 @@ export class RabbitmqService { this.logger.verbose('create rabbitmq: ' + instance.instanceName); this.waMonitor.waInstances[instance.instanceName].setRabbitmq(data); + initQueues(instance.instanceName, data.events); return { rabbitmq: { ...instance, rabbitmq: data } }; } diff --git a/src/whatsapp/services/typebot.service.ts b/src/whatsapp/services/typebot.service.ts index 1128bb0d..ff595c6b 100644 --- a/src/whatsapp/services/typebot.service.ts +++ b/src/whatsapp/services/typebot.service.ts @@ -4,6 +4,7 @@ import { Logger } from '../../config/logger.config'; import { InstanceDto } from '../dto/instance.dto'; import { Session, TypebotDto } from '../dto/typebot.dto'; import { MessageRaw } from '../models'; +import { Events } from '../types/wa.types'; import { WAMonitoringService } from './monitor.service'; export class TypebotService { @@ -53,6 +54,7 @@ export class TypebotService { keyword_finish: findData.keyword_finish, delay_message: findData.delay_message, unknown_message: findData.unknown_message, + listening_from_me: findData.listening_from_me, sessions: findData.sessions, }; @@ -76,11 +78,20 @@ export class TypebotService { keyword_finish: findData.keyword_finish, delay_message: findData.delay_message, unknown_message: findData.unknown_message, + listening_from_me: findData.listening_from_me, sessions: findData.sessions, }; this.create(instance, typebotData); + this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_CHANGE_STATUS, { + remoteJid: remoteJid, + status: status, + url: findData.url, + typebot: findData.typebot, + session, + }); + return { typebot: { ...instance, typebot: typebotData } }; } @@ -88,6 +99,15 @@ export class TypebotService { const remoteJid = data.remoteJid; const url = data.url; const typebot = data.typebot; + const variables = data.variables; + + const prefilledVariables = { + remoteJid: remoteJid, + }; + + variables.forEach((variable) => { + prefilledVariables[variable.name] = variable.value; + }); const id = Math.floor(Math.random() * 10000000000).toString(); @@ -95,14 +115,9 @@ export class TypebotService { sessionId: id, startParams: { typebot: data.typebot, - prefilledVariables: { - remoteJid: data.remoteJid, - pushName: data.pushName, - instanceName: instance.instanceName, - }, + prefilledVariables: prefilledVariables, }, }; - console.log(reqData); const request = await axios.post(data.url + '/api/v1/sendMessage', reqData); @@ -114,6 +129,14 @@ export class TypebotService { request.data.clientSideActions, ); + this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_START, { + remoteJid: remoteJid, + url: url, + typebot: typebot, + variables: variables, + sessionId: id, + }); + return { typebot: { ...instance, @@ -121,6 +144,7 @@ export class TypebotService { url: url, remoteJid: remoteJid, typebot: typebot, + variables: variables, }, }, }; @@ -195,6 +219,7 @@ export class TypebotService { keyword_finish: data.keyword_finish, delay_message: data.delay_message, unknown_message: data.unknown_message, + listening_from_me: data.listening_from_me, sessions: data.sessions, }; @@ -354,13 +379,15 @@ export class TypebotService { } public async sendTypebot(instance: InstanceDto, remoteJid: string, msg: MessageRaw) { - const url = (await this.find(instance)).url; - const typebot = (await this.find(instance)).typebot; - const sessions = ((await this.find(instance)).sessions as Session[]) ?? []; - const expire = (await this.find(instance)).expire; - const keyword_finish = (await this.find(instance)).keyword_finish; - const delay_message = (await this.find(instance)).delay_message; - const unknown_message = (await this.find(instance)).unknown_message; + const findTypebot = await this.find(instance); + const url = findTypebot.url; + const typebot = findTypebot.typebot; + const sessions = (findTypebot.sessions as Session[]) ?? []; + const expire = findTypebot.expire; + const keyword_finish = findTypebot.keyword_finish; + const delay_message = findTypebot.delay_message; + const unknown_message = findTypebot.unknown_message; + const listening_from_me = findTypebot.listening_from_me; const session = sessions.find((session) => session.remoteJid === remoteJid); @@ -381,6 +408,7 @@ export class TypebotService { keyword_finish: keyword_finish, delay_message: delay_message, unknown_message: unknown_message, + listening_from_me: listening_from_me, sessions: sessions, remoteJid: remoteJid, pushName: msg.pushName, @@ -404,6 +432,7 @@ export class TypebotService { keyword_finish: keyword_finish, delay_message: delay_message, unknown_message: unknown_message, + listening_from_me: listening_from_me, sessions: sessions, remoteJid: remoteJid, pushName: msg.pushName, @@ -428,6 +457,7 @@ export class TypebotService { keyword_finish: keyword_finish, delay_message: delay_message, unknown_message: unknown_message, + listening_from_me: listening_from_me, sessions, }; @@ -462,6 +492,7 @@ export class TypebotService { keyword_finish: keyword_finish, delay_message: delay_message, unknown_message: unknown_message, + listening_from_me: listening_from_me, sessions, }; diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index d11946ee..2e5e79f6 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -113,7 +113,7 @@ import { SendTextDto, StatusMessage, } from '../dto/sendMessage.dto'; -import { ProxyRaw, RabbitmqRaw, SettingsRaw, TypebotRaw } from '../models'; +import { ChamaaiRaw, ProxyRaw, RabbitmqRaw, SettingsRaw, TypebotRaw } from '../models'; import { ChatRaw } from '../models/chat.model'; import { ChatwootRaw } from '../models/chatwoot.model'; import { ContactRaw } from '../models/contact.model'; @@ -126,7 +126,9 @@ import { MessageUpQuery } from '../repository/messageUp.repository'; import { RepositoryBroker } from '../repository/repository.manager'; import { Events, MessageSubtype, TypeMediaMessage, wa } from '../types/wa.types'; import { waMonitor } from '../whatsapp.module'; +import { ChamaaiService } from './chamaai.service'; import { ChatwootService } from './chatwoot.service'; +//import { SocksProxyAgent } from './socks-proxy-agent'; import { TypebotService } from './typebot.service'; export class WAStartupService { @@ -151,6 +153,7 @@ export class WAStartupService { private readonly localRabbitmq: wa.LocalRabbitmq = {}; public readonly localTypebot: wa.LocalTypebot = {}; private readonly localProxy: wa.LocalProxy = {}; + private readonly localChamaai: wa.LocalChamaai = {}; public stateConnection: wa.StateConnection = { state: 'close' }; public readonly storePath = join(ROOT_DIR, 'store'); private readonly msgRetryCounterCache: CacheStore = new NodeCache(); @@ -164,6 +167,8 @@ export class WAStartupService { private typebotService = new TypebotService(waMonitor); + private chamaaiService = new ChamaaiService(waMonitor, this.configService); + public set instanceName(name: string) { this.logger.verbose(`Initializing instance '${name}'`); if (!name) { @@ -515,6 +520,9 @@ export class WAStartupService { this.localTypebot.unknown_message = data?.unknown_message; this.logger.verbose(`Typebot unknown_message: ${this.localTypebot.unknown_message}`); + this.localTypebot.listening_from_me = data?.listening_from_me; + this.logger.verbose(`Typebot listening_from_me: ${this.localTypebot.listening_from_me}`); + this.localTypebot.sessions = data?.sessions; this.logger.verbose('Typebot loaded'); @@ -528,6 +536,7 @@ export class WAStartupService { this.logger.verbose(`Typebot keyword_finish: ${data.keyword_finish}`); this.logger.verbose(`Typebot delay_message: ${data.delay_message}`); this.logger.verbose(`Typebot unknown_message: ${data.unknown_message}`); + this.logger.verbose(`Typebot listening_from_me: ${data.listening_from_me}`); Object.assign(this.localTypebot, data); this.logger.verbose('Typebot set'); } @@ -579,6 +588,52 @@ export class WAStartupService { return data; } + private async loadChamaai() { + this.logger.verbose('Loading chamaai'); + const data = await this.repository.chamaai.find(this.instanceName); + + this.localChamaai.enabled = data?.enabled; + this.logger.verbose(`Chamaai enabled: ${this.localChamaai.enabled}`); + + this.localChamaai.url = data?.url; + this.logger.verbose(`Chamaai url: ${this.localChamaai.url}`); + + this.localChamaai.token = data?.token; + this.logger.verbose(`Chamaai token: ${this.localChamaai.token}`); + + this.localChamaai.waNumber = data?.waNumber; + this.logger.verbose(`Chamaai waNumber: ${this.localChamaai.waNumber}`); + + this.localChamaai.answerByAudio = data?.answerByAudio; + this.logger.verbose(`Chamaai answerByAudio: ${this.localChamaai.answerByAudio}`); + + this.logger.verbose('Chamaai loaded'); + } + + public async setChamaai(data: ChamaaiRaw) { + this.logger.verbose('Setting chamaai'); + await this.repository.chamaai.create(data, this.instanceName); + this.logger.verbose(`Chamaai url: ${data.url}`); + this.logger.verbose(`Chamaai token: ${data.token}`); + this.logger.verbose(`Chamaai waNumber: ${data.waNumber}`); + this.logger.verbose(`Chamaai answerByAudio: ${data.answerByAudio}`); + + Object.assign(this.localChamaai, data); + this.logger.verbose('Chamaai set'); + } + + public async findChamaai() { + this.logger.verbose('Finding chamaai'); + const data = await this.repository.chamaai.find(this.instanceName); + + if (!data) { + this.logger.verbose('Chamaai not found'); + throw new NotFoundException('Chamaai not found'); + } + + return data; + } + public async sendDataWebhook(event: Events, data: T, local = true) { const webhookGlobal = this.configService.get('WEBHOOK'); const webhookLocal = this.localWebhook.events; @@ -633,6 +688,25 @@ export class WAStartupService { } amqp.publish(exchangeName, event, Buffer.from(JSON.stringify(message))); + + if (this.configService.get('LOG').LEVEL.includes('WEBHOOKS')) { + const logData = { + local: WAStartupService.name + '.sendData-RabbitMQ', + event, + instance: this.instance.name, + data, + server_url: serverUrl, + apikey: (expose && instanceApikey) || null, + date_time: now, + sender: this.wuid, + }; + + if (expose && instanceApikey) { + logData['apikey'] = instanceApikey; + } + + this.logger.log(logData); + } } } } @@ -658,6 +732,25 @@ export class WAStartupService { this.logger.verbose('Sending data to socket.io in channel: ' + this.instance.name); io.of(`/${this.instance.name}`).emit(event, message); + + if (this.configService.get('LOG').LEVEL.includes('WEBHOOKS')) { + const logData = { + local: WAStartupService.name + '.sendData-Websocket', + event, + instance: this.instance.name, + data, + server_url: serverUrl, + apikey: (expose && instanceApikey) || null, + date_time: now, + sender: this.wuid, + }; + + if (expose && instanceApikey) { + logData['apikey'] = instanceApikey; + } + + this.logger.log(logData); + } } } @@ -696,7 +789,7 @@ export class WAStartupService { } try { - if (this.localWebhook.enabled && isURL(this.localWebhook.url)) { + if (this.localWebhook.enabled && isURL(this.localWebhook.url, { require_tld: false })) { const httpService = axios.create({ baseURL }); const postData = { event, @@ -1065,6 +1158,7 @@ export class WAStartupService { this.loadRabbitmq(); this.loadTypebot(); this.loadProxy(); + this.loadChamaai(); this.instance.authState = await this.defineAuthState(); @@ -1383,8 +1477,18 @@ export class WAStartupService { ); } - if (this.localTypebot.enabled && messageRaw.key.remoteJid.includes('@s.whatsapp.net')) { - await this.typebotService.sendTypebot( + if (this.localTypebot.enabled) { + if (!(this.localTypebot.listening_from_me === false && messageRaw.key.fromMe === true)) { + await this.typebotService.sendTypebot( + { instanceName: this.instance.name }, + messageRaw.key.remoteJid, + messageRaw, + ); + } + } + + if (this.localChamaai.enabled && messageRaw.key.fromMe === false) { + await this.chamaaiService.sendChamaai( { instanceName: this.instance.name }, messageRaw.key.remoteJid, messageRaw, @@ -2315,7 +2419,7 @@ export class WAStartupService { return await this.sendMessageWithTyping(data.number, { ...generate.message }, data?.options); } - private async processAudio(audio: string, number: string) { + public async processAudio(audio: string, number: string) { this.logger.verbose('Processing audio'); let tempAudioPath: string; let outputAudio: string; diff --git a/src/whatsapp/types/wa.types.ts b/src/whatsapp/types/wa.types.ts index 893b5f87..2025e7f7 100644 --- a/src/whatsapp/types/wa.types.ts +++ b/src/whatsapp/types/wa.types.ts @@ -23,6 +23,9 @@ export enum Events { GROUPS_UPDATE = 'groups.update', GROUP_PARTICIPANTS_UPDATE = 'group-participants.update', CALL = 'call', + TYPEBOT_START = 'typebot.start', + TYPEBOT_CHANGE_STATUS = 'typebot.change-status', + CHAMA_AI_ACTION = 'chama-ai.action', } export declare namespace wa { @@ -94,6 +97,7 @@ export declare namespace wa { keyword_finish?: string; delay_message?: number; unknown_message?: string; + listening_from_me?: boolean; sessions?: Session[]; }; @@ -102,6 +106,14 @@ export declare namespace wa { proxy?: string; }; + export type LocalChamaai = { + enabled?: boolean; + url?: string; + token?: string; + waNumber?: string; + answerByAudio?: boolean; + }; + export type StateConnection = { instance?: string; state?: WAConnectionState | 'refused'; diff --git a/src/whatsapp/whatsapp.module.ts b/src/whatsapp/whatsapp.module.ts index d8ed5a62..a37e98ef 100644 --- a/src/whatsapp/whatsapp.module.ts +++ b/src/whatsapp/whatsapp.module.ts @@ -3,6 +3,7 @@ import { eventEmitter } from '../config/event.config'; import { Logger } from '../config/logger.config'; import { dbserver } from '../libs/db.connect'; import { RedisCache } from '../libs/redis.client'; +import { ChamaaiController } from './controllers/chamaai.controller'; import { ChatController } from './controllers/chat.controller'; import { ChatwootController } from './controllers/chatwoot.controller'; import { GroupController } from './controllers/group.controller'; @@ -17,6 +18,7 @@ import { WebhookController } from './controllers/webhook.controller'; import { WebsocketController } from './controllers/websocket.controller'; import { AuthModel, + ChamaaiModel, ChatModel, ChatwootModel, ContactModel, @@ -30,6 +32,7 @@ import { WebsocketModel, } from './models'; import { AuthRepository } from './repository/auth.repository'; +import { ChamaaiRepository } from './repository/chamaai.repository'; import { ChatRepository } from './repository/chat.repository'; import { ChatwootRepository } from './repository/chatwoot.repository'; import { ContactRepository } from './repository/contact.repository'; @@ -43,6 +46,7 @@ import { TypebotRepository } from './repository/typebot.repository'; import { WebhookRepository } from './repository/webhook.repository'; import { WebsocketRepository } from './repository/websocket.repository'; import { AuthService } from './services/auth.service'; +import { ChamaaiService } from './services/chamaai.service'; import { ChatwootService } from './services/chatwoot.service'; import { WAMonitoringService } from './services/monitor.service'; import { ProxyService } from './services/proxy.service'; @@ -62,6 +66,7 @@ const typebotRepository = new TypebotRepository(TypebotModel, configService); const webhookRepository = new WebhookRepository(WebhookModel, configService); const websocketRepository = new WebsocketRepository(WebsocketModel, configService); const proxyRepository = new ProxyRepository(ProxyModel, configService); +const chamaaiRepository = new ChamaaiRepository(ChamaaiModel, configService); const rabbitmqRepository = new RabbitmqRepository(RabbitmqModel, configService); const chatwootRepository = new ChatwootRepository(ChatwootModel, configService); const settingsRepository = new SettingsRepository(SettingsModel, configService); @@ -79,6 +84,7 @@ export const repository = new RepositoryBroker( rabbitmqRepository, typebotRepository, proxyRepository, + chamaaiRepository, authRepository, configService, dbserver?.getClient(), @@ -106,6 +112,10 @@ const proxyService = new ProxyService(waMonitor); export const proxyController = new ProxyController(proxyService); +const chamaaiService = new ChamaaiService(waMonitor, configService); + +export const chamaaiController = new ChamaaiController(chamaaiService); + const rabbitmqService = new RabbitmqService(waMonitor); export const rabbitmqController = new RabbitmqController(rabbitmqService);