mirror of
https://github.com/aljazceru/enclava.git
synced 2025-12-17 23:44:24 +01:00
rag improvements
This commit is contained in:
@@ -7,7 +7,7 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
// Make request to backend auth endpoint without requiring existing auth
|
||||
const baseUrl = process.env.INTERNAL_API_URL || `http://enclava-backend:${process.env.BACKEND_INTERNAL_PORT || '8000'}`
|
||||
const url = `${baseUrl}/api/auth/login`
|
||||
const url = `${baseUrl}/api-internal/v1/auth/login`
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
|
||||
@@ -85,8 +85,31 @@ function RAGPageContent() {
|
||||
const loadStats = async () => {
|
||||
try {
|
||||
const data = await apiClient.get('/api-internal/v1/rag/stats')
|
||||
setStats(data.stats)
|
||||
console.log('Stats API response:', data)
|
||||
|
||||
// Check if the response has the expected structure
|
||||
if (data && data.stats && data.stats.collections) {
|
||||
console.log('✓ Stats has collections property')
|
||||
setStats(data.stats)
|
||||
} else {
|
||||
console.error('✗ Invalid stats structure:', data)
|
||||
// Set default empty stats to prevent error
|
||||
setStats({
|
||||
collections: { total: 0, active: 0 },
|
||||
documents: { total: 0, processing: 0, processed: 0 },
|
||||
storage: { total_size_bytes: 0, total_size_mb: 0 },
|
||||
vectors: { total: 0 }
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading stats:', error)
|
||||
// Set default empty stats on error
|
||||
setStats({
|
||||
collections: { total: 0, active: 0 },
|
||||
documents: { total: 0, processing: 0, processed: 0 },
|
||||
storage: { total_size_bytes: 0, total_size_mb: 0 },
|
||||
vectors: { total: 0 }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Badge } from "@/components/ui/badge"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
|
||||
import { Search, FileText, Trash2, Eye, Download, Calendar, Hash, FileIcon, Filter } from "lucide-react"
|
||||
import { Search, FileText, Trash2, Eye, Download, Calendar, Hash, FileIcon, Filter, RefreshCw } from "lucide-react"
|
||||
import { useToast } from "@/hooks/use-toast"
|
||||
import { apiClient } from "@/lib/api-client"
|
||||
import { config } from "@/lib/config"
|
||||
@@ -56,6 +56,7 @@ export function DocumentBrowser({ collections, selectedCollection, onCollectionS
|
||||
const [filterStatus, setFilterStatus] = useState("all")
|
||||
const [selectedDocument, setSelectedDocument] = useState<Document | null>(null)
|
||||
const [deleting, setDeleting] = useState<string | null>(null)
|
||||
const [reprocessing, setReprocessing] = useState<string | null>(null)
|
||||
const { toast } = useToast()
|
||||
|
||||
useEffect(() => {
|
||||
@@ -157,6 +158,43 @@ export function DocumentBrowser({ collections, selectedCollection, onCollectionS
|
||||
}
|
||||
}
|
||||
|
||||
const handleReprocessDocument = async (documentId: string) => {
|
||||
setReprocessing(documentId)
|
||||
|
||||
try {
|
||||
await apiClient.post(`/api-internal/v1/rag/documents/${documentId}/reprocess`)
|
||||
|
||||
// Update the document status to processing in the UI
|
||||
setDocuments(prev => prev.map(doc =>
|
||||
doc.id === documentId
|
||||
? { ...doc, status: 'processing' as const, processed_at: new Date().toISOString() }
|
||||
: doc
|
||||
))
|
||||
|
||||
toast({
|
||||
title: "Success",
|
||||
description: "Document reprocessing started",
|
||||
})
|
||||
|
||||
// Reload documents after a short delay to see status updates
|
||||
setTimeout(() => {
|
||||
loadDocuments()
|
||||
}, 2000)
|
||||
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : "Failed to reprocess document"
|
||||
toast({
|
||||
title: "Error",
|
||||
description: errorMessage.includes("Cannot reprocess document with status 'processed'")
|
||||
? "Cannot reprocess documents that are already processed"
|
||||
: errorMessage,
|
||||
variant: "destructive",
|
||||
})
|
||||
} finally {
|
||||
setReprocessing(null)
|
||||
}
|
||||
}
|
||||
|
||||
const formatFileSize = (bytes: number) => {
|
||||
if (bytes === 0) return '0 Bytes'
|
||||
const k = 1024
|
||||
@@ -432,6 +470,21 @@ export function DocumentBrowser({ collections, selectedCollection, onCollectionS
|
||||
<Download className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-8 w-8 p-0 hover:bg-blue-100"
|
||||
onClick={() => handleReprocessDocument(document.id)}
|
||||
disabled={reprocessing === document.id || document.status === 'processed'}
|
||||
title={document.status === 'processed' ? "Document already processed" : "Reprocess document"}
|
||||
>
|
||||
{reprocessing === document.id ? (
|
||||
<RefreshCw className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<RefreshCw className={`h-4 w-4 ${document.status === 'processed' ? 'text-gray-400' : ''}`} />
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button
|
||||
|
||||
@@ -67,12 +67,13 @@ const Navigation = () => {
|
||||
// Core navigation items that are always visible
|
||||
const coreNavItems = [
|
||||
{ href: "/dashboard", label: "Dashboard" },
|
||||
{
|
||||
href: "/llm",
|
||||
{
|
||||
href: "/llm",
|
||||
label: "LLM",
|
||||
children: [
|
||||
{ href: "/llm", label: "Models & Config" },
|
||||
{ href: "/playground", label: "Playground" },
|
||||
{ href: "/rag-demo", label: "RAG Demo" },
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user