Spaces:
Paused
Paused
| /** | |
| * Hugging Face Hub Storage Integration | |
| * | |
| * NOTE: This still goes through Vercel serverless functions, | |
| * so it won't bypass Vercel's 4.5MB/50MB request size limits. | |
| * For true 2GB uploads, you need direct client uploads (S3, R2, etc.) | |
| */ | |
| export interface HuggingFaceFileResult { | |
| file_id: string; | |
| file_url: string; | |
| repo_path: string; | |
| } | |
| const HF_API_BASE = 'https://huggingface.co/api'; | |
| /** | |
| * Upload a file to Hugging Face Hub using the commit endpoint | |
| */ | |
| export async function uploadToHuggingFace( | |
| file: Blob, | |
| fileName: string, | |
| fileId: string | |
| ): Promise<HuggingFaceFileResult> { | |
| const token = process.env.HF_TOKEN; | |
| const repoId = process.env.HF_REPO_ID; | |
| const repoType = process.env.HF_REPO_TYPE || 'dataset'; | |
| if (!token || !repoId) { | |
| throw new Error('Hugging Face credentials not configured. Set HF_TOKEN and HF_REPO_ID'); | |
| } | |
| // Convert Blob to base64 for the commit API | |
| const arrayBuffer = await file.arrayBuffer(); | |
| const buffer = Buffer.from(arrayBuffer); | |
| const base64Content = buffer.toString('base64'); | |
| // Determine file extension | |
| const ext = fileName.split('.').pop() || 'bin'; | |
| const pathInRepo = `files/${fileId}.${ext}`; | |
| // Use the commit endpoint (new API) | |
| // Format: POST /api/{repo_type}s/{repo_id}/commit/{revision} | |
| const repoTypePlural = repoType === 'dataset' ? 'datasets' : 'models'; | |
| const commitUrl = `${HF_API_BASE}/${repoTypePlural}/${repoId}/commit/main`; | |
| // The commit API expects operations in a specific format | |
| const commitData = { | |
| operations: [ | |
| { | |
| operation: 'add', | |
| path: pathInRepo, | |
| content: base64Content, | |
| } | |
| ], | |
| commit_message: `Upload ${fileName}`, | |
| }; | |
| const response = await fetch(commitUrl, { | |
| method: 'POST', | |
| headers: { | |
| 'Authorization': `Bearer ${token}`, | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(commitData), | |
| }); | |
| if (!response.ok) { | |
| const errorText = await response.text(); | |
| throw new Error(`Hugging Face API error: ${response.status} - ${errorText}`); | |
| } | |
| // Get the public URL | |
| const fileUrl = `https://huggingface.co/${repoType === 'dataset' ? 'datasets' : repoType}/${repoId}/resolve/main/${pathInRepo}`; | |
| // Alternative CDN URL (may be faster) | |
| const cdnUrl = `https://cdn.huggingface.co/${repoId}/main/${pathInRepo}`; | |
| return { | |
| file_id: fileId, | |
| file_url: cdnUrl, // Use CDN URL for faster access | |
| repo_path: pathInRepo, | |
| }; | |
| } | |
| /** | |
| * Get file URL from Hugging Face Hub | |
| */ | |
| export async function getHuggingFaceUrl( | |
| fileId: string, | |
| extension: string = 'jpg' | |
| ): Promise<string> { | |
| const repoId = process.env.HF_REPO_ID; | |
| const repoType = process.env.HF_REPO_TYPE || 'dataset'; | |
| const pathInRepo = `files/${fileId}.${extension}`; | |
| // Try CDN first (faster) | |
| return `https://cdn.huggingface.co/${repoId}/main/${pathInRepo}`; | |
| } | |
| /** | |
| * Check if Hugging Face is configured | |
| */ | |
| export function isHuggingFaceConfigured(): boolean { | |
| return !!(process.env.HF_TOKEN && process.env.HF_REPO_ID); | |
| } | |