Spaces:
Running
Running
feat: implement backend configuration, dynamic frontend API routing, and core React application structure with modular components
320a9c2 | // Helper to check if the current hostname is a local loopback or private network address | |
| const isLocalHost = () => { | |
| const hostname = window.location.hostname; | |
| return ( | |
| hostname === 'localhost' || | |
| hostname === '127.0.0.1' || | |
| hostname === '[::1]' || | |
| // Private IPv4 ranges (RFC 1918) | |
| /^192\.168\./.test(hostname) || | |
| /^10\./.test(hostname) || | |
| /^172\.(1[6-9]|2\d|3[01])\./.test(hostname) || | |
| // mDNS local hostnames | |
| /\.local$/.test(hostname) | |
| ); | |
| }; | |
| // Dynamic backend URL to support local development and production Hugging Face Space | |
| const BASE_URL = isLocalHost() | |
| ? `http://${window.location.hostname}:8001` | |
| : 'https://jenishmakwana-rag.hf.space'; | |
| // Helper to parse error details and attach status code | |
| async function handleResponseError(response, defaultMsg) { | |
| let errorMsg = defaultMsg; | |
| try { | |
| const errorData = await response.json(); | |
| errorMsg = errorData.detail || errorMsg; | |
| } catch (e) { | |
| // Ignore JSON parsing errors for non-JSON responses | |
| } | |
| const err = new Error(errorMsg); | |
| err.status = response.status; | |
| throw err; | |
| } | |
| export async function login(email, password) { | |
| const formData = new URLSearchParams(); | |
| formData.append('username', email); // OAuth2 expects 'username' field | |
| formData.append('password', password); | |
| const response = await fetch(`${BASE_URL}/token`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/x-www-form-urlencoded', | |
| }, | |
| body: formData, | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Login failed'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function register(username, email, password) { | |
| const response = await fetch(`${BASE_URL}/register`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ username, email, password }), | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Registration failed'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function fetchDocuments(token) { | |
| const response = await fetch(`${BASE_URL}/documents/`, { | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Failed to fetch documents'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function uploadDocument(token, file, sessionId = null) { | |
| const formData = new FormData(); | |
| formData.append('file', file); | |
| if (sessionId) { | |
| formData.append('session_id', sessionId); | |
| } | |
| const response = await fetch(`${BASE_URL}/documents/upload`, { | |
| method: 'POST', | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| body: formData, | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Upload failed'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function deleteDocument(token, filename) { | |
| const response = await fetch(`${BASE_URL}/documents/${encodeURIComponent(filename)}`, { | |
| method: 'DELETE', | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Delete failed'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function chatQuery(token, query, sessionId, filename = null, filenames = null) { | |
| const response = await fetch(`${BASE_URL}/chat/`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| body: JSON.stringify({ | |
| query, | |
| session_id: sessionId, | |
| filename, | |
| filenames | |
| }), | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Chat query failed'); | |
| } | |
| // Return the raw response so the UI can read the stream | |
| return response; | |
| } | |
| export async function fetchChatSessions(token) { | |
| const response = await fetch(`${BASE_URL}/chat/sessions`, { | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Failed to fetch chat sessions'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function fetchChatHistory(token, sessionId) { | |
| const response = await fetch(`${BASE_URL}/chat/history/${sessionId}`, { | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Failed to fetch chat history'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function fetchSessionDocuments(token, sessionId) { | |
| const response = await fetch(`${BASE_URL}/documents/session/${sessionId}`, { | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Failed to fetch session documents'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function deleteChatSession(token, sessionId) { | |
| const response = await fetch(`${BASE_URL}/chat/session/${sessionId}`, { | |
| method: 'DELETE', | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Failed to delete chat session'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function transcribeVoice(token, audioBlob) { | |
| const formData = new FormData(); | |
| // Name the file 'recording.webm' so backend knows how to save it | |
| formData.append('file', audioBlob, 'recording.webm'); | |
| const response = await fetch(`${BASE_URL}/voice/transcribe`, { | |
| method: 'POST', | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| body: formData, | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'Failed to transcribe audio'); | |
| } | |
| return await response.json(); | |
| } | |
| export async function getTtsAudio(token, text, signal) { | |
| const response = await fetch(`${BASE_URL}/chat/speak`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| body: JSON.stringify({ text }), | |
| signal | |
| }); | |
| if (!response.ok) { | |
| await handleResponseError(response, 'TTS request failed'); | |
| } | |
| return response; | |
| } | |