2026-06-09 10:16:04 +07:00
|
|
|
import type { Request, Response } from "express";
|
2026-08-01 22:09:02 +07:00
|
|
|
import { createChildLogger } from "@/shared/logger/index";
|
2026-06-09 19:46:08 +07:00
|
|
|
import { asyncHandler } from "../../shared/middlewares/index.js";
|
2026-07-28 15:00:29 +07:00
|
|
|
import { chatbotService } from "./chatbot.service.js";
|
2026-06-03 15:01:34 +07:00
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
const logger = createChildLogger("chatbot.controller");
|
2026-06-03 15:01:34 +07:00
|
|
|
|
2026-06-09 13:07:01 +07:00
|
|
|
interface AuthenticatedRequest extends Request {
|
|
|
|
|
userId?: string;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-03 06:24:19 +07:00
|
|
|
/**
|
|
|
|
|
* Resolve the actor id for a request. Frontend (no-login) sends a per-device
|
|
|
|
|
* UUID via X-User-Id so chat history stays isolated per visitor; a registered
|
|
|
|
|
* auth middleware userId takes precedence when present.
|
|
|
|
|
*/
|
|
|
|
|
function resolveUserId(req: Request): string {
|
|
|
|
|
const authId = (req as AuthenticatedRequest).userId;
|
|
|
|
|
if (authId) return authId;
|
|
|
|
|
const header = (req.headers["x-user-id"] as string | undefined)?.trim();
|
|
|
|
|
return header || "anonymous";
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
export const handleChatbotChat = asyncHandler(
|
2026-06-09 19:46:08 +07:00
|
|
|
async (req: Request, res: Response) => {
|
2026-07-27 21:54:31 +07:00
|
|
|
const { message, context } = req.body as {
|
|
|
|
|
message: string;
|
|
|
|
|
context?: Record<string, unknown>;
|
|
|
|
|
};
|
2026-07-02 03:54:44 +07:00
|
|
|
|
2026-07-27 21:54:31 +07:00
|
|
|
// Validate required fields
|
2026-07-02 03:54:44 +07:00
|
|
|
if (!message || typeof message !== "string") {
|
2026-06-03 15:01:34 +07:00
|
|
|
return res.status(400).json({
|
|
|
|
|
error: "INVALID_INPUT",
|
2026-07-02 03:54:44 +07:00
|
|
|
message: "Message is required and must be a string",
|
2026-06-03 15:01:34 +07:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-03 06:24:19 +07:00
|
|
|
// Get user ID from X-User-Id header (no-login device uuid) or auth
|
|
|
|
|
const userId = resolveUserId(req);
|
2026-06-03 15:01:34 +07:00
|
|
|
|
|
|
|
|
logger.debug(
|
|
|
|
|
{ userId, messageLength: message.length, context },
|
2026-07-28 15:00:29 +07:00
|
|
|
"Received chatbot chat message",
|
2026-06-03 15:01:34 +07:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Process message & generate response
|
2026-07-28 15:00:29 +07:00
|
|
|
const response = await chatbotService.processMessage(
|
2026-06-09 10:16:04 +07:00
|
|
|
message,
|
|
|
|
|
context,
|
|
|
|
|
userId,
|
|
|
|
|
);
|
2026-06-03 15:01:34 +07:00
|
|
|
|
|
|
|
|
// Save conversation to database
|
2026-07-28 15:00:29 +07:00
|
|
|
await chatbotService.saveConversation({
|
2026-06-03 15:01:34 +07:00
|
|
|
userId,
|
|
|
|
|
userMessage: message,
|
2026-07-28 15:00:29 +07:00
|
|
|
botResponse: response,
|
2026-06-03 15:01:34 +07:00
|
|
|
context,
|
|
|
|
|
timestamp: new Date(),
|
|
|
|
|
});
|
|
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
logger.info({ userId }, "Chatbot chat processed successfully");
|
2026-06-03 15:01:34 +07:00
|
|
|
|
|
|
|
|
res.status(200).json({
|
|
|
|
|
response,
|
|
|
|
|
timestamp: new Date().toISOString(),
|
|
|
|
|
});
|
2026-06-09 19:46:08 +07:00
|
|
|
},
|
|
|
|
|
);
|
2026-06-03 15:01:34 +07:00
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
export const getChatbotHistory = asyncHandler(
|
2026-06-09 19:46:08 +07:00
|
|
|
async (req: Request, res: Response) => {
|
2026-08-03 06:24:19 +07:00
|
|
|
const userId = resolveUserId(req);
|
2026-07-26 14:27:36 +07:00
|
|
|
const limit = Math.min(parseInt(req.query.limit as string, 10) || 50, 100);
|
2026-06-03 15:01:34 +07:00
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
const history = await chatbotService.getChatHistory(userId, limit);
|
2026-06-03 15:01:34 +07:00
|
|
|
|
|
|
|
|
res.status(200).json({
|
|
|
|
|
history,
|
|
|
|
|
total: history.length,
|
|
|
|
|
});
|
2026-06-09 19:46:08 +07:00
|
|
|
},
|
|
|
|
|
);
|
2026-06-03 15:01:34 +07:00
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
export const clearChatbotHistory = asyncHandler(
|
2026-06-09 19:46:08 +07:00
|
|
|
async (req: Request, res: Response) => {
|
2026-08-03 06:24:19 +07:00
|
|
|
const userId = resolveUserId(req);
|
2026-06-03 15:01:34 +07:00
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
await chatbotService.clearChatHistory(userId);
|
2026-06-03 15:01:34 +07:00
|
|
|
|
|
|
|
|
res.status(200).json({
|
|
|
|
|
message: "Chat history cleared successfully",
|
|
|
|
|
});
|
2026-06-09 19:46:08 +07:00
|
|
|
},
|
|
|
|
|
);
|