chat
This commit is contained in:
@@ -54,13 +54,11 @@ import { ChatService } from "../modules/chat/chat.service";
|
||||
import { ChatRepo, createChatRepo } from "../modules/chat/repository/chat.repository";
|
||||
import { ChatMessageRepo, createChatMessageRepo } from "../modules/chat/repository/message.repository";
|
||||
import { WsAuthService } from "../modules/chat/wsAuth.service";
|
||||
import { ChatbotGateway } from "../modules/chatbot/chatbot.gateway";
|
||||
import { ChatbotService } from "../modules/chatbot/providers/chatbot.service";
|
||||
import { DataContextService } from "../modules/chatbot/providers/data-context.service";
|
||||
import { LLMService } from "../modules/chatbot/providers/llm.service";
|
||||
import { WebSocketAuthService } from "../modules/chatbot/providers/websocket-auth.service";
|
||||
import { ChatbotGateway } from "../modules/chatbot/chatbot.gateway";
|
||||
import { ChatSessionRepository, createChatSessionRepository } from "../modules/chatbot/repositories/chat-session.repository";
|
||||
import { ChatMessageRepository, createChatMessageRepository } from "../modules/chatbot/repositories/chat-message.repository";
|
||||
import { ContactUsRepo, CreateContactUsRepo } from "../modules/contact-us/contactUs.repository";
|
||||
import { ContactUsService } from "../modules/contact-us/contactUs.service";
|
||||
import { CouponRepo, CouponUsageRepo, createCouponRepo, createCouponUsageRepo } from "../modules/Coupon/coupon.repository";
|
||||
@@ -291,9 +289,6 @@ const containerModules = new AsyncContainerModule(async (bind) => {
|
||||
bind<AboutUsRepo>(IOCTYPES.AboutUsRepo).toDynamicValue(CreateAboutUsRepo).inSingletonScope();
|
||||
bind<SiteSettingRepo>(IOCTYPES.SiteSettingRepo).toDynamicValue(CreateSiteSettingRepo).inSingletonScope();
|
||||
bind<NewsletterRepo>(IOCTYPES.NewsletterRepo).toDynamicValue(CreateNewsletterRepo).inSingletonScope();
|
||||
bind<ChatSessionRepository>(IOCTYPES.ChatbotChatSessionRepository).toDynamicValue(createChatSessionRepository).inSingletonScope();
|
||||
bind<ChatMessageRepository>(IOCTYPES.ChatbotChatMessageRepository).toDynamicValue(createChatMessageRepository).inSingletonScope();
|
||||
// #endregion
|
||||
});
|
||||
|
||||
export { containerModules };
|
||||
|
||||
@@ -279,12 +279,6 @@ export class ChatbotGateway {
|
||||
return;
|
||||
}
|
||||
|
||||
// The bot response will be generated asynchronously by the service
|
||||
// We'll need to emit it when it's ready
|
||||
// For now, we'll rely on the service's internal async generation
|
||||
// In a production system, you might want to use Redis pub/sub or similar
|
||||
// to notify when the bot response is ready
|
||||
|
||||
// Emit that bot is typing
|
||||
socket.emit(WEBSOCKET_EVENTS.BOT_RESPONSE_START, {
|
||||
status: "success",
|
||||
@@ -292,9 +286,24 @@ export class ChatbotGateway {
|
||||
timestamp: new Date().toISOString(),
|
||||
} as WebSocketResponse);
|
||||
|
||||
// Note: The actual bot response will be generated by ChatbotService.generateBotResponse
|
||||
// which runs asynchronously. In a real implementation, you might want to use
|
||||
// Redis pub/sub or a message queue to notify when the response is ready
|
||||
// Generate bot response and wait for it
|
||||
const botMessage = await this.chatbotService.generateBotResponse(sessionId, userMessageId, ulid);
|
||||
|
||||
if (botMessage) {
|
||||
// Emit bot response to the client
|
||||
socket.emit(WEBSOCKET_EVENTS.BOT_RESPONSE, {
|
||||
status: "success",
|
||||
data: botMessage,
|
||||
timestamp: new Date().toISOString(),
|
||||
} as WebSocketResponse);
|
||||
|
||||
// Also emit to others in the session (if any)
|
||||
socket.to(`session_${sessionId}`).emit(WEBSOCKET_EVENTS.BOT_RESPONSE, {
|
||||
status: "success",
|
||||
data: botMessage,
|
||||
timestamp: new Date().toISOString(),
|
||||
} as WebSocketResponse);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error("Error generating bot response", error);
|
||||
socket.emit(WEBSOCKET_EVENTS.BOT_RESPONSE, {
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Schema, model } from "mongoose";
|
||||
|
||||
import { IChatMessage, MessageStatus, MessageType } from "./Abstraction/IChatMessage";
|
||||
|
||||
const chatMessageSchema = new Schema<IChatMessage>(
|
||||
{
|
||||
content: { type: String, required: true },
|
||||
type: { type: String, enum: MessageType, required: true },
|
||||
status: { type: String, enum: MessageStatus, default: MessageStatus.SENT },
|
||||
session: { type: Schema.Types.ObjectId, ref: "ChatSession", required: true },
|
||||
sender: { type: Schema.Types.ObjectId, ref: "User", default: null },
|
||||
metadata: { type: Schema.Types.Mixed, default: null },
|
||||
responseToId: { type: String, default: null },
|
||||
tokensUsed: { type: Number, default: 0 },
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
toJSON: { virtuals: true, versionKey: false },
|
||||
id: false,
|
||||
},
|
||||
);
|
||||
|
||||
chatMessageSchema.index({ session: 1, createdAt: -1 });
|
||||
chatMessageSchema.index({ session: 1, createdAt: 1 });
|
||||
|
||||
const ChatMessageModel = model<IChatMessage>("ChatbotMessage", chatMessageSchema);
|
||||
|
||||
export { ChatMessageModel, MessageStatus, MessageType };
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { Schema, model } from "mongoose";
|
||||
|
||||
import { ChatSessionStatus, IChatSession } from "./Abstraction/IChatSession";
|
||||
|
||||
const chatSessionSchema = new Schema<IChatSession>(
|
||||
{
|
||||
title: { type: String, required: true, maxlength: 255 },
|
||||
user: { type: Schema.Types.ObjectId, ref: "User", required: true },
|
||||
status: { type: String, enum: ChatSessionStatus, default: ChatSessionStatus.ACTIVE },
|
||||
context: { type: Schema.Types.Mixed, default: null },
|
||||
lastMessageAt: { type: Date, default: null },
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
toJSON: { virtuals: true, versionKey: false },
|
||||
id: false,
|
||||
},
|
||||
);
|
||||
|
||||
chatSessionSchema.index({ user: 1, lastMessageAt: -1 });
|
||||
chatSessionSchema.index({ status: 1 });
|
||||
|
||||
const ChatSessionModel = model<IChatSession>("ChatSession", chatSessionSchema);
|
||||
|
||||
export { ChatSessionModel, ChatSessionStatus };
|
||||
|
||||
@@ -8,8 +8,8 @@ import { IOCTYPES } from "../../../IOC/ioc.types";
|
||||
import { CacheService } from "../../../utils/cache.service";
|
||||
import { SendMessageDto } from "../DTO/send-message.dto";
|
||||
import { IChatContext } from "../interfaces/chatbot.interface";
|
||||
import { MessageStatus, MessageType } from "../models/chat-message.model";
|
||||
import { ChatSessionStatus } from "../models/chat-session.model";
|
||||
import { MessageStatus, MessageType } from "../models/Abstraction/IChatMessage";
|
||||
import { ChatSessionStatus } from "../models/Abstraction/IChatSession";
|
||||
|
||||
interface CachedSession {
|
||||
id: string;
|
||||
@@ -170,8 +170,7 @@ export class ChatbotService {
|
||||
session.lastMessageAt = now;
|
||||
await this.cacheService.setAsync(sessionKey, JSON.stringify(session), this.CACHE_TTL_SECONDS);
|
||||
|
||||
// Generate bot response asynchronously using OpenAI service
|
||||
this.generateBotResponse(sendDto.sessionId, messageId, ulid);
|
||||
// Note: Bot response will be generated by the gateway after emitting user message
|
||||
|
||||
return this.mapMessageToDto(userMessage);
|
||||
}
|
||||
@@ -240,7 +239,11 @@ export class ChatbotService {
|
||||
};
|
||||
}
|
||||
|
||||
private async generateBotResponse(sessionId: string, userMessageId: string, ulid: string): Promise<void> {
|
||||
async generateBotResponse(
|
||||
sessionId: string,
|
||||
userMessageId: string,
|
||||
ulid: string,
|
||||
): Promise<ReturnType<typeof this.mapMessageToDto> | null> {
|
||||
try {
|
||||
// Get messages from cache
|
||||
const messagesKey = this.getMessagesCacheKey(sessionId);
|
||||
@@ -316,6 +319,7 @@ export class ChatbotService {
|
||||
await this.cacheService.setAsync(sessionKey, JSON.stringify(session), this.CACHE_TTL_SECONDS);
|
||||
|
||||
this.logger.info(`Generated bot response for session ${sessionId}`);
|
||||
return this.mapMessageToDto(botMessage);
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to generate bot response for session ${sessionId}`, error);
|
||||
|
||||
@@ -339,6 +343,7 @@ export class ChatbotService {
|
||||
|
||||
messages.push(errorMessage);
|
||||
await this.cacheService.setAsync(messagesKey, JSON.stringify(messages), this.CACHE_TTL_SECONDS);
|
||||
return this.mapMessageToDto(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import { BaseRepository } from "../../../common/base/repository";
|
||||
import { ChatMessageModel } from "../models/chat-message.model";
|
||||
import { IChatMessage, MessageStatus } from "../models/Abstraction/IChatMessage";
|
||||
|
||||
class ChatMessageRepository extends BaseRepository<IChatMessage> {
|
||||
constructor() {
|
||||
super(ChatMessageModel);
|
||||
}
|
||||
|
||||
async findBySessionWithPagination(sessionId: string, offset = 0, limit = 50) {
|
||||
return this.model
|
||||
.find({ session: sessionId })
|
||||
.populate("sender")
|
||||
.sort({ createdAt: 1 })
|
||||
.skip(offset)
|
||||
.limit(limit)
|
||||
.exec();
|
||||
}
|
||||
|
||||
async getConversationHistory(sessionId: string, limit = 20) {
|
||||
return this.model
|
||||
.find({ session: sessionId })
|
||||
.sort({ createdAt: -1 })
|
||||
.limit(limit)
|
||||
.exec();
|
||||
}
|
||||
|
||||
async markAsRead(messageIds: string[]) {
|
||||
return this.model.updateMany({ _id: { $in: messageIds } }, { status: MessageStatus.READ });
|
||||
}
|
||||
}
|
||||
|
||||
function createChatMessageRepository(): ChatMessageRepository {
|
||||
return new ChatMessageRepository();
|
||||
}
|
||||
|
||||
export { ChatMessageRepository, createChatMessageRepository };
|
||||
@@ -1,40 +0,0 @@
|
||||
import { BaseRepository } from "../../../common/base/repository";
|
||||
import { ChatSessionModel, ChatSessionStatus } from "../models/chat-session.model";
|
||||
import { IChatSession } from "../models/Abstraction/IChatSession";
|
||||
|
||||
class ChatSessionRepository extends BaseRepository<IChatSession> {
|
||||
constructor() {
|
||||
super(ChatSessionModel);
|
||||
}
|
||||
|
||||
async findByUserWithMessages(userId: string, limit = 10) {
|
||||
return this.model
|
||||
.find({ user: userId })
|
||||
.populate("messages")
|
||||
.sort({ lastMessageAt: -1 })
|
||||
.limit(limit)
|
||||
.exec();
|
||||
}
|
||||
|
||||
async findActiveByUser(userId: string) {
|
||||
return this.model
|
||||
.find({ user: userId, status: ChatSessionStatus.ACTIVE })
|
||||
.populate("messages")
|
||||
.sort({ lastMessageAt: -1 })
|
||||
.exec();
|
||||
}
|
||||
|
||||
async updateLastMessageTime(sessionId: string) {
|
||||
return this.model.findByIdAndUpdate(sessionId, { lastMessageAt: new Date() }, { new: true });
|
||||
}
|
||||
|
||||
async findByUserAndId(sessionId: string, userId: string) {
|
||||
return this.model.findOne({ _id: sessionId, user: userId }).populate("messages").populate("messages.sender").exec();
|
||||
}
|
||||
}
|
||||
|
||||
function createChatSessionRepository(): ChatSessionRepository {
|
||||
return new ChatSessionRepository();
|
||||
}
|
||||
|
||||
export { ChatSessionRepository, createChatSessionRepository };
|
||||
Reference in New Issue
Block a user