Spaces:
Running
Running
File size: 5,801 Bytes
2ecc4a7 73905db dc7b682 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 f4970d3 2ecc4a7 bf7338b 2ecc4a7 f4970d3 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db 2ecc4a7 73905db | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | import React, { useState, useEffect, useRef } from 'react';
import { Boxes, User, Lock } from 'lucide-react';
import Navbar from './components/Navbar';
import IngestionPage from './pages/IngestionPage';
import SearchPlaygroundPage from './pages/SearchPlaygroundPage';
import AdvancedRagPage from './pages/AdvancedRagPage';
import VectorDbPage from './pages/VectorDbPage';
import FundamentalsPage from './pages/FundamentalsPage';
import RagasEvalPage from './pages/RagasEvalPage';
import { usePipelineStore } from './store/pipelineStore';
import { useAuthStore } from './store/authStore';
import api from './api/client';
function App() {
const { isAuthenticated, login, logout } = useAuthStore();
const [username, setUsername] = useState('admin');
const [password, setPassword] = useState('admin123');
const [activeTab, setActiveTab] = useState('search');
const { setDocuments, activeJob, addStep } = usePipelineStore();
const ws = useRef(null);
// Sync hash routing
useEffect(() => {
const hash = window.location.hash.replace('#', '');
if (['ingest', 'search', 'advanced', 'vectordb', 'fundamentals', 'eval'].includes(hash)) {
setActiveTab(hash);
}
}, []);
// Load documents
useEffect(() => {
if (isAuthenticated) {
api.get('/ingest/documents').then(res => {
setDocuments(res.data);
const { selectedDoc, setSelectedDoc } = usePipelineStore.getState();
if (res.data && res.data.length > 0) {
if (!selectedDoc || !res.data.some(d => d.id === selectedDoc.id)) {
setSelectedDoc(res.data[0]);
}
}
}).catch(console.error);
}
}, [isAuthenticated]);
// WebSocket Connection for Pipeline Trace
useEffect(() => {
if (activeJob && isAuthenticated) {
const token = sessionStorage.getItem('token');
const apiBase = import.meta.env.VITE_API_BASE_URL || window.location.origin;
const wsProtocol = apiBase.startsWith('https') ? 'wss' : 'ws';
const wsHost = apiBase.replace(/^https?:\/\//, '');
const wsUrl = `${wsProtocol}://${wsHost}/ws/pipeline/${activeJob}?token=${token}`;
ws.current = new WebSocket(wsUrl);
ws.current.onmessage = (event) => {
const step = JSON.parse(event.data);
addStep(step);
if (step.step === 'DONE') {
api.get('/ingest/documents').then(res => {
setDocuments(res.data);
if (res.data && res.data.length > 0) {
const newDoc = step.metadata?.doc_id
? res.data.find(d => d.id === step.metadata.doc_id) || res.data[0]
: res.data[0];
usePipelineStore.getState().setSelectedDoc(newDoc);
}
}).catch(console.error);
}
};
return () => {
if (ws.current) ws.current.close();
};
}
}, [activeJob, isAuthenticated]);
const handleAuth = async (e) => {
e.preventDefault();
await login(username, password);
};
if (!isAuthenticated) {
return (
<div className="min-h-screen bg-surface-900 flex items-center justify-center p-4">
<div className="w-full max-w-md card space-y-8 p-10 shadow-2xl">
<div className="text-center space-y-2">
<div className="inline-block p-4 bg-accent-500/10 rounded-full mb-4 ring-1 ring-accent-500/20">
<Boxes className="w-12 h-12 text-accent-500" />
</div>
<h1 className="text-3xl font-bold text-white tracking-tight">RAG PLATFORM</h1>
<p className="text-gray-400 font-mono text-xs">Enterprise A-to-Z RAG Ecosystem v3.0</p>
</div>
<form className="space-y-4" onSubmit={handleAuth}>
<div className="space-y-1">
<label className="text-xs uppercase font-bold text-gray-500">Username</label>
<div className="relative">
<User className="absolute left-3 top-3 w-4 h-4 text-gray-500" />
<input
type="text" value={username} onChange={e => setUsername(e.target.value)}
className="w-full input-field pl-10" placeholder="admin"
/>
</div>
</div>
<div className="space-y-1">
<label className="text-xs uppercase font-bold text-gray-500">Password</label>
<div className="relative">
<Lock className="absolute left-3 top-3 w-4 h-4 text-gray-500" />
<input
type="password" value={password} onChange={e => setPassword(e.target.value)}
className="w-full input-field pl-10" placeholder="••••••••"
/>
</div>
</div>
<button className="w-full btn-accent font-bold py-3 mt-4 hover:scale-[1.02] active:scale-[0.98]">
Login to Platform
</button>
</form>
<div className="text-center pt-4 border-t border-surface-700">
<p className="text-xs text-gray-500 font-mono tracking-widest">DEFAULT CREDENTIALS: admin / admin123</p>
</div>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-surface-950 text-gray-100 pb-20 selection:bg-accent-500/30 font-sans">
<Navbar activeTab={activeTab} setActiveTab={setActiveTab} onLogout={logout} />
<main className="transition-all duration-300">
{activeTab === 'ingest' && <IngestionPage />}
{activeTab === 'search' && <SearchPlaygroundPage />}
{activeTab === 'advanced' && <AdvancedRagPage />}
{activeTab === 'vectordb' && <VectorDbPage />}
{activeTab === 'fundamentals' && <FundamentalsPage />}
{activeTab === 'eval' && <RagasEvalPage />}
</main>
</div>
);
}
export default App;
|