chore: Crud openai complete

This commit is contained in:
Davidson Gomes 2024-07-18 10:14:53 -03:00
parent 5b13de377b
commit 29b9e688a8
12 changed files with 2417 additions and 135 deletions

View File

@ -119,6 +119,9 @@ CHATWOOT_MESSAGE_READ=false
CHATWOOT_IMPORT_DATABASE_CONNECTION_URI=postgresql://user:pass@host:5432/dbname CHATWOOT_IMPORT_DATABASE_CONNECTION_URI=postgresql://user:pass@host:5432/dbname
CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE=false CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE=false
OPENAI_ENABLED=false
OPENAI_API_KEY_GLOBAL=
CACHE_REDIS_ENABLED=true CACHE_REDIS_ENABLED=true
CACHE_REDIS_URI=redis://localhost:6379/6 CACHE_REDIS_URI=redis://localhost:6379/6
CACHE_REDIS_PREFIX_KEY=evolution CACHE_REDIS_PREFIX_KEY=evolution

View File

@ -0,0 +1,118 @@
-- AlterTable
ALTER TABLE "Message" ADD COLUMN "openaiSessionId" TEXT;
-- CreateTable
CREATE TABLE "OpenaiCreds" (
"id" TEXT NOT NULL,
"apiKey" VARCHAR(255) NOT NULL,
"createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL,
"instanceId" TEXT NOT NULL,
CONSTRAINT "OpenaiCreds_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "OpenaiBot" (
"id" TEXT NOT NULL,
"botType" VARCHAR(100) NOT NULL,
"assistantId" VARCHAR(255),
"model" VARCHAR(100),
"systemMessages" JSONB,
"assistantMessages" JSONB,
"userMessages" JSONB,
"maxTokens" INTEGER,
"expire" INTEGER DEFAULT 0,
"keywordFinish" VARCHAR(100),
"delayMessage" INTEGER,
"unknownMessage" VARCHAR(100),
"listeningFromMe" BOOLEAN DEFAULT false,
"stopBotFromMe" BOOLEAN DEFAULT false,
"keepOpen" BOOLEAN DEFAULT false,
"debounceTime" INTEGER,
"ignoreJids" JSONB,
"triggerType" "TriggerType",
"triggerOperator" "TriggerOperator",
"triggerValue" TEXT,
"createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL,
"openaiCredsId" TEXT NOT NULL,
"instanceId" TEXT NOT NULL,
CONSTRAINT "OpenaiBot_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "OpenaiSession" (
"id" TEXT NOT NULL,
"sessionId" VARCHAR(255) NOT NULL,
"remoteJid" VARCHAR(100) NOT NULL,
"status" "TypebotSessionStatus" NOT NULL,
"awaitUser" BOOLEAN NOT NULL DEFAULT false,
"createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL,
"openaiBotId" TEXT NOT NULL,
"instanceId" TEXT NOT NULL,
CONSTRAINT "OpenaiSession_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "OpenaiSetting" (
"id" TEXT NOT NULL,
"expire" INTEGER DEFAULT 0,
"keywordFinish" VARCHAR(100),
"delayMessage" INTEGER,
"unknownMessage" VARCHAR(100),
"listeningFromMe" BOOLEAN DEFAULT false,
"stopBotFromMe" BOOLEAN DEFAULT false,
"keepOpen" BOOLEAN DEFAULT false,
"debounceTime" INTEGER,
"ignoreJids" JSONB,
"createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP NOT NULL,
"openaiCredsId" TEXT NOT NULL,
"openaiIdFallback" VARCHAR(100),
"instanceId" TEXT NOT NULL,
CONSTRAINT "OpenaiSetting_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "OpenaiCreds_apiKey_key" ON "OpenaiCreds"("apiKey");
-- CreateIndex
CREATE UNIQUE INDEX "OpenaiCreds_instanceId_key" ON "OpenaiCreds"("instanceId");
-- CreateIndex
CREATE UNIQUE INDEX "OpenaiBot_assistantId_key" ON "OpenaiBot"("assistantId");
-- CreateIndex
CREATE UNIQUE INDEX "OpenaiSetting_instanceId_key" ON "OpenaiSetting"("instanceId");
-- AddForeignKey
ALTER TABLE "Message" ADD CONSTRAINT "Message_openaiSessionId_fkey" FOREIGN KEY ("openaiSessionId") REFERENCES "OpenaiSession"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "OpenaiCreds" ADD CONSTRAINT "OpenaiCreds_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "OpenaiBot" ADD CONSTRAINT "OpenaiBot_openaiCredsId_fkey" FOREIGN KEY ("openaiCredsId") REFERENCES "OpenaiCreds"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "OpenaiBot" ADD CONSTRAINT "OpenaiBot_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "OpenaiSession" ADD CONSTRAINT "OpenaiSession_openaiBotId_fkey" FOREIGN KEY ("openaiBotId") REFERENCES "OpenaiBot"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "OpenaiSession" ADD CONSTRAINT "OpenaiSession_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "OpenaiSetting" ADD CONSTRAINT "OpenaiSetting_openaiCredsId_fkey" FOREIGN KEY ("openaiCredsId") REFERENCES "OpenaiCreds"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "OpenaiSetting" ADD CONSTRAINT "OpenaiSetting_openaiIdFallback_fkey" FOREIGN KEY ("openaiIdFallback") REFERENCES "OpenaiBot"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "OpenaiSetting" ADD CONSTRAINT "OpenaiSetting_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "OpenaiBot" ADD COLUMN "enabled" BOOLEAN NOT NULL DEFAULT true;

View File

@ -47,41 +47,40 @@ enum TriggerOperator {
} }
model Instance { model Instance {
id String @id @default(cuid()) id String @id @default(cuid())
name String @unique @db.VarChar(255) name String @unique @db.VarChar(255)
connectionStatus InstanceConnectionStatus @default(open) connectionStatus InstanceConnectionStatus @default(open)
ownerJid String? @db.VarChar(100) ownerJid String? @db.VarChar(100)
profileName String? @db.VarChar(100) profileName String? @db.VarChar(100)
profilePicUrl String? @db.VarChar(500) profilePicUrl String? @db.VarChar(500)
integration String? @db.VarChar(100) integration String? @db.VarChar(100)
number String? @db.VarChar(100) number String? @db.VarChar(100)
businessId String? @db.VarChar(100) businessId String? @db.VarChar(100)
token String? @unique @db.VarChar(255) token String? @unique @db.VarChar(255)
clientName String? @db.VarChar(100) clientName String? @db.VarChar(100)
createdAt DateTime? @default(now()) @db.Timestamp createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime? @updatedAt @db.Timestamp updatedAt DateTime? @updatedAt @db.Timestamp
Chat Chat[] Chat Chat[]
Contact Contact[] Contact Contact[]
Message Message[] Message Message[]
Webhook Webhook? Webhook Webhook?
Chatwoot Chatwoot? Chatwoot Chatwoot?
Label Label[] Label Label[]
Proxy Proxy? Proxy Proxy?
Setting Setting? Setting Setting?
Rabbitmq Rabbitmq? Rabbitmq Rabbitmq?
Sqs Sqs? Sqs Sqs?
Websocket Websocket? Websocket Websocket?
Typebot Typebot[] Typebot Typebot[]
Session Session? Session Session?
MessageUpdate MessageUpdate[] MessageUpdate MessageUpdate[]
TypebotSession TypebotSession[] TypebotSession TypebotSession[]
TypebotSetting TypebotSetting? TypebotSetting TypebotSetting?
Media Media[] Media Media[]
OpenaiCreds OpenaiCreds? OpenaiCreds OpenaiCreds?
OpenaiAssistant OpenaiAssistant[] OpenaiBot OpenaiBot[]
OpenaiAssistantThread OpenaiAssistantThread[] OpenaiSession OpenaiSession[]
OpenaiChatCompletion OpenaiChatCompletion[] OpenaiSetting OpenaiSetting?
OpenaiChatCompletionSession OpenaiChatCompletionSession[]
} }
model Session { model Session {
@ -114,30 +113,28 @@ model Contact {
} }
model Message { model Message {
id String @id @default(cuid()) id String @id @default(cuid())
key Json @db.JsonB key Json @db.JsonB
pushName String? @db.VarChar(100) pushName String? @db.VarChar(100)
participant String? @db.VarChar(100) participant String? @db.VarChar(100)
messageType String @db.VarChar(100) messageType String @db.VarChar(100)
message Json @db.JsonB message Json @db.JsonB
contextInfo Json? @db.JsonB contextInfo Json? @db.JsonB
source DeviceMessage source DeviceMessage
messageTimestamp Int @db.Integer messageTimestamp Int @db.Integer
chatwootMessageId Int? @db.Integer chatwootMessageId Int? @db.Integer
chatwootInboxId Int? @db.Integer chatwootInboxId Int? @db.Integer
chatwootConversationId Int? @db.Integer chatwootConversationId Int? @db.Integer
chatwootContactInboxSourceId String? @db.VarChar(100) chatwootContactInboxSourceId String? @db.VarChar(100)
chatwootIsRead Boolean? @db.Boolean chatwootIsRead Boolean? @db.Boolean
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String instanceId String
typebotSessionId String? typebotSessionId String?
MessageUpdate MessageUpdate[] MessageUpdate MessageUpdate[]
TypebotSession TypebotSession? @relation(fields: [typebotSessionId], references: [id]) TypebotSession TypebotSession? @relation(fields: [typebotSessionId], references: [id])
Media Media? Media Media?
OpenaiAssistantThread OpenaiAssistantThread? @relation(fields: [openaiAssistantThreadId], references: [id]) OpenaiSession OpenaiSession? @relation(fields: [openaiSessionId], references: [id])
openaiAssistantThreadId String? openaiSessionId String?
OpenaiChatCompletionSession OpenaiChatCompletionSession? @relation(fields: [openaiChatCompletionSessionId], references: [id])
openaiChatCompletionSessionId String?
} }
model MessageUpdate { model MessageUpdate {
@ -336,87 +333,80 @@ model Media {
} }
model OpenaiCreds { model OpenaiCreds {
id String @id @default(cuid()) id String @id @default(cuid())
apiKey String @unique @db.VarChar(255) apiKey String @unique @db.VarChar(255)
createdAt DateTime? @default(now()) @db.Timestamp createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String @unique instanceId String @unique
OpenaiAssistant OpenaiBot[]
OpenaiSetting OpenaiSetting[]
} }
model OpenaiAssistant { model OpenaiBot {
id String @id @default(cuid()) id String @id @default(cuid())
assistantId String @unique @db.VarChar(255) enabled Boolean @default(true) @db.Boolean
expire Int? @default(0) @db.Integer botType String @db.VarChar(100)
keywordFinish String? @db.VarChar(100) assistantId String? @unique @db.VarChar(255)
delayMessage Int? @db.Integer model String? @db.VarChar(100)
unknownMessage String? @db.VarChar(100) systemMessages Json? @db.JsonB
listeningFromMe Boolean? @default(false) @db.Boolean assistantMessages Json? @db.JsonB
stopBotFromMe Boolean? @default(false) @db.Boolean userMessages Json? @db.JsonB
keepOpen Boolean? @default(false) @db.Boolean maxTokens Int? @db.Integer
debounceTime Int? @db.Integer expire Int? @default(0) @db.Integer
ignoreJids Json? keywordFinish String? @db.VarChar(100)
triggerType TriggerType? delayMessage Int? @db.Integer
triggerOperator TriggerOperator? unknownMessage String? @db.VarChar(100)
triggerValue String? listeningFromMe Boolean? @default(false) @db.Boolean
createdAt DateTime? @default(now()) @db.Timestamp stopBotFromMe Boolean? @default(false) @db.Boolean
updatedAt DateTime @updatedAt @db.Timestamp keepOpen Boolean? @default(false) @db.Boolean
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) debounceTime Int? @db.Integer
instanceId String ignoreJids Json?
OpenaiAssistantThread OpenaiAssistantThread[] triggerType TriggerType?
} triggerOperator TriggerOperator?
triggerValue String?
model OpenaiAssistantThread { createdAt DateTime? @default(now()) @db.Timestamp
id String @id @default(cuid()) updatedAt DateTime @updatedAt @db.Timestamp
threadId String @db.VarChar(255) OpenaiCreds OpenaiCreds @relation(fields: [openaiCredsId], references: [id], onDelete: Cascade)
remoteJid String @db.VarChar(100) openaiCredsId String
status TypebotSessionStatus Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
awaitUser Boolean @default(false) @db.Boolean
createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp
OpenaiAssistant OpenaiAssistant @relation(fields: [openaiAssistantId], references: [id], onDelete: Cascade)
openaiAssistantId String
Message Message[]
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String instanceId String
OpenaiSession OpenaiSession[]
OpenaiSetting OpenaiSetting[]
} }
model OpenaiChatCompletion { model OpenaiSession {
id String @id @default(cuid()) id String @id @default(cuid())
model String @db.VarChar(100) sessionId String @db.VarChar(255)
systemMessages Json? @db.JsonB remoteJid String @db.VarChar(100)
assistantMessages Json? @db.JsonB status TypebotSessionStatus
userMessages Json? @db.JsonB awaitUser Boolean @default(false) @db.Boolean
maxTokens Int? @db.Integer createdAt DateTime? @default(now()) @db.Timestamp
expire Int? @default(0) @db.Integer updatedAt DateTime @updatedAt @db.Timestamp
keywordFinish String? @db.VarChar(100) OpenaiBot OpenaiBot @relation(fields: [openaiBotId], references: [id], onDelete: Cascade)
delayMessage Int? @db.Integer openaiBotId String
unknownMessage String? @db.VarChar(100) Message Message[]
listeningFromMe Boolean? @default(false) @db.Boolean Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
stopBotFromMe Boolean? @default(false) @db.Boolean instanceId String
keepOpen Boolean? @default(false) @db.Boolean
debounceTime Int? @db.Integer
ignoreJids Json?
triggerType TriggerType?
triggerOperator TriggerOperator?
triggerValue String?
createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String
OpenaiChatCompletionSession OpenaiChatCompletionSession[]
} }
model OpenaiChatCompletionSession { model OpenaiSetting {
id String @id @default(cuid()) id String @id @default(cuid())
remoteJid String @db.VarChar(100) expire Int? @default(0) @db.Integer
sessionId String @db.VarChar(100) keywordFinish String? @db.VarChar(100)
status TypebotSessionStatus delayMessage Int? @db.Integer
createdAt DateTime? @default(now()) @db.Timestamp unknownMessage String? @db.VarChar(100)
updatedAt DateTime @updatedAt @db.Timestamp listeningFromMe Boolean? @default(false) @db.Boolean
OpenaiChatCompletion OpenaiChatCompletion @relation(fields: [openaiChatCompletionId], references: [id], onDelete: Cascade) stopBotFromMe Boolean? @default(false) @db.Boolean
openaiChatCompletionId String keepOpen Boolean? @default(false) @db.Boolean
Message Message[] debounceTime Int? @db.Integer
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) ignoreJids Json?
instanceId String createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp
OpenaiCreds OpenaiCreds? @relation(fields: [openaiCredsId], references: [id])
openaiCredsId String
Fallback OpenaiBot? @relation(fields: [openaiIdFallback], references: [id])
openaiIdFallback String? @db.VarChar(100)
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String @unique
} }

