core-edge / src /lib /huggingface.ts
dragxd's picture
Fix: Update Hugging Face API to use commit endpoint instead of deprecated upload endpoint
f4c0fa3
/**
* 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);
}