import type { Dataset, DatasetMetadata, DataItem, Modality } from '../types'; /** * A helper function to handle API errors. */ const handleApiError = async (response: Response) => { if (!response.ok) { let errorMessage = `API error! status: ${response.status}`; try { // First, get the response text, as it might not be JSON. const text = await response.text(); try { // Try to parse it as JSON const errorData = JSON.parse(text); errorMessage = errorData.detail || JSON.stringify(errorData); } catch (e) { // If parsing fails, use the raw text. errorMessage = text || errorMessage; } } catch (e) { // Fallback if reading the body fails for some reason. // This is unlikely to be hit with the logic above. } throw new Error(errorMessage); } // Only call .json() on success to avoid "body already read" errors. return response.json(); }; /** * Returns the metadata for all available shared datasets by querying the backend. */ export const getSharedDatasetMetadata = async (): Promise => { try { const response = await fetch('/api/shared-dataset-metadata'); const metadataList = await handleApiError(response); // The backend returns strings for dates, convert them to Date objects. return metadataList.map((meta: any) => ({ ...meta, uploadDate: new Date(meta.uploadDate), })); } catch (error) { console.error("Failed to fetch shared dataset metadata:", error); // Re-throw the error so the UI layer can handle it. throw error; } }; /** * Returns the full data structure for a specific shared dataset from the backend. * The content for each item remains null, only the URLs are provided. */ export const getSharedDataset = async (id: string): Promise => { try { // NOTE: The backend API endpoint for fetching the full dataset is assumed to exist. // It should return the full Dataset object structure based on the scanned files. const response = await fetch(`/api/shared-dataset?id=${id}`); const dataset = await handleApiError(response); // Convert date string from API to Date object dataset.uploadDate = new Date(dataset.uploadDate); return dataset; } catch (error) { console.error(`Failed to fetch shared dataset with id ${id}:`, error); // Re-throw the error so the UI layer can handle it. throw error; } }; /** * Fetches the actual content of a single lazy-loaded item from the server's static files. * This function is used for text and mesh files. Images are loaded directly by the browser tag. */ export const getItemContent = async (url: string): Promise => { const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch content from ${url}: ${response.statusText}`); } // Determine content type based on file extension if (url.endsWith('.txt')) { return response.text(); } else if (url.endsWith('.stl')) { return response.arrayBuffer(); } else { // This case is for completeness; images are usually handled by `` src attribute. const blob = await response.blob(); return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result as string); reader.onerror = reject; reader.readAsDataURL(blob); }); } };