149 lines
7.0 KiB
TypeScript
149 lines
7.0 KiB
TypeScript
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<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("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<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();
|
|
// }
|
|
// }
|
|
}
|