UNPKG

@restnfeel/agentc-starter-kit

Version:

한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템

249 lines (215 loc) 7.3 kB
import { NextRequest, NextResponse } from "next/server"; import { RAGEngine } from "../../../../rag"; interface ChatRequestBody { message: string; sessionId?: string; context?: Record<string, any>; } // 간단한 세션 저장소 (실제 프로덕션에서는 Redis나 데이터베이스 사용) const sessions = new Map< string, { id: string; messages: Array<{ id: string; content: string; sender: "user" | "ai"; timestamp: Date; }>; createdAt: Date; lastActivity: Date; } >(); // RAG 엔진 인스턴스 (실제로는 싱글톤 패턴 사용) let ragEngine: RAGEngine | null = null; async function initializeRAGEngine() { if (!ragEngine) { ragEngine = new RAGEngine({ embeddingModel: "text-embedding-ada-002", chunkSize: 1000, chunkOverlap: 200, vectorStorePath: "./store", supabaseConfig: { url: process.env.SUPABASE_URL || "", anonKey: process.env.SUPABASE_ANON_KEY || "", bucket: "documents", }, llmConfig: { modelName: process.env.OPENAI_MODEL || "gpt-3.5-turbo", temperature: 0.7, maxTokens: 1000, apiKey: process.env.OPENAI_API_KEY || "", }, }); try { await ragEngine.initialize(); } catch (error) { console.error("RAG 엔진 초기화 실패:", error); ragEngine = null; throw error; } } return ragEngine; } function generateMessageId(): string { return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } function getOrCreateSession(sessionId: string) { if (!sessions.has(sessionId)) { sessions.set(sessionId, { id: sessionId, messages: [], createdAt: new Date(), lastActivity: new Date(), }); } const session = sessions.get(sessionId)!; session.lastActivity = new Date(); return session; } export async function POST(request: NextRequest) { try { const body: ChatRequestBody = await request.json(); if (!body.message?.trim()) { return NextResponse.json( { error: "메시지를 입력해주세요" }, { status: 400 } ); } const sessionId = body.sessionId || `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const session = getOrCreateSession(sessionId); // 사용자 메시지 저장 const userMessage = { id: generateMessageId(), content: body.message, sender: "user" as const, timestamp: new Date(), }; session.messages.push(userMessage); let aiResponse: string; let sources: Array<{ title: string; content: string; url?: string; score: number; }> = []; try { // RAG 엔진 초기화 및 응답 생성 const engine = await initializeRAGEngine(); if (engine) { // RAG 검색 수행 const searchResults = await engine.search(body.message, 3); // 컨텍스트 구성 const context = searchResults .map((result) => result.chunk.content) .join("\n\n"); // LLM에 컨텍스트와 함께 질문 전달 const prompt = `다음 컨텍스트를 바탕으로 사용자의 질문에 답변해주세요: 컨텍스트: ${context} 사용자 질문: ${body.message} 답변은 한국어로 친근하고 도움이 되는 톤으로 작성해주세요. 컨텍스트에 관련 정보가 없다면 일반적인 도움을 제공해주세요.`; // OpenAI API를 직접 호출하여 응답 생성 const response = await fetch( "https://api.openai.com/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, }, body: JSON.stringify({ model: "gpt-3.5-turbo", messages: [{ role: "user", content: prompt }], max_tokens: 500, temperature: 0.7, }), } ); if (response.ok) { const data = await response.json(); aiResponse = data.choices[0]?.message?.content || getDefaultResponse(body.message); } else { aiResponse = getDefaultResponse(body.message); } // 검색 결과를 sources로 변환 sources = searchResults.map((result, index) => ({ title: `관련 문서 ${index + 1}`, content: result.chunk.content.substring(0, 200) + "...", score: result.score, })); } else { // RAG 엔진이 없을 때 기본 응답 aiResponse = getDefaultResponse(body.message); } } catch (ragError) { console.error("RAG 처리 오류:", ragError); aiResponse = getDefaultResponse(body.message); } // AI 응답 저장 const aiMessage = { id: generateMessageId(), content: aiResponse, sender: "ai" as const, timestamp: new Date(), }; session.messages.push(aiMessage); // 응답 반환 return NextResponse.json({ id: aiMessage.id, content: aiResponse, timestamp: aiMessage.timestamp, sessionId, sources: sources.length > 0 ? sources : undefined, metadata: { messageCount: session.messages.length, sessionCreated: session.createdAt, }, }); } catch (error) { console.error("챗봇 API 오류:", error); return NextResponse.json( { error: "죄송합니다. 일시적인 오류가 발생했습니다. 잠시 후 다시 시도해주세요.", code: "INTERNAL_ERROR", }, { status: 500 } ); } } function getDefaultResponse(message: string): string { const lowerMessage = message.toLowerCase(); if (lowerMessage.includes("안녕") || lowerMessage.includes("hello")) { return "안녕하세요! 무엇을 도와드릴까요?"; } if (lowerMessage.includes("가격") || lowerMessage.includes("요금")) { return "가격 관련 문의를 주셔서 감사합니다. 자세한 요금제 정보는 영업팀에 문의해주시면 상세히 안내드리겠습니다."; } if (lowerMessage.includes("기능") || lowerMessage.includes("서비스")) { return "저희 서비스는 다양한 기능을 제공합니다. 구체적으로 어떤 부분이 궁금하신지 말씀해주시면 더 자세히 설명드릴게요."; } if ( lowerMessage.includes("문제") || lowerMessage.includes("오류") || lowerMessage.includes("error") ) { return "문제가 발생하신 것 같네요. 구체적인 상황을 말씀해주시면 해결 방법을 안내드리겠습니다. 급한 경우 고객지원팀으로 연락해주세요."; } return "말씀해주신 내용에 대해 더 구체적인 정보가 필요합니다. 어떤 부분이 궁금하신지 자세히 알려주시면 더 정확한 답변을 드릴 수 있습니다."; } // OPTIONS 메서드 처리 (CORS) export async function OPTIONS() { return new NextResponse(null, { status: 200, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "POST, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization", }, }); }