git-proxy / functions /api /hf /[[path]].ts
github-actions[bot]
Update from GitHub Actions
01ab30b
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;
// 从 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' }
});
}
};