Translsis commited on
Commit
65475b1
·
verified ·
1 Parent(s): 0e77c26

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +257 -0
app.py ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import asyncio
3
+ import shutil
4
+ import os
5
+ import tempfile
6
+ from pathlib import Path
7
+ from huggingface_hub import HfApi, login, create_repo, upload_file
8
+ import git
9
+
10
+ # ========================== GLOBAL ==========================
11
+ api = HfApi()
12
+ temp_dir = Path(tempfile.mkdtemp())
13
+ token = None
14
+ current_user = None
15
+ last_download_path = None
16
+
17
+ # ====================== ĐĂNG NHẬP / ĐĂNG XUẤT ======================
18
+ def login_hf(t):
19
+ global token, current_user
20
+ t = t.strip()
21
+ if not t:
22
+ return "Token không được để trống!", gr.update(value="Chưa đăng nhập")
23
+
24
+ try:
25
+ login(t)
26
+ info = api.whoami(token=t)
27
+ token = t
28
+ current_user = info["name"]
29
+
30
+ status = f"Đã đăng nhập: **{current_user}**"
31
+ return "Đăng nhập thành công! Sẵn sàng sử dụng tất cả chức năng", gr.update(value=status)
32
+ except Exception as e:
33
+ current_user = None
34
+ token = None
35
+ return f"Login thất bại: {str(e)}", gr.update(value="Login thất bại")
36
+
37
+ def logout_hf():
38
+ global token, current_user
39
+ from huggingface_hub import logout
40
+ logout()
41
+ token = None
42
+ current_user = None
43
+ return "Đã đăng xuất thành công!", gr.update(value="Chưa đăng nhập")
44
+
45
+ # ====================== CÁC HÀM CHÍNH ======================
46
+ async def download(url, type_, progress=gr.Progress()):
47
+ global last_download_path
48
+ if not url.strip():
49
+ return "Vui lòng nhập URL!", None
50
+
51
+ out = temp_dir / "downloaded"
52
+ if out.exists():
53
+ shutil.rmtree(out)
54
+ out.mkdir(parents=True, exist_ok=True)
55
+
56
+ try:
57
+ progress(0, desc="Chuẩn bị...")
58
+ if type_ == "git":
59
+ progress(0.2, desc="Đang clone bằng git...")
60
+ await asyncio.to_thread(git.Repo.clone_from, url.strip(), out, depth=1)
61
+ else:
62
+ progress(0.2, desc="Đang tải bằng wget...")
63
+ proc = await asyncio.create_subprocess_exec(
64
+ "wget", "-r", "-np", "-nH", "--cut-dirs=10", "-P", str(out), url.strip(),
65
+ stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
66
+ )
67
+ await proc.communicate()
68
+
69
+ count = len(list(out.rglob("*")))
70
+ last_download_path = str(out)
71
+ return f"Tải thành công! Tìm thấy {count} file/thư mục", last_download_path
72
+ except Exception as e:
73
+ shutil.rmtree(out, ignore_errors=True)
74
+ return f"Lỗi tải xuống: {e}", None
75
+
76
+ async def create_repo(name, rtype, private):
77
+ if not token:
78
+ return "Chưa đăng nhập Hugging Face!"
79
+ name = name.strip()
80
+ if "/" not in name:
81
+ return "Tên repo phải có định dạng username/repo-name!"
82
+
83
+ try:
84
+ create_repo(repo_id=name, repo_type=rtype, private=private, token=token, exist_ok=True)
85
+ return f"Tạo repo thành công!\nhttps://huggingface.co/{name}"
86
+ except Exception as e:
87
+ return f"Lỗi tạo repo: {e}"
88
+
89
+ async def upload(folder, repo, rtype, zip_it, password, use_dl, dl_path, progress=gr.Progress()):
90
+ if not token:
91
+ return "Chưa đăng nhập!"
92
+
93
+ repo = repo.strip()
94
+ path = Path(dl_path if use_dl and dl_path else folder)
95
+ if not path or not path.exists():
96
+ return "Thư mục không tồn tại hoặc chưa tải!"
97
+
98
+ try:
99
+ if zip_it:
100
+ progress(0, desc="Đang nén thành ZIP...")
101
+ zip_name = f"{repo.split('/')[-1]}_archive.zip"
102
+ zip_path = temp_dir / zip_name
103
+ cmd = ["zip", "-r"] + (["-P", password] if password else []) + [str(zip_path), "."]
104
+ proc = await asyncio.create_subprocess_exec(*cmd, cwd=str(path))
105
+ await proc.wait()
106
+
107
+ progress(0.7, desc="Đang upload file ZIP...")
108
+ await asyncio.to_thread(upload_file,
109
+ path_or_fileobj=str(zip_path),
110
+ path_in_repo=zip_name,
111
+ repo_id=repo,
112
+ repo_type=rtype,
113
+ token=token)
114
+ return f"Upload ZIP thành công!\nhttps://huggingface.co/{repo}/blob/main/{zip_name}"
115
+
116
+ else:
117
+ files = [f for f in path.rglob("*") if f.is_file()]
118
+ if not files:
119
+ return "Không có file nào để upload!"
120
+
121
+ for i, f in enumerate(files):
122
+ rel = f.relative_to(path)
123
+ progress((i + 1) / len(files), desc=f"Upload {i+1}/{len(files)}: {rel}")
124
+ await asyncio.to_thread(upload_file,
125
+ path_or_fileobj=str(f),
126
+ path_in_repo=str(rel),
127
+ repo_id=repo,
128
+ repo_type=rtype,
129
+ token=token)
130
+
131
+ return f"Upload thành công {len(files)} file!\nhttps://huggingface.co/{repo}"
132
+ except Exception as e:
133
+ return f"Lỗi upload: {e}"
134
+
135
+ async def delete_files(local, repo, rtype, dry, progress=gr.Progress()):
136
+ if not token:
137
+ return "Chưa đăng nhập!"
138
+
139
+ try:
140
+ local_path = Path(local)
141
+ if not local_path.exists():
142
+ return "Thư mục local không tồn tại!"
143
+
144
+ repo_files = await asyncio.to_thread(api.list_repo_files, repo_id=repo, repo_type=rtype, token=token)
145
+ to_del = [str(p.relative_to(local_path)) for p in local_path.rglob("*") if p.is_file() and str(p.relative_to(local_path)) in repo_files]
146
+
147
+ if not to_del:
148
+ return "Không tìm thấy file nào trùng để xóa trên repo."
149
+
150
+ if dry:
151
+ preview = "\n".join(f"- {f}" for f in to_del[:20])
152
+ more = f"\n... và {len(to_del)-20} file khác" if len(to_del) > 20 else ""
153
+ return f"**Dry-run**: Sẽ xóa {len(to_del)} file:\n{preview}{more}"
154
+
155
+ for i, f in enumerate(to_del):
156
+ progress((i + 1) / len(to_del), desc=f"Đang xóa {i+1}/{len(to_del)}")
157
+ await asyncio.to_thread(api.delete_file, path_in_repo=f, repo_id=repo, repo_type=rtype, token=token)
158
+
159
+ return f"Đã xóa thành công {len(to_del)} file trên repo!"
160
+ except Exception as e:
161
+ return f"Lỗi khi xóa: {e}"
162
+
163
+ # ========================== GIAO DIỆN GRADIO ==========================
164
+ with gr.Blocks(title="HF Manager Pro") as app:
165
+ gr.Markdown("# HF Manager Pro\nTải • Tạo Repo • Upload • Xóa file trên HF - Siêu tiện & nhanh!")
166
+
167
+ # ===== TRẠNG THÁI ĐĂNG NHẬP Ở ĐẦU =====
168
+ with gr.Row():
169
+ status_login = gr.Markdown("**Chưa đăng nhập**", elem_classes="status")
170
+ logout_btn = gr.Button("Đăng xuất", variant="stop", visible=False, size="sm")
171
+
172
+ with gr.Tabs():
173
+ # ==================== TAB LOGIN ====================
174
+ with gr.Tab("Đăng nhập HF"):
175
+ gr.Markdown("Dán token từ: https://huggingface.co/settings/tokens")
176
+ tk = gr.Textbox(label="Hugging Face Token", type="password", placeholder="hf_xxxxxxxxxxxxxxxxxxxxxx")
177
+ login_btn = gr.Button("Đăng nhập", variant="primary")
178
+ login_out = gr.Textbox(label="Kết quả")
179
+
180
+ login_btn.click(
181
+ login_hf,
182
+ inputs=tk,
183
+ outputs=[login_out, status_login]
184
+ ).then(
185
+ lambda: gr.update(visible=True),
186
+ outputs=logout_btn
187
+ )
188
+
189
+ logout_btn.click(
190
+ logout_hf,
191
+ outputs=[login_out, status_login]
192
+ ).then(
193
+ lambda: gr.update(visible=False),
194
+ outputs=logout_btn
195
+ )
196
+
197
+ # ==================== TAB TẢI XUỐNG ====================
198
+ with gr.Tab("Tải xuống"):
199
+ url = gr.Textbox(label="URL (GitHub, Google Drive public, git repo...)", placeholder="https://...")
200
+ typ = gr.Radio(["wget", "git"], label="Phương thức tải", value="wget")
201
+ dl_btn = gr.Button("Bắt đầu tải", variant="primary")
202
+ dl_out = gr.Textbox(label="Trạng thái tải")
203
+ dl_path = gr.Textbox(visible=False)
204
+
205
+ dl_btn.click(download, [url, typ], [dl_out, dl_path])
206
+
207
+ # ==================== TAB TẠO REPO ====================
208
+ with gr.Tab("Tạo Repo mới"):
209
+ name = gr.Textbox(label="Tên repo", placeholder="your-username/my-awesome-model")
210
+ rt = gr.Dropdown(["model", "dataset", "space"], value="model", label="Loại repo")
211
+ priv = gr.Checkbox(label="Repo riêng tư (Private)", value=True)
212
+ create_out = gr.Textbox(label="Kết quả", lines=3)
213
+ gr.Button("Tạo repo ngay", variant="primary").click(
214
+ create_repo, [name, rt, priv], create_out
215
+ )
216
+
217
+ # ==================== TAB UPLOAD ====================
218
+ with gr.Tab("Upload lên HF"):
219
+ folder = gr.Textbox(label="Thư mục local (bỏ qua nếu dùng tải sẵn)", placeholder="/path/to/your/folder")
220
+ use_dl = gr.Checkbox(label="Dùng thư mục vừa tải xuống (khuyên dùng)", value=True)
221
+ repo = gr.Textbox(label="Repo đích", placeholder="your-username/my-awesome-model")
222
+ rt2 = gr.Dropdown(["model", "dataset", "space"], value="model", label="Loại")
223
+ zipc = gr.Checkbox(label="Nén thành ZIP (có thể đặt mật khẩu)")
224
+ pw = gr.Textbox(label="Mật khẩu ZIP (nếu có)", type="password", visible=False)
225
+ zipc.change(lambda x: gr.update(visible=x), zipc, pw)
226
+
227
+ up_out = gr.Textbox(label="Kết quả upload", lines=5)
228
+ gr.Button("Upload ngay", variant="primary").click(
229
+ upload, [folder, repo, rt2, zipc, pw, use_dl, dl_path], up_out
230
+ )
231
+
232
+ # ==================== TAB XÓA FILE TRÊN REPO ====================
233
+ with gr.Tab("Xóa file trên Repo"):
234
+ gr.Markdown("So sánh thư mục local → xóa các file trùng trên repo")
235
+ loc = gr.Textbox(label="Thư mục local để đối chiếu", placeholder="/path/to/local/folder")
236
+ repo2 = gr.Textbox(label="Repo cần dọn dẹp", placeholder="username/repo")
237
+ rt3 = gr.Dropdown(["model", "dataset", "space"], value="model")
238
+ dry = gr.Checkbox(label="Chỉ xem trước (Dry-run) - an toàn", value=True)
239
+ del_out = gr.Textbox(label="Kết quả", lines=8)
240
+ gr.Button("Thực hiện xóa", variant="stop").click(
241
+ delete_files, [loc, repo2, rt3, dry], del_out
242
+ )
243
+
244
+ gr.Markdown("**Mẹo:** Sau khi tải xong → tick “Dùng thư mục vừa tải xuống” → Upload ngay không cần nhập đường dẫn!")
245
+
246
+ # CSS nhỏ cho đẹp
247
+ app.css = """
248
+ .status { font-size: 1.3em; font-weight: bold; margin: 10px 0; }
249
+ """
250
+
251
+ # ========================== KHỞI CHẠY ==========================
252
+ app.queue(max_size=20).launch(
253
+ share=True,
254
+ debug=True,
255
+ server_name="0.0.0.0",
256
+ server_port=7860
257
+ )