afulara/PythonicRAG-FastAPI-React
0
1import React, { useState } from 'react';2import './App.css';3 4interface DocumentResponse {5 text: string;6 type: string;7 score?: number;8}9 10function App() {11 const [file, setFile] = useState<File | null>(null);12 const [query, setQuery] = useState('');13 const [results, setResults] = useState<DocumentResponse[]>([]);14 const [loading, setLoading] = useState(false);15 const [message, setMessage] = useState('');16 const [sessionId, setSessionId] = useState<string | null>(null);17 const [currentAnswer, setCurrentAnswer] = useState<string>('');18 19 const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {20 if (e.target.files && e.target.files[0]) {21 setFile(e.target.files[0]);22 }23 };24 25 const handleUpload = async () => {26 if (!file) {27 setMessage('Please select a file first');28 return;29 }30 31 setLoading(true);32 const formData = new FormData();33 formData.append('file', file);34 35 try {36 const response = await fetch('http://localhost:9000/upload', {37 method: 'POST',38 body: formData,39 });40 41 if (!response.ok) {42 throw new Error('Upload failed');43 }44 45 const data = await response.json();46 setMessage(data.message);47 setSessionId(data.session_id);48 setResults([]);49 setCurrentAnswer('');50 } catch (error) {51 setMessage('Error uploading file');52 } finally {53 setLoading(false);54 }55 };56 57 const handleQuery = async () => {58 if (!query.trim()) {59 setMessage('Please enter a query');60 return;61 }62 63 if (!sessionId) {64 setMessage('Please upload a document first');65 return;66 }67 68 setLoading(true);69 setCurrentAnswer('');70 try {71 const response = await fetch(`http://localhost:9000/query/${sessionId}`, {72 method: 'POST',73 headers: {74 'Content-Type': 'application/json',75 },76 body: JSON.stringify({ text: query, k: 4 }),77 });78 79 if (!response.ok) {80 throw new Error('Query failed');81 }82 83 // Handle streaming response84 const reader = response.body?.getReader();85 const decoder = new TextDecoder();86 let buffer = '';87 88 if (!reader) {89 throw new Error('No reader available');90 }91 92 while (true) {93 const { done, value } = await reader.read();94 if (done) break;95 96 buffer += decoder.decode(value, { stream: true });97 const lines = buffer.split('\n');98 buffer = lines.pop() || '';99 100 for (const line of lines) {101 if (line.startsWith('data: ')) {102 const data = JSON.parse(line.slice(6));103 if (data.type === 'token') {104 setCurrentAnswer(prev => prev + data.text);105 } else if (data.type === 'context') {106 setResults(data.context);107 }108 }109 }110 }111 } catch (error) {112 setMessage('Error querying documents');113 } finally {114 setLoading(false);115 }116 };117 118 return (119 <div className="App">120 <header className="App-header">121 <h1>RAG System</h1>122 </header>123 124 <main className="App-main">125 <section className="upload-section">126 <h2>Upload PDF Document</h2>127 <input type="file" accept=".pdf" onChange={handleFileChange} />128 <button onClick={handleUpload} disabled={loading || !file}>129 {loading ? 'Uploading...' : 'Upload'}130 </button>131 </section>132 133 <section className="query-section">134 <h2>Query Documents</h2>135 <input136 type="text"137 value={query}138 onChange={(e) => setQuery(e.target.value)}139 placeholder="Enter your query..."140 disabled={!sessionId}141 />142 <button onClick={handleQuery} disabled={loading || !query.trim() || !sessionId}>143 {loading ? 'Searching...' : 'Search'}144 </button>145 </section>146 147 {message && <div className="message">{message}</div>}148 149 <section className="results-section">150 <h2>Results</h2>151 {currentAnswer && (152 <div className="llm-response">153 <h3>AI Response</h3>154 <p className="result-text">{currentAnswer}</p>155 </div>156 )}157 158 {results.length > 0 && (159 <div className="relevant-chunks">160 <h3>Relevant Document Chunks</h3>161 {results.map((result, index) => (162 <div key={index} className="result-item">163 <p className="result-text">{result.text}</p>164 {result.score !== undefined && (165 <p className="result-score">Relevance Score: {result.score.toFixed(2)}</p>166 )}167 </div>168 ))}169 </div>170 )}171 </section>172 </main>173 </div>174 );175}176 177export default App;178 