Skip to content

Commit 5990b22

Browse files
Merge branch 'main' into move-zapier-to-user-menu
2 parents 369ff41 + c339ce9 commit 5990b22

70 files changed

Lines changed: 2995 additions & 388 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/src/ai-core/tools/query-validators.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,11 @@ export function cleanAIJsonResponse(response: string): string {
107107
if (cleanedResponse.endsWith('```')) {
108108
cleanedResponse = cleanedResponse.slice(0, -3);
109109
}
110+
cleanedResponse = cleanedResponse.trim();
111+
112+
cleanedResponse = cleanedResponse.replace(/^\s*\/\/.*$/gm, '');
113+
cleanedResponse = cleanedResponse.replace(/\/\*[\s\S]*?\*\//g, '');
114+
cleanedResponse = cleanedResponse.replace(/,(\s*[}\]])/g, '$1');
115+
110116
return cleanedResponse.trim();
111117
}

backend/src/common/application/global-database-context.interface.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ import { DashboardEntity } from '../../entities/visualizations/dashboard/dashboa
6262
import { DashboardWidgetEntity } from '../../entities/visualizations/dashboard-widget/dashboard-widget.entity.js';
6363
import { IDashboardRepository } from '../../entities/visualizations/dashboard/repository/dashboard.repository.interface.js';
6464
import { IDashboardWidgetRepository } from '../../entities/visualizations/dashboard-widget/repository/dashboard-widget.repository.interface.js';
65+
import { UserAiChatEntity } from '../../entities/ai/ai-conversation-history/user-ai-chat/user-ai-chat.entity.js';
66+
import { IUserAiChatRepository } from '../../entities/ai/ai-conversation-history/user-ai-chat/repository/user-ai-chat-repository.interface.js';
67+
import { AiChatMessageEntity } from '../../entities/ai/ai-conversation-history/ai-chat-messages/ai-chat-message.entity.js';
68+
import { IAiChatMessageRepository } from '../../entities/ai/ai-conversation-history/ai-chat-messages/repository/ai-chat-message-repository.interface.js';
6569

