Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 32 additions & 40 deletions app/api/chat/message/route.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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)
}
}
}
19 changes: 4 additions & 15 deletions app/api/rag/query/route.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -106,4 +95,4 @@ export async function POST(request: NextRequest) {
{ status: 500 }
);
}
}
}
19 changes: 3 additions & 16 deletions app/api/rag/session/route.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -78,4 +65,4 @@ export async function GET(request: NextRequest) {
{ status: 500 }
);
}
}
}
26 changes: 26 additions & 0 deletions lib/rag/agent.ts
Original file line number Diff line number Diff line change
@@ -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
}