import os import tempfile from flask import Flask, request, jsonify, send_file from huggingface_hub import ( batch_bucket_files, download_bucket_files, list_bucket_tree ) app = Flask(__name__) HF_TOKEN = os.environ.get("HF_TOKEN") if not HF_TOKEN: raise ValueError("HF_TOKEN environment variable not set. Please add it to Space Secrets.") BUCKET_ID = "nagose/filebed" HTML_CONTENT = """
所有请求均需在 Hugging Face Space 内调用(同源),无需额外认证。
POST /upload
请求格式: multipart/form-data
参数:
file (必填) - 要上传的文件dir (可选) - 目标目录路径,例如 "images/" 或 "logs/2026/"。留空则上传到根目录。成功响应: {"success": true, "filename": "远程完整路径"}
失败响应: {"error": "错误信息"} (HTTP 4xx/5xx)
// 使用 FormData 上传
const fileInput = document.getElementById('fileInput'); // 文件选择 input
const file = fileInput.files[0];
const dir = "images/"; // 可选目录
const formData = new FormData();
formData.append('file', file);
formData.append('dir', dir);
fetch('/upload', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(data => {
if (data.error) throw new Error(data.error);
console.log('上传成功:', data.filename);
})
.catch(err => console.error('上传失败:', err.message));
GET /list?dir=...
查询参数:
dir (可选) - 目录路径,例如 "images/"。留空则列出根目录下的第一层内容。成功响应: 字符串数组,每个元素是文件或目录的完整路径(目录路径以 / 结尾)。例如:["file.txt", "images/", "logs/"]
失败响应: {"error": "错误信息"} (HTTP 5xx)
// 列出根目录内容
fetch('/list')
.then(res => res.json())
.then(files => {
files.forEach(path => {
if (path.endsWith('/')) {
console.log('目录:', path);
} else {
console.log('文件:', path);
}
});
});
// 列出指定目录(如 images/)内容
const dir = "images/";
fetch(`/list?dir=${encodeURIComponent(dir)}`)
.then(res => res.json())
.then(files => console.log(files));
GET /file/<filename>
路径参数:
filename - 文件的完整路径(可包含目录),例如 "images/avatar.png"。成功响应: 文件内容(作为附件下载)。
失败响应: {"error": "错误信息"} (HTTP 4xx/5xx)
// 触发浏览器下载
const filename = "images/avatar.png";
window.location.href = `/file/${encodeURIComponent(filename)}`;
// 或者用 fetch 获取文件 Blob
fetch(`/file/${encodeURIComponent(filename)}`)
.then(res => {
if (!res.ok) throw new Error('文件不存在');
return res.blob();
})
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename.split('/').pop(); // 提取文件名
a.click();
})
.catch(err => console.error('下载失败:', err.message));
HEAD /file/<filename>
路径参数: 同下载接口的 filename。
成功响应: HTTP 200,无响应体。
失败响应: HTTP 404 并返回 JSON 错误信息。
const filename = "config.json";
fetch(`/file/${encodeURIComponent(filename)}`, { method: 'HEAD' })
.then(res => {
if (res.ok) {
console.log('文件存在');
} else {
return res.json().then(err => { throw new Error(err.error); });
}
})
.catch(err => console.error('检查失败:', err.message));
DELETE /delete/<filename>
路径参数: 同下载接口的 filename。
成功响应: {"success": true}
失败响应: {"error": "错误信息"} (HTTP 4xx/5xx)
const filename = "temp.log";
fetch(`/delete/${encodeURIComponent(filename)}`, { method: 'DELETE' })
.then(res => res.json())
.then(data => {
if (data.success) {
console.log('删除成功');
} else {
throw new Error(data.error);
}
})
.catch(err => console.error('删除失败:', err.message));