diff --git a/src/main.ts b/src/main.ts index 75dd95b3..2095bd4c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -47,6 +47,8 @@ function bootstrap() { app.set('views', join(ROOT_DIR, 'views')); app.use(express.static(join(ROOT_DIR, 'public'))); + app.use('/store', express.static(join(ROOT_DIR, 'store'))); + app.use('/', router); app.use( diff --git a/src/validate/validate.schema.ts b/src/validate/validate.schema.ts index bce05660..ebfed66a 100644 --- a/src/validate/validate.schema.ts +++ b/src/validate/validate.schema.ts @@ -1023,3 +1023,17 @@ export const proxySchema: JSONSchema7 = { required: ['enabled', 'proxy'], ...isNotEmpty('enabled', 'proxy'), }; + +export const chamaaiSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean', enum: [true, false] }, + url: { type: 'string' }, + token: { type: 'string' }, + waNumber: { type: 'string' }, + answerByAudio: { type: 'boolean', enum: [true, false] }, + }, + required: ['enabled', 'url', 'token', 'waNumber', 'answerByAudio'], + ...isNotEmpty('enabled', 'url', 'token', 'waNumber', 'answerByAudio'), +}; diff --git a/src/whatsapp/controllers/chamaai.controller.ts b/src/whatsapp/controllers/chamaai.controller.ts new file mode 100644 index 00000000..e9cafb50 --- /dev/null +++ b/src/whatsapp/controllers/chamaai.controller.ts @@ -0,0 +1,29 @@ +import { Logger } from '../../config/logger.config'; +import { ChamaaiDto } from '../dto/chamaai.dto'; +import { InstanceDto } from '../dto/instance.dto'; +import { ChamaaiService } from '../services/chamaai.service'; + +const logger = new Logger('ChamaaiController'); + +export class ChamaaiController { + constructor(private readonly chamaaiService: ChamaaiService) {} + + public async createChamaai(instance: InstanceDto, data: ChamaaiDto) { + logger.verbose('requested createChamaai from ' + instance.instanceName + ' instance'); + + if (!data.enabled) { + logger.verbose('chamaai disabled'); + data.url = ''; + data.token = ''; + data.waNumber = ''; + data.answerByAudio = false; + } + + return this.chamaaiService.create(instance, data); + } + + public async findChamaai(instance: InstanceDto) { + logger.verbose('requested findChamaai from ' + instance.instanceName + ' instance'); + return this.chamaaiService.find(instance); + } +} diff --git a/src/whatsapp/dto/chamaai.dto.ts b/src/whatsapp/dto/chamaai.dto.ts new file mode 100644 index 00000000..2c71a07d --- /dev/null +++ b/src/whatsapp/dto/chamaai.dto.ts @@ -0,0 +1,7 @@ +export class ChamaaiDto { + enabled: boolean; + url: string; + token: string; + waNumber: string; + answerByAudio: boolean; +} diff --git a/src/whatsapp/models/chamaai.model.ts b/src/whatsapp/models/chamaai.model.ts new file mode 100644 index 00000000..d3d10aff --- /dev/null +++ b/src/whatsapp/models/chamaai.model.ts @@ -0,0 +1,24 @@ +import { Schema } from 'mongoose'; + +import { dbserver } from '../../libs/db.connect'; + +export class ChamaaiRaw { + _id?: string; + enabled?: boolean; + url?: string; + token?: string; + waNumber?: string; + answerByAudio?: boolean; +} + +const chamaaiSchema = new Schema({ + _id: { type: String, _id: true }, + enabled: { type: Boolean, required: true }, + url: { type: String, required: true }, + token: { type: String, required: true }, + waNumber: { type: String, required: true }, + answerByAudio: { type: Boolean, required: true }, +}); + +export const ChamaaiModel = dbserver?.model(ChamaaiRaw.name, chamaaiSchema, 'chamaai'); +export type IChamaaiModel = typeof ChamaaiModel; diff --git a/src/whatsapp/models/index.ts b/src/whatsapp/models/index.ts index 5d71911d..e79093f9 100644 --- a/src/whatsapp/models/index.ts +++ b/src/whatsapp/models/index.ts @@ -1,4 +1,5 @@ export * from './auth.model'; +export * from './chamaai.model'; export * from './chat.model'; export * from './chatwoot.model'; export * from './contact.model'; diff --git a/src/whatsapp/repository/chamaai.repository.ts b/src/whatsapp/repository/chamaai.repository.ts new file mode 100644 index 00000000..a2009f41 --- /dev/null +++ b/src/whatsapp/repository/chamaai.repository.ts @@ -0,0 +1,62 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; + +import { ConfigService } from '../../config/env.config'; +import { Logger } from '../../config/logger.config'; +import { IInsert, Repository } from '../abstract/abstract.repository'; +import { ChamaaiRaw, IChamaaiModel } from '../models'; + +export class ChamaaiRepository extends Repository { + constructor(private readonly chamaaiModel: IChamaaiModel, private readonly configService: ConfigService) { + super(configService); + } + + private readonly logger = new Logger('ChamaaiRepository'); + + public async create(data: ChamaaiRaw, instance: string): Promise { + try { + this.logger.verbose('creating chamaai'); + if (this.dbSettings.ENABLED) { + this.logger.verbose('saving chamaai to db'); + const insert = await this.chamaaiModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); + + this.logger.verbose('chamaai saved to db: ' + insert.modifiedCount + ' chamaai'); + return { insertCount: insert.modifiedCount }; + } + + this.logger.verbose('saving chamaai to store'); + + this.writeStore({ + path: join(this.storePath, 'chamaai'), + fileName: instance, + data, + }); + + this.logger.verbose('chamaai saved to store in path: ' + join(this.storePath, 'chamaai') + '/' + instance); + + this.logger.verbose('chamaai created'); + return { insertCount: 1 }; + } catch (error) { + return error; + } + } + + public async find(instance: string): Promise { + try { + this.logger.verbose('finding chamaai'); + if (this.dbSettings.ENABLED) { + this.logger.verbose('finding chamaai in db'); + return await this.chamaaiModel.findOne({ _id: instance }); + } + + this.logger.verbose('finding chamaai in store'); + return JSON.parse( + readFileSync(join(this.storePath, 'chamaai', instance + '.json'), { + encoding: 'utf-8', + }), + ) as ChamaaiRaw; + } catch (error) { + return {}; + } + } +} diff --git a/src/whatsapp/repository/repository.manager.ts b/src/whatsapp/repository/repository.manager.ts index 2cd4931e..1c16fdef 100644 --- a/src/whatsapp/repository/repository.manager.ts +++ b/src/whatsapp/repository/repository.manager.ts @@ -5,6 +5,7 @@ import { join } from 'path'; import { Auth, ConfigService, Database } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { AuthRepository } from './auth.repository'; +import { ChamaaiRepository } from './chamaai.repository'; import { ChatRepository } from './chat.repository'; import { ChatwootRepository } from './chatwoot.repository'; import { ContactRepository } from './contact.repository'; @@ -29,6 +30,7 @@ export class RepositoryBroker { public readonly rabbitmq: RabbitmqRepository, public readonly typebot: TypebotRepository, public readonly proxy: ProxyRepository, + public readonly chamaai: ChamaaiRepository, public readonly auth: AuthRepository, private configService: ConfigService, dbServer?: MongoClient, @@ -63,6 +65,7 @@ export class RepositoryBroker { const rabbitmqDir = join(storePath, 'rabbitmq'); const typebotDir = join(storePath, 'typebot'); const proxyDir = join(storePath, 'proxy'); + const chamaaiDir = join(storePath, 'chamaai'); const tempDir = join(storePath, 'temp'); if (!fs.existsSync(authDir)) { @@ -113,6 +116,10 @@ export class RepositoryBroker { this.logger.verbose('creating proxy dir: ' + proxyDir); fs.mkdirSync(proxyDir, { recursive: true }); } + if (!fs.existsSync(chamaaiDir)) { + this.logger.verbose('creating chamaai dir: ' + chamaaiDir); + fs.mkdirSync(chamaaiDir, { recursive: true }); + } if (!fs.existsSync(tempDir)) { this.logger.verbose('creating temp dir: ' + tempDir); fs.mkdirSync(tempDir, { recursive: true }); diff --git a/src/whatsapp/routers/chamaai.router.ts b/src/whatsapp/routers/chamaai.router.ts new file mode 100644 index 00000000..e8021306 --- /dev/null +++ b/src/whatsapp/routers/chamaai.router.ts @@ -0,0 +1,52 @@ +import { RequestHandler, Router } from 'express'; + +import { Logger } from '../../config/logger.config'; +import { chamaaiSchema, instanceNameSchema } from '../../validate/validate.schema'; +import { RouterBroker } from '../abstract/abstract.router'; +import { ChamaaiDto } from '../dto/chamaai.dto'; +import { InstanceDto } from '../dto/instance.dto'; +import { chamaaiController } from '../whatsapp.module'; +import { HttpStatus } from './index.router'; + +const logger = new Logger('ChamaaiRouter'); + +export class ChamaaiRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('set'), ...guards, async (req, res) => { + logger.verbose('request received in setChamaai'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: chamaaiSchema, + ClassRef: ChamaaiDto, + execute: (instance, data) => chamaaiController.createChamaai(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + logger.verbose('request received in findChamaai'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: instanceNameSchema, + ClassRef: InstanceDto, + execute: (instance) => chamaaiController.findChamaai(instance), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router = Router(); +} diff --git a/src/whatsapp/routers/index.router.ts b/src/whatsapp/routers/index.router.ts index a84e815d..f67c936a 100644 --- a/src/whatsapp/routers/index.router.ts +++ b/src/whatsapp/routers/index.router.ts @@ -4,6 +4,7 @@ import fs from 'fs'; import { Auth, configService } from '../../config/env.config'; import { authGuard } from '../guards/auth.guard'; import { instanceExistsGuard, instanceLoggedGuard } from '../guards/instance.guard'; +import { ChamaaiRouter } from './chamaai.router'; import { ChatRouter } from './chat.router'; import { ChatwootRouter } from './chatwoot.router'; import { GroupRouter } from './group.router'; @@ -52,6 +53,7 @@ router .use('/websocket', new WebsocketRouter(...guards).router) .use('/rabbitmq', new RabbitmqRouter(...guards).router) .use('/typebot', new TypebotRouter(...guards).router) - .use('/proxy', new ProxyRouter(...guards).router); + .use('/proxy', new ProxyRouter(...guards).router) + .use('/chamaai', new ChamaaiRouter(...guards).router); export { HttpStatus, router }; diff --git a/src/whatsapp/services/chamaai.service.ts b/src/whatsapp/services/chamaai.service.ts new file mode 100644 index 00000000..9e42ffca --- /dev/null +++ b/src/whatsapp/services/chamaai.service.ts @@ -0,0 +1,196 @@ +import axios from 'axios'; +import { writeFileSync } from 'fs'; +import path from 'path'; + +import { ConfigService, HttpServer } from '../../config/env.config'; +import { Logger } from '../../config/logger.config'; +import { ChamaaiDto } from '../dto/chamaai.dto'; +import { InstanceDto } from '../dto/instance.dto'; +import { ChamaaiRaw } from '../models'; +import { WAMonitoringService } from './monitor.service'; + +export class ChamaaiService { + constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {} + + private readonly logger = new Logger(ChamaaiService.name); + + public create(instance: InstanceDto, data: ChamaaiDto) { + this.logger.verbose('create chamaai: ' + instance.instanceName); + this.waMonitor.waInstances[instance.instanceName].setChamaai(data); + + return { chamaai: { ...instance, chamaai: data } }; + } + + public async find(instance: InstanceDto): Promise { + try { + this.logger.verbose('find chamaai: ' + instance.instanceName); + const result = await this.waMonitor.waInstances[instance.instanceName].findChamaai(); + + if (Object.keys(result).length === 0) { + throw new Error('Chamaai not found'); + } + + return result; + } catch (error) { + return { enabled: false, url: '', token: '', waNumber: '', answerByAudio: false }; + } + } + + private getTypeMessage(msg: any) { + this.logger.verbose('get type message'); + + const types = { + conversation: msg.conversation, + extendedTextMessage: msg.extendedTextMessage?.text, + }; + + this.logger.verbose('type message: ' + types); + + return types; + } + + private getMessageContent(types: any) { + this.logger.verbose('get message content'); + const typeKey = Object.keys(types).find((key) => types[key] !== undefined); + + const result = typeKey ? types[typeKey] : undefined; + + this.logger.verbose('message content: ' + result); + + return result; + } + + private getConversationMessage(msg: any) { + this.logger.verbose('get conversation message'); + + const types = this.getTypeMessage(msg); + + const messageContent = this.getMessageContent(types); + + this.logger.verbose('conversation message: ' + messageContent); + + return messageContent; + } + + private calculateTypingTime(text: string) { + const wordsPerMinute = 100; + + const wordCount = text.split(' ').length; + const typingTimeInMinutes = wordCount / wordsPerMinute; + const typingTimeInMilliseconds = typingTimeInMinutes * 60; + return typingTimeInMilliseconds; + } + + private convertToMilliseconds(count: number) { + const averageCharactersPerSecond = 10; + const characterCount = count; + const speakingTimeInSeconds = characterCount / averageCharactersPerSecond; + return speakingTimeInSeconds; + } + + public async sendChamaai(instance: InstanceDto, remoteJid: string, msg: any) { + const content = this.getConversationMessage(msg.message); + const msgType = msg.messageType; + const find = await this.find(instance); + const url = find.url; + const token = find.token; + const waNumber = find.waNumber; + const answerByAudio = find.answerByAudio; + + if (!content && msgType !== 'audioMessage') { + return; + } + + let data; + let endpoint; + + if (msgType === 'audioMessage') { + const downloadBase64 = await this.waMonitor.waInstances[instance.instanceName].getBase64FromMediaMessage({ + message: { + ...msg, + }, + }); + + const random = Math.random().toString(36).substring(7); + const nameFile = `${random}.ogg`; + + const fileData = Buffer.from(downloadBase64.base64, 'base64'); + + const fileName = `${path.join( + this.waMonitor.waInstances[instance.instanceName].storePath, + 'temp', + `${nameFile}`, + )}`; + + writeFileSync(fileName, fileData, 'utf8'); + + const urlServer = this.configService.get('SERVER').URL; + + const url = `${urlServer}/store/temp/${nameFile}`; + + data = { + waNumber: waNumber, + audioUrl: url, + queryNumber: remoteJid.split('@')[0], + answerByAudio: answerByAudio, + }; + endpoint = 'processMessageAudio'; + } else { + data = { + waNumber: waNumber, + question: content, + queryNumber: remoteJid.split('@')[0], + answerByAudio: answerByAudio, + }; + endpoint = 'processMessageText'; + } + + const request = await axios.post(`${url}/${endpoint}`, data, { + headers: { + Authorization: `${token}`, + }, + }); + + console.log(request.data); + + const answer = request.data?.answer; + + const type = request.data?.type; + + const characterCount = request.data?.characterCount; + + if (answer) { + if (type === 'text') { + this.waMonitor.waInstances[instance.instanceName].textMessage({ + number: remoteJid.split('@')[0], + options: { + delay: this.calculateTypingTime(answer) * 1000 || 1000, + presence: 'composing', + linkPreview: false, + quoted: { + key: msg.key, + message: msg.message, + }, + }, + textMessage: { + text: answer, + }, + }); + } + + if (type === 'audio') { + this.waMonitor.waInstances[instance.instanceName].audioWhatsapp({ + number: remoteJid.split('@')[0], + options: { + delay: characterCount ? this.convertToMilliseconds(characterCount) * 1000 || 1000 : 1000, + presence: 'recording', + encoding: true, + }, + audioMessage: { + audio: answer, + }, + }); + } + } + } +} diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index d11946ee..445069a5 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -113,7 +113,7 @@ import { SendTextDto, StatusMessage, } from '../dto/sendMessage.dto'; -import { ProxyRaw, RabbitmqRaw, SettingsRaw, TypebotRaw } from '../models'; +import { ChamaaiRaw, ProxyRaw, RabbitmqRaw, SettingsRaw, TypebotRaw } from '../models'; import { ChatRaw } from '../models/chat.model'; import { ChatwootRaw } from '../models/chatwoot.model'; import { ContactRaw } from '../models/contact.model'; @@ -126,6 +126,7 @@ import { MessageUpQuery } from '../repository/messageUp.repository'; import { RepositoryBroker } from '../repository/repository.manager'; import { Events, MessageSubtype, TypeMediaMessage, wa } from '../types/wa.types'; import { waMonitor } from '../whatsapp.module'; +import { ChamaaiService } from './chamaai.service'; import { ChatwootService } from './chatwoot.service'; import { TypebotService } from './typebot.service'; @@ -151,6 +152,7 @@ export class WAStartupService { private readonly localRabbitmq: wa.LocalRabbitmq = {}; public readonly localTypebot: wa.LocalTypebot = {}; private readonly localProxy: wa.LocalProxy = {}; + private readonly localChamaai: wa.LocalChamaai = {}; public stateConnection: wa.StateConnection = { state: 'close' }; public readonly storePath = join(ROOT_DIR, 'store'); private readonly msgRetryCounterCache: CacheStore = new NodeCache(); @@ -164,6 +166,8 @@ export class WAStartupService { private typebotService = new TypebotService(waMonitor); + private chamaaiService = new ChamaaiService(waMonitor, this.configService); + public set instanceName(name: string) { this.logger.verbose(`Initializing instance '${name}'`); if (!name) { @@ -579,6 +583,52 @@ export class WAStartupService { return data; } + private async loadChamaai() { + this.logger.verbose('Loading chamaai'); + const data = await this.repository.chamaai.find(this.instanceName); + + this.localChamaai.enabled = data?.enabled; + this.logger.verbose(`Chamaai enabled: ${this.localChamaai.enabled}`); + + this.localChamaai.url = data?.url; + this.logger.verbose(`Chamaai url: ${this.localChamaai.url}`); + + this.localChamaai.token = data?.token; + this.logger.verbose(`Chamaai token: ${this.localChamaai.token}`); + + this.localChamaai.waNumber = data?.waNumber; + this.logger.verbose(`Chamaai waNumber: ${this.localChamaai.waNumber}`); + + this.localChamaai.answerByAudio = data?.answerByAudio; + this.logger.verbose(`Chamaai answerByAudio: ${this.localChamaai.answerByAudio}`); + + this.logger.verbose('Chamaai loaded'); + } + + public async setChamaai(data: ChamaaiRaw) { + this.logger.verbose('Setting chamaai'); + await this.repository.chamaai.create(data, this.instanceName); + this.logger.verbose(`Chamaai url: ${data.url}`); + this.logger.verbose(`Chamaai token: ${data.token}`); + this.logger.verbose(`Chamaai waNumber: ${data.waNumber}`); + this.logger.verbose(`Chamaai answerByAudio: ${data.answerByAudio}`); + + Object.assign(this.localChamaai, data); + this.logger.verbose('Chamaai set'); + } + + public async findChamaai() { + this.logger.verbose('Finding chamaai'); + const data = await this.repository.chamaai.find(this.instanceName); + + if (!data) { + this.logger.verbose('Chamaai not found'); + throw new NotFoundException('Chamaai not found'); + } + + return data; + } + public async sendDataWebhook(event: Events, data: T, local = true) { const webhookGlobal = this.configService.get('WEBHOOK'); const webhookLocal = this.localWebhook.events; @@ -1065,6 +1115,7 @@ export class WAStartupService { this.loadRabbitmq(); this.loadTypebot(); this.loadProxy(); + this.loadChamaai(); this.instance.authState = await this.defineAuthState(); @@ -1383,7 +1434,7 @@ export class WAStartupService { ); } - if (this.localTypebot.enabled && messageRaw.key.remoteJid.includes('@s.whatsapp.net')) { + if (this.localTypebot.enabled && messageRaw.key.fromMe === false) { await this.typebotService.sendTypebot( { instanceName: this.instance.name }, messageRaw.key.remoteJid, @@ -1391,6 +1442,14 @@ export class WAStartupService { ); } + if (this.localChamaai.enabled && messageRaw.key.fromMe === false) { + await this.chamaaiService.sendChamaai( + { instanceName: this.instance.name }, + messageRaw.key.remoteJid, + messageRaw, + ); + } + this.logger.verbose('Inserting message in database'); await this.repository.message.insert([messageRaw], this.instance.name, database.SAVE_DATA.NEW_MESSAGE); @@ -2315,7 +2374,7 @@ export class WAStartupService { return await this.sendMessageWithTyping(data.number, { ...generate.message }, data?.options); } - private async processAudio(audio: string, number: string) { + public async processAudio(audio: string, number: string) { this.logger.verbose('Processing audio'); let tempAudioPath: string; let outputAudio: string; diff --git a/src/whatsapp/types/wa.types.ts b/src/whatsapp/types/wa.types.ts index 893b5f87..72718b65 100644 --- a/src/whatsapp/types/wa.types.ts +++ b/src/whatsapp/types/wa.types.ts @@ -102,6 +102,14 @@ export declare namespace wa { proxy?: string; }; + export type LocalChamaai = { + enabled?: boolean; + url?: string; + token?: string; + waNumber?: string; + answerByAudio?: boolean; + }; + export type StateConnection = { instance?: string; state?: WAConnectionState | 'refused'; diff --git a/src/whatsapp/whatsapp.module.ts b/src/whatsapp/whatsapp.module.ts index d8ed5a62..a37e98ef 100644 --- a/src/whatsapp/whatsapp.module.ts +++ b/src/whatsapp/whatsapp.module.ts @@ -3,6 +3,7 @@ import { eventEmitter } from '../config/event.config'; import { Logger } from '../config/logger.config'; import { dbserver } from '../libs/db.connect'; import { RedisCache } from '../libs/redis.client'; +import { ChamaaiController } from './controllers/chamaai.controller'; import { ChatController } from './controllers/chat.controller'; import { ChatwootController } from './controllers/chatwoot.controller'; import { GroupController } from './controllers/group.controller'; @@ -17,6 +18,7 @@ import { WebhookController } from './controllers/webhook.controller'; import { WebsocketController } from './controllers/websocket.controller'; import { AuthModel, + ChamaaiModel, ChatModel, ChatwootModel, ContactModel, @@ -30,6 +32,7 @@ import { WebsocketModel, } from './models'; import { AuthRepository } from './repository/auth.repository'; +import { ChamaaiRepository } from './repository/chamaai.repository'; import { ChatRepository } from './repository/chat.repository'; import { ChatwootRepository } from './repository/chatwoot.repository'; import { ContactRepository } from './repository/contact.repository'; @@ -43,6 +46,7 @@ import { TypebotRepository } from './repository/typebot.repository'; import { WebhookRepository } from './repository/webhook.repository'; import { WebsocketRepository } from './repository/websocket.repository'; import { AuthService } from './services/auth.service'; +import { ChamaaiService } from './services/chamaai.service'; import { ChatwootService } from './services/chatwoot.service'; import { WAMonitoringService } from './services/monitor.service'; import { ProxyService } from './services/proxy.service'; @@ -62,6 +66,7 @@ const typebotRepository = new TypebotRepository(TypebotModel, configService); const webhookRepository = new WebhookRepository(WebhookModel, configService); const websocketRepository = new WebsocketRepository(WebsocketModel, configService); const proxyRepository = new ProxyRepository(ProxyModel, configService); +const chamaaiRepository = new ChamaaiRepository(ChamaaiModel, configService); const rabbitmqRepository = new RabbitmqRepository(RabbitmqModel, configService); const chatwootRepository = new ChatwootRepository(ChatwootModel, configService); const settingsRepository = new SettingsRepository(SettingsModel, configService); @@ -79,6 +84,7 @@ export const repository = new RepositoryBroker( rabbitmqRepository, typebotRepository, proxyRepository, + chamaaiRepository, authRepository, configService, dbserver?.getClient(), @@ -106,6 +112,10 @@ const proxyService = new ProxyService(waMonitor); export const proxyController = new ProxyController(proxyService); +const chamaaiService = new ChamaaiService(waMonitor, configService); + +export const chamaaiController = new ChamaaiController(chamaaiService); + const rabbitmqService = new RabbitmqService(waMonitor); export const rabbitmqController = new RabbitmqController(rabbitmqService);