Spaces:
Sleeping
Sleeping
| /** | |
| * 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<string> { | |
| 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<string> { | |
| 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<string> { | |
| 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<string[]> { | |
| 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<string[]> { | |
| 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); | |
| } | |