6670
export interface IGlobalDatabaseContext extends IDatabaseContext {
6771
userRepository: Repository<UserEntity> & IUserRepository;
@@ -104,4 +108,6 @@ export interface IGlobalDatabaseContext extends IDatabaseContext {
104108
savedDbQueryRepository: Repository<SavedDbQueryEntity> & ISavedDbQueryRepository;
105109
dashboardRepository: Repository<DashboardEntity> & IDashboardRepository;
106110
dashboardWidgetRepository: Repository<DashboardWidgetEntity> & IDashboardWidgetRepository;
111+
userAiChatRepository: Repository<UserAiChatEntity> & IUserAiChatRepository;
112+
aiChatMessageRepository: Repository<AiChatMessageEntity> & IAiChatMessageRepository;
107113
}

backend/src/common/application/global-database-context.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ import { IDashboardRepository } from '../../entities/visualizations/dashboard/re
111111
import { IDashboardWidgetRepository } from '../../entities/visualizations/dashboard-widget/repository/dashboard-widget.repository.interface.js';
112112
import { dashboardCustomRepositoryExtension } from '../../entities/visualizations/dashboard/repository/dashboard-custom-repository-extension.js';
113113
import { dashboardWidgetCustomRepositoryExtension } from '../../entities/visualizations/dashboard-widget/repository/dashboard-widget-custom-repository-extension.js';
114+
import { UserAiChatEntity } from '../../entities/ai/ai-conversation-history/user-ai-chat/user-ai-chat.entity.js';
115+
import { IUserAiChatRepository } from '../../entities/ai/ai-conversation-history/user-ai-chat/repository/user-ai-chat-repository.interface.js';
116+
import { userAiChatRepositoryExtension } from '../../entities/ai/ai-conversation-history/user-ai-chat/repository/user-ai-chat-repository.extension.js';
117+
import { AiChatMessageEntity } from '../../entities/ai/ai-conversation-history/ai-chat-messages/ai-chat-message.entity.js';
118+
import { IAiChatMessageRepository } from '../../entities/ai/ai-conversation-history/ai-chat-messages/repository/ai-chat-message-repository.interface.js';
119+
import { aiChatMessageRepositoryExtension } from '../../entities/ai/ai-conversation-history/ai-chat-messages/repository/ai-chat-message-repository.extension.js';
114120

115121
@Injectable({ scope: Scope.REQUEST })
116122
export class GlobalDatabaseContext implements IGlobalDatabaseContext {
@@ -156,6 +162,8 @@ export class GlobalDatabaseContext implements IGlobalDatabaseContext {
156162
private _savedDbQueryRepository: Repository<SavedDbQueryEntity> & ISavedDbQueryRepository;
157163
private _dashboardRepository: Repository<DashboardEntity> & IDashboardRepository;
158164
private _dashboardWidgetRepository: Repository<DashboardWidgetEntity> & IDashboardWidgetRepository;
165+
private _userAiChatRepository: Repository<UserAiChatEntity> & IUserAiChatRepository;
166+
private _aiChatMessageRepository: Repository<AiChatMessageEntity> & IAiChatMessageRepository;
159167

160168
public constructor(
161169
@Inject(BaseType.DATA_SOURCE)
@@ -265,6 +273,12 @@ export class GlobalDatabaseContext implements IGlobalDatabaseContext {
265273
this._dashboardWidgetRepository = this.appDataSource
266274
.getRepository(DashboardWidgetEntity)
267275
.extend(dashboardWidgetCustomRepositoryExtension);
276+
this._userAiChatRepository = this.appDataSource
277+
.getRepository(UserAiChatEntity)
278+
.extend(userAiChatRepositoryExtension);
279+
this._aiChatMessageRepository = this.appDataSource
280+
.getRepository(AiChatMessageEntity)
281+
.extend(aiChatMessageRepositoryExtension);
268282
}
269283

270284
public get userRepository(): Repository<UserEntity> & IUserRepository {
@@ -429,6 +443,14 @@ export class GlobalDatabaseContext implements IGlobalDatabaseContext {
429443
return this._dashboardWidgetRepository;
430444
}
431445

446+
public get userAiChatRepository(): Repository<UserAiChatEntity> & IUserAiChatRepository {
447+
return this._userAiChatRepository;
448+
}
449+
450+
public get aiChatMessageRepository(): Repository<AiChatMessageEntity> & IAiChatMessageRepository {
451+
return this._aiChatMessageRepository;
452+
}
453+
432454
public startTransaction(): Promise<void> {
433455
this._queryRunner = this.appDataSource.createQueryRunner();
434456
this._queryRunner.startTransaction();

backend/src/common/data-injection.tokens.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,11 @@ export enum UseCaseType {
159159

160160
REQUEST_INFO_FROM_TABLE_WITH_AI_V2 = 'REQUEST_INFO_FROM_TABLE_WITH_AI_V2',
161161
REQUEST_INFO_FROM_TABLE_WITH_AI_V3 = 'REQUEST_INFO_FROM_TABLE_WITH_AI_V3',
162+
REQUEST_INFO_FROM_TABLE_WITH_AI_V4 = 'REQUEST_INFO_FROM_TABLE_WITH_AI_V4',
162163
REQUEST_AI_SETTINGS_AND_WIDGETS_CREATION = 'REQUEST_AI_SETTINGS_AND_WIDGETS_CREATION',
164+
FIND_USER_AI_CHATS = 'FIND_USER_AI_CHATS',
165+
FIND_USER_AI_CHAT_BY_ID = 'FIND_USER_AI_CHAT_BY_ID',
166+
DELETE_USER_AI_CHAT = 'DELETE_USER_AI_CHAT',
163167

164168
CREATE_TABLE_FILTERS = 'CREATE_TABLE_FILTERS',
165169
FIND_TABLE_FILTERS = 'FIND_TABLE_FILTERS',

backend/src/decorators/slug-uuid.decorator.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ export type SlugUuidParameter =
1414
| 'apiKeyId'
1515
| 'companyId'
1616
| 'threadId'
17-
| 'filterId';
17+
| 'filterId'
18+
| 'chatId';
1819
export const SlugUuid = createParamDecorator(
1920
(parameterName: SlugUuidParameter = 'slug', ctx: ExecutionContext): string => {
2021
const request: IRequestWithCognitoInfo = ctx.switchToHttp().getRequest();
@@ -29,7 +30,8 @@ export const SlugUuid = createParamDecorator(
2930
'eventId',
3031
'companyId',
3132
'threadId',
32-
'filterId'
33+
'filterId',
34+
'chatId'
3335
];
3436
if (!availableSlagParameters.includes(parameterName)) {
3537
throw new BadRequestException(Messages.UUID_INVALID);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
Column,
3+
CreateDateColumn,
4+
Entity,
5+
JoinColumn,
6+
ManyToOne,
7+
PrimaryGeneratedColumn,
8+
Relation,
9+
UpdateDateColumn,
10+
} from 'typeorm';
11+
import { MessageRole } from './message-role.enum.js';
12+
import { UserAiChatEntity } from '../user-ai-chat/user-ai-chat.entity.js';
13+
14+
@Entity('ai_chat_message')
15+
export class AiChatMessageEntity {
16+
@PrimaryGeneratedColumn('uuid')
17+
id: string;
18+
19+
@Column({ default: null, type: 'text' })
20+
message: string;
21+
22+
@Column({ nullable: true, default: null, type: 'enum', enum: MessageRole })
23+
role: MessageRole;
24+
25+
@Column({ nullable: true, default: null, type: 'varchar', length: 255 })
26+
response_id: string;
27+
28+
@CreateDateColumn({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
29+
created_at: Date;
30+
31+
@UpdateDateColumn({ type: 'timestamp', nullable: true, default: null })
32+
updated_at: Date;
33+
34+
@ManyToOne(
35+
() => UserAiChatEntity,
36+
(ai_chat) => ai_chat.messages,
37+
)
38+
@JoinColumn({ name: 'ai_chat_id' })
39+
ai_chat: Relation<UserAiChatEntity>;
40+
41+
@Column()
42+
ai_chat_id: string;
43+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export enum MessageRole {
2+
user = 'user',
3+
ai = 'ai',
4+
system = 'system',
5+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { IAiChatMessageRepository } from './ai-chat-message-repository.interface.js';
2+
import { AiChatMessageEntity } from '../ai-chat-message.entity.js';
3+
import { MessageRole } from '../message-role.enum.js';
4+
5+
export const aiChatMessageRepositoryExtension: IAiChatMessageRepository = {
6+
async findMessagesForChat(chatId: string): Promise<AiChatMessageEntity[]> {
7+
return await this.createQueryBuilder('ai_chat_message')
8+
.where('ai_chat_message.ai_chat_id = :chatId', { chatId })
9+
.orderBy('ai_chat_message.created_at', 'ASC')
10+
.getMany();
11+
},
12+
13+
async findLastAiMessageForChat(chatId: string): Promise<AiChatMessageEntity | null> {
14+
return await this.createQueryBuilder('ai_chat_message')
15+
.where('ai_chat_message.ai_chat_id = :chatId', { chatId })
16+
.andWhere('ai_chat_message.role = :role', { role: MessageRole.ai })
17+
.orderBy('ai_chat_message.created_at', 'DESC')
18+
.getOne();
19+
},
20+
21+
async deleteMessagesForChat(chatId: string): Promise<void> {
22+
await this.createQueryBuilder()
23+
.delete()
24+
.from('ai_chat_message')
25+
.where('ai_chat_id = :chatId', { chatId })
26+
.execute();
27+
},
28+
29+
async saveMessage(
30+
chatId: string,
31+
message: string,
32+
role: MessageRole,
33+
responseId?: string,
34+
): Promise<AiChatMessageEntity> {
35+
const newMessage = this.create({
36+
ai_chat_id: chatId,
37+
message,
38+
role,
39+
response_id: responseId,
40+
});
41+
return await this.save(newMessage);
42+
},
43+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { AiChatMessageEntity } from '../ai-chat-message.entity.js';
2+
import { MessageRole } from '../message-role.enum.js';
3+
4+
export interface IAiChatMessageRepository {
5+
findMessagesForChat(chatId: string): Promise<AiChatMessageEntity[]>;
6+
findLastAiMessageForChat(chatId: string): Promise<AiChatMessageEntity | null>;
7+
deleteMessagesForChat(chatId: string): Promise<void>;
8+
saveMessage(chatId: string, message: string, role: MessageRole, responseId?: string): Promise<AiChatMessageEntity>;
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export class FindUserAiChatsDs {
2+
userId: string;
3+
}
4+
5+
export class FindUserAiChatByIdDs {
6+
userId: string;
7+
chatId: string;
8+
}
9+
10+
export class DeleteUserAiChatDs {
11+
userId: string;
12+
chatId: string;
13+
}

0 commit comments

Comments
 (0)