2026-07-27 21:54:31 +07:00
|
|
|
import { and, desc, eq, type SQL, sql } from "drizzle-orm";
|
|
|
|
|
import { getDatabase } from "../../shared/database/index.js";
|
2026-08-01 22:09:02 +07:00
|
|
|
import { pgChatbotMessagesTable, pgMessagesTable } from "../../shared/index.js";
|
|
|
|
|
import { createChildLogger } from "../../shared/logger/index.js";
|
2026-06-09 10:16:04 +07:00
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
const logger = createChildLogger("chatbot.repository");
|
2026-06-09 10:16:04 +07:00
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
export interface ChatbotContext {
|
2026-06-09 10:16:04 +07:00
|
|
|
messageCount?: number;
|
|
|
|
|
activeParticipants?: number;
|
|
|
|
|
lastActivity?: string;
|
|
|
|
|
topicsDiscussed?: string[];
|
|
|
|
|
guildId?: string;
|
|
|
|
|
channelId?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SaveConversationInput {
|
|
|
|
|
userId: string;
|
|
|
|
|
userMessage: string;
|
2026-07-28 15:00:29 +07:00
|
|
|
botResponse: string;
|
|
|
|
|
context?: ChatbotContext;
|
2026-06-09 10:16:04 +07:00
|
|
|
timestamp: Date;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
export interface ChatbotHistoryRow {
|
2026-06-09 10:16:04 +07:00
|
|
|
id: string;
|
|
|
|
|
user_id: string;
|
|
|
|
|
user_message: string;
|
2026-07-28 15:00:29 +07:00
|
|
|
bot_response: string;
|
|
|
|
|
context: ChatbotContext | null;
|
2026-06-09 10:16:04 +07:00
|
|
|
created_at: string;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
export class ChatbotRepository {
|
2026-06-09 10:16:04 +07:00
|
|
|
async saveConversation(input: SaveConversationInput): Promise<void> {
|
2026-07-27 21:54:31 +07:00
|
|
|
const db = getDatabase();
|
2026-06-09 10:16:04 +07:00
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
await db.insert(pgChatbotMessagesTable).values({
|
2026-07-27 21:54:31 +07:00
|
|
|
user_id: input.userId,
|
|
|
|
|
user_message: input.userMessage,
|
2026-07-28 15:00:29 +07:00
|
|
|
bot_response: input.botResponse,
|
2026-07-27 21:54:31 +07:00
|
|
|
context: (input.context ?? {}) as Record<string, unknown>,
|
|
|
|
|
created_at: input.timestamp,
|
|
|
|
|
});
|
2026-06-09 10:16:04 +07:00
|
|
|
|
|
|
|
|
logger.debug({ userId: input.userId }, "Conversation saved");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getChatHistory(
|
|
|
|
|
userId: string,
|
|
|
|
|
limit: number,
|
2026-07-28 15:00:29 +07:00
|
|
|
): Promise<ChatbotHistoryRow[]> {
|
2026-07-27 21:54:31 +07:00
|
|
|
const db = getDatabase();
|
2026-06-09 10:16:04 +07:00
|
|
|
|
2026-07-27 21:54:31 +07:00
|
|
|
const rows = await db
|
|
|
|
|
.select()
|
2026-07-28 15:00:29 +07:00
|
|
|
.from(pgChatbotMessagesTable)
|
|
|
|
|
.where(eq(pgChatbotMessagesTable.user_id, userId))
|
|
|
|
|
.orderBy(desc(pgChatbotMessagesTable.created_at))
|
2026-07-27 21:54:31 +07:00
|
|
|
.limit(limit);
|
2026-06-09 10:16:04 +07:00
|
|
|
|
|
|
|
|
logger.debug({ userId, count: rows.length }, "Chat history fetched");
|
2026-07-28 15:00:29 +07:00
|
|
|
return rows.reverse() as unknown as ChatbotHistoryRow[];
|
2026-06-09 10:16:04 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async clearChatHistory(userId: string): Promise<void> {
|
2026-07-27 21:54:31 +07:00
|
|
|
const db = getDatabase();
|
2026-06-09 10:16:04 +07:00
|
|
|
|
2026-07-27 21:54:31 +07:00
|
|
|
const deleted = await db
|
2026-07-28 15:00:29 +07:00
|
|
|
.delete(pgChatbotMessagesTable)
|
|
|
|
|
.where(eq(pgChatbotMessagesTable.user_id, userId))
|
|
|
|
|
.returning({ id: pgChatbotMessagesTable.id });
|
2026-07-27 21:54:31 +07:00
|
|
|
|
|
|
|
|
logger.info(
|
|
|
|
|
{ userId, deletedRows: deleted.length },
|
|
|
|
|
"Chat history cleared",
|
2026-06-09 10:16:04 +07:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-28 15:00:29 +07:00
|
|
|
export const chatbotRepository = new ChatbotRepository();
|