import { Body, Controller, Get, Param, Post, Put, Query, Res } from "@nestjs/common"; import { ApiOperation, ApiResponse } from "@nestjs/swagger"; import { FastifyReply } from "fastify"; import { CreateChatSessionDto } from "./DTO/create-chat-session.dto"; import { SendMessageDto } from "./DTO/send-message.dto"; import { SessionIdParamDto } from "./DTO/session-id.param.dto"; import { ChatbotService } from "./providers/chatbot.service"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; import { UserDec } from "../../common/decorators/user.decorator"; import { PaginationDto } from "../../common/DTO/pagination.dto"; @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" }) createSession(@UserDec("id") userId: string, @Body() createDto: CreateChatSessionDto) { return this.chatbotService.createChatSession(userId, createDto); } @Get("sessions") @ApiOperation({ summary: "Get user's chat sessions" }) @ApiResponse({ status: 200, description: "Chat sessions retrieved successfully" }) getUserSessions(@UserDec("id") userId: string, @Query() queryDto: PaginationDto) { return this.chatbotService.getUserChatSessions(userId, queryDto.limit); } @Get("sessions/:sessionId") @ApiOperation({ summary: "Get a specific chat session with messages" }) @ApiResponse({ status: 200, description: "Chat session retrieved successfully" }) getSession(@UserDec("id") userId: string, @Param() param: SessionIdParamDto) { return this.chatbotService.getChatSession(param.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" }) sendMessage(@UserDec("id") userId: string, @Body() sendDto: SendMessageDto) { 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 { 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("training/refresh") @ApiOperation({ summary: "Refresh LangChain training data from database" }) @ApiResponse({ status: 200, description: "Training data refreshed successfully" }) refreshTrainingData(@UserDec("id") _userId: string) { return this.chatbotService.refreshLangChainData(); } @Put("sessions/:sessionId/close") @ApiOperation({ summary: "Close a chat session" }) @ApiResponse({ status: 200, description: "Chat session closed successfully" }) closeSession(@UserDec("id") userId: string, @Param() param: SessionIdParamDto) { return this.chatbotService.closeChatSession(param.sessionId, userId); } @Put("sessions/:sessionId/messages/read") @ApiOperation({ summary: "Mark messages as read" }) @ApiResponse({ status: 200, description: "Messages marked as read successfully" }) markMessagesAsRead(@UserDec("id") userId: string, @Param() param: SessionIdParamDto, @Body() body: { messageIds: string[] }) { return this.chatbotService.markMessagesAsRead(param.sessionId, userId, body.messageIds); } // @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 }) // sendMessageWithLangChain(@UserDec("id") userId: string, @Body() sendDto: SendMessageDto): Promise { // 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 { // 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(); // } // } }