|
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<Response> => { |
|
const request = context.request; |
|
const env = context.env as Env; |
|
|
|
|
|
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'); |
|
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 |
|
}; |
|
|
|
|
|
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' } |
|
}); |
|
} |
|
} |
|
|
|
|
|
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' } |
|
}); |
|
} |
|
}; |
|
|