View File

@ -0,0 +1,81 @@
import { configService, Openai } from '../../../../config/env.config';
import { BadRequestException } from '../../../../exceptions';
import { InstanceDto } from '../../../dto/instance.dto';
import { OpenaiCredsDto, OpenaiDto, OpenaiIgnoreJidDto } from '../dto/openai.dto';
import { OpenaiService } from '../services/openai.service';
export class OpenaiController {
constructor(private readonly openaiService: OpenaiService) {}
public async createOpenaiCreds(instance: InstanceDto, data: OpenaiCredsDto) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.createCreds(instance, data);
}
public async findOpenaiCreds(instance: InstanceDto) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.findCreds(instance);
}
public async createOpenai(instance: InstanceDto, data: OpenaiDto) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.create(instance, data);
}
public async findOpenai(instance: InstanceDto) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.find(instance);
}
public async fetchOpenai(instance: InstanceDto, openaiBotId: string) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.fetch(instance, openaiBotId);
}
public async updateOpenai(instance: InstanceDto, openaiBotId: string, data: OpenaiDto) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.update(instance, openaiBotId, data);
}
public async deleteOpenai(instance: InstanceDto, openaiBotId: string) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.delete(instance, openaiBotId);
}
public async settings(instance: InstanceDto, data: any) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.setDefaultSettings(instance, data);
}
public async fetchSettings(instance: InstanceDto) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.fetchDefaultSettings(instance);
}
public async changeStatus(instance: InstanceDto, data: any) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.changeStatus(instance, data);
}
public async fetchSessions(instance: InstanceDto, openaiBotId: string) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.fetchSessions(instance, openaiBotId);
}
public async ignoreJid(instance: InstanceDto, data: OpenaiIgnoreJidDto) {
if (!configService.get<Openai>('OPENAI').ENABLED) throw new BadRequestException('Openai is disabled');
return this.openaiService.ignoreJid(instance, data);
}
}

View File

@ -0,0 +1,56 @@
import { TriggerOperator, TriggerType } from '@prisma/client';
export class Session {
remoteJid?: string;
sessionId?: string;
status?: string;
createdAt?: number;
updateAt?: number;
}
export class OpenaiCredsDto {
apiKey: string;
}
export class OpenaiDto {
enabled?: boolean;
openaiCredsId: string;
botType?: string;
assistantId?: string;
model?: string;
systemMessages?: string[];
assistantMessages?: string[];
userMessages?: string[];
maxTokens?: number;
expire?: number;
keywordFinish?: string;
delayMessage?: number;
unknownMessage?: string;
listeningFromMe?: boolean;
stopBotFromMe?: boolean;
keepOpen?: boolean;
debounceTime?: number;
triggerType?: TriggerType;
triggerOperator?: TriggerOperator;
triggerValue?: string;
ignoreJids?: any;
}
export class OpenaiSettingDto {
openaiCredsId?: string;
expire?: number;
keywordFinish?: string;
delayMessage?: number;
unknownMessage?: string;
listeningFromMe?: boolean;
stopBotFromMe?: boolean;
keepOpen?: boolean;
debounceTime?: number;
openaiIdFallback?: string;
ignoreJids?: any;
}
export class OpenaiIgnoreJidDto {
remoteJid?: string;
action?: string;
}

View File

@ -0,0 +1,144 @@
import { RequestHandler, Router } from 'express';
import {
instanceSchema,
openaiCredsSchema,
openaiIgnoreJidSchema,
openaiSchema,
openaiSettingSchema,
openaiStatusSchema,
} from '../../../../validate/validate.schema';
import { RouterBroker } from '../../../abstract/abstract.router';
import { InstanceDto } from '../../../dto/instance.dto';
import { HttpStatus } from '../../../routes/index.router';
import { openaiController } from '../../../server.module';
import { OpenaiCredsDto, OpenaiDto, OpenaiIgnoreJidDto, OpenaiSettingDto } from '../dto/openai.dto';
export class OpenaiRouter extends RouterBroker {
constructor(...guards: RequestHandler[]) {
super();
this.router
.post(this.routerPath('creds'), ...guards, async (req, res) => {
const response = await this.dataValidate<OpenaiCredsDto>({
request: req,
schema: openaiCredsSchema,
ClassRef: OpenaiCredsDto,
execute: (instance, data) => openaiController.createOpenaiCreds(instance, data),
});
res.status(HttpStatus.CREATED).json(response);
})
.get(this.routerPath('creds'), ...guards, async (req, res) => {
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceSchema,
ClassRef: InstanceDto,
execute: (instance) => openaiController.findOpenaiCreds(instance),
});
res.status(HttpStatus.OK).json(response);
})
.post(this.routerPath('create'), ...guards, async (req, res) => {
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) => {
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceSchema,
ClassRef: InstanceDto,
execute: (instance) => openaiController.findOpenai(instance),
});
res.status(HttpStatus.OK).json(response);
})
.get(this.routerPath('fetch/:openaiBotId'), ...guards, async (req, res) => {
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceSchema,
ClassRef: InstanceDto,
execute: (instance) => openaiController.fetchOpenai(instance, req.params.openaiBotId),
});
res.status(HttpStatus.OK).json(response);
})
.put(this.routerPath('update/:openaiBotId'), ...guards, async (req, res) => {
const response = await this.dataValidate<OpenaiDto>({
request: req,
schema: openaiSchema,
ClassRef: OpenaiDto,
execute: (instance, data) => openaiController.updateOpenai(instance, req.params.openaiBotId, data),
});
res.status(HttpStatus.OK).json(response);
})
.delete(this.routerPath('delete/:openaiBotId'), ...guards, async (req, res) => {
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceSchema,
ClassRef: InstanceDto,
execute: (instance) => openaiController.deleteOpenai(instance, req.params.openaiBotId),
});
res.status(HttpStatus.OK).json(response);
})
.post(this.routerPath('settings'), ...guards, async (req, res) => {
const response = await this.dataValidate<OpenaiSettingDto>({
request: req,
schema: openaiSettingSchema,
ClassRef: OpenaiSettingDto,
execute: (instance, data) => openaiController.settings(instance, data),
});
res.status(HttpStatus.OK).json(response);
})
.get(this.routerPath('fetchSettings'), ...guards, async (req, res) => {
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceSchema,
ClassRef: InstanceDto,
execute: (instance) => openaiController.fetchSettings(instance),
});
res.status(HttpStatus.OK).json(response);
})
.post(this.routerPath('changeStatus'), ...guards, async (req, res) => {
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: openaiStatusSchema,
ClassRef: InstanceDto,
execute: (instance, data) => openaiController.changeStatus(instance, data),
});
res.status(HttpStatus.OK).json(response);
})
.get(this.routerPath('fetchSessions/:openaiBotId'), ...guards, async (req, res) => {
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceSchema,
ClassRef: InstanceDto,
execute: (instance) => openaiController.fetchSessions(instance, req.params.openaiBotId),
});
res.status(HttpStatus.OK).json(response);
})
.post(this.routerPath('ignoreJid'), ...guards, async (req, res) => {
const response = await this.dataValidate<OpenaiIgnoreJidDto>({
request: req,
schema: openaiIgnoreJidSchema,
ClassRef: OpenaiIgnoreJidDto,
execute: (instance, data) => openaiController.ignoreJid(instance, data),
});
res.status(HttpStatus.OK).json(response);
});
}
public readonly router = Router();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,125 @@
import { JSONSchema7 } from 'json-schema';
import { v4 } from 'uuid';
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
const properties = {};
propertyNames.forEach(
(property) =>
(properties[property] = {
minLength: 1,
description: `The "${property}" cannot be empty`,
}),
);
return {
if: {
propertyNames: {
enum: [...propertyNames],
},
},
then: { properties },
};
};
export const openaiSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean' },
openaiCredsId: { type: 'string' },
botType: { type: 'string', enum: ['assistant', 'chatCompletion'] },
assistantId: { type: 'string' },
model: { type: 'string' },
systemMessages: { type: 'array', items: { type: 'string' } },
assistantMessages: { type: 'array', items: { type: 'string' } },
userMessages: { type: 'array', items: { type: 'string' } },
maxTokens: { type: 'integer' },
triggerType: { type: 'string', enum: ['all', 'keyword'] },
triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex', 'none'] },
triggerValue: { type: 'string' },
expire: { type: 'integer' },
keywordFinish: { type: 'string' },
delayMessage: { type: 'integer' },
unknownMessage: { type: 'string' },
listeningFromMe: { type: 'boolean' },
stopBotFromMe: { type: 'boolean' },
keepOpen: { type: 'boolean' },
debounceTime: { type: 'integer' },
ignoreJids: { type: 'array', items: { type: 'string' } },
},
required: ['enabled', 'openaiCredsId', 'botType', 'triggerType'],
...isNotEmpty('enabled', 'openaiCredsId', 'botType', 'triggerType'),
};
export const openaiCredsSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
apiKey: { type: 'string' },
},
required: ['enabled', 'apiKey'],
...isNotEmpty('enabled', 'apiKey'),
};
export const openaiStatusSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
remoteJid: { type: 'string' },
status: { type: 'string', enum: ['opened', 'closed', 'paused'] },
},
required: ['remoteJid', 'status'],
...isNotEmpty('remoteJid', 'status'),
};
export const openaiSettingSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
openaiCredsId: { type: 'string' },
expire: { type: 'integer' },
keywordFinish: { type: 'string' },
delayMessage: { type: 'integer' },
unknownMessage: { type: 'string' },
listeningFromMe: { type: 'boolean' },
stopBotFromMe: { type: 'boolean' },
keepOpen: { type: 'boolean' },
debounceTime: { type: 'integer' },
ignoreJids: { type: 'array', items: { type: 'string' } },
openaiIdFallback: { type: 'string' },
},
required: [
'openaiCredsId',
'expire',
'keywordFinish',
'delayMessage',
'unknownMessage',
'listeningFromMe',
'stopBotFromMe',
'keepOpen',
'debounceTime',
'ignoreJids',
],
...isNotEmpty(
'openaiCredsId',
'expire',
'keywordFinish',
'delayMessage',
'unknownMessage',
'listeningFromMe',
'stopBotFromMe',
'keepOpen',
'debounceTime',
'ignoreJids',
),
};
export const openaiIgnoreJidSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
remoteJid: { type: 'string' },
action: { type: 'string', enum: ['add', 'remove'] },
},
required: ['remoteJid', 'action'],
...isNotEmpty('remoteJid', 'action'),
};

View File

@ -13,6 +13,8 @@ import { TemplateController } from './controllers/template.controller';
import { WebhookController } from './controllers/webhook.controller'; import { WebhookController } from './controllers/webhook.controller';
import { ChatwootController } from './integrations/chatwoot/controllers/chatwoot.controller'; import { ChatwootController } from './integrations/chatwoot/controllers/chatwoot.controller';
import { ChatwootService } from './integrations/chatwoot/services/chatwoot.service'; import { ChatwootService } from './integrations/chatwoot/services/chatwoot.service';
import { OpenaiController } from './integrations/openai/controllers/openai.controller';
import { OpenaiService } from './integrations/openai/services/openai.service';
import { RabbitmqController } from './integrations/rabbitmq/controllers/rabbitmq.controller'; import { RabbitmqController } from './integrations/rabbitmq/controllers/rabbitmq.controller';
import { RabbitmqService } from './integrations/rabbitmq/services/rabbitmq.service'; import { RabbitmqService } from './integrations/rabbitmq/services/rabbitmq.service';
import { S3Controller } from './integrations/s3/controllers/s3.controller'; import { S3Controller } from './integrations/s3/controllers/s3.controller';
@ -65,6 +67,9 @@ const authService = new AuthService(prismaRepository);
const typebotService = new TypebotService(waMonitor, configService, prismaRepository); const typebotService = new TypebotService(waMonitor, configService, prismaRepository);
export const typebotController = new TypebotController(typebotService); export const typebotController = new TypebotController(typebotService);
const openaiService = new OpenaiService(waMonitor, configService, prismaRepository);
export const openaiController = new OpenaiController(openaiService);
const s3Service = new S3Service(prismaRepository); const s3Service = new S3Service(prismaRepository);
export const s3Controller = new S3Controller(s3Service); export const s3Controller = new S3Controller(s3Service);

