diff --git a/app/api/chat/message/route.ts b/app/api/chat/message/route.ts index b9f2909..2e31593 100644 --- a/app/api/chat/message/route.ts +++ b/app/api/chat/message/route.ts @@ -1,4 +1,5 @@ import { createServerClientSSR } from '@/lib/supabase/server' +import { getRAGAgent } from '@/lib/rag/agent' import { requireAuth } from '@/lib/utils/auth' import { ChatMessageSchema } from '@/lib/types' import { successResponse, errorResponse, handleError } from '@/lib/utils/api-response' @@ -24,56 +25,47 @@ export async function POST(request: NextRequest) { return errorResponse('Session not found', 404) } - // Save user message - const { data: userMessage, error: userMessageError } = await supabase - .from('chat_messages') - .insert({ - session_id: validatedData.sessionId, - role: 'user' as const, - content: validatedData.content, - } as any) - .select() - .single() - - if (userMessageError) { - throw userMessageError - } - - // TODO: Implement RAG pipeline - // 1. Retrieve relevant chunks from paper_chunks using vector similarity - // 2. Build context with citations - // 3. Generate response using GPT-4o-mini - // 4. Save assistant message with citations + const ragAgent = getRAGAgent() + const result = await ragAgent.query( + validatedData.content, + user.id, + validatedData.sessionId, + session.paper_id || undefined + ) - // For now, return a placeholder response - const placeholderResponse = "I'm ready to help you understand this paper! However, the RAG (Retrieval Augmented Generation) system is not yet implemented. Once it's ready, I'll be able to:\n\n1. Search through the paper content\n2. Find relevant sections to answer your question\n3. Provide accurate responses with citations\n\nPlease check back soon!" - - // Save assistant message (placeholder) - const { data: assistantMessage, error: assistantMessageError } = await supabase + const { data: latestMessages, error: latestMessagesError } = await supabase .from('chat_messages') - .insert({ - session_id: validatedData.sessionId, - role: 'assistant' as const, - content: placeholderResponse, - } as any) - .select() - .single() + .select('*') + .eq('session_id', validatedData.sessionId) + .in('role', ['user', 'assistant']) + .order('created_at', { ascending: false }) + .limit(4) - if (assistantMessageError) { - throw assistantMessageError + if (latestMessagesError) { + throw latestMessagesError } - // Update session's updated_at timestamp - await (supabase - .from('chat_sessions') as any) - .update({ updated_at: new Date().toISOString() }) - .eq('id', validatedData.sessionId) + const userMessage = + latestMessages?.find((message: any) => ( + message.role === 'user' && message.content === validatedData.content + )) || + latestMessages?.find((message: any) => message.role === 'user') || + null + + const assistantMessage = + latestMessages?.find((message: any) => message.role === 'assistant') || + null return successResponse({ userMessage, assistantMessage, + answer: result.answer, + sources: result.sources, + citations: result.citations, + queryTime: result.queryTime, + sessionId: result.sessionId, }) } catch (error) { return handleError(error) } -} \ No newline at end of file +} diff --git a/app/api/rag/query/route.ts b/app/api/rag/query/route.ts index 24c099d..6810da2 100644 --- a/app/api/rag/query/route.ts +++ b/app/api/rag/query/route.ts @@ -1,20 +1,9 @@ import { NextRequest, NextResponse } from 'next/server'; -import { RAGAgent } from '@/lib/rag/rag_agent'; +import { getRAGAgent } from '@/lib/rag/agent'; import { ConfigManager, loadConfigFromEnv } from '@/lib/rag/config'; -const configManager = new ConfigManager(loadConfigFromEnv()); -const config = configManager.get(); - -const ragAgent = new RAGAgent({ - openaiApiKey: config.openai.apiKey, - supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!, - supabaseKey: process.env.SUPABASE_SERVICE_ROLE_KEY!, - chromaUrl: config.vectorStore.chromaUrl, - vectorStoreType: config.vectorStore.type, - modelName: config.openai.model, - chunkSize: config.chunking.chunkSize, - chunkOverlap: config.chunking.chunkOverlap, -}); +const config = new ConfigManager(loadConfigFromEnv()).get(); +const ragAgent = getRAGAgent(); export async function POST(request: NextRequest) { try { @@ -106,4 +95,4 @@ export async function POST(request: NextRequest) { { status: 500 } ); } -} \ No newline at end of file +} diff --git a/app/api/rag/session/route.ts b/app/api/rag/session/route.ts index 0312fc2..0845e92 100644 --- a/app/api/rag/session/route.ts +++ b/app/api/rag/session/route.ts @@ -1,20 +1,7 @@ import { NextRequest, NextResponse } from 'next/server'; -import { RAGAgent } from '@/lib/rag/rag_agent'; -import { ConfigManager, loadConfigFromEnv } from '@/lib/rag/config'; +import { getRAGAgent } from '@/lib/rag/agent'; -const configManager = new ConfigManager(loadConfigFromEnv()); -const config = configManager.get(); - -const ragAgent = new RAGAgent({ - openaiApiKey: config.openai.apiKey, - supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!, - supabaseKey: process.env.SUPABASE_SERVICE_ROLE_KEY!, - chromaUrl: config.vectorStore.chromaUrl, - vectorStoreType: config.vectorStore.type, - modelName: config.openai.model, - chunkSize: config.chunking.chunkSize, - chunkOverlap: config.chunking.chunkOverlap, -}); +const ragAgent = getRAGAgent(); export async function POST(request: NextRequest) { try { @@ -78,4 +65,4 @@ export async function GET(request: NextRequest) { { status: 500 } ); } -} \ No newline at end of file +} diff --git a/lib/rag/agent.ts b/lib/rag/agent.ts new file mode 100644 index 0000000..e58539b --- /dev/null +++ b/lib/rag/agent.ts @@ -0,0 +1,26 @@ +import { ConfigManager, loadConfigFromEnv } from './config' +import { RAGAgent } from './rag_agent' + +let ragAgent: RAGAgent | null = null + +export function getRAGAgent(): RAGAgent { + if (ragAgent) { + return ragAgent + } + + const configManager = new ConfigManager(loadConfigFromEnv()) + const config = configManager.get() + + ragAgent = new RAGAgent({ + openaiApiKey: config.openai.apiKey, + supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!, + supabaseKey: process.env.SUPABASE_SERVICE_ROLE_KEY!, + chromaUrl: config.vectorStore.chromaUrl, + vectorStoreType: config.vectorStore.type, + modelName: config.openai.model, + chunkSize: config.chunking.chunkSize, + chunkOverlap: config.chunking.chunkOverlap, + }) + + return ragAgent +}