mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-26 18:38:39 -06:00
Implementação com o Chat GPT e inbox Chatwoot
Realizei a implementação com o ChatGPT e com o id do inbox do chatwoot
This commit is contained in:
parent
f8d874453c
commit
ca34f34eba
5
dev-env
Normal file
5
dev-env
Normal file
@ -0,0 +1,5 @@
|
||||
# OPENAI_API_KEY=""
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_DB=0
|
||||
REDIS_PASS=0
|
14
src/config.ts
Normal file
14
src/config.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import dotenv from "dotenv"
|
||||
|
||||
dotenv.config()
|
||||
|
||||
export const config = {
|
||||
openAI: {
|
||||
apiToken: process.env.OPENAI_API_KEY,
|
||||
},
|
||||
redis: {
|
||||
host: process.env.REDIS_HOST || "localhost",
|
||||
port: (process.env.REDIS_PORT as unknown as number) || 6379,
|
||||
db: (process.env.REDIS_DB as unknown as number) || 0,
|
||||
},
|
||||
}
|
@ -48,6 +48,7 @@ export type CleanStoreConf = {
|
||||
export type DBConnection = {
|
||||
URI: string;
|
||||
DB_PREFIX_NAME: string;
|
||||
DB_PREFIX_FINAL_NAME: string;
|
||||
};
|
||||
export type Database = {
|
||||
CONNECTION: DBConnection;
|
||||
@ -74,6 +75,12 @@ export type Sqs = {
|
||||
REGION: string;
|
||||
};
|
||||
|
||||
export type Openai = {
|
||||
CHAVE: string;
|
||||
ENABLED: boolean;
|
||||
URI: string;
|
||||
};
|
||||
|
||||
export type Websocket = {
|
||||
ENABLED: boolean;
|
||||
};
|
||||
@ -145,6 +152,7 @@ export interface Env {
|
||||
REDIS: Redis;
|
||||
RABBITMQ: Rabbitmq;
|
||||
SQS: Sqs;
|
||||
OPENAI: Openai;
|
||||
WEBSOCKET: Websocket;
|
||||
LOG: Log;
|
||||
DEL_INSTANCE: DelInstance;
|
||||
@ -218,6 +226,7 @@ export class ConfigService {
|
||||
CONNECTION: {
|
||||
URI: process.env.DATABASE_CONNECTION_URI || '',
|
||||
DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME || 'evolution',
|
||||
DB_PREFIX_FINAL_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_FINAL_NAME || '-api',
|
||||
},
|
||||
ENABLED: process.env?.DATABASE_ENABLED === 'true',
|
||||
SAVE_DATA: {
|
||||
@ -244,6 +253,12 @@ export class ConfigService {
|
||||
ACCOUNT_ID: process.env.SQS_ACCOUNT_ID || '',
|
||||
REGION: process.env.SQS_REGION || '',
|
||||
},
|
||||
|
||||
OPENAI: {
|
||||
CHAVE: process.env?.OPENAI_ENABLED || '',
|
||||
ENABLED: process.env?.OPENAI_ENABLED === 'true',
|
||||
URI: process.env.OPENAI_URI || '',
|
||||
},
|
||||
WEBSOCKET: {
|
||||
ENABLED: process.env?.WEBSOCKET_ENABLED === 'true',
|
||||
},
|
||||
|
@ -7,8 +7,8 @@
|
||||
# Choose the server type for the application
|
||||
SERVER:
|
||||
TYPE: http # https
|
||||
PORT: 8080 # 443
|
||||
URL: localhost
|
||||
PORT: 3333 # 443
|
||||
URL: 127.0.0.1
|
||||
|
||||
CORS:
|
||||
ORIGIN:
|
||||
@ -48,8 +48,8 @@ DEL_INSTANCE: false # or false
|
||||
|
||||
# Temporary data storage
|
||||
STORE:
|
||||
MESSAGES: true
|
||||
MESSAGE_UP: true
|
||||
MESSAGES: false
|
||||
MESSAGE_UP: false
|
||||
CONTACTS: true
|
||||
CHATS: true
|
||||
|
||||
@ -62,17 +62,20 @@ CLEAN_STORE:
|
||||
|
||||
# Permanent data storage
|
||||
DATABASE:
|
||||
ENABLED: false
|
||||
ENABLED: true
|
||||
CONNECTION:
|
||||
URI: "mongodb://root:root@localhost:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true"
|
||||
DB_PREFIX_NAME: evolution
|
||||
|
||||
DB_PREFIX_NAME: whatsapp
|
||||
DB_PREFIX_FINAL_NAME: "-api"
|
||||
DB_PREFIX_FINAL_NAME_VENOM: "-venom"
|
||||
# Choose the data you want to save in the application's database or store
|
||||
SAVE_DATA:
|
||||
INSTANCE: false
|
||||
INSTANCE: true
|
||||
NEW_MESSAGE: false
|
||||
MESSAGE_UPDATE: false
|
||||
CONTACTS: false
|
||||
CHATS: false
|
||||
CONTACTS: true
|
||||
CHATS: true
|
||||
|
||||
REDIS:
|
||||
ENABLED: false
|
||||
@ -83,8 +86,14 @@ RABBITMQ:
|
||||
ENABLED: false
|
||||
URI: "amqp://guest:guest@localhost:5672"
|
||||
|
||||
OPENAI:
|
||||
CHAVE: ""
|
||||
ENABLED: false
|
||||
PROMPTS: false
|
||||
URI: ""
|
||||
|
||||
SQS:
|
||||
ENABLED: true
|
||||
ENABLED: false
|
||||
ACCESS_KEY_ID: ""
|
||||
SECRET_ACCESS_KEY: ""
|
||||
ACCOUNT_ID: ""
|
||||
@ -93,12 +102,15 @@ SQS:
|
||||
WEBSOCKET:
|
||||
ENABLED: false
|
||||
|
||||
TYPEBOT:
|
||||
API_VERSION: 'v1' # v1 | v2
|
||||
|
||||
# Global Webhook Settings
|
||||
# Each instance's Webhook URL and events will be requested at the time it is created
|
||||
WEBHOOK:
|
||||
# Define a global webhook that will listen for enabled events from all instances
|
||||
GLOBAL:
|
||||
URL: <url>
|
||||
URL: ""
|
||||
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_BY_EVENTS: false
|
||||
@ -134,11 +146,11 @@ WEBHOOK:
|
||||
CHAMA_AI_ACTION: false
|
||||
# This event is used to send errors to the webhook
|
||||
ERRORS: false
|
||||
ERRORS_WEBHOOK: <url>
|
||||
ERRORS_WEBHOOK: ""
|
||||
|
||||
CONFIG_SESSION_PHONE:
|
||||
# Name that will be displayed on smartphone connection
|
||||
CLIENT: "Evolution API"
|
||||
CLIENT: "Chat API"
|
||||
NAME: Chrome # Chrome | Firefox | Edge | Opera | Safari
|
||||
|
||||
# Set qrcode display limit
|
||||
@ -146,9 +158,6 @@ QRCODE:
|
||||
LIMIT: 30
|
||||
COLOR: "#198754"
|
||||
|
||||
TYPEBOT:
|
||||
API_VERSION: 'v1' # v1 | v2
|
||||
|
||||
# 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
|
||||
|
@ -25,7 +25,7 @@ info:
|
||||
</font>
|
||||
|
||||
[](https://god.gw.postman.com/run-collection/26869335-5546d063-156b-4529-915f-909dd628c090?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D26869335-5546d063-156b-4529-915f-909dd628c090%26entityType%3Dcollection%26workspaceId%3D339a4ee7-378b-45c9-b5b8-fd2c0a9c2442)
|
||||
version: 1.5.5
|
||||
version: 1.5.4
|
||||
contact:
|
||||
name: DavidsonGomes
|
||||
email: contato@agenciadgcode.com
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as amqp from 'amqplib/callback_api';
|
||||
|
||||
import { configService, Rabbitmq } from '../config/env.config';
|
||||
import { configService, Rabbitmq, Openai } from '../config/env.config';
|
||||
import { Logger } from '../config/logger.config';
|
||||
|
||||
const logger = new Logger('AMQP');
|
||||
|
@ -10,7 +10,8 @@ export const dbserver = (() => {
|
||||
if (db.ENABLED) {
|
||||
logger.verbose('connecting');
|
||||
const dbs = mongoose.createConnection(db.CONNECTION.URI, {
|
||||
dbName: db.CONNECTION.DB_PREFIX_NAME + '-whatsapp-api',
|
||||
|
||||
dbName: db.CONNECTION.DB_PREFIX_NAME + db.CONNECTION.DB_PREFIX_FINAL_NAME + '-config',
|
||||
});
|
||||
logger.verbose('connected in ' + db.CONNECTION.URI);
|
||||
logger.info('ON - dbName: ' + dbs['$dbName']);
|
||||
|
34
src/libs/openai.ts
Normal file
34
src/libs/openai.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { Configuration, OpenAIApi } from "openai"
|
||||
|
||||
import { config } from "../config"
|
||||
|
||||
const configuration = new Configuration({
|
||||
apiKey: config.openAI.apiToken,
|
||||
})
|
||||
|
||||
export const openai = new OpenAIApi(configuration)
|
||||
|
||||
|
||||
export class OpenAIService {
|
||||
constructor(
|
||||
private readonly apikey: String,
|
||||
) {
|
||||
}
|
||||
|
||||
private WaOpenai: OpenAIApi;
|
||||
|
||||
public SetOpenai() {
|
||||
|
||||
const configuration = new Configuration({
|
||||
apiKey: config.openAI.apiToken,
|
||||
})
|
||||
|
||||
this.WaOpenai = new OpenAIApi(configuration)
|
||||
}
|
||||
|
||||
public openai() {
|
||||
|
||||
return this.WaOpenai;
|
||||
}
|
||||
|
||||
}
|
@ -5,11 +5,6 @@ import { Redis } from '../config/env.config';
|
||||
import { Logger } from '../config/logger.config';
|
||||
|
||||
export class RedisCache {
|
||||
private readonly logger = new Logger(RedisCache.name);
|
||||
private client: RedisClientType;
|
||||
private statusConnection = false;
|
||||
private instanceName: string;
|
||||
private redisEnv: Redis;
|
||||
|
||||
constructor() {
|
||||
this.logger.verbose('RedisCache instance created');
|
||||
@ -19,6 +14,21 @@ export class RedisCache {
|
||||
});
|
||||
}
|
||||
|
||||
// constructor() {
|
||||
// this.logger.verbose('instance created');
|
||||
// process.on('beforeExit', async () => {
|
||||
// this.logger.verbose('instance destroyed');
|
||||
// if (this.statusConnection) {
|
||||
// this.logger.verbose('instance disconnect');
|
||||
// await this.client.disconnect();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
private statusConnection = false;
|
||||
private instanceName: string;
|
||||
private redisEnv: Redis;
|
||||
|
||||
public set reference(reference: string) {
|
||||
this.logger.verbose('set reference: ' + reference);
|
||||
this.instanceName = reference;
|
||||
@ -27,14 +37,18 @@ export class RedisCache {
|
||||
public async connect(redisEnv: Redis) {
|
||||
this.logger.verbose('Connecting to Redis...');
|
||||
this.client = createClient({ url: redisEnv.URI });
|
||||
//this.logger.verbose('connected in ' + redisEnv.URI);
|
||||
this.client.on('error', (err) => this.logger.error('Redis Client Error ' + err));
|
||||
|
||||
await this.client.connect();
|
||||
this.statusConnection = true;
|
||||
this.redisEnv = redisEnv;
|
||||
this.logger.verbose(`Connected to ${redisEnv.URI}`);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger(RedisCache.name);
|
||||
private client: RedisClientType;
|
||||
|
||||
|
||||
public async disconnect() {
|
||||
if (this.statusConnection) {
|
||||
await this.client.disconnect();
|
||||
@ -46,11 +60,14 @@ export class RedisCache {
|
||||
public async instanceKeys(): Promise<string[]> {
|
||||
const keys: string[] = [];
|
||||
try {
|
||||
//this.logger.verbose('instance keys: ' + this.redisEnv.PREFIX_KEY + ':*');
|
||||
//return await this.client.sendCommand(['keys', this.redisEnv.PREFIX_KEY + ':*']);
|
||||
this.logger.verbose('Fetching instance keys');
|
||||
for await (const key of this.client.scanIterator({ MATCH: `${this.redisEnv.PREFIX_KEY}:*` })) {
|
||||
keys.push(key);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
this.logger.error('Error fetching instance keys ' + error);
|
||||
}
|
||||
return keys;
|
||||
|
9
src/libs/redis.ts
Normal file
9
src/libs/redis.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Redis } from "ioredis"
|
||||
|
||||
import { config } from "../config"
|
||||
|
||||
export const redis = new Redis({
|
||||
host: config.redis.host,
|
||||
port: config.redis.port,
|
||||
db: config.redis.db,
|
||||
})
|
49
src/prompts/contabilAgent.ts
Normal file
49
src/prompts/contabilAgent.ts
Normal file
@ -0,0 +1,49 @@
|
||||
export const promptContabil = `Você é uma assistente virtual de atendimento de um escritorio de contabilidade chamado {{ storeName }}. Você deve ser educada, atenciosa, amigável, cordial e muito paciente.
|
||||
|
||||
|
||||
|
||||
O roteiro de atendimento é:
|
||||
|
||||
1. Saudação inicial: Cumprimente o cliente e agradeça por entrar em contato.
|
||||
2. Coleta de informações: Solicite ao cliente seu nome para registro caso ainda não tenha registrado. Informe que os dados são apenas para controle de atendimento e não serão compartilhados com terceiros.
|
||||
3. Pergunte o setor que deseja seguir, sendo o seguinte Financeiro, suporte ou novo cliente.
|
||||
|
||||
4. Serviços de Contabilidade:
|
||||
4.1 Apresente os principais serviços de contabilidade oferecidos pelo escritório.
|
||||
4.2 Oferecemos uma ampla gama de serviços contábeis, incluindo ABERTURA DE EMPRESA, ABERTURA DE FILIAL, ASSESSORIA CONTÁBIL, ASSESSORIA FISCAL, BAIXA E REGULARIZAÇÃO DE EMPRESAS, CONSULTORIA CONTÁBIL, PLANEJAMENTO TRIBUTÁRIO, RECURSOS HUMANOS, REVISÃO TRIBUTÁRIA, Administração de Condomínios. Como posso ajudá-lo com seus desafios financeiros hoje?
|
||||
5. Perguntas Frequentes (FAQ):
|
||||
5.1 Forneça respostas para perguntas frequentes sobre impostos, contabilidade e serviços específicos.
|
||||
5.2 Aqui estão algumas perguntas frequentes sobre nossos serviços: [
|
||||
Pergunta 1: Vou precisar falar com meu antigo contador ou escritório de contabilidade sobre a migração?
|
||||
Resposta 1: Não. Fique tranquilo pois a Anexo Gestão Contábil cuida disso para você. Você só precisará enviar o seu Certificado Digital. Caso não tenha um e-CNPJ(A1), vamos te ajudar no processo de migração de outra forma, falando com o contador ou auxiliando na contratação de um Certificado Digital. Depois dessa etapa nós vamos fazer todo o seu processo com o seu antigo contador ou escritório de contabilidade. É simples, transparente e sem burocracia para você.
|
||||
|
||||
Pergunta 2: Quanto tempo demora para mudar para a Anexo Gestão Contábil?
|
||||
Resposta 2: O processo é rápido, prático e você não precisa sair de casa. Aproximadamente 5 dias úteis é o prazo após conseguirmos acessar a documentação via Certificado Digital ou com o contador antigo.
|
||||
].
|
||||
|
||||
5. Agendamento de Consulta:
|
||||
5.2 Permita que os usuários agendem uma consulta com um contador.
|
||||
5.3 Pergunte sobre a data e hora preferidas.
|
||||
5.3 Se você gostaria de agendar uma consulta com um de nossos contadores, por favor, informe-nos sobre a data e horário que funcionam melhor para você.
|
||||
|
||||
6. Impostos:
|
||||
6.1 Forneça informações sobre prazos de declaração de impostos, documentos necessários e dicas fiscais.
|
||||
6.2 Os prazos para a declaração de impostos estão se aproximando. Aqui estão algumas dicas sobre como se preparar e os documentos necessários.
|
||||
|
||||
7. Contato e Localização:
|
||||
7.1 Fornecer informações de contato, incluindo número de telefone, endereço de e-mail e endereço físico do escritório.
|
||||
7.2 Você pode nos contatar pelo telefone [número], enviar um e-mail para [e-mail] ou nos visitar no seguinte endereço [endereço].
|
||||
|
||||
8. Encaminhamento para um Contador:
|
||||
8.1 Se o chatbot não puder responder a uma pergunta específica, ofereça a opção de ser encaminhado para um contador real.
|
||||
8.2 Se você tiver uma pergunta mais complexa que eu não possa responder, gostaria de ser encaminhado para um dos nossos contadores?"
|
||||
|
||||
9. Despedida:
|
||||
9.1 Encerre a conversa de maneira cortês e ofereça informações de contato adicionais.
|
||||
9.2 Obrigado por usar nossos serviços! Se precisar de assistência futura, estamos à disposição. Tenha um ótimo dia!"
|
||||
|
||||
10. Feedback:
|
||||
10.1 Solicite feedback aos usuários para melhorar o desempenho do chatbot.
|
||||
10.2 Gostaríamos de ouvir sua opinião! Em uma escala de 1 a 5, quão útil você achou nosso chatbot hoje?
|
||||
|
||||
`
|
94
src/prompts/pizzaAgent.ts
Normal file
94
src/prompts/pizzaAgent.ts
Normal file
@ -0,0 +1,94 @@
|
||||
export const promptPizza = `Você é uma assistente virtual de atendimento de uma pizzaria chamada {{ storeName }}. Você deve ser educada, atenciosa, amigável, cordial e muito paciente.
|
||||
|
||||
Você não pode oferecer nenhum item ou sabor que não esteja em nosso cardápio. Siga estritamente as listas de opções.
|
||||
|
||||
O código do pedido é: {{ orderCode }}
|
||||
|
||||
O roteiro de atendimento é:
|
||||
|
||||
1. Saudação inicial: Cumprimente o cliente e agradeça por entrar em contato.
|
||||
2. Coleta de informações: Solicite ao cliente seu nome para registro caso ainda não tenha registrado. Informe que os dados são apenas para controle de pedidos e não serão compartilhados com terceiros.
|
||||
3. Quantidade de pizzas: Pergunte ao cliente quantas pizzas ele deseja pedir.
|
||||
4. Sabores: Envie a lista resumida apenas com os nomes de sabores salgados e doces e pergunte ao cliente quais sabores de pizza ele deseja pedir.
|
||||
4.1 O cliente pode escolher a pizza fracionada em até 2 sabores na mesma pizza.
|
||||
4.2 Se o cliente escolher mais de uma pizza, pergunte se ele deseja que os sabores sejam repetidos ou diferentes.
|
||||
4.3 Se o cliente escolher sabores diferentes, pergunte quais são os sabores de cada pizza.
|
||||
4.4 Se o cliente escolher sabores repetidos, pergunte quantas pizzas de cada sabor ele deseja.
|
||||
4.5 Se o cliente estiver indeciso, ofereça sugestões de sabores ou se deseja receber o cardápio completo.
|
||||
4.6 Se o sabor não estiver no cardápio, não deve prosseguir com o atendimento. Nesse caso informe que o sabor não está disponível e agradeça o cliente.
|
||||
5. Tamanho: Pergunte ao cliente qual o tamanho das pizzas.
|
||||
5.1 Se o cliente escolher mais de um tamanho, pergunte se ele deseja que os tamanhos sejam repetidos ou diferentes.
|
||||
5.2 Se o cliente escolher tamanhos diferentes, pergunte qual o tamanho de cada pizza.
|
||||
5.3 Se o cliente escolher tamanhos repetidos, pergunte quantas pizzas de cada tamanho ele deseja.
|
||||
5.4 Se o cliente estiver indeciso, ofereça sugestões de tamanhos. Se for para 1 pessoa o tamanho pequeno é ideal, para 2 pessoas o tamanho médio é ideal e para 3 ou mais pessoas o tamanho grande é ideal.
|
||||
6. Ingredientes adicionais: Pergunte ao cliente se ele deseja adicionar algum ingrediente extra.
|
||||
6.1 Se o cliente escolher ingredientes extras, pergunte quais são os ingredientes adicionais de cada pizza.
|
||||
6.2 Se o cliente estiver indeciso, ofereça sugestões de ingredientes extras.
|
||||
7. Remover ingredientes: Pergunte ao cliente se ele deseja remover algum ingrediente, por exemplo, cebola.
|
||||
7.1 Se o cliente escolher ingredientes para remover, pergunte quais são os ingredientes que ele deseja remover de cada pizza.
|
||||
7.2 Não é possível remover ingredientes que não existam no cardápio.
|
||||
8. Borda: Pergunte ao cliente se ele deseja borda recheada.
|
||||
8.1 Se o cliente escolher borda recheada, pergunte qual o sabor da borda recheada.
|
||||
8.2 Se o cliente estiver indeciso, ofereça sugestões de sabores de borda recheada. Uma dica é oferecer a borda como sobremesa com sabor de chocolate.
|
||||
9. Bebidas: Pergunte ao cliente se ele deseja pedir alguma bebida.
|
||||
9.1 Se o cliente escolher bebidas, pergunte quais são as bebidas que ele deseja pedir.
|
||||
9.2 Se o cliente estiver indeciso, ofereça sugestões de bebidas.
|
||||
10. Entrega: Pergunte ao cliente se ele deseja receber o pedido em casa ou se prefere retirar no balcão.
|
||||
10.1 Se o cliente escolher entrega, pergunte qual o endereço de entrega. O endereço deverá conter Rua, Número, Bairro e CEP.
|
||||
10.2 Os CEPs de 12.220-000 até 12.330-000 possuem uma taxa de entrega de R$ 10,00.
|
||||
10.3 Se o cliente escolher retirar no balcão, informe o endereço da pizzaria e o horário de funcionamento: Rua Abaeté, 123, Centro, São José dos Campos, SP. Horário de funcionamento: 18h às 23h.
|
||||
11. Forma de pagamento: Pergunte ao cliente qual a forma de pagamento desejada, oferecendo opções como dinheiro, PIX, cartão de crédito ou débito na entrega.
|
||||
11.1 Se o cliente escolher dinheiro, pergunte o valor em mãos e calcule o troco. O valor informado não pode ser menor que o valor total do pedido.
|
||||
11.2 Se o cliente escolher PIX, forneça a chave PIX CNPJ: 1234
|
||||
11.3 Se o cliente escolher cartão de crédito/débito, informe que a máquininha será levada pelo entregador.
|
||||
12. Mais alguma coisa? Pergunte ao cliente se ele deseja pedir mais alguma coisa.
|
||||
12.1 Se o cliente desejar pedir mais alguma coisa, pergunte o que ele deseja pedir.
|
||||
12.2 Se o cliente não desejar pedir mais nada, informe o resumo do pedido: Dados do cliente, quantidade de pizzas, sabores, tamanhos, ingredientes adicionais, ingredientes removidos, borda, bebidas, endereço de entrega, forma de pagamento e valor total.
|
||||
12.3 Confirmação do pedido: Pergunte ao cliente se o pedido está correto.
|
||||
12.4 Se o cliente confirmar o pedido, informe o tempo de entrega médio de 45 minutos e agradeça.
|
||||
12.5 Se o cliente não confirmar o pedido, pergunte o que está errado e corrija o pedido.
|
||||
13. Despedida: Agradeça o cliente por entrar em contato. É muito importante que se despeça informando o número do pedido.
|
||||
|
||||
Cardápio de pizzas salgadas (os valores estão separados por tamanho - Broto, Médio e Grande):
|
||||
|
||||
- Muzzarella: Queijo mussarela, tomate e orégano. R$ 25,00 / R$ 30,00 / R$ 35,00
|
||||
- Calabresa: Calabresa, cebola e orégano. R$ 30,00 / R$ 35,00 / R$ 40,00
|
||||
- Nordestina: Carne de sol, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
|
||||
- Frango: Frango desfiado, milho e orégano. R$ 30,00 / R$ 35,00 / R$ 40,00
|
||||
- Frango c/ Catupiry: Frango desfiado, catupiry e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
|
||||
- A moda da Casa: Carne de sol, bacon, cebola e orégano. R$ 40,00 / R$ 45,00 / R$ 50,00
|
||||
- Presunto: Presunto, queijo mussarela e orégano. R$ 30,00 / R$ 35,00 / R$ 40,00
|
||||
- Quatro Estações: Presunto, queijo mussarela, ervilha, milho, palmito e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
|
||||
- Mista: Presunto, queijo mussarela, calabresa, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
|
||||
- Toscana: Calabresa, bacon, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
|
||||
- Portuguesa: Presunto, queijo mussarela, calabresa, ovo, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
|
||||
- Dois Queijos: Queijo mussarela, catupiry e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
|
||||
- Quatro Queijos: Queijo mussarela, provolone, catupiry, parmesão e orégano. R$ 40,00 / R$ 45,00 / R$ 50,00
|
||||
- Salame: Salame, queijo mussarela e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
|
||||
- Atum: Atum, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
|
||||
|
||||
Cardápio de pizzas doces (os valores estão separados por tamanho - Broto, Médio e Grande):
|
||||
|
||||
- Chocolate: Chocolate ao leite e granulado. R$ 30,00 / R$ 35,00 / R$ 40,00
|
||||
- Romeu e Julieta: Goiabada e queijo mussarela. R$ 30,00 / R$ 35,00 / R$ 40,00
|
||||
- California: Banana, canela e açúcar. R$ 30,00 / R$ 35,00 / R$ 40,00
|
||||
|
||||
Extras/Adicionais (os valores estão separados por tamanho - Broto, Médio e Grande):
|
||||
|
||||
- Catupiry: R$ 5,00 / R$ 7,00 / R$ 9,00
|
||||
|
||||
Bordas (os valores estão separados por tamanho - Broto, Médio e Grande):
|
||||
|
||||
- Chocolate: R$ 5,00 / R$ 7,00 / R$ 9,00
|
||||
- Cheddar: R$ 5,00 / R$ 7,00 / R$ 9,00
|
||||
- Catupiry: R$ 5,00 / R$ 7,00 / R$ 9,00
|
||||
|
||||
Bebidas:
|
||||
|
||||
- Coca-Cola 2L: R$ 10,00
|
||||
- Coca-Cola Lata: R$ 8,00
|
||||
- Guaraná 2L: R$ 10,00
|
||||
- Guaraná Lata: R$ 7,00
|
||||
- Água com Gás 500 ml: R$ 5,00
|
||||
- Água sem Gás 500 ml: R$ 4,00
|
||||
`
|
13
src/utils/initPrompt.ts
Normal file
13
src/utils/initPrompt.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { promptPizza } from "../prompts/pizzaAgent"
|
||||
|
||||
export function initPrompt(storeName: string, orderCode: string, prompt?: string ): string {
|
||||
if(prompt){
|
||||
return prompt
|
||||
.replace(/{{[\s]?storeName[\s]?}}/g, storeName)
|
||||
.replace(/{{[\s]?orderCode[\s]?}}/g, orderCode)
|
||||
}else{
|
||||
return promptPizza
|
||||
.replace(/{{[\s]?storeName[\s]?}}/g, storeName)
|
||||
.replace(/{{[\s]?orderCode[\s]?}}/g, orderCode)
|
||||
}
|
||||
}
|
@ -19,7 +19,10 @@ export async function useMultiFileAuthStateDb(
|
||||
const client = dbserver.getClient();
|
||||
|
||||
const collection = client
|
||||
.db(configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_NAME + '-instances')
|
||||
.db(
|
||||
configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_NAME +
|
||||
configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_FINAL_NAME
|
||||
)
|
||||
.collection(coll);
|
||||
|
||||
const writeData = async (data: any, key: string): Promise<any> => {
|
||||
@ -33,6 +36,7 @@ export async function useMultiFileAuthStateDb(
|
||||
};
|
||||
}
|
||||
return await collection.replaceOne({ _id: key }, msgParsed, {
|
||||
//return await collection.replaceOne({ _id: key }, JSON.parse(JSON.stringify(data, BufferJSON.replacer)), {
|
||||
upsert: true,
|
||||
});
|
||||
} catch (error) {
|
||||
@ -47,6 +51,7 @@ export async function useMultiFileAuthStateDb(
|
||||
if (data?.content_array) {
|
||||
data = data.content_array;
|
||||
}
|
||||
//const data = await collection.findOne({ _id: key });
|
||||
const creds = JSON.stringify(data);
|
||||
return JSON.parse(creds, BufferJSON.reviver);
|
||||
} catch (error) {
|
||||
|
@ -987,6 +987,51 @@ export const rabbitmqSchema: JSONSchema7 = {
|
||||
...isNotEmpty('enabled'),
|
||||
};
|
||||
|
||||
export const openaiSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
chave: { type: 'string' },
|
||||
enabled: { type: 'boolean', enum: [true, false] },
|
||||
events: {
|
||||
type: 'array',
|
||||
minItems: 0,
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['enabled'],
|
||||
...isNotEmpty('enabled'),
|
||||
};
|
||||
|
||||
|
||||
export const sqsSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
|
@ -72,6 +72,7 @@ export class ChatwootController {
|
||||
token: '',
|
||||
sign_msg: false,
|
||||
name_inbox: '',
|
||||
id_inbox: '',
|
||||
webhook_url: '',
|
||||
};
|
||||
}
|
||||
@ -86,6 +87,7 @@ export class ChatwootController {
|
||||
|
||||
public async receiveWebhook(instance: InstanceDto, data: any) {
|
||||
logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance');
|
||||
|
||||
const chatwootService = new ChatwootService(waMonitor, this.configService);
|
||||
|
||||
return chatwootService.receiveWebhook(instance, data);
|
||||
|
@ -13,6 +13,7 @@ import { ChatwootService } from '../services/chatwoot.service';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
import { ProxyService } from '../services/proxy.service';
|
||||
import { RabbitmqService } from '../services/rabbitmq.service';
|
||||
import { OpenaiService } from '../services/openai.service';
|
||||
import { SettingsService } from '../services/settings.service';
|
||||
import { SqsService } from '../services/sqs.service';
|
||||
import { TypebotService } from '../services/typebot.service';
|
||||
@ -33,6 +34,7 @@ export class InstanceController {
|
||||
private readonly settingsService: SettingsService,
|
||||
private readonly websocketService: WebsocketService,
|
||||
private readonly rabbitmqService: RabbitmqService,
|
||||
private readonly openaiService: OpenaiService,
|
||||
private readonly proxyService: ProxyService,
|
||||
private readonly sqsService: SqsService,
|
||||
private readonly typebotService: TypebotService,
|
||||
@ -66,8 +68,14 @@ export class InstanceController {
|
||||
websocket_events,
|
||||
rabbitmq_enabled,
|
||||
rabbitmq_events,
|
||||
|
||||
openai_chave,
|
||||
openai_enabled,
|
||||
openai_events,
|
||||
|
||||
sqs_enabled,
|
||||
sqs_events,
|
||||
|
||||
typebot_url,
|
||||
typebot,
|
||||
typebot_expire,
|
||||
@ -81,6 +89,7 @@ export class InstanceController {
|
||||
this.logger.verbose('requested createInstance from ' + instanceName + ' instance');
|
||||
|
||||
this.logger.verbose('checking duplicate token');
|
||||
|
||||
await this.authService.checkDuplicateToken(token);
|
||||
|
||||
this.logger.verbose('creating instance');
|
||||
@ -250,6 +259,56 @@ export class InstanceController {
|
||||
}
|
||||
}
|
||||
|
||||
let openaiEvents: string[];
|
||||
|
||||
if (openai_enabled) {
|
||||
this.logger.verbose('creating openai');
|
||||
try {
|
||||
let newChave: string = "";
|
||||
let newEvents: string[] = [];
|
||||
if (openai_events.length === 0) {
|
||||
newEvents = [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
];
|
||||
} else {
|
||||
newEvents = openai_events;
|
||||
}
|
||||
this.openaiService.create(instance, {
|
||||
chave: newChave,
|
||||
enabled: true,
|
||||
events: newEvents,
|
||||
});
|
||||
|
||||
openaiEvents = (await this.openaiService.find(instance)).events;
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (proxy) {
|
||||
this.logger.verbose('creating proxy');
|
||||
try {
|
||||
@ -266,6 +325,7 @@ export class InstanceController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let sqsEvents: string[];
|
||||
|
||||
if (sqs_enabled) {
|
||||
@ -380,6 +440,11 @@ export class InstanceController {
|
||||
enabled: rabbitmq_enabled,
|
||||
events: rabbitmqEvents,
|
||||
},
|
||||
openai: {
|
||||
chave: openai_chave,
|
||||
enabled: openai_enabled,
|
||||
events: openaiEvents,
|
||||
},
|
||||
sqs: {
|
||||
enabled: sqs_enabled,
|
||||
events: sqsEvents,
|
||||
@ -396,7 +461,6 @@ export class InstanceController {
|
||||
},
|
||||
settings,
|
||||
qrcode: getQrcode,
|
||||
proxy,
|
||||
};
|
||||
|
||||
this.logger.verbose('instance created');
|
||||
@ -479,6 +543,11 @@ export class InstanceController {
|
||||
enabled: rabbitmq_enabled,
|
||||
events: rabbitmqEvents,
|
||||
},
|
||||
openai: {
|
||||
chave: openai_chave,
|
||||
enabled: openai_enabled,
|
||||
events: openaiEvents,
|
||||
},
|
||||
sqs: {
|
||||
enabled: sqs_enabled,
|
||||
events: sqsEvents,
|
||||
@ -506,7 +575,6 @@ export class InstanceController {
|
||||
name_inbox: instance.instanceName,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
|
||||
},
|
||||
proxy,
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(error.message[0]);
|
||||
@ -514,6 +582,23 @@ export class InstanceController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async qrInstance({ instanceName }: InstanceDto) {
|
||||
try {
|
||||
this.logger.verbose('requested qrInstance from ' + instanceName + ' instance');
|
||||
|
||||
this.logger.verbose('logging out instance: ' + instanceName);
|
||||
///this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
|
||||
|
||||
const qrcode = await this.waMonitor.waInstances[instanceName]?.instance.qrcode;
|
||||
return qrcode.base64;
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) {
|
||||
try {
|
||||
this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance');
|
||||
@ -628,18 +713,21 @@ export class InstanceController {
|
||||
}
|
||||
try {
|
||||
this.waMonitor.waInstances[instanceName]?.removeRabbitmqQueues();
|
||||
this.waMonitor.waInstances[instanceName]?.removeOpenaiQueues();
|
||||
|
||||
if (instance.state === 'connecting') {
|
||||
this.logger.verbose('logging out instance: ' + instanceName);
|
||||
|
||||
await this.logout({ instanceName });
|
||||
delete this.waMonitor.waInstances[instanceName];
|
||||
return { status: 'SUCCESS', error: false, response: { message: 'Instance deleted' } };
|
||||
} else {
|
||||
this.logger.verbose('deleting instance: ' + instanceName);
|
||||
|
||||
delete this.waMonitor.waInstances[instanceName];
|
||||
this.eventEmitter.emit('remove.instance', instanceName, 'inner');
|
||||
return { status: 'SUCCESS', error: false, response: { message: 'Instance deleted' } };
|
||||
}
|
||||
|
||||
this.logger.verbose('deleting instance: ' + instanceName);
|
||||
|
||||
delete this.waMonitor.waInstances[instanceName];
|
||||
this.eventEmitter.emit('remove.instance', instanceName, 'inner');
|
||||
return { status: 'SUCCESS', error: false, response: { message: 'Instance deleted' } };
|
||||
} catch (error) {
|
||||
throw new BadRequestException(error.toString());
|
||||
}
|
||||
|
85
src/whatsapp/controllers/openai.controller.ts
Normal file
85
src/whatsapp/controllers/openai.controller.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { OpenaiDto } from '../dto/openai.dto';
|
||||
import { ContactOpenaiDto } from '../dto/contactopenai.dto';
|
||||
import { OpenaiService } from '../services/openai.service';
|
||||
|
||||
const logger = new Logger('OpenaiController');
|
||||
|
||||
export class OpenaiController {
|
||||
constructor(private readonly openaiService: OpenaiService) {}
|
||||
|
||||
public async createOpenai(instance: InstanceDto, data: OpenaiDto) {
|
||||
logger.verbose('requested createOpenai from ' + instance.instanceName + ' instance');
|
||||
|
||||
if (!data.chave) {
|
||||
logger.verbose('openai sem chave');
|
||||
data.chave = '';
|
||||
}
|
||||
|
||||
if (!data.enabled) {
|
||||
logger.verbose('openai disabled');
|
||||
data.events = [];
|
||||
}
|
||||
|
||||
if (data.events?.length === 0) {
|
||||
logger.verbose('openai events empty');
|
||||
data.events = [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
];
|
||||
}
|
||||
|
||||
return this.openaiService.create(instance, data);
|
||||
}
|
||||
|
||||
public async findOpenai(instance: InstanceDto) {
|
||||
logger.verbose('requested findOpenai from ' + instance.instanceName + ' instance');
|
||||
return this.openaiService.find(instance);
|
||||
}
|
||||
|
||||
public async createContactOpenai(instance: InstanceDto, data: ContactOpenaiDto) {
|
||||
logger.verbose('requested createOpenai from ' + instance.instanceName + ' instance');
|
||||
|
||||
if (!data.contact) {
|
||||
logger.verbose('openai sem chave');
|
||||
data.contact = '';
|
||||
}
|
||||
|
||||
if (!data.enabled) {
|
||||
logger.verbose('openai disabled');
|
||||
data.enabled = false;
|
||||
}
|
||||
|
||||
data.owner = instance.instanceName;
|
||||
|
||||
return this.openaiService.createContact(instance, data);
|
||||
}
|
||||
|
||||
public async findContactOpenai(instance: InstanceDto) {
|
||||
logger.verbose('requested findOpenai from ' + instance.instanceName + ' instance');
|
||||
return this.openaiService.findContact(instance);
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import { SqsService } from '../services/sqs.service';
|
||||
const logger = new Logger('SqsController');
|
||||
|
||||
export class SqsController {
|
||||
constructor(private readonly sqsService: SqsService) {}
|
||||
constructor(private readonly sqsService: SqsService) { }
|
||||
|
||||
public async createSqs(instance: InstanceDto, data: SqsDto) {
|
||||
logger.verbose('requested createSqs from ' + instance.instanceName + ' instance');
|
||||
|
@ -4,6 +4,7 @@ export class ChatwootDto {
|
||||
token?: string;
|
||||
url?: string;
|
||||
name_inbox?: string;
|
||||
id_inbox?: string;
|
||||
sign_msg?: boolean;
|
||||
number?: string;
|
||||
reopen_conversation?: boolean;
|
||||
|
5
src/whatsapp/dto/contactopenai.dto.ts
Normal file
5
src/whatsapp/dto/contactopenai.dto.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export class ContactOpenaiDto {
|
||||
contact?: string;
|
||||
enabled: boolean;
|
||||
owner: string;
|
||||
}
|
@ -23,8 +23,15 @@ export class InstanceDto {
|
||||
websocket_events?: string[];
|
||||
rabbitmq_enabled?: boolean;
|
||||
rabbitmq_events?: string[];
|
||||
|
||||
openai_chave?: boolean;
|
||||
openai_prompts?: string;
|
||||
openai_enabled?: boolean;
|
||||
openai_events?: string[];
|
||||
|
||||
sqs_enabled?: boolean;
|
||||
sqs_events?: string[];
|
||||
|
||||
typebot_url?: string;
|
||||
typebot?: string;
|
||||
typebot_expire?: number;
|
||||
@ -32,5 +39,6 @@ export class InstanceDto {
|
||||
typebot_delay_message?: number;
|
||||
typebot_unknown_message?: string;
|
||||
typebot_listening_from_me?: boolean;
|
||||
proxy_enabled?: boolean;
|
||||
proxy?: string;
|
||||
}
|
||||
|
6
src/whatsapp/dto/openai.dto.ts
Normal file
6
src/whatsapp/dto/openai.dto.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export class OpenaiDto {
|
||||
chave?: string;
|
||||
enabled: boolean;
|
||||
prompts?: string;
|
||||
events?: string[];
|
||||
}
|
@ -29,7 +29,9 @@ async function getInstance(instanceName: string) {
|
||||
if (db.ENABLED) {
|
||||
const collection = dbserver
|
||||
.getClient()
|
||||
.db(db.CONNECTION.DB_PREFIX_NAME + '-instances')
|
||||
.db(
|
||||
db.CONNECTION.DB_PREFIX_NAME +
|
||||
db.CONNECTION.DB_PREFIX_FINAL_NAME)
|
||||
.collection(instanceName);
|
||||
return exists || (await collection.find({}).toArray()).length > 0;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ export class ChatwootRaw {
|
||||
token?: string;
|
||||
url?: string;
|
||||
name_inbox?: string;
|
||||
id_inbox?: string;
|
||||
sign_msg?: boolean;
|
||||
number?: string;
|
||||
reopen_conversation?: boolean;
|
||||
@ -22,6 +23,7 @@ const chatwootSchema = new Schema<ChatwootRaw>({
|
||||
token: { type: String, required: true },
|
||||
url: { type: String, required: true },
|
||||
name_inbox: { type: String, required: true },
|
||||
id_inbox: { type: String, required: true },
|
||||
sign_msg: { type: Boolean, required: true },
|
||||
number: { type: String, required: true },
|
||||
reopen_conversation: { type: Boolean, required: true },
|
||||
|
20
src/whatsapp/models/contactOpenai.model.ts
Normal file
20
src/whatsapp/models/contactOpenai.model.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Schema } from 'mongoose';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class ContactOpenaiRaw {
|
||||
_id?: string;
|
||||
contact?: string;
|
||||
enabled?: boolean;
|
||||
owner: string;
|
||||
}
|
||||
|
||||
const contactOpenaiSchema = new Schema<ContactOpenaiRaw>({
|
||||
_id: { type: String, _id: true },
|
||||
contact: { type: String, required: true, minlength: 1 },
|
||||
enabled: { type: Boolean, required: true },
|
||||
owner: { type: String, required: true, minlength: 1 },
|
||||
});
|
||||
|
||||
export const ContactOpenaiModel = dbserver?.model(ContactOpenaiRaw.name, contactOpenaiSchema, 'openai_contacts');
|
||||
export type IContactOpenaiModel = typeof ContactOpenaiModel;
|
@ -11,3 +11,5 @@ export * from './sqs.model';
|
||||
export * from './typebot.model';
|
||||
export * from './webhook.model';
|
||||
export * from './websocket.model';
|
||||
export * from './openai.model';
|
||||
export * from './contactOpenai.model';
|
||||
|
22
src/whatsapp/models/openai.model.ts
Normal file
22
src/whatsapp/models/openai.model.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { Schema } from 'mongoose';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class OpenaiRaw {
|
||||
_id?: string;
|
||||
chave?: string;
|
||||
prompts?: string;
|
||||
enabled?: boolean;
|
||||
events?: string[];
|
||||
}
|
||||
|
||||
const openaiSchema = new Schema<OpenaiRaw>({
|
||||
_id: { type: String, _id: true },
|
||||
chave: { type: String, required: true },
|
||||
prompts: { type: String, required: false },
|
||||
enabled: { type: Boolean, required: true },
|
||||
events: { type: [String], required: true },
|
||||
});
|
||||
|
||||
export const OpenaiModel = dbserver?.model(OpenaiRaw.name, openaiSchema, 'openai');
|
||||
export type IOpenaiModel = typeof OpenaiModel;
|
153
src/whatsapp/repository/openai.repository.ts
Normal file
153
src/whatsapp/repository/openai.repository.ts
Normal file
@ -0,0 +1,153 @@
|
||||
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 { IContactOpenaiModel, ContactOpenaiRaw, IOpenaiModel, OpenaiRaw } from '../models';
|
||||
|
||||
export class OpenaiRepository extends Repository {
|
||||
constructor(
|
||||
private readonly openaiModel: IOpenaiModel,
|
||||
private readonly contactopenaiModel: IContactOpenaiModel,
|
||||
private readonly configService: ConfigService
|
||||
) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('OpenaiRepository');
|
||||
|
||||
public async create(data: OpenaiRaw, instance: string): Promise<IInsert> {
|
||||
try {
|
||||
this.logger.verbose('creating openai');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving openai to db');
|
||||
const insert = await this.openaiModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose('openai saved to db: ' + insert.modifiedCount + ' openai');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
}
|
||||
|
||||
this.logger.verbose('saving openai to store');
|
||||
|
||||
this.writeStore<OpenaiRaw>({
|
||||
path: join(this.storePath, 'openai'),
|
||||
fileName: instance,
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose('openai saved to store in path: ' + join(this.storePath, 'openai') + '/' + instance);
|
||||
|
||||
this.logger.verbose('openai created');
|
||||
return { insertCount: 1 };
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
public async createContact(data: ContactOpenaiRaw, instance: string): Promise<IInsert> {
|
||||
try {
|
||||
this.logger.verbose('creating contact openai');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving openai to db');
|
||||
var resultado = await this.openaiModel.findOne({ owner: instance, contact: data.contact });
|
||||
if(!resultado){
|
||||
const insert = await this.contactopenaiModel.insertMany({ ...data });
|
||||
|
||||
this.logger.verbose('openai saved to db: ' + insert.length + ' openai_contacts');
|
||||
return { insertCount: insert.length };
|
||||
|
||||
}else{
|
||||
const contacts = []
|
||||
contacts[0] = {
|
||||
updateOne: {
|
||||
filter: { owner: data.owner, contact: data.contact },
|
||||
update: { ...data },
|
||||
upsert: true,
|
||||
},
|
||||
};
|
||||
|
||||
const { nModified } = await this.contactopenaiModel.bulkWrite(contacts);
|
||||
|
||||
this.logger.verbose('contacts updated in db: ' + nModified + ' contacts');
|
||||
return { insertCount: nModified };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.logger.verbose('saving openai to store');
|
||||
|
||||
this.writeStore<OpenaiRaw>({
|
||||
path: join(this.storePath, 'openai_contact'),
|
||||
fileName: instance,
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose('openai contact saved to store in path: ' + join(this.storePath, 'openai_contact') + '/' + instance);
|
||||
|
||||
this.logger.verbose('openai contact created');
|
||||
return { insertCount: 1 };
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public async find(instance: string): Promise<OpenaiRaw> {
|
||||
try {
|
||||
this.logger.verbose('finding openai');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('finding openai in db');
|
||||
return await this.openaiModel.findOne({ _id: instance });
|
||||
}
|
||||
|
||||
this.logger.verbose('finding openai in store');
|
||||
return JSON.parse(
|
||||
readFileSync(join(this.storePath, 'openai', instance + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
) as OpenaiRaw;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
public async findContact(instance: string, contact: string): Promise<ContactOpenaiRaw> {
|
||||
try {
|
||||
this.logger.verbose('finding openai');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('finding openai in db');
|
||||
|
||||
return await this.contactopenaiModel.findOne({ owner: instance,contact: contact});
|
||||
}
|
||||
|
||||
this.logger.verbose('finding openai in store');
|
||||
return JSON.parse(
|
||||
readFileSync(join(this.storePath, 'openai_contact', instance + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
) as ContactOpenaiRaw;
|
||||
} catch (error) {
|
||||
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
public async findContactAll(instance: string): Promise<any> {
|
||||
try {
|
||||
this.logger.verbose('finding openai');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('finding openai in db');
|
||||
return await this.contactopenaiModel.find({ owner: instance });
|
||||
}
|
||||
|
||||
this.logger.verbose('finding openai in store');
|
||||
return JSON.parse(
|
||||
readFileSync(join(this.storePath, 'openai_contact', instance + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
) as ContactOpenaiRaw;
|
||||
} catch (error) {
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import { MessageRepository } from './message.repository';
|
||||
import { MessageUpRepository } from './messageUp.repository';
|
||||
import { ProxyRepository } from './proxy.repository';
|
||||
import { RabbitmqRepository } from './rabbitmq.repository';
|
||||
import { OpenaiRepository } from './openai.repository';
|
||||
import { SettingsRepository } from './settings.repository';
|
||||
import { SqsRepository } from './sqs.repository';
|
||||
import { TypebotRepository } from './typebot.repository';
|
||||
@ -29,6 +30,8 @@ export class RepositoryBroker {
|
||||
public readonly settings: SettingsRepository,
|
||||
public readonly websocket: WebsocketRepository,
|
||||
public readonly rabbitmq: RabbitmqRepository,
|
||||
public readonly openai: OpenaiRepository,
|
||||
public readonly openai_contact: OpenaiRepository,
|
||||
public readonly sqs: SqsRepository,
|
||||
public readonly typebot: TypebotRepository,
|
||||
public readonly proxy: ProxyRepository,
|
||||
@ -63,9 +66,10 @@ export class RepositoryBroker {
|
||||
const webhookDir = join(storePath, 'webhook');
|
||||
const chatwootDir = join(storePath, 'chatwoot');
|
||||
const settingsDir = join(storePath, 'settings');
|
||||
const sqsDir = join(storePath, 'sqs');
|
||||
const websocketDir = join(storePath, 'websocket');
|
||||
const rabbitmqDir = join(storePath, 'rabbitmq');
|
||||
const sqsDir = join(storePath, 'sqs');
|
||||
const openaiDir = join(storePath, 'openai');
|
||||
const typebotDir = join(storePath, 'typebot');
|
||||
const proxyDir = join(storePath, 'proxy');
|
||||
const chamaaiDir = join(storePath, 'chamaai');
|
||||
@ -103,6 +107,12 @@ export class RepositoryBroker {
|
||||
this.logger.verbose('creating settings dir: ' + settingsDir);
|
||||
fs.mkdirSync(settingsDir, { recursive: true });
|
||||
}
|
||||
|
||||
if (!fs.existsSync(sqsDir)) {
|
||||
this.logger.verbose('creating sqs dir: ' + sqsDir);
|
||||
fs.mkdirSync(sqsDir, { recursive: true });
|
||||
}
|
||||
|
||||
if (!fs.existsSync(websocketDir)) {
|
||||
this.logger.verbose('creating websocket dir: ' + websocketDir);
|
||||
fs.mkdirSync(websocketDir, { recursive: true });
|
||||
@ -111,9 +121,9 @@ export class RepositoryBroker {
|
||||
this.logger.verbose('creating rabbitmq dir: ' + rabbitmqDir);
|
||||
fs.mkdirSync(rabbitmqDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(sqsDir)) {
|
||||
this.logger.verbose('creating sqs dir: ' + sqsDir);
|
||||
fs.mkdirSync(sqsDir, { recursive: true });
|
||||
if (!fs.existsSync(openaiDir)) {
|
||||
this.logger.verbose('creating openai dir: ' + openaiDir);
|
||||
fs.mkdirSync(openaiDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(typebotDir)) {
|
||||
this.logger.verbose('creating typebot dir: ' + typebotDir);
|
||||
|
@ -11,6 +11,7 @@ import { GroupRouter } from './group.router';
|
||||
import { InstanceRouter } from './instance.router';
|
||||
import { ProxyRouter } from './proxy.router';
|
||||
import { RabbitmqRouter } from './rabbitmq.router';
|
||||
import { OpenaiRouter } from './openai.router';
|
||||
import { MessageRouter } from './sendMessage.router';
|
||||
import { SettingsRouter } from './settings.router';
|
||||
import { SqsRouter } from './sqs.router';
|
||||
@ -39,9 +40,9 @@ router
|
||||
.get('/', (req, res) => {
|
||||
res.status(HttpStatus.OK).json({
|
||||
status: HttpStatus.OK,
|
||||
message: 'Welcome to the Evolution API, it is working!',
|
||||
version: packageJson.version,
|
||||
documentation: `${req.protocol}://${req.get('host')}/docs`,
|
||||
message: 'Api',
|
||||
// version: packageJson.version,
|
||||
// documentation: `${req.protocol}://${req.get('host')}/docs`,
|
||||
});
|
||||
})
|
||||
.use('/instance', new InstanceRouter(configService, ...guards).router)
|
||||
@ -54,7 +55,7 @@ router
|
||||
.use('/settings', new SettingsRouter(...guards).router)
|
||||
.use('/websocket', new WebsocketRouter(...guards).router)
|
||||
.use('/rabbitmq', new RabbitmqRouter(...guards).router)
|
||||
.use('/sqs', new SqsRouter(...guards).router)
|
||||
.use('/openai', new OpenaiRouter(...guards).router)
|
||||
.use('/typebot', new TypebotRouter(...guards).router)
|
||||
.use('/proxy', new ProxyRouter(...guards).router)
|
||||
.use('/chamaai', new ChamaaiRouter(...guards).router);
|
||||
|
@ -32,7 +32,15 @@ export class InstanceRouter extends RouterBroker {
|
||||
execute: (instance) => instanceController.createInstance(instance),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.CREATED).json(response);
|
||||
|
||||
if (req.query['qrcode']) {
|
||||
return res.status(HttpStatus.OK).render('qrcode', {
|
||||
qrcode: response.qrcode.base64,
|
||||
});
|
||||
} else {
|
||||
return res.status(HttpStatus.CREATED).json(response);
|
||||
}
|
||||
//return res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.put(this.routerPath('restart'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in restartInstance');
|
||||
@ -50,6 +58,22 @@ export class InstanceRouter extends RouterBroker {
|
||||
|
||||
return res.status(HttpStatus.OK).json(response);
|
||||
})
|
||||
.get(this.routerPath('qr'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in get qrCode');
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceNameSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => instanceController.qrInstance(instance),
|
||||
});
|
||||
return res.status(HttpStatus.OK).render('qrcode', {
|
||||
qrcode: response,
|
||||
});
|
||||
|
||||
})
|
||||
.get(this.routerPath('connect'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in connectInstance');
|
||||
logger.verbose('request body: ');
|
||||
|
86
src/whatsapp/routers/openai.router.ts
Normal file
86
src/whatsapp/routers/openai.router.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { instanceNameSchema, openaiSchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { OpenaiDto } from '../dto/openai.dto';
|
||||
import { ContactOpenaiDto } from '../dto/contactopenai.dto';
|
||||
import { openaiController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('OpenaiRouter');
|
||||
|
||||
export class OpenaiRouter extends RouterBroker {
|
||||
constructor(...guards: RequestHandler[]) {
|
||||
super();
|
||||
this.router
|
||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in setOpenai');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<OpenaiDto>({
|
||||
request: req,
|
||||
schema: openaiSchema,
|
||||
ClassRef: OpenaiDto,
|
||||
execute: (instance, data) => openaiController.createOpenai(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in findOpenai');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceNameSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => openaiController.findOpenai(instance),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
})
|
||||
.post(this.routerPath('contact'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in setOpenai');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<ContactOpenaiDto>({
|
||||
request: req,
|
||||
schema: openaiSchema,
|
||||
ClassRef: ContactOpenaiDto,
|
||||
execute: (instance, data) => openaiController.createContactOpenai(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
|
||||
.get(this.routerPath('findcontact'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in findOpenai');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceNameSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => openaiController.findContactOpenai(instance),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
});
|
||||
}
|
||||
|
||||
public readonly router = Router();
|
||||
}
|
BIN
src/whatsapp/services/._whatsapp.service.ts
Normal file
BIN
src/whatsapp/services/._whatsapp.service.ts
Normal file
Binary file not shown.
@ -211,8 +211,8 @@ export class ChatwootService {
|
||||
'123456',
|
||||
inboxId,
|
||||
false,
|
||||
'EvolutionAPI',
|
||||
'https://evolution-api.com/files/evolution-api-favicon.png',
|
||||
'Nex API',
|
||||
'https://nex-api.com.br/shared/themes/site/files/images/logo-purple.pnghttps://evolution-api.com/files/evolution-api-favicon.png',
|
||||
)) as any);
|
||||
|
||||
if (!contact) {
|
||||
@ -345,11 +345,17 @@ export class ChatwootService {
|
||||
data,
|
||||
});
|
||||
|
||||
// const contact = await client.contacts.update({
|
||||
// accountId: this.provider.account_id,
|
||||
// id,
|
||||
// data,
|
||||
// });
|
||||
this.logger.verbose('contact updated');
|
||||
return contact;
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async findContact(instance: InstanceDto, phoneNumber: string) {
|
||||
@ -415,11 +421,18 @@ export class ChatwootService {
|
||||
nameContact = !body.key.fromMe ? body.pushName : chatId;
|
||||
|
||||
this.logger.verbose('get inbox to instance: ' + instance.instanceName);
|
||||
const filterInbox = await this.getInbox(instance);
|
||||
|
||||
if (!filterInbox) {
|
||||
this.logger.warn('inbox not found');
|
||||
return null;
|
||||
var idInboxChat = 0;
|
||||
|
||||
if(this.provider?.id_inbox){
|
||||
idInboxChat = this.provider?.id_inbox;
|
||||
}else{
|
||||
const filterInbox = await this.getInbox(instance);
|
||||
if (!filterInbox) {
|
||||
this.logger.warn('inbox not found');
|
||||
return null;
|
||||
}
|
||||
idInboxChat = filterInbox.id;
|
||||
}
|
||||
|
||||
if (isGroup) {
|
||||
@ -443,11 +456,14 @@ export class ChatwootService {
|
||||
avatar_url: picture_url.profilePictureUrl || null,
|
||||
});
|
||||
}
|
||||
// if (!contact) {
|
||||
// contact = await this.findContact(instance, chatId);
|
||||
// }
|
||||
} else {
|
||||
await this.createContact(
|
||||
instance,
|
||||
body.key.participant.split('@')[0],
|
||||
filterInbox.id,
|
||||
idInboxChat,
|
||||
false,
|
||||
body.pushName,
|
||||
picture_url.profilePictureUrl || null,
|
||||
@ -473,7 +489,7 @@ export class ChatwootService {
|
||||
contact = await this.createContact(
|
||||
instance,
|
||||
chatId,
|
||||
filterInbox.id,
|
||||
idInboxChat,
|
||||
isGroup,
|
||||
nameContact,
|
||||
picture_url.profilePictureUrl || null,
|
||||
@ -492,15 +508,12 @@ export class ChatwootService {
|
||||
avatar_url: picture_url.profilePictureUrl || null,
|
||||
});
|
||||
}
|
||||
if (!contact) {
|
||||
contact = await this.findContact(instance, chatId);
|
||||
}
|
||||
} else {
|
||||
const jid = isGroup ? null : body.key.remoteJid;
|
||||
contact = await this.createContact(
|
||||
instance,
|
||||
chatId,
|
||||
filterInbox.id,
|
||||
idInboxChat,
|
||||
isGroup,
|
||||
nameContact,
|
||||
picture_url.profilePictureUrl || null,
|
||||
@ -532,7 +545,7 @@ export class ChatwootService {
|
||||
if (contactConversations) {
|
||||
let conversation: any;
|
||||
if (this.provider.reopen_conversation) {
|
||||
conversation = contactConversations.payload.find((conversation) => conversation.inbox_id == filterInbox.id);
|
||||
conversation = contactConversations.payload.find((conversation) => conversation.inbox_id == idInboxChat);
|
||||
|
||||
if (this.provider.conversation_pending) {
|
||||
await client.conversations.toggleStatus({
|
||||
@ -545,7 +558,7 @@ export class ChatwootService {
|
||||
}
|
||||
} else {
|
||||
conversation = contactConversations.payload.find(
|
||||
(conversation) => conversation.status !== 'resolved' && conversation.inbox_id == filterInbox.id,
|
||||
(conversation) => conversation.status !== 'resolved' && conversation.inbox_id == idInboxChat,
|
||||
);
|
||||
}
|
||||
this.logger.verbose('return conversation if exists');
|
||||
@ -559,7 +572,7 @@ export class ChatwootService {
|
||||
this.logger.verbose('create conversation in chatwoot');
|
||||
const data = {
|
||||
contact_id: contactId.toString(),
|
||||
inbox_id: filterInbox.id.toString(),
|
||||
inbox_id: idInboxChat.toString(),
|
||||
};
|
||||
|
||||
if (this.provider.conversation_pending) {
|
||||
@ -685,20 +698,31 @@ export class ChatwootService {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.logger.verbose('get inbox to instance: ' + instance.instanceName);
|
||||
const filterInbox = await this.getInbox(instance);
|
||||
if(this.provider?.id_inbox){
|
||||
|
||||
if (!filterInbox) {
|
||||
this.logger.warn('inbox not found');
|
||||
return null;
|
||||
this.logger.verbose('find conversation in chatwoot');
|
||||
var findConversation = await client.conversations.list({
|
||||
accountId: this.provider.account_id,
|
||||
inboxId: this.provider?.id_inbox,
|
||||
});
|
||||
|
||||
}else{
|
||||
|
||||
this.logger.verbose('get inbox to instance: ' + instance.instanceName);
|
||||
const filterInbox = await this.getInbox(instance);
|
||||
|
||||
if (!filterInbox) {
|
||||
this.logger.warn('inbox not found');
|
||||
return null;
|
||||
}
|
||||
|
||||
this.logger.verbose('find conversation in chatwoot');
|
||||
var findConversation = await client.conversations.list({
|
||||
accountId: this.provider.account_id,
|
||||
inboxId: filterInbox.id,
|
||||
});
|
||||
}
|
||||
|
||||
this.logger.verbose('find conversation in chatwoot');
|
||||
const findConversation = await client.conversations.list({
|
||||
accountId: this.provider.account_id,
|
||||
inboxId: filterInbox.id,
|
||||
});
|
||||
|
||||
if (!findConversation) {
|
||||
this.logger.warn('conversation not found');
|
||||
return null;
|
||||
@ -805,20 +829,32 @@ export class ChatwootService {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.logger.verbose('get inbox to instance: ' + instance.instanceName);
|
||||
const filterInbox = await this.getInbox(instance);
|
||||
|
||||
if (!filterInbox) {
|
||||
this.logger.warn('inbox not found');
|
||||
return null;
|
||||
if (this.provider?.id_inbox) {
|
||||
|
||||
this.logger.verbose('find conversation in chatwoot');
|
||||
var findConversation = await client.conversations.list({
|
||||
accountId: this.provider.account_id,
|
||||
inboxId: this.provider?.id_inbox,
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
this.logger.verbose('get inbox to instance: ' + instance.instanceName);
|
||||
const filterInbox = await this.getInbox(instance);
|
||||
|
||||
if (!filterInbox) {
|
||||
this.logger.warn('inbox not found');
|
||||
return null;
|
||||
}
|
||||
|
||||
this.logger.verbose('find conversation in chatwoot');
|
||||
var findConversation = await client.conversations.list({
|
||||
accountId: this.provider.account_id,
|
||||
inboxId: filterInbox.id,
|
||||
});
|
||||
}
|
||||
|
||||
this.logger.verbose('find conversation in chatwoot');
|
||||
const findConversation = await client.conversations.list({
|
||||
accountId: this.provider.account_id,
|
||||
inboxId: filterInbox.id,
|
||||
});
|
||||
|
||||
if (!findConversation) {
|
||||
this.logger.warn('conversation not found');
|
||||
return null;
|
||||
@ -1053,6 +1089,29 @@ export class ChatwootService {
|
||||
formatText = this.provider.sign_msg ? `*${senderName}:*\n${messageReceived}` : messageReceived;
|
||||
}
|
||||
|
||||
if (body.content_attributes.in_reply_to){
|
||||
var idResposta = (body.content_attributes.in_reply_to-1);
|
||||
var conversationId = body.conversation.contact_inbox.inbox_id;
|
||||
let config = {
|
||||
method: 'get',
|
||||
maxBodyLength: Infinity,
|
||||
url: `${this.provider.url}/api/v1/accounts/${this.provider.account_id}/conversations/${conversationId}/messages?after=` + idResposta,
|
||||
headers: {
|
||||
'api_access_token': this.provider.token
|
||||
}
|
||||
};
|
||||
try {
|
||||
const { data } = await axios.request(config);
|
||||
if (data.payload[0] && data.payload[0].id == body.content_attributes.in_reply_to) {
|
||||
formatText = formatText +`\n\nResposta à: \n` + data.payload[0].content + ``;
|
||||
}
|
||||
this.logger.verbose('data sent');
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (const message of body.conversation.messages) {
|
||||
this.logger.verbose('check if message is media');
|
||||
if (message.attachments && message.attachments.length > 0) {
|
||||
@ -1522,14 +1581,20 @@ export class ChatwootService {
|
||||
if (event === 'status.instance') {
|
||||
this.logger.verbose('event status.instance');
|
||||
const data = body;
|
||||
const inbox = await this.getInbox(instance);
|
||||
|
||||
if (!inbox) {
|
||||
this.logger.warn('inbox not found');
|
||||
return;
|
||||
if (this.provider?.id_inbox) {
|
||||
var msgStatus = `⚡️ Instance status ${this.provider?.name_inbox}: ${data.status}`;
|
||||
} else {
|
||||
const inbox = await this.getInbox(instance);
|
||||
|
||||
if (!inbox) {
|
||||
this.logger.warn('inbox not found');
|
||||
return;
|
||||
}
|
||||
|
||||
var msgStatus = `⚡️ Instance status ${inbox.name}: ${data.status}`;
|
||||
}
|
||||
|
||||
const msgStatus = `⚡️ Instance status ${inbox.name}: ${data.status}`;
|
||||
|
||||
this.logger.verbose('send message to chatwoot');
|
||||
await this.createBotMessage(instance, msgStatus, 'incoming');
|
||||
|
@ -24,6 +24,7 @@ import {
|
||||
TypebotModel,
|
||||
WebhookModel,
|
||||
WebsocketModel,
|
||||
|
||||
} from '../models';
|
||||
import { RepositoryBroker } from '../repository/repository.manager';
|
||||
import { WAStartupService } from './whatsapp.service';
|
||||
@ -45,7 +46,10 @@ export class WAMonitoringService {
|
||||
Object.assign(this.redis, configService.get<Redis>('REDIS'));
|
||||
|
||||
this.dbInstance = this.db.ENABLED
|
||||
? this.repository.dbServer?.db(this.db.CONNECTION.DB_PREFIX_NAME + '-instances')
|
||||
? this.repository.dbServer?.db(
|
||||
this.db.CONNECTION.DB_PREFIX_NAME +
|
||||
this.db.CONNECTION.DB_PREFIX_FINAL_NAME
|
||||
)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
@ -239,19 +243,21 @@ export class WAMonitoringService {
|
||||
|
||||
this.logger.verbose('cleaning store database instance: ' + instanceName);
|
||||
|
||||
await AuthModel.deleteMany({ owner: instanceName });
|
||||
await ChatModel.deleteMany({ owner: instanceName });
|
||||
await ContactModel.deleteMany({ owner: instanceName });
|
||||
await MessageUpModel.deleteMany({ owner: instanceName });
|
||||
await MessageModel.deleteMany({ owner: instanceName });
|
||||
|
||||
await AuthModel.deleteMany({ _id: instanceName });
|
||||
await MessageUpModel.deleteMany({ owner: instanceName });
|
||||
await WebhookModel.deleteMany({ _id: instanceName });
|
||||
await ChatwootModel.deleteMany({ _id: instanceName });
|
||||
|
||||
await ChamaaiModel.deleteMany({ _id: instanceName });
|
||||
await ProxyModel.deleteMany({ _id: instanceName });
|
||||
await RabbitmqModel.deleteMany({ _id: instanceName });
|
||||
await TypebotModel.deleteMany({ _id: instanceName });
|
||||
await WebsocketModel.deleteMany({ _id: instanceName });
|
||||
|
||||
await SettingsModel.deleteMany({ _id: instanceName });
|
||||
|
||||
return;
|
||||
@ -277,6 +283,7 @@ export class WAMonitoringService {
|
||||
const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache);
|
||||
instance.instanceName = name;
|
||||
this.logger.verbose('Instance loaded: ' + name);
|
||||
|
||||
await instance.connectToWhatsapp();
|
||||
this.logger.verbose('connectToWhatsapp: ' + name);
|
||||
|
||||
|
57
src/whatsapp/services/openai.service.ts
Normal file
57
src/whatsapp/services/openai.service.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { initQueues } from '../../libs/amqp.server';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { OpenaiDto } from '../dto/openai.dto';
|
||||
import { ContactOpenaiDto } from '../dto/contactopenai.dto';
|
||||
import { OpenaiRaw } from '../models';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class OpenaiService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
|
||||
private readonly logger = new Logger(OpenaiService.name);
|
||||
|
||||
public create(instance: InstanceDto, data: OpenaiDto) {
|
||||
this.logger.verbose('create openai: ' + instance.instanceName);
|
||||
this.waMonitor.waInstances[instance.instanceName].setOpenai(data);
|
||||
return { openai: { ...instance, openai: data } };
|
||||
}
|
||||
|
||||
public async find(instance: InstanceDto): Promise<OpenaiRaw> {
|
||||
try {
|
||||
this.logger.verbose('find openai: ' + instance.instanceName);
|
||||
const result = await this.waMonitor.waInstances[instance.instanceName].findOpenai();
|
||||
|
||||
if (Object.keys(result).length === 0) {
|
||||
throw new Error('openai not found');
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { chave: '', enabled: false, events: [] };
|
||||
}
|
||||
}
|
||||
|
||||
public createContact(instance: InstanceDto, data: ContactOpenaiDto) {
|
||||
this.logger.verbose('create openai: ' + instance.instanceName);
|
||||
this.waMonitor.waInstances[instance.instanceName].setContactOpenai(data);
|
||||
return { openai: { ...instance, openai: data } };
|
||||
}
|
||||
|
||||
|
||||
public async findContact(instance: InstanceDto): Promise<OpenaiRaw> {
|
||||
try {
|
||||
this.logger.verbose('find openai: ' + instance.instanceName);
|
||||
const result = await this.waMonitor.waInstances[instance.instanceName].findContactOpenai();
|
||||
|
||||
if (Object.keys(result).length === 0) {
|
||||
throw new Error('openai not found');
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { chave: '', enabled: false, events: [] };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -6,7 +6,7 @@ import { SqsRaw } from '../models';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class SqsService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
constructor(private readonly waMonitor: WAMonitoringService) { }
|
||||
|
||||
private readonly logger = new Logger(SqsService.name);
|
||||
|
||||
|
@ -9,7 +9,8 @@ import { Events } from '../types/wa.types';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class TypebotService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {}
|
||||
//constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) { }
|
||||
|
||||
private readonly logger = new Logger(TypebotService.name);
|
||||
|
||||
@ -177,6 +178,8 @@ export class TypebotService {
|
||||
};
|
||||
|
||||
try {
|
||||
//const request = await axios.post(data.url + '/api/v1/sendMessage', reqData);
|
||||
|
||||
const version = this.configService.get<Typebot>('TYPEBOT').API_VERSION;
|
||||
const request = await axios.post(`${data.url}/api/${version}/sendMessage`, reqData);
|
||||
|
||||
@ -267,6 +270,8 @@ export class TypebotService {
|
||||
};
|
||||
|
||||
try {
|
||||
//const request = await axios.post(data.url + '/api/v1/sendMessage', reqData);
|
||||
|
||||
const version = this.configService.get<Typebot>('TYPEBOT').API_VERSION;
|
||||
const request = await axios.post(`${data.url}/api/${version}/sendMessage`, reqData);
|
||||
|
||||
@ -386,7 +391,7 @@ export class TypebotService {
|
||||
}
|
||||
|
||||
if (element.underline) {
|
||||
text = `*${text}*`;
|
||||
text = `~${text}~`;
|
||||
}
|
||||
|
||||
if (element.url) {
|
||||
@ -571,6 +576,7 @@ export class TypebotService {
|
||||
};
|
||||
|
||||
try {
|
||||
//const request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||
const version = this.configService.get<Typebot>('TYPEBOT').API_VERSION;
|
||||
const request = await axios.post(`${data.url}/api/${version}/sendMessage`, reqData);
|
||||
|
||||
@ -658,9 +664,9 @@ export class TypebotService {
|
||||
|
||||
let request: any;
|
||||
try {
|
||||
//request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||
const version = this.configService.get<Typebot>('TYPEBOT').API_VERSION;
|
||||
request = await axios.post(`${data.url}/api/${version}/sendMessage`, reqData);
|
||||
|
||||
await this.sendWAMessage(
|
||||
instance,
|
||||
remoteJid,
|
||||
@ -739,6 +745,7 @@ export class TypebotService {
|
||||
sessionId: session.sessionId.split('-')[1],
|
||||
};
|
||||
|
||||
//const request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||
const version = this.configService.get<Typebot>('TYPEBOT').API_VERSION;
|
||||
const request = await axios.post(`${url}/api/${version}/sendMessage`, reqData);
|
||||
|
||||
@ -755,5 +762,249 @@ export class TypebotService {
|
||||
this.logger.error(error);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
if (session && expire && expire > 0) {
|
||||
const now = Date.now();
|
||||
|
||||
const diff = now - session.updateAt;
|
||||
|
||||
const diffInMinutes = Math.floor(diff / 1000 / 60);
|
||||
|
||||
if (diffInMinutes > expire) {
|
||||
//sessions.splice(sessions.indexOf(session), 1);
|
||||
const newSessions = await this.clearSessions(instance, remoteJid);
|
||||
|
||||
const data = await this.createNewSession(instance, {
|
||||
enabled: findTypebot.enabled,
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
keyword_finish: keyword_finish,
|
||||
delay_message: delay_message,
|
||||
unknown_message: unknown_message,
|
||||
listening_from_me: listening_from_me,
|
||||
//sessions: sessions,
|
||||
sessions: newSessions,
|
||||
remoteJid: remoteJid,
|
||||
pushName: msg.pushName,
|
||||
});
|
||||
|
||||
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
||||
|
||||
if (data.messages.length === 0) {
|
||||
const content = this.getConversationMessage(msg.message);
|
||||
|
||||
if (!content) {
|
||||
if (unknown_message) {
|
||||
this.waMonitor.waInstances[instance.instanceName].textMessage({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: delay_message || 1000,
|
||||
presence: 'composing',
|
||||
},
|
||||
textMessage: {
|
||||
text: unknown_message,
|
||||
},
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) {
|
||||
sessions.splice(sessions.indexOf(session), 1);
|
||||
|
||||
const typebotData = {
|
||||
enabled: findTypebot.enabled,
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
keyword_finish: keyword_finish,
|
||||
delay_message: delay_message,
|
||||
unknown_message: unknown_message,
|
||||
listening_from_me: listening_from_me,
|
||||
sessions,
|
||||
};
|
||||
|
||||
this.create(instance, typebotData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const reqData = {
|
||||
message: content,
|
||||
sessionId: data.sessionId,
|
||||
};
|
||||
|
||||
const request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||
|
||||
await this.sendWAMessage(
|
||||
instance,
|
||||
remoteJid,
|
||||
request.data.messages,
|
||||
request.data.input,
|
||||
request.data.clientSideActions,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (session && session.status !== 'opened') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
const data = await this.createNewSession(instance, {
|
||||
enabled: findTypebot.enabled,
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
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,
|
||||
});
|
||||
|
||||
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
||||
|
||||
if (data.messages.length === 0) {
|
||||
const content = this.getConversationMessage(msg.message);
|
||||
|
||||
if (!content) {
|
||||
if (unknown_message) {
|
||||
this.waMonitor.waInstances[instance.instanceName].textMessage({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: delay_message || 1000,
|
||||
presence: 'composing',
|
||||
},
|
||||
textMessage: {
|
||||
text: unknown_message,
|
||||
},
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) {
|
||||
sessions.splice(sessions.indexOf(session), 1);
|
||||
|
||||
const typebotData = {
|
||||
enabled: findTypebot.enabled,
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
keyword_finish: keyword_finish,
|
||||
delay_message: delay_message,
|
||||
unknown_message: unknown_message,
|
||||
listening_from_me: listening_from_me,
|
||||
sessions,
|
||||
};
|
||||
|
||||
this.create(instance, typebotData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const reqData = {
|
||||
message: content,
|
||||
sessionId: data.sessionId,
|
||||
};
|
||||
|
||||
const request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||
|
||||
await this.sendWAMessage(
|
||||
instance,
|
||||
remoteJid,
|
||||
request.data.messages,
|
||||
request.data.input,
|
||||
request.data.clientSideActions,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sessions.map((session) => {
|
||||
if (session.remoteJid === remoteJid) {
|
||||
session.updateAt = Date.now();
|
||||
}
|
||||
});
|
||||
|
||||
const typebotData = {
|
||||
enabled: findTypebot.enabled,
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
keyword_finish: keyword_finish,
|
||||
delay_message: delay_message,
|
||||
unknown_message: unknown_message,
|
||||
listening_from_me: listening_from_me,
|
||||
sessions,
|
||||
};
|
||||
|
||||
this.create(instance, typebotData);
|
||||
|
||||
const content = this.getConversationMessage(msg.message);
|
||||
|
||||
if (!content) {
|
||||
if (unknown_message) {
|
||||
this.waMonitor.waInstances[instance.instanceName].textMessage({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: delay_message || 1000,
|
||||
presence: 'composing',
|
||||
},
|
||||
textMessage: {
|
||||
text: unknown_message,
|
||||
},
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) {
|
||||
sessions.splice(sessions.indexOf(session), 1);
|
||||
|
||||
const typebotData = {
|
||||
enabled: findTypebot.enabled,
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
keyword_finish: keyword_finish,
|
||||
delay_message: delay_message,
|
||||
unknown_message: unknown_message,
|
||||
listening_from_me: listening_from_me,
|
||||
sessions,
|
||||
};
|
||||
|
||||
this.create(instance, typebotData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const reqData = {
|
||||
message: content,
|
||||
sessionId: session.sessionId.split('-')[1],
|
||||
};
|
||||
|
||||
const request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||
|
||||
await this.sendWAMessage(
|
||||
instance,
|
||||
remoteJid,
|
||||
request.data.messages,
|
||||
request.data.input,
|
||||
request.data.clientSideActions,
|
||||
);
|
||||
|
||||
return;
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,8 @@ import {
|
||||
SendTextDto,
|
||||
StatusMessage,
|
||||
} from '../dto/sendMessage.dto';
|
||||
import { ChamaaiRaw, ProxyRaw, RabbitmqRaw, SettingsRaw, SqsRaw, TypebotRaw } from '../models';
|
||||
import { ChamaaiRaw, ProxyRaw, RabbitmqRaw, OpenaiRaw, SettingsRaw, SqsRaw, TypebotRaw, ContactOpenaiRaw } from '../models';
|
||||
|
||||
import { ChatRaw } from '../models/chat.model';
|
||||
import { ChatwootRaw } from '../models/chatwoot.model';
|
||||
import { ContactRaw } from '../models/contact.model';
|
||||
@ -130,7 +131,51 @@ 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';
|
||||
|
||||
import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "openai"
|
||||
|
||||
import { openai, OpenAIService } from "../../libs/openai"
|
||||
import { redis } from "../../libs/redis"
|
||||
|
||||
import { initPrompt } from "../../utils/initPrompt"
|
||||
import { ContactOpenaiDto } from '../dto/contactopenai.dto';
|
||||
|
||||
// https://wa.me/+5512982754592
|
||||
interface CustomerChat {
|
||||
status?: "open" | "closed"
|
||||
orderCode: string
|
||||
chatAt: string
|
||||
customer: {
|
||||
name: string
|
||||
phone: string
|
||||
}
|
||||
messages: ChatCompletionRequestMessage[]
|
||||
orderSummary?: string
|
||||
}
|
||||
|
||||
async function completion(
|
||||
apiKey: string,
|
||||
messages: ChatCompletionRequestMessage[]
|
||||
): Promise<string | undefined> {
|
||||
|
||||
const configuration = new Configuration({
|
||||
apiKey: apiKey,
|
||||
})
|
||||
|
||||
const openai = new OpenAIApi(configuration)
|
||||
|
||||
const completion = await openai.createChatCompletion({
|
||||
model: "gpt-3.5-turbo",
|
||||
temperature: 0,
|
||||
max_tokens: 256,
|
||||
messages,
|
||||
})
|
||||
|
||||
return completion.data.choices[0].message?.content
|
||||
}
|
||||
|
||||
export class WAStartupService {
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
@ -151,6 +196,7 @@ export class WAStartupService {
|
||||
private readonly localSettings: wa.LocalSettings = {};
|
||||
private readonly localWebsocket: wa.LocalWebsocket = {};
|
||||
private readonly localRabbitmq: wa.LocalRabbitmq = {};
|
||||
private readonly localOpenai: wa.LocalOpenai = {};
|
||||
private readonly localSqs: wa.LocalSqs = {};
|
||||
public readonly localTypebot: wa.LocalTypebot = {};
|
||||
private readonly localProxy: wa.LocalProxy = {};
|
||||
@ -166,6 +212,7 @@ export class WAStartupService {
|
||||
|
||||
private chatwootService = new ChatwootService(waMonitor, this.configService);
|
||||
|
||||
//private typebotService = new TypebotService(waMonitor);
|
||||
private typebotService = new TypebotService(waMonitor, this.configService);
|
||||
|
||||
private chamaaiService = new ChamaaiService(waMonitor, this.configService);
|
||||
@ -216,7 +263,10 @@ export class WAStartupService {
|
||||
this.logger.verbose('Database enabled, trying to get from database');
|
||||
const collection = dbserver
|
||||
.getClient()
|
||||
.db(this.configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_NAME + '-instances')
|
||||
.db(
|
||||
this.configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_NAME +
|
||||
this.configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_FINAL_NAME
|
||||
)
|
||||
.collection(this.instanceName);
|
||||
const data = await collection.findOne({ _id: 'creds' });
|
||||
if (data) {
|
||||
@ -465,6 +515,72 @@ export class WAStartupService {
|
||||
return data;
|
||||
}
|
||||
|
||||
private async loadOpenai() {
|
||||
this.logger.verbose('Loading openai');
|
||||
const data = await this.repository.openai.find(this.instanceName);
|
||||
|
||||
this.localOpenai.chave = data?.chave;
|
||||
this.logger.verbose(`Openai chave: ${this.localOpenai.chave}`);
|
||||
|
||||
this.localOpenai.enabled = data?.enabled;
|
||||
this.logger.verbose(`Openai enabled: ${this.localOpenai.enabled}`);
|
||||
|
||||
this.localOpenai.events = data?.events;
|
||||
this.logger.verbose(`Openai events: ${this.localOpenai.events}`);
|
||||
|
||||
this.logger.verbose('Openai loaded');
|
||||
}
|
||||
|
||||
public async setOpenai(data: OpenaiRaw) {
|
||||
this.logger.verbose('Setting openai');
|
||||
await this.repository.openai.create(data, this.instanceName);
|
||||
this.logger.verbose(`Openai events: ${data.events}`);
|
||||
Object.assign(this.localOpenai, data);
|
||||
this.logger.verbose('Openai set');
|
||||
}
|
||||
|
||||
public async setContactOpenai(data: ContactOpenaiRaw) {
|
||||
this.logger.verbose('Setting openai');
|
||||
await this.repository.openai.createContact(data, this.instanceName);
|
||||
|
||||
this.logger.verbose(`Openai events: ${data.enabled}`);
|
||||
Object.assign(this.localOpenai, data);
|
||||
this.logger.verbose('Openai set');
|
||||
}
|
||||
|
||||
public async findContactOpenai() {
|
||||
this.logger.verbose('Finding openai');
|
||||
const data = await this.repository.openai.findContactAll(this.instanceName);
|
||||
|
||||
if (!data) {
|
||||
this.logger.verbose('Openai not found');
|
||||
throw new NotFoundException('Openai not found');
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public async findOpenai() {
|
||||
this.logger.verbose('Finding openai');
|
||||
const data = await this.repository.openai.find(this.instanceName);
|
||||
|
||||
if (!data) {
|
||||
this.logger.verbose('Openai not found');
|
||||
throw new NotFoundException('Openai not found');
|
||||
}
|
||||
|
||||
this.logger.verbose(`Openai events: ${data.events}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
public async removeOpenaiQueues() {
|
||||
this.logger.verbose('Removing openai');
|
||||
|
||||
if (this.localOpenai.enabled) {
|
||||
removeQueues(this.instanceName, this.localOpenai.events);
|
||||
}
|
||||
}
|
||||
|
||||
private async loadRabbitmq() {
|
||||
this.logger.verbose('Loading rabbitmq');
|
||||
const data = await this.repository.rabbitmq.find(this.instanceName);
|
||||
@ -507,6 +623,7 @@ export class WAStartupService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async loadSqs() {
|
||||
this.logger.verbose('Loading sqs');
|
||||
const data = await this.repository.sqs.find(this.instanceName);
|
||||
@ -626,10 +743,11 @@ export class WAStartupService {
|
||||
this.logger.verbose(`Proxy proxy: ${data.proxy}`);
|
||||
Object.assign(this.localProxy, data);
|
||||
this.logger.verbose('Proxy set');
|
||||
|
||||
//this.reloadConnection();
|
||||
if (reload) {
|
||||
this.reloadConnection();
|
||||
}
|
||||
//this.client?.ws?.close();
|
||||
}
|
||||
|
||||
public async findProxy() {
|
||||
@ -768,6 +886,7 @@ export class WAStartupService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (this.localSqs.enabled) {
|
||||
const sqs = getSQS();
|
||||
|
||||
@ -1299,14 +1418,18 @@ export class WAStartupService {
|
||||
let options;
|
||||
|
||||
if (this.localProxy.enabled) {
|
||||
this.logger.info('Proxy enabled: ' + this.localProxy.proxy);
|
||||
|
||||
this.logger.verbose('Proxy enabled');
|
||||
// options = {
|
||||
// agent: new ProxyAgent(this.localProxy.proxy as any),
|
||||
// fetchAgent: new ProxyAgent(this.localProxy.proxy as any),
|
||||
// };
|
||||
if (this.localProxy.proxy.includes('proxyscrape')) {
|
||||
const response = await axios.get(this.localProxy.proxy);
|
||||
const text = response.data;
|
||||
const proxyUrls = text.split('\r\n');
|
||||
const rand = Math.floor(Math.random() * Math.floor(proxyUrls.length));
|
||||
const proxyUrl = 'http://' + proxyUrls[rand];
|
||||
console.log(proxyUrl);
|
||||
options = {
|
||||
agent: new ProxyAgent(proxyUrl as any),
|
||||
};
|
||||
@ -1656,9 +1779,132 @@ export class WAStartupService {
|
||||
|
||||
let messageRaw: MessageRaw;
|
||||
|
||||
if (received.key.remoteJid.includes('@g.us')) {
|
||||
}else{
|
||||
|
||||
if (messages[0].message.conversation){
|
||||
|
||||
const openai = await this.repository.openai_contact.find(this.instance.name);
|
||||
|
||||
if (openai && openai?.chave && openai?.enabled == true && openai?.prompts){
|
||||
|
||||
const customerPhone = `+${received.key.remoteJid.replace("@s.whatsapp.net", "")}`
|
||||
const customerName = messages[0].pushName
|
||||
|
||||
const contactOpenaiC = await this.repository.openai_contact.findContact(this.instance.name, customerPhone);
|
||||
if (!contactOpenaiC){
|
||||
var data = new ContactOpenaiDto;
|
||||
data.contact = customerPhone;
|
||||
data.enabled = true;
|
||||
data.owner = this.instance.name;
|
||||
|
||||
await this.repository.openai_contact.createContact(data, this.instance.name)
|
||||
}
|
||||
|
||||
const contactOpenai = await this.repository.openai_contact.findContact(this.instance.name, customerPhone);
|
||||
|
||||
if(contactOpenai?.enabled == true){
|
||||
|
||||
const customerKey = `instancia:${this.instance.name}customer:${customerPhone}:chat`
|
||||
const orderCode = `#sk-${("00000" + Math.random()).slice(-5)}`
|
||||
|
||||
const lastChat = JSON.parse((await redis.get(customerKey)) || "{}")
|
||||
var storeName = 'Nome';
|
||||
const customerChat: CustomerChat =
|
||||
lastChat?.status === "open"
|
||||
? (lastChat as CustomerChat)
|
||||
: {
|
||||
status: "open",
|
||||
orderCode,
|
||||
chatAt: new Date().toISOString(),
|
||||
customer: {
|
||||
name: customerName,
|
||||
phone: customerPhone,
|
||||
},
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: initPrompt(storeName, orderCode, openai?.prompts),
|
||||
},
|
||||
],
|
||||
orderSummary: "",
|
||||
}
|
||||
|
||||
this.logger.verbose(customerPhone+" 👤 "+ messages[0].message.conversation)
|
||||
|
||||
customerChat.messages.push({
|
||||
role: "user",
|
||||
content: messages[0].message.conversation,
|
||||
})
|
||||
|
||||
const content =
|
||||
(await completion(openai.chave,
|
||||
customerChat.messages)) || "Não entendi..."
|
||||
|
||||
customerChat.messages.push({
|
||||
role: "assistant",
|
||||
content,
|
||||
})
|
||||
|
||||
this.logger.verbose(customerPhone + " 🤖 "+ content)
|
||||
|
||||
var dadosMessage = {
|
||||
textMessage: received.message.conversation,
|
||||
};
|
||||
|
||||
let mentions: string[];
|
||||
|
||||
const linkPreview = true;
|
||||
|
||||
let quoted: WAMessage;
|
||||
|
||||
const option = {
|
||||
quoted,
|
||||
};
|
||||
|
||||
this.client.sendMessage(
|
||||
received.key.remoteJid,
|
||||
{
|
||||
text: content,
|
||||
mentions,
|
||||
linkPreview: linkPreview,
|
||||
} as unknown as AnyMessageContent,
|
||||
option as unknown as MiscMessageGenerationOptions,
|
||||
);
|
||||
|
||||
if (
|
||||
customerChat.status === "open" &&
|
||||
content.match(customerChat.orderCode)
|
||||
) {
|
||||
customerChat.status = "closed"
|
||||
|
||||
customerChat.messages.push({
|
||||
role: "user",
|
||||
content:
|
||||
"Gere um resumo de pedido para registro no sistema da pizzaria, quem está solicitando é um robô.",
|
||||
})
|
||||
|
||||
const content =
|
||||
(await completion(openai.chave,customerChat.messages)) || "Não entendi..."
|
||||
|
||||
this.logger.verbose(customerPhone + " 📦 "+ content)
|
||||
|
||||
customerChat.orderSummary = content
|
||||
}
|
||||
redis.set(customerKey, JSON.stringify(customerChat))
|
||||
|
||||
this.logger.verbose(received);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (
|
||||
(this.localWebhook.webhook_base64 === true && received?.message.documentMessage) ||
|
||||
received?.message?.imageMessage
|
||||
received?.message.imageMessage
|
||||
) {
|
||||
const buffer = await downloadMediaMessage(
|
||||
{ key: received.key, message: received?.message },
|
||||
@ -1714,6 +1960,7 @@ export class WAStartupService {
|
||||
);
|
||||
}
|
||||
|
||||
//if (this.localTypebot.enabled) {
|
||||
const typebotSessionRemoteJid = this.localTypebot.sessions?.find(
|
||||
(session) => session.remoteJid === received.key.remoteJid,
|
||||
);
|
||||
@ -2060,7 +2307,9 @@ export class WAStartupService {
|
||||
private createJid(number: string): string {
|
||||
this.logger.verbose('Creating jid with number: ' + number);
|
||||
|
||||
//if (number.includes('@g.us') || number.includes('@s.whatsapp.net')) {
|
||||
if (number.includes('@g.us') || number.includes('@s.whatsapp.net') || number.includes('@lid')) {
|
||||
//this.logger.verbose('Number already contains @g.us or @s.whatsapp.net');
|
||||
this.logger.verbose('Number already contains @g.us or @s.whatsapp.net or @lid');
|
||||
return number;
|
||||
}
|
||||
@ -2285,6 +2534,7 @@ export class WAStartupService {
|
||||
!message['conversation'] &&
|
||||
sender !== 'status@broadcast'
|
||||
) {
|
||||
|
||||
if (message['reactionMessage']) {
|
||||
this.logger.verbose('Sending reaction');
|
||||
return await this.client.sendMessage(
|
||||
@ -2314,6 +2564,7 @@ export class WAStartupService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (message['conversation']) {
|
||||
this.logger.verbose('Sending message');
|
||||
return await this.client.sendMessage(
|
||||
@ -2573,9 +2824,15 @@ export class WAStartupService {
|
||||
|
||||
let mimetype: string;
|
||||
|
||||
// if (isURL(mediaMessage.media)) {
|
||||
// mimetype = getMIMEType(mediaMessage.media);
|
||||
// } else {
|
||||
// mimetype = getMIMEType(mediaMessage.fileName);
|
||||
// }
|
||||
|
||||
if (mediaMessage.mimetype) {
|
||||
mimetype = mediaMessage.mimetype;
|
||||
} else {
|
||||
}else{
|
||||
if (isURL(mediaMessage.media)) {
|
||||
mimetype = getMIMEType(mediaMessage.media);
|
||||
} else {
|
||||
@ -3229,6 +3486,7 @@ export class WAStartupService {
|
||||
await this.client.updateGroupsAddPrivacy(settings.privacySettings.groupadd);
|
||||
this.logger.verbose('Groups add privacy updated');
|
||||
|
||||
//this.client?.ws?.close();
|
||||
this.reloadConnection();
|
||||
|
||||
return {
|
||||
|
@ -89,6 +89,12 @@ export declare namespace wa {
|
||||
events?: string[];
|
||||
};
|
||||
|
||||
export type LocalOpenai = {
|
||||
chave?: string;
|
||||
enabled?: boolean;
|
||||
events?: string[];
|
||||
};
|
||||
|
||||
type Session = {
|
||||
remoteJid?: string;
|
||||
sessionId?: string;
|
||||
|
@ -10,6 +10,7 @@ import { GroupController } from './controllers/group.controller';
|
||||
import { InstanceController } from './controllers/instance.controller';
|
||||
import { ProxyController } from './controllers/proxy.controller';
|
||||
import { RabbitmqController } from './controllers/rabbitmq.controller';
|
||||
import { OpenaiController } from './controllers/openai.controller';
|
||||
import { SendMessageController } from './controllers/sendMessage.controller';
|
||||
import { SettingsController } from './controllers/settings.controller';
|
||||
import { SqsController } from './controllers/sqs.controller';
|
||||
@ -27,6 +28,8 @@ import {
|
||||
MessageUpModel,
|
||||
ProxyModel,
|
||||
RabbitmqModel,
|
||||
OpenaiModel,
|
||||
ContactOpenaiModel,
|
||||
SettingsModel,
|
||||
SqsModel,
|
||||
TypebotModel,
|
||||
@ -42,6 +45,7 @@ import { MessageRepository } from './repository/message.repository';
|
||||
import { MessageUpRepository } from './repository/messageUp.repository';
|
||||
import { ProxyRepository } from './repository/proxy.repository';
|
||||
import { RabbitmqRepository } from './repository/rabbitmq.repository';
|
||||
import { OpenaiRepository } from './repository/openai.repository';
|
||||
import { RepositoryBroker } from './repository/repository.manager';
|
||||
import { SettingsRepository } from './repository/settings.repository';
|
||||
import { SqsRepository } from './repository/sqs.repository';
|
||||
@ -54,6 +58,7 @@ import { ChatwootService } from './services/chatwoot.service';
|
||||
import { WAMonitoringService } from './services/monitor.service';
|
||||
import { ProxyService } from './services/proxy.service';
|
||||
import { RabbitmqService } from './services/rabbitmq.service';
|
||||
import { OpenaiService } from './services/openai.service';
|
||||
import { SettingsService } from './services/settings.service';
|
||||
import { SqsService } from './services/sqs.service';
|
||||
import { TypebotService } from './services/typebot.service';
|
||||
@ -72,9 +77,10 @@ const websocketRepository = new WebsocketRepository(WebsocketModel, configServic
|
||||
const proxyRepository = new ProxyRepository(ProxyModel, configService);
|
||||
const chamaaiRepository = new ChamaaiRepository(ChamaaiModel, configService);
|
||||
const rabbitmqRepository = new RabbitmqRepository(RabbitmqModel, configService);
|
||||
const sqsRepository = new SqsRepository(SqsModel, configService);
|
||||
const openaiRepository = new OpenaiRepository(OpenaiModel,ContactOpenaiModel, configService);
|
||||
const chatwootRepository = new ChatwootRepository(ChatwootModel, configService);
|
||||
const settingsRepository = new SettingsRepository(SettingsModel, configService);
|
||||
const sqsRepository = new SqsRepository(SqsModel, configService);
|
||||
const authRepository = new AuthRepository(AuthModel, configService);
|
||||
|
||||
export const repository = new RepositoryBroker(
|
||||
@ -87,6 +93,8 @@ export const repository = new RepositoryBroker(
|
||||
settingsRepository,
|
||||
websocketRepository,
|
||||
rabbitmqRepository,
|
||||
openaiRepository,
|
||||
openaiRepository,
|
||||
sqsRepository,
|
||||
typebotRepository,
|
||||
proxyRepository,
|
||||
@ -130,6 +138,10 @@ const sqsService = new SqsService(waMonitor);
|
||||
|
||||
export const sqsController = new SqsController(sqsService);
|
||||
|
||||
const openaiService = new OpenaiService(waMonitor);
|
||||
|
||||
export const openaiController = new OpenaiController(openaiService);
|
||||
|
||||
const chatwootService = new ChatwootService(waMonitor, configService);
|
||||
|
||||
export const chatwootController = new ChatwootController(chatwootService, configService);
|
||||
@ -149,6 +161,7 @@ export const instanceController = new InstanceController(
|
||||
settingsService,
|
||||
websocketService,
|
||||
rabbitmqService,
|
||||
openaiService,
|
||||
proxyService,
|
||||
sqsService,
|
||||
typebotService,
|
||||
|
Loading…
Reference in New Issue
Block a user