/** * Hugging Face XetHub Storage Helpers * * These utilities upload files to your HF Space's persistent storage * (assets/ for GLB models, outputs/ for rendered videos). * * Requires the HF_TOKEN environment variable to be set as a Space Secret. * * Usage in your component: * import { uploadAsset, uploadOutput } from '../utils/hfStorage'; * await uploadAsset(file, 'my-space/studio3d'); */ const HF_API = 'https://huggingface.co/api'; /** * Upload a GLB model to the Space's assets/ folder via HF API */ export async function uploadAsset( file: File, repoId: string, hfToken: string ): Promise { const filename = `assets/${Date.now()}_${file.name}`; return uploadToHF(file, repoId, filename, hfToken); } /** * Upload a rendered video/image to the Space's outputs/ folder */ export async function uploadOutput( blob: Blob, filename: string, repoId: string, hfToken: string ): Promise { const file = new File([blob], filename, { type: blob.type }); const path = `outputs/${Date.now()}_${filename}`; return uploadToHF(file, repoId, path, hfToken); } async function uploadToHF( file: File, repoId: string, path: string, hfToken: string ): Promise { const arrayBuffer = await file.arrayBuffer(); const response = await fetch( `${HF_API}/spaces/${repoId}/upload/${encodeURIComponent(path)}`, { method: 'POST', headers: { Authorization: `Bearer ${hfToken}`, 'Content-Type': file.type || 'application/octet-stream', }, body: arrayBuffer, } ); if (!response.ok) { throw new Error(`HF upload failed: ${response.statusText}`); } const data = await response.json(); // Return the public URL to the uploaded file return `https://huggingface.co/spaces/${repoId}/resolve/main/${path}`; } /** * List files in assets/ folder of the Space */ export async function listAssets(repoId: string, hfToken: string): Promise { const response = await fetch( `${HF_API}/spaces/${repoId}/tree/main/assets`, { headers: { Authorization: `Bearer ${hfToken}` }, } ); if (!response.ok) return []; const data = await response.json(); return data.map((f: any) => f.path); } /** * List files in outputs/ folder of the Space */ export async function listOutputs(repoId: string, hfToken: string): Promise { const response = await fetch( `${HF_API}/spaces/${repoId}/tree/main/outputs`, { headers: { Authorization: `Bearer ${hfToken}` }, } ); if (!response.ok) return []; const data = await response.json(); return data.map((f: any) => f.path); }