/** * HuggingFace 大文件直传 API * * 流程: * 1. 前端计算 SHA256 和文件样本 * 2. 前端调用此 API 获取 LFS 上传 URL * 3. 前端直接上传到 HuggingFace S3 * 4. 前端调用 commitUpload API 提交文件引用 * * 这样可以绕过 CF Workers 的 100MB 请求体限制和 CPU 时间限制 */ import { HuggingFaceAPI } from '../../utils/huggingfaceAPI.js'; import { getUploadConfig } from '../../utils/sysConfig.js'; export async function onRequestPost(context) { const { request, env } = context; try { // 验证认证码 const authCode = request.headers.get('authcode'); if (env.AUTH_CODE && authCode !== env.AUTH_CODE) { return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401, headers: { 'Content-Type': 'application/json' } }); } const body = await request.json(); const { fileSize, fileName, sha256, fileSample, channelName } = body; if (!fileSize || !fileName || !sha256 || !fileSample) { return new Response(JSON.stringify({ error: 'Missing required fields: fileSize, fileName, sha256, fileSample' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } // 获取 HuggingFace 配置 const uploadConfig = await getUploadConfig(env); const hfSettings = uploadConfig.huggingface; if (!hfSettings || !hfSettings.channels || hfSettings.channels.length === 0) { return new Response(JSON.stringify({ error: 'No HuggingFace channel configured' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } // 选择渠道 let hfChannel; if (channelName) { hfChannel = hfSettings.channels.find(c => c.name === channelName); } if (!hfChannel) { hfChannel = hfSettings.loadBalance?.enabled ? hfSettings.channels[Math.floor(Math.random() * hfSettings.channels.length)] : hfSettings.channels[0]; } if (!hfChannel || !hfChannel.token || !hfChannel.repo) { return new Response(JSON.stringify({ error: 'HuggingFace channel not properly configured' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } // 构建文件路径 const now = new Date(); const yearMonth = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}`; // 生成唯一文件名 const ext = fileName.includes('.') ? fileName.substring(fileName.lastIndexOf('.')) : ''; const uniqueId = crypto.randomUUID().replace(/-/g, ''); const fullId = uniqueId + ext; const filePath = `images/${yearMonth}/${fullId}`; // 获取 LFS 上传信息 const huggingfaceAPI = new HuggingFaceAPI(hfChannel.token, hfChannel.repo, hfChannel.isPrivate || false); const uploadInfo = await huggingfaceAPI.getLfsUploadInfo(fileSize, filePath, sha256, fileSample); // 返回上传信息 return new Response(JSON.stringify({ success: true, fullId, filePath, channelName: hfChannel.name, repo: hfChannel.repo, isPrivate: hfChannel.isPrivate || false, ...uploadInfo }), { status: 200, headers: { 'Content-Type': 'application/json' } }); } catch (error) { console.error('getUploadUrl error:', error.message); return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } }