import { useState, useEffect } from 'react' import { Button } from '@/components/ui/button' import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card' import { Slider } from '@/components/ui/slider' import { Label } from '@/components/ui/label' import { User, Upload, File, X, BookOpen } from 'lucide-react' interface UploadedFile { id: string name: string size: number type: string uploadedAt: string status: string chunks?: number assistantId?: string | null } interface SelectedAssistant { id: string name: string type: 'user'|'template'|'new' originalTemplate?: string } interface DocumentsTabProps { isLoading: boolean ragEnabled: boolean setRagEnabled: (enabled: boolean) => void retrievalCount: number setRetrievalCount: (count: number) => void currentAssistant: SelectedAssistant | null } export function DocumentsTab({ isLoading, ragEnabled, setRagEnabled, retrievalCount, setRetrievalCount, currentAssistant }: DocumentsTabProps) { const [uploadedFiles, setUploadedFiles] = useState([]) const [isUploading, setIsUploading] = useState(false) // Load assistant-specific documents when assistant changes useEffect(() => { const loadDocuments = async () => { if (!currentAssistant) { // Load all documents when no assistant is selected try { const response = await fetch('/rag/documents') if (response.ok) { const data = await response.json() const allFiles: UploadedFile[] = data.documents.map((doc: any) => ({ id: doc.id, name: doc.filename, size: doc.size || 0, type: doc.content_type || 'application/octet-stream', uploadedAt: doc.upload_date, status: 'processed', chunks: doc.chunk_count, assistantId: doc.assistant_id })) setUploadedFiles(allFiles) } } catch (error) { console.error('Error loading documents:', error) } return } try { // For now, load all documents but filter by assistant in the future const response = await fetch('/rag/documents') if (response.ok) { const data = await response.json() if (data.documents) { const documentList = Object.entries(data.documents).map(([docId, docInfo]: [string, any]) => ({ id: docId, name: docInfo.filename, size: 0, type: docInfo.file_type, uploadedAt: new Date().toISOString(), status: docInfo.status, chunks: docInfo.chunks, assistantId: docInfo.assistant_id || null // Future: filter by assistant })) as UploadedFile[] // TODO: Filter documents by currentAssistant.id when backend supports it setUploadedFiles(documentList) } } } catch (error) { console.error('Error loading documents:', error) } } loadDocuments() }, [currentAssistant]) const handleFileUpload = async (event: React.ChangeEvent) => { const files = event.target.files if (!files) return setIsUploading(true) try { const formData = new FormData() // Add assistant ID to the upload (if available) if (currentAssistant) { formData.append('assistant_id', currentAssistant.id) } for (const file of Array.from(files)) { formData.append('files', file) } const response = await fetch('/rag/upload', { method: 'POST', body: formData, }) if (response.ok) { const result = await response.json() // Add successfully processed files to the list const newFiles = result.results .filter((r: any) => r.success) .map((r: any) => ({ id: r.doc_id, name: r.filename, size: 0, // Server doesn't return size currently type: 'processed', uploadedAt: new Date().toISOString(), status: 'processed', chunks: r.chunks, assistantId: currentAssistant?.id })) as UploadedFile[] setUploadedFiles((prev: UploadedFile[]) => [...prev, ...newFiles]) // Show errors for failed uploads const failedUploads = result.results.filter((r: any) => !r.success) if (failedUploads.length > 0) { console.error('Some files failed to upload:', failedUploads) } } else { console.error('Upload failed:', response.statusText) } // Reset input event.target.value = '' } catch (error) { console.error('File upload error:', error) } finally { setIsUploading(false) } } const removeFile = async (fileId: string) => { try { const response = await fetch(`/rag/documents/${fileId}`, { method: 'DELETE', }) if (response.ok) { setUploadedFiles((prev: UploadedFile[]) => prev.filter((f: UploadedFile) => f.id !== fileId)) } else { console.error('Failed to delete document:', response.statusText) } } catch (error) { console.error('Error deleting document:', error) // Remove from UI anyway setUploadedFiles((prev: UploadedFile[]) => prev.filter((f: UploadedFile) => f.id !== fileId)) } } return (
{!currentAssistant ? ( Documents & Knowledge Base {/* Upload Area */}
{/* Documents List */} {uploadedFiles.length > 0 && (
{uploadedFiles.map((file) => (
{file.name} {file.chunks && ( {file.chunks} chunks )}
))}
)} {/* Empty State */} {uploadedFiles.length === 0 && (

No documents uploaded yet

)}
) : (
{currentAssistant.name} {currentAssistant.type === 'user' ? 'My Assistant' : currentAssistant.type === 'template' ? 'Template' : 'New Assistant'}
setRagEnabled(e.target.checked)} className="rounded" disabled={isLoading || uploadedFiles.length === 0} /> {ragEnabled && uploadedFiles.length > 0 && (
Active
)}
{/* RAG Settings - Compact */} {ragEnabled && (
{retrievalCount} chunks
setRetrievalCount(value[0])} max={10} min={1} step={1} className="w-full" />
)} {/* Upload Area */}
{/* Documents List - Compact */} {uploadedFiles.length > 0 && (
{ragEnabled && ( Using {Math.min(retrievalCount, uploadedFiles.length)} for context )}
{uploadedFiles.map((file) => (
{file.name} {file.chunks && ( {file.chunks} chunks )}
))}
)} {/* Empty State */} {uploadedFiles.length === 0 && (

No documents uploaded yet

)}
)}
) }