e2dew32 commited on
Commit
d475d3b
·
verified ·
1 Parent(s): 6ed5ca3

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +131 -0
  2. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import streamlit as st
3
+ from huggingface_hub import HfApi
4
+ import tempfile
5
+ import shutil
6
+
7
+ st.set_page_config(page_title="☁️ HF Cloud Drive", page_icon="☁️", layout="wide")
8
+
9
+ REPO_ID = "e2dew32/cloud-drive"
10
+ REPO_TYPE = "dataset"
11
+
12
+ @st.cache_resource
13
+ def get_api():
14
+ return HfApi()
15
+
16
+ def format_size(size_bytes):
17
+ if size_bytes is None:
18
+ return "—"
19
+ if size_bytes < 1024:
20
+ return f"{size_bytes} B"
21
+ elif size_bytes < 1024 * 1024:
22
+ return f"{size_bytes / 1024:.1f} KB"
23
+ elif size_bytes < 1024 * 1024 * 1024:
24
+ return f"{size_bytes / 1024 / 1024:.1f} MB"
25
+ else:
26
+ return f"{size_bytes / 1024 / 1024 / 1024:.2f} GB"
27
+
28
+ # ---- Sidebar ----
29
+ with st.sidebar:
30
+ st.header("☁️ HF Cloud Drive")
31
+ st.markdown(f"**仓库:** `{REPO_ID}`")
32
+ st.markdown("---")
33
+ if st.button("🔄 刷新", use_container_width=True):
34
+ st.rerun()
35
+
36
+ # ---- Main ----
37
+ st.title("☁️ HF Cloud Drive")
38
+ st.caption(f"后端仓库: [{REPO_ID}](https://huggingface.co/datasets/{REPO_ID})")
39
+
40
+ api = get_api()
41
+
42
+ # ---- Upload ----
43
+ with st.expander("📤 上传文件", expanded=True):
44
+ uploaded_files = st.file_uploader("拖拽或选择文件上传", accept_multiple_files=True, label_visibility="collapsed")
45
+ if uploaded_files:
46
+ if st.button("🚀 开始上传", type="primary", use_container_width=True):
47
+ progress_bar = st.progress(0, text="上传中...")
48
+ success_count = 0
49
+ for i, uploaded in enumerate(uploaded_files):
50
+ with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(uploaded.name)[1]) as tmp:
51
+ tmp.write(uploaded.getvalue())
52
+ tmp_path = tmp.name
53
+ try:
54
+ api.upload_file(
55
+ path_or_fileobj=tmp_path,
56
+ path_in_repo=uploaded.name,
57
+ repo_id=REPO_ID,
58
+ repo_type=REPO_TYPE,
59
+ commit_message=f"Upload {uploaded.name} via Cloud Drive",
60
+ )
61
+ success_count += 1
62
+ except Exception as e:
63
+ st.error(f"❌ {uploaded.name}: {e}")
64
+ finally:
65
+ os.unlink(tmp_path)
66
+ progress_bar.progress((i + 1) / len(uploaded_files), text=f"已上传 {i+1}/{len(uploaded_files)}")
67
+ if success_count == len(uploaded_files):
68
+ st.success(f"✅ 全部上传成功 ({success_count}/{len(uploaded_files)})")
69
+ else:
70
+ st.warning(f"⚠️ 部分上传成功 ({success_count}/{len(uploaded_files)})")
71
+ st.rerun()
72
+
73
+ # ---- File Browser ----
74
+ st.subheader("📁 文件列表")
75
+
76
+ try:
77
+ tree = list(api.list_repo_tree(repo_id=REPO_ID, repo_type=REPO_TYPE, recursive=True))
78
+ except Exception as e:
79
+ st.error(f"无法获取文件列表: {e}")
80
+ st.info("请确保 Hugging Face Token 已配置,且在 Space Settings 中设置了 HF_TOKEN secret。")
81
+ tree = []
82
+
83
+ files = sorted([f for f in tree if f.type == "file"], key=lambda x: x.path)
84
+ dirs = sorted([f for f in tree if f.type == "directory"], key=lambda x: x.path)
85
+
86
+ total_size = sum(getattr(f, "size", 0) or 0 for f in files)
87
+ st.info(f"📊 {len(files)} 个文件 | {len(dirs)} 个目录 | 总大小: {format_size(total_size)}")
88
+
89
+ if not files:
90
+ st.info("仓库为空,上传一些文件开始使用吧!")
91
+ else:
92
+ # Directories
93
+ for d in dirs:
94
+ st.markdown(f"📁 **`{d.path}/`**")
95
+
96
+ # Files
97
+ for f in files:
98
+ cols = st.columns([5, 1, 2])
99
+ fname = f.path.split("/")[-1]
100
+ cols[0].markdown(f"📄 `{f.path}`")
101
+ cols[1].text(format_size(getattr(f, "size", None)))
102
+
103
+ # Download
104
+ try:
105
+ dl_path = api.hf_hub_download(repo_id=REPO_ID, filename=f.path, repo_type=REPO_TYPE)
106
+ with open(dl_path, "rb") as fh:
107
+ data = fh.read()
108
+ cols[2].download_button(
109
+ label="⬇️",
110
+ data=data,
111
+ file_name=fname,
112
+ key=f"dl_{f.path}",
113
+ )
114
+ except Exception:
115
+ cols[2].button("⬇️", disabled=True, key=f"dl_{f.path}")
116
+
117
+ # ---- Delete ----
118
+ st.markdown("---")
119
+ st.subheader("🗑️ 删除文件")
120
+ if files:
121
+ to_delete = st.multiselect("选择要删除的文件", [f.path for f in files])
122
+ if to_delete and st.button("确认删除", type="primary"):
123
+ for fp in to_delete:
124
+ try:
125
+ api.delete_file(path_in_repo=fp, repo_id=REPO_ID, repo_type=REPO_TYPE, commit_message=f"Delete {fp}")
126
+ st.success(f"✅ 已删除: {fp}")
127
+ except Exception as e:
128
+ st.error(f"❌ 删除 {fp} 失败: {e}")
129
+ st.rerun()
130
+ else:
131
+ st.info("没有文件可删除")
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ streamlit>=1.28.0
2
+ huggingface_hub>=0.19.0
3
+ requests>=2.31.0