View File

@ -191,6 +191,7 @@ export type Chatwoot = {
PLACEHOLDER_MEDIA_MESSAGE: boolean; PLACEHOLDER_MEDIA_MESSAGE: boolean;
}; };
}; };
export type Openai = { ENABLED: boolean; API_KEY_GLOBAL?: string };
export type S3 = { export type S3 = {
ACCESS_KEY: string; ACCESS_KEY: string;
@ -224,6 +225,7 @@ export interface Env {
QRCODE: QrCode; QRCODE: QrCode;
TYPEBOT: Typebot; TYPEBOT: Typebot;
CHATWOOT: Chatwoot; CHATWOOT: Chatwoot;
OPENAI: Openai;
CACHE: CacheConf; CACHE: CacheConf;
S3?: S3; S3?: S3;
AUTHENTICATION: Auth; AUTHENTICATION: Auth;
@ -431,6 +433,10 @@ export class ConfigService {
PLACEHOLDER_MEDIA_MESSAGE: process.env?.CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE === 'true', PLACEHOLDER_MEDIA_MESSAGE: process.env?.CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE === 'true',
}, },
}, },
OPENAI: {
ENABLED: process.env?.OPENAI_ENABLED === 'true',
API_KEY_GLOBAL: process.env?.OPENAI_API_KEY_GLOBAL || null,
},
CACHE: { CACHE: {
REDIS: { REDIS: {
ENABLED: process.env?.CACHE_REDIS_ENABLED === 'true', ENABLED: process.env?.CACHE_REDIS_ENABLED === 'true',

View File

@ -1,5 +1,6 @@
// Integrations Schema // Integrations Schema
export * from '../api/integrations/chatwoot/validate/chatwoot.schema'; export * from '../api/integrations/chatwoot/validate/chatwoot.schema';
export * from '../api/integrations/openai/validate/openai.schema';
export * from '../api/integrations/rabbitmq/validate/rabbitmq.schema'; export * from '../api/integrations/rabbitmq/validate/rabbitmq.schema';
export * from '../api/integrations/sqs/validate/sqs.schema'; export * from '../api/integrations/sqs/validate/sqs.schema';
export * from '../api/integrations/typebot/validate/typebot.schema'; export * from '../api/integrations/typebot/validate/typebot.schema';