import React, { useState, useEffect, useRef } from 'react'; import { Send, Sparkles, AlertTriangle, CheckCircle, Shield, Database, Zap, ArrowRight, RefreshCw, Star, Info, Lock, Check, LogOut, Mail, Key, Upload, FileText, MessageSquare, Trash2, Library, ChevronRight, Activity, FilePlus, Edit2, Copy, User, Eye, EyeOff } from 'lucide-react'; import './App.css'; const API_URL = process.env.REACT_APP_API_URL || (window.location.hostname === 'localhost' ? 'http://localhost:5000' : ''); function App() { const [token, setToken] = useState(localStorage.getItem('token') || ''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [loginError, setLoginError] = useState(''); // Auth view mode ('login' or 'register') const [authMode, setAuthMode] = useState('login'); // Registration States const [regEmail, setRegEmail] = useState(''); const [regPassword, setRegPassword] = useState(''); const [regConfirmPassword, setRegConfirmPassword] = useState(''); const [regName, setRegName] = useState(''); const [regAvatar, setRegAvatar] = useState('👨‍💻'); const [regError, setRegError] = useState(''); // Password Visibility States const [showLoginPassword, setShowLoginPassword] = useState(false); const [showRegPassword, setShowRegPassword] = useState(false); const [showRegConfirmPassword, setShowRegConfirmPassword] = useState(false); // Navigation Sidebar const [activeTab, setActiveTab] = useState('workspace'); // 'workspace', 'library', 'telemetry' // RAG States const [documents, setDocuments] = useState([]); const [selectedProjectId, setSelectedProjectId] = useState(''); const [queryAllDocs, setQueryAllDocs] = useState(false); const [activeTelemetry, setActiveTelemetry] = useState(null); // Chat Threads States const [chatThreads, setChatThreads] = useState([]); const [activeChatId, setActiveChatId] = useState(''); const [messages, setMessages] = useState([]); const [query, setQuery] = useState(''); const [loading, setLoading] = useState(false); // User Profile details const [userStatus, setUserStatus] = useState({ isPremium: false, name: '', queryCount: 0, totalStorageBytes: 0, uploadedDocuments: [] }); // Library Viewer & File Upload & Copy Paste States const [selectedDocContent, setSelectedDocContent] = useState(null); const [viewingDocId, setViewingDocId] = useState(''); const [uploadTitle, setUploadTitle] = useState(''); const [selectedFile, setSelectedFile] = useState(null); const [copyPasteText, setCopyPasteText] = useState(''); const [ingestMode, setIngestMode] = useState('upload'); // 'upload', 'copypaste' const [uploadLoading, setUploadLoading] = useState(false); const [uploadStatus, setUploadStatus] = useState({ type: '', text: '' }); const [copiedId, setCopiedId] = useState(''); const [docSearchQuery, setDocSearchQuery] = useState(''); // Razorpay Simulation Overlay States const [showRzpModal, setShowRzpModal] = useState(false); const [rzpOrderDetails, setRzpOrderDetails] = useState(null); const [rzpPaymentStep, setRzpPaymentStep] = useState('methods'); // 'methods', 'card', 'upi', 'processing' const [rzpCardNumber, setRzpCardNumber] = useState(''); const [rzpCardExpiry, setRzpCardExpiry] = useState(''); const [rzpCardCvv, setRzpCardCvv] = useState(''); const [rzpUpiId, setRzpUpiId] = useState(''); const [rzpActiveOptions, setRzpActiveOptions] = useState(null); // Account Settings States const [profileName, setProfileName] = useState(''); const [profileEmail, setProfileEmail] = useState(''); const [profilePhone, setProfilePhone] = useState(''); const [profilePhoto, setProfilePhoto] = useState('👨‍💻'); const [profileSaveLoading, setProfileSaveLoading] = useState(false); const [profileSaveStatus, setProfileSaveStatus] = useState({ type: '', text: '' }); const messagesEndRef = useRef(null); // Initialize and load datasets useEffect(() => { if (token) { fetchUserStatus(); fetchDocuments(); } }, [token]); // Synchronize profile states with loaded user details useEffect(() => { if (userStatus) { setProfileName(userStatus.name || ''); setProfileEmail(userStatus.email || ''); setProfilePhone(userStatus.phoneNumber || ''); setProfilePhoto(userStatus.profilePhoto || '👨‍💻'); } }, [userStatus]); // Dynamically load Razorpay SDK script useEffect(() => { const script = document.createElement("script"); script.src = "https://checkout.razorpay.com/v1/checkout.js"; script.async = true; document.body.appendChild(script); return () => { document.body.removeChild(script); }; }, []); // Load chat threads when project (document) changes useEffect(() => { if (token && selectedProjectId) { fetchChatThreads(selectedProjectId); } else { setChatThreads([]); setActiveChatId(''); setMessages([]); } }, [selectedProjectId, token]); // Load message history when active chat thread changes useEffect(() => { if (activeChatId) { const activeThread = chatThreads.find(t => t.chatId === activeChatId); if (activeThread) { setMessages(activeThread.messages || []); const lastAiMsg = [...(activeThread.messages || [])].reverse().find(m => m.sender === 'ai'); if (lastAiMsg && lastAiMsg.telemetry) { setActiveTelemetry(lastAiMsg.telemetry); } } } else { setMessages([]); } }, [activeChatId, chatThreads]); useEffect(() => { const params = new URLSearchParams(window.location.search); if (params.get('payment') === 'success') { alert("🎉 Thank you! Your account has been upgraded to Premium."); window.history.replaceState({}, document.title, "/"); if (token) fetchUserStatus(); } else if (params.get('payment') === 'cancel') { alert("❌ Payment was cancelled. Feel free to upgrade anytime!"); window.history.replaceState({}, document.title, "/"); } }, [token]); useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); const handleCopyToClipboard = (text, msgIdx) => { navigator.clipboard.writeText(text); setCopiedId(msgIdx); setTimeout(() => setCopiedId(''), 2000); }; const renderFormattedMessage = (text) => { if (!text) return null; const codeBlockRegex = /```([\s\S]*?)```/g; const parts = []; let lastIndex = 0; let match; while ((match = codeBlockRegex.exec(text)) !== null) { if (match.index > lastIndex) { parts.push({ type: 'text', content: text.substring(lastIndex, match.index) }); } parts.push({ type: 'code', content: match[1] }); lastIndex = codeBlockRegex.lastIndex; } if (lastIndex < text.length) { parts.push({ type: 'text', content: text.substring(lastIndex) }); } return parts.map((part, idx) => { if (part.type === 'code') { return (
            {part.content.trim()}
          
); } else { const lines = part.content.split('\n'); return lines.map((line, lineIdx) => { const isListItem = line.trim().startsWith('- ') || line.trim().startsWith('* '); const content = line.replace(/^[\s*-]+/, ''); const formatBold = (str) => { const boldRegex = /\*\*([\s\S]*?)\*\*/g; const boldParts = []; let bLastIndex = 0; let bMatch; while ((bMatch = boldRegex.exec(str)) !== null) { if (bMatch.index > bLastIndex) { boldParts.push(str.substring(bLastIndex, bMatch.index)); } boldParts.push({bMatch[1]}); bLastIndex = boldRegex.lastIndex; } if (bLastIndex < str.length) { boldParts.push(str.substring(bLastIndex)); } return boldParts.length > 0 ? boldParts : str; }; if (isListItem) { return (
  • {formatBold(content)}
  • ); } else { return (

    {formatBold(line)}

    ); } }); } }); }; const handleLogin = async (e, devEmail = null) => { if (e) e.preventDefault(); setLoginError(''); const targetEmail = devEmail || email; const targetPassword = devEmail ? 'password123' : password; try { const res = await fetch(`${API_URL}/api/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: targetEmail, password: targetPassword }) }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Login failed"); localStorage.setItem('token', data.token); setToken(data.token); setEmail(''); setPassword(''); } catch (err) { setLoginError(err.message); } }; const getPasswordStrength = (pwd) => { if (!pwd) return { score: 0, label: 'Empty', color: '#718096' }; let score = 0; if (pwd.length >= 6) score += 1; if (/\d/.test(pwd)) score += 1; if (/[!@#$%^&*(),.?":{}|<>]/.test(pwd)) score += 1; if (score === 1) return { score: 33, label: 'Weak', color: '#ef4444' }; if (score === 2) return { score: 66, label: 'Medium', color: '#f59e0b' }; if (score === 3) return { score: 100, label: 'Strong', color: '#22c55e' }; return { score: 0, label: 'Empty', color: '#718096' }; }; const handleRegisterSubmit = async (e) => { e.preventDefault(); setRegError(''); if (regPassword !== regConfirmPassword) { setRegError("Passwords do not match!"); return; } const strength = getPasswordStrength(regPassword); if (strength.label === 'Weak' || regPassword.length < 6) { setRegError("Password must be at least 6 characters, contain a number, and a special character."); return; } try { const res = await fetch(`${API_URL}/api/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: regEmail, password: regPassword, name: regName, profilePhoto: regAvatar }) }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Registration failed"); localStorage.setItem('token', data.token); setToken(data.token); setRegEmail(''); setRegPassword(''); setRegConfirmPassword(''); setRegName(''); setAuthMode('login'); } catch (err) { setRegError(err.message); } }; const handleLogout = () => { localStorage.removeItem('token'); setToken(''); setUserStatus({ isPremium: false, name: '', queryCount: 0, totalStorageBytes: 0, uploadedDocuments: [] }); setActiveTelemetry(null); setDocuments([]); setSelectedProjectId(''); setChatThreads([]); setActiveChatId(''); setMessages([]); }; const fetchUserStatus = async () => { try { const res = await fetch(`${API_URL}/api/user-status`, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await res.json(); if (res.status === 401 || res.status === 403) handleLogout(); else setUserStatus(data); } catch (err) { console.error("Failed to connect to Gateway server."); } }; const fetchDocuments = async () => { try { const res = await fetch(`${API_URL}/api/documents`, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await res.json(); if (Array.isArray(data)) { setDocuments(data); if (data.length > 0 && !selectedProjectId) setSelectedProjectId(data[0].id); } else { setDocuments([]); } } catch (err) { console.error("Failed to fetch documents list."); setDocuments([]); } }; const fetchChatThreads = async (projId) => { try { const res = await fetch(`${API_URL}/api/projects/${projId}/chats`, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await res.json(); setChatThreads(data); if (data.length > 0) setActiveChatId(data[0].chatId); else handleCreateChatThread(projId, "General Discussion"); } catch (err) { console.error("Failed to load chat threads."); } }; const handleCreateChatThread = async (projId, threadTitle) => { try { const res = await fetch(`${API_URL}/api/projects/${projId}/chats`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ title: threadTitle }) }); const newThread = await res.json(); setChatThreads(prev => [...prev, newThread]); setActiveChatId(newThread.chatId); } catch (err) { console.error("Failed to create new chat thread."); } }; const handleDeleteChatThread = async (e, threadId) => { e.stopPropagation(); try { await fetch(`${API_URL}/api/projects/${selectedProjectId}/chats/${threadId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); setChatThreads(prev => prev.filter(t => t.chatId !== threadId)); if (activeChatId === threadId) setActiveChatId(''); } catch (err) { console.error("Failed to delete chat thread."); } }; const handleRenameChatThread = async (e, threadId, currentTitle) => { e.stopPropagation(); const titleInput = prompt("Rename conversation thread to:", currentTitle); if (titleInput === null) return; const newTitle = titleInput.trim() || currentTitle; if (newTitle === currentTitle) return; try { const res = await fetch(`${API_URL}/api/projects/${selectedProjectId}/chats/${threadId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ title: newTitle }) }); const data = await res.json(); if (res.ok) { setChatThreads(prev => prev.map(t => t.chatId === threadId ? { ...t, chatTitle: data.chatTitle } : t)); } } catch (err) { console.error("Failed to rename thread."); } }; const handleDeleteDocument = async (e, docId) => { e.stopPropagation(); if (!window.confirm("Are you sure you want to delete this document from the database? This will permanently wipe its text vectors and conversation history.")) return; try { const res = await fetch(`${API_URL}/api/documents/${docId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); const data = await res.json(); if (res.ok) { alert("🗑️ Document deleted successfully!"); if (viewingDocId === docId) { setSelectedDocContent(null); setViewingDocId(''); } if (selectedProjectId === docId) { setSelectedProjectId(''); } fetchDocuments(); fetchUserStatus(); } else { alert(`Error: ${data.error || "Failed to delete document"}`); } } catch (err) { alert("Failed to connect to Gateway server during deletion."); } }; const handleExportChat = () => { if (messages.length === 0) { alert("No messages to export!"); return; } let mdContent = `# Chat Export - ${documents.find(d => d.id === selectedProjectId)?.title || "Workspace"}\n`; mdContent += `Exported on: ${new Date().toLocaleString()}\n\n---\n\n`; messages.forEach(msg => { const senderName = msg.sender === 'user' ? 'User' : 'AI Assistant'; mdContent += `### 💬 ${senderName}\n${msg.text}\n\n`; if (msg.telemetry) { mdContent += `*Audit Trace: Execution Speed: ${msg.telemetry.execution_time_sec?.toFixed(2)}s | NLI Fact-check: ${msg.telemetry.success ? 'PASSED' : 'BLOCKED'}*\n\n`; } mdContent += `---\n\n`; }); const blob = new Blob([mdContent], { type: 'text/markdown;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.setAttribute("href", url); link.setAttribute("download", `chat_export_${selectedProjectId || 'session'}.md`); document.body.appendChild(link); link.click(); document.body.removeChild(link); }; const handleSendQuery = async (e) => { e.preventDefault(); if (!query.trim() || !activeChatId) return; const userMessage = { sender: 'user', text: query, timestamp: new Date().toISOString() }; setMessages(prev => [...prev, userMessage]); setQuery(''); setLoading(true); try { const response = await fetch(`${API_URL}/api/query`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ query: userMessage.text, projectId: queryAllDocs ? 'all' : selectedProjectId, chatId: activeChatId }) }); const data = await response.json(); if (response.status === 403 && data.is_blocked) { setMessages(prev => [...prev, { sender: 'ai', text: data.message, isBlocked: true, timestamp: new Date().toISOString() }]); } else if (data.error) { setMessages(prev => [...prev, { sender: 'ai', text: `Error: ${data.error}`, timestamp: new Date().toISOString() }]); } else { const aiResponse = { sender: 'ai', text: data.answer, telemetry: data.telemetry, timestamp: new Date().toISOString() }; setMessages(prev => [...prev, aiResponse]); setActiveTelemetry(data.telemetry); fetchUserStatus(); } } catch (err) { setMessages(prev => [...prev, { sender: 'ai', text: "Connection failed.", timestamp: new Date().toISOString() }]); } finally { setLoading(false); } }; const handleFileUpload = async (e) => { e.preventDefault(); if (!selectedFile || !uploadTitle.trim()) return; setUploadLoading(true); setUploadStatus({ type: '', text: '' }); const docId = `doc_${uploadTitle.toLowerCase().replace(/[^a-z0-9]/g, '_')}`; const formData = new FormData(); formData.append('file', selectedFile); formData.append('doc_id', docId); formData.append('title', uploadTitle); try { const res = await fetch(`${API_URL}/api/ingest-file`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}` }, body: formData }); const data = await res.json(); if (!res.ok) throw new Error(data.message || data.error || "Failed to upload."); setUploadStatus({ type: 'success', text: `Success: "${uploadTitle}" indexed.` }); setUploadTitle(''); setSelectedFile(null); const fileInput = document.getElementById('device-file-input'); if (fileInput) fileInput.value = ''; fetchDocuments(); fetchUserStatus(); } catch (err) { setUploadStatus({ type: 'error', text: err.message }); } finally { setUploadLoading(false); } }; const handleCopyPasteIngest = async (e) => { e.preventDefault(); if (!uploadTitle.trim() || !copyPasteText.trim()) return; setUploadLoading(true); setUploadStatus({ type: '', text: '' }); const docId = `doc_${uploadTitle.toLowerCase().replace(/[^a-z0-9]/g, '_')}`; try { const res = await fetch(`${API_URL}/api/ingest`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ doc_id: docId, title: uploadTitle, text: copyPasteText }) }); const data = await res.json(); if (!res.ok) throw new Error(data.message || data.error || "Failed to index text."); setUploadStatus({ type: 'success', text: `Success: "${uploadTitle}" indexed.` }); setUploadTitle(''); setCopyPasteText(''); fetchDocuments(); fetchUserStatus(); } catch (err) { setUploadStatus({ type: 'error', text: err.message }); } finally { setUploadLoading(false); } }; const handleViewDocContent = async (docId) => { try { const res = await fetch(`${API_URL}/api/documents/${docId}`, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await res.json(); if (data.text) { setSelectedDocContent(data.text); setViewingDocId(docId); } } catch (err) { alert("Failed to load document text."); } }; const handleUpgrade = async () => { try { const res = await fetch(`${API_URL}/api/create-razorpay-order`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } }); const order = await res.json(); if (res.status !== 200 || !order.id) { alert("Failed to create payment order: " + (order.error || "Gateway error")); return; } const options = { key: order.key_id, amount: order.amount, currency: order.currency, name: "VigilantRAG Premium", description: "Premium Plan Upgrade (Unlock Unlimited Document search, factuality guard)", order_id: order.id, handler: async function (response) { try { const verifyRes = await fetch(`${API_URL}/api/verify-razorpay-payment`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify({ razorpay_order_id: response.razorpay_order_id, razorpay_payment_id: response.razorpay_payment_id, razorpay_signature: response.razorpay_signature, isMock: order.isMock }) }); const verifyData = await verifyRes.json(); if (verifyRes.ok) { alert("🎉 Upgrade successful! Welcome to VigilantRAG Premium."); fetchUserStatus(); } else { alert(`Verification failed: ${verifyData.error}`); } } catch (err) { alert("Payment verification connection error."); } }, prefill: { name: userStatus.name || "Aryan", email: "user@example.com" }, theme: { color: "#8b5cf6" } }; if (order.isMock) { console.log("⚠️ Dev Mode: Initializing custom Razorpay overlay simulation."); setRzpOrderDetails(order); setRzpActiveOptions(options); setRzpPaymentStep('methods'); setShowRzpModal(true); return; } if (window.Razorpay) { const rzp = new window.Razorpay(options); rzp.open(); } else { alert("Razorpay payment SDK failed to load. Please check your internet connection."); } } catch (err) { alert("Failed to initiate payment gateway."); } }; const handleSaveProfile = async (e) => { e.preventDefault(); setProfileSaveLoading(true); setProfileSaveStatus({ type: '', text: '' }); try { const res = await fetch(`${API_URL}/api/user-profile`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ name: profileName, email: profileEmail, phoneNumber: profilePhone, profilePhoto: profilePhoto }) }); const data = await res.json(); if (res.ok) { setProfileSaveStatus({ type: 'success', text: '🎉 Profile changes saved successfully!' }); fetchUserStatus(); } else { setProfileSaveStatus({ type: 'error', text: data.error || 'Failed to update profile details.' }); } } catch (err) { setProfileSaveStatus({ type: 'error', text: 'Gateway server connection failure.' }); } finally { setProfileSaveLoading(false); } }; const handleCancelSubscription = async () => { const confirmCancel = window.confirm("Are you sure you want to cancel your Premium subscription? \n\nThis will downgrade your account to the Free Plan and lower your document limits."); if (!confirmCancel) return; try { const res = await fetch(`${API_URL}/api/cancel-subscription`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}` } }); if (res.ok) { alert("🛡️ Subscription cancelled successfully. Account downgraded to Free."); fetchUserStatus(); } else { alert("Subscription cancellation request failed."); } } catch (err) { alert("Billing server connection error."); } }; if (!token) { return (
    {authMode === 'login' ? (

    Welcome to VigilantRAG

    Access your self-correcting RAG workspace

    handleLogin(e)} className="login-form"> {loginError &&
    {loginError}
    }
    setEmail(e.target.value)} required />
    setPassword(e.target.value)} required />
    Don't have an account?
    Sandbox Logins
    ) : (

    Create Account

    Sign up to start searching and verifying your documents

    {regError &&
    {regError}
    }
    setRegName(e.target.value)} required />
    setRegEmail(e.target.value)} required />
    setRegPassword(e.target.value)} required />
    {/* Password Strength Meter */} {regPassword && (
    Strength: {getPasswordStrength(regPassword).label}
    )}
    setRegConfirmPassword(e.target.value)} required />
    {/* Onboarding Avatar Selector */}

    Select Profile Avatar

    {['👨‍💻', '🚀', '🤖', '🕵️‍♂️', '👩‍💻', '🧬', '🧠', '🌟'].map((emoji) => ( ))}
    Already have an account?
    )}
    ); } return (

    VigilantRAG v2.0

    {userStatus.isPremium ? setActiveTab('account')} style={{ cursor: 'pointer' }}> Premium : }
    {activeTab === 'workspace' && ( <>
    setDocSearchQuery(e.target.value)} className="sidebar-search-input" style={{ width: '100%', background: 'rgba(255, 255, 255, 0.03)', border: '1px solid var(--border-color)', borderRadius: '6px', color: 'white', padding: '6px 10px', fontSize: '0.8rem', outline: 'none', boxSizing: 'border-box' }} />

    Projects

    {documents.filter(doc => doc.title.toLowerCase().includes(docSearchQuery.toLowerCase())).map(doc => ( ))} {documents.length === 0 && (

    No projects found.

    )}
    {selectedProjectId && (

    Conversations

    {chatThreads.map(thread => ( ))}
    )}
    {userStatus.isPremium ? ( ) : Single Doc Mode} {messages.length > 0 && ( )}
    {messages.length === 0 ? (

    VigilantRAG Active Workspace

    Ask anything about your document project. The AI will search, analyze, and fact-check its answers automatically.

    ) : ( messages.map((msg, i) => (
    {msg.sender === 'ai' ? renderFormattedMessage(msg.text) :

    {msg.text}

    } {msg.sender === 'ai' && (
    {msg.telemetry && ( )}
    )}
    )) )} {loading && (
    )}
    setQuery(e.target.value)} placeholder={activeChatId ? "Type your query here..." : "Select a document project thread to chat..."} disabled={!activeChatId} className="chat-input" />
    )} {activeTab === 'library' && (

    Ingested Documents

    setDocSearchQuery(e.target.value)} className="sidebar-search-input" style={{ width: '100%', background: 'rgba(255, 255, 255, 0.03)', border: '1px solid var(--border-color)', borderRadius: '6px', color: 'white', padding: '6px 10px', fontSize: '0.8rem', outline: 'none', boxSizing: 'border-box' }} />
    {documents.filter(doc => doc.title.toLowerCase().includes(docSearchQuery.toLowerCase())).map(doc => (
    ))} {documents.length === 0 && (

    No documents found.

    )}
    {selectedDocContent ? (

    Document Text: {documents.find(d => d.id === viewingDocId)?.title}

    {selectedDocContent}
    ) : (

    Indexed Document Sandbox

    Index documents directly from your device, or copy-paste raw text contents. They will be partitioned into semantic chunks and embedded instantly.

    {uploadStatus.text && (
    {uploadStatus.text}
    )} {ingestMode === 'upload' ? (
    setUploadTitle(e.target.value)} required />
    { setSelectedFile(e.target.files[0]); if (e.target.files[0] && !uploadTitle) { const nameWithoutExt = e.target.files[0].name.replace(/\.[^/.]+$/, ""); setUploadTitle(nameWithoutExt.replace(/_/g, ' ')); } }} required /> {selectedFile ? ( Selected: {selectedFile.name} ({(selectedFile.size / 1024).toFixed(1)} KB) ) : ( Drag & drop your file here, or click to browse files )}
    ) : (
    setUploadTitle(e.target.value)} required />