chore: chat bot

This commit is contained in:
mahyargdz
2025-06-08 17:01:33 +03:30
parent a457bb276e
commit 173e8675c3
30 changed files with 7184 additions and 1681 deletions
+158
View File
@@ -0,0 +1,158 @@
import { Body, Controller, Get, Param, ParseIntPipe, ParseUUIDPipe, Post, Put, Query, Res } from "@nestjs/common";
import { ApiOperation, ApiResponse } from "@nestjs/swagger";
import { FastifyReply } from "fastify";
import { ChatMessageResponseDto, ChatSessionResponseDto } from "./DTO/chat-response.dto";
import { CreateChatSessionDto } from "./DTO/create-chat-session.dto";
import { SendMessageDto } from "./DTO/send-message.dto";
import { ChatbotService } from "./providers/chatbot.service";
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
import { UserDec } from "../../common/decorators/user.decorator";
@Controller("chatbot")
@AuthGuards()
export class ChatbotController {
constructor(private chatbotService: ChatbotService) {}
@Post("sessions")
@ApiOperation({ summary: "Create a new chat session" })
@ApiResponse({ status: 201, description: "Chat session created successfully", type: ChatSessionResponseDto })
async createSession(@UserDec("id") userId: string, @Body() createDto: CreateChatSessionDto): Promise<ChatSessionResponseDto> {
return this.chatbotService.createChatSession(userId, createDto);
}
@Get("sessions")
@ApiOperation({ summary: "Get user's chat sessions" })
@ApiResponse({ status: 200, description: "Chat sessions retrieved successfully", type: [ChatSessionResponseDto] })
async getUserSessions(
@UserDec("id") userId: string,
@Query("limit", new ParseIntPipe({ optional: true })) limit = 10,
): Promise<ChatSessionResponseDto[]> {
return this.chatbotService.getUserChatSessions(userId, limit);
}
@Get("sessions/:sessionId")
@ApiOperation({ summary: "Get a specific chat session with messages" })
@ApiResponse({ status: 200, description: "Chat session retrieved successfully", type: ChatSessionResponseDto })
async getSession(@UserDec("id") userId: string, @Param("sessionId", ParseUUIDPipe) sessionId: string): Promise<ChatSessionResponseDto> {
return this.chatbotService.getChatSession(sessionId, userId);
}
@Post("messages")
@ApiOperation({ summary: "Send a message in a chat session (Enhanced with LangChain + Fallback)" })
@ApiResponse({ status: 201, description: "Message sent successfully with enhanced AI", type: ChatMessageResponseDto })
async sendMessage(@UserDec("id") userId: string, @Body() sendDto: SendMessageDto): Promise<ChatMessageResponseDto> {
// Now uses LangChain by default with automatic Gemini fallback
return this.chatbotService.sendMessage(userId, sendDto);
}
@Post("messages/stream")
@ApiOperation({ summary: "Send a message and get streaming response (Enhanced with LangChain + Fallback)" })
@ApiResponse({ status: 200, description: "Enhanced streaming response initiated" })
async sendMessageStream(@UserDec("id") userId: string, @Body() sendDto: SendMessageDto, @Res() res: FastifyReply): Promise<void> {
try {
// Now uses LangChain by default with automatic Gemini fallback
const { userMessage, streamGenerator } = await this.chatbotService.sendMessageStream(userId, sendDto);
// Set headers for Server-Sent Events
res.header("Content-Type", "text/event-stream");
res.header("Cache-Control", "no-cache");
res.header("Connection", "keep-alive");
res.header("Access-Control-Allow-Origin", "*");
// Send initial user message
res.raw.write(`data: ${JSON.stringify({ type: "user_message", data: userMessage, enhanced: true })}\n\n`);
// Start streaming bot response
res.raw.write(`data: ${JSON.stringify({ type: "bot_response_start", provider: "enhanced" })}\n\n`);
const stream = await streamGenerator();
for await (const chunk of stream) {
if (chunk) {
res.raw.write(`data: ${JSON.stringify({ type: "bot_response_chunk", data: chunk })}\n\n`);
}
}
// End streaming
res.raw.write(`data: ${JSON.stringify({ type: "bot_response_end" })}\n\n`);
res.raw.end();
} catch (error) {
console.error(error);
res.raw.write(
`data: ${JSON.stringify({ type: "error", data: "خطا در تولید پاسخ هوشمند. LangChain با خطا مواجه شد و به Gemini بازگشت ⚠️" })}\n\n`,
);
res.raw.end();
}
}
@Post("messages/langchain")
@ApiOperation({ summary: "Send a message using LangChain with enhanced RAG capabilities" })
@ApiResponse({ status: 201, description: "Message sent successfully with LangChain", type: ChatMessageResponseDto })
async sendMessageWithLangChain(@UserDec("id") userId: string, @Body() sendDto: SendMessageDto): Promise<ChatMessageResponseDto> {
return this.chatbotService.sendMessageWithLangChain(userId, sendDto);
}
@Post("messages/langchain/stream")
@ApiOperation({ summary: "Send a message and get streaming response using LangChain" })
@ApiResponse({ status: 200, description: "Streaming response initiated with LangChain" })
async sendMessageStreamWithLangChain(@UserDec("id") userId: string, @Body() sendDto: SendMessageDto, @Res() res: FastifyReply): Promise<void> {
try {
const { userMessage, streamGenerator } = await this.chatbotService.sendMessageStreamWithLangChain(userId, sendDto);
// Set headers for Server-Sent Events
res.header("Content-Type", "text/event-stream");
res.header("Cache-Control", "no-cache");
res.header("Connection", "keep-alive");
res.header("Access-Control-Allow-Origin", "*");
// Send initial user message
res.raw.write(`data: ${JSON.stringify({ type: "user_message", data: userMessage })}\n\n`);
// Start streaming bot response
res.raw.write(`data: ${JSON.stringify({ type: "bot_response_start", provider: "langchain" })}\n\n`);
const stream = await streamGenerator();
for await (const chunk of stream) {
if (chunk) {
res.raw.write(`data: ${JSON.stringify({ type: "bot_response_chunk", data: chunk })}\n\n`);
}
}
// End streaming
res.raw.write(`data: ${JSON.stringify({ type: "bot_response_end" })}\n\n`);
res.raw.end();
} catch (error) {
console.error(error);
res.raw.write(`data: ${JSON.stringify({ type: "error", data: "خطا در تولید پاسخ با LangChain. لطفاً دوباره تلاش کنید. ⚠️" })}\n\n`);
res.raw.end();
}
}
@Post("training/refresh")
@ApiOperation({ summary: "Refresh LangChain training data from database" })
@ApiResponse({ status: 200, description: "Training data refreshed successfully" })
async refreshTrainingData(@UserDec("id") _userId: string): Promise<{ message: string }> {
await this.chatbotService.refreshLangChainData();
return { message: "داده‌های آموزشی با موفقیت به‌روزرسانی شدند 🔄" };
}
@Put("sessions/:sessionId/close")
@ApiOperation({ summary: "Close a chat session" })
@ApiResponse({ status: 200, description: "Chat session closed successfully" })
async closeSession(@UserDec("id") userId: string, @Param("sessionId", ParseUUIDPipe) sessionId: string): Promise<{ message: string }> {
await this.chatbotService.closeChatSession(sessionId, userId);
return { message: "جلسه چت با موفقیت بسته شد ✅" };
}
@Put("sessions/:sessionId/messages/read")
@ApiOperation({ summary: "Mark messages as read" })
@ApiResponse({ status: 200, description: "Messages marked as read successfully" })
async markMessagesAsRead(
@UserDec("id") userId: string,
@Param("sessionId", ParseUUIDPipe) sessionId: string,
@Body() body: { messageIds: string[] },
): Promise<{ message: string }> {
await this.chatbotService.markMessagesAsRead(sessionId, userId, body.messageIds);
return { message: "پیام‌ها با موفقیت به عنوان خوانده شده علامت‌گذاری شدند ✅" };
}
}