import { downloadFile, commit, listFiles, RepoType, CommitOperation } from "@huggingface/hub"; interface CommitBody { path: string; content?: string; message?: string; lfs?: boolean; } export const onRequest = async (context: RouteContext): Promise => { const request = context.request; const env = context.env as Env; // 从 Authorization header 中获取 token const authHeader = request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response(JSON.stringify({ error: '未提供有效的授权令牌' }), { status: 401, headers: { 'Content-Type': 'application/json' } }); } const hfToken = authHeader.replace('Bearer ', ''); console.log('Request URL:', request.url); try { const url = new URL(request.url); const pathParts = url.pathname.split('/').filter(Boolean); // 提取路径参数 const owner = pathParts[2] || url.searchParams.get('owner'); // 仓库所有者 const repo = pathParts[3] || url.searchParams.get('repo'); // 仓库名称 const operation = pathParts[4] || url.searchParams.get('op'); // 操作类型: raw, upload, tree, delete const ref = pathParts[5] || url.searchParams.get('ref') || 'main'; if (!owner || !repo) { return new Response(JSON.stringify({ error: '缺少仓库所有者或仓库名称' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } const apiParams = { repo: { name: `${owner}/${repo}`, type: 'dataset' as RepoType }, accessToken: hfToken, revision: ref }; // 处理 GET 请求 - 获取文件内容或列出文件 if (operation === 'raw' && request.method === 'GET') { const path = pathParts.length > 6 ? pathParts.slice(6).join('/') : ''; try { const response = await downloadFile({ ...apiParams, path: path }); if (!response) { return new Response(JSON.stringify({ error: '文件不存在' }), { status: 404, headers: { 'Content-Type': 'application/json' } }); } return response; } catch (error: any) { return new Response(JSON.stringify({ error: '获取文件失败', details: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } } if (operation === 'tree' && request.method === 'GET') { const path = pathParts.length > 6 ? pathParts.slice(6).join('/') : ''; try { const cursor = listFiles({ ...apiParams, path: path }); const files = []; for await (const entry of cursor) { files.push(entry); } return new Response(JSON.stringify(files), { headers: { 'Content-Type': 'application/json' } }); } catch (error: any) { return new Response(JSON.stringify({ error: '列出文件失败', details: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } } // 处理 POST 请求 - 上传文件 if (operation === 'commit' && (request.method === 'POST' || request.method === 'PUT' || request.method === 'DELETE')) { const body = await request.json() as CommitBody; try { let operation: CommitOperation; if (request.method === 'DELETE') { operation = { operation: 'delete', path: body.path }; } else { const content = body.content || ''; let blobContent: Blob; if (body.lfs === true && body.content) { const binary = atob(body.content); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } blobContent = new Blob([bytes]); } else { blobContent = new Blob([content]); } operation = { operation: 'addOrUpdate', path: body.path, content: blobContent }; } const response = await commit({ ...apiParams, operations: [operation], title: `${request.method === 'DELETE' ? 'Delete' : 'Update'} ${body.path}`, description: body.message || `Changed via API` }); return new Response(JSON.stringify(response), { status: 200, headers: { 'Content-Type': 'application/json' } }); } catch (error: any) { return new Response(JSON.stringify({ error: '提交更改失败', details: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } } // 不支持的请求方法或路径 return new Response(JSON.stringify({ error: '不支持的请求方法或路径' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } catch (error: any) { console.error('Error:', error); return new Response(JSON.stringify({ error: '服务器内部错误', details: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } };