Translsis commited on
Commit
da3008f
·
verified ·
1 Parent(s): 4907007

Delete app(2).py

Browse files
Files changed (1) hide show
  1. app(2).py +0 -501
app(2).py DELETED
@@ -1,501 +0,0 @@
1
- import gradio as gr
2
- import os
3
- import logging
4
- import asyncio
5
- import tempfile
6
- import git
7
- import shutil
8
- from pathlib import Path
9
- from typing import Tuple, Optional
10
- from huggingface_hub import login, HfApi, create_repo, upload_file
11
- from urllib.parse import urlparse
12
- from functools import partial
13
-
14
- # Setup logging
15
- logging.basicConfig(
16
- level=logging.INFO,
17
- format='%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s'
18
- )
19
- logger = logging.getLogger(__name__)
20
-
21
- class HuggingFaceManager:
22
- def __init__(self):
23
- self.api = HfApi()
24
- self.token: Optional[str] = None
25
- self.temp_dir = Path(tempfile.mkdtemp())
26
-
27
- def cleanup(self):
28
- """Clean up temporary directory"""
29
- if self.temp_dir.exists():
30
- shutil.rmtree(self.temp_dir, ignore_errors=True)
31
-
32
- def validate_repo_name(self, repo_name: str) -> bool:
33
- """Validate repository name format"""
34
- if not repo_name or '/' not in repo_name:
35
- raise ValueError("Repository name must be in format 'username/repo-name'")
36
- username, repo = repo_name.split('/', 1)
37
- return all(name.strip() for name in [username, repo])
38
-
39
- def validate_url(self, url: str) -> bool:
40
- """Validate URL format"""
41
- try:
42
- result = urlparse(url)
43
- return all([result.scheme, result.netloc])
44
- except Exception:
45
- return False
46
-
47
- async def login_and_validate(self, token: str) -> str:
48
- """Login to Hugging Face and validate token"""
49
- if not token.strip():
50
- return "Error: Token cannot be empty"
51
-
52
- try:
53
- loop = asyncio.get_event_loop()
54
- await loop.run_in_executor(None, login, token)
55
- await loop.run_in_executor(None, self.api.whoami)
56
-
57
- self.token = token
58
- return "Login successful!"
59
- except Exception as e:
60
- logger.error(f"Login failed: {e}")
61
- return f"Login failed: {str(e)}"
62
-
63
- async def download_from_url(
64
- self,
65
- url: str,
66
- download_type: str,
67
- progress: Optional[gr.Progress] = None
68
- ) -> Tuple[str, Optional[str]]:
69
- """Download content from URL using wget or git"""
70
- if not self.validate_url(url):
71
- return "Invalid URL format!", None
72
-
73
- output_path = self.temp_dir / "downloaded_content"
74
- if output_path.exists():
75
- shutil.rmtree(output_path)
76
- output_path.mkdir(parents=True)
77
-
78
- try:
79
- if download_type == "wget":
80
- if progress:
81
- progress(0, desc="Downloading with wget...")
82
-
83
- process = await asyncio.create_subprocess_exec(
84
- 'wget', '-P', str(output_path), url,
85
- stdout=asyncio.subprocess.PIPE,
86
- stderr=asyncio.subprocess.PIPE
87
- )
88
-
89
- try:
90
- stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=300)
91
- if process.returncode != 0:
92
- raise Exception(f"wget failed: {stderr.decode()}")
93
- except asyncio.TimeoutError:
94
- raise Exception("Download timed out after 5 minutes")
95
-
96
- elif download_type == "git":
97
- if progress:
98
- progress(0, desc="Cloning git repository...")
99
-
100
- await asyncio.get_event_loop().run_in_executor(
101
- None,
102
- partial(git.Repo.clone_from, url, str(output_path), depth=1)
103
- )
104
-
105
- if progress:
106
- progress(1, desc="Download complete")
107
-
108
- return "Download successful!", str(output_path)
109
-
110
- except Exception as e:
111
- logger.error(f"Download failed: {e}")
112
- if output_path.exists():
113
- shutil.rmtree(output_path)
114
- return f"Download failed: {str(e)}", None
115
-
116
- async def create_repository(
117
- self,
118
- repo_name: str,
119
- repo_type: str,
120
- is_private: bool
121
- ) -> str:
122
- """Create a new repository on Hugging Face"""
123
- if not self.token:
124
- return "Please login first!"
125
-
126
- try:
127
- self.validate_repo_name(repo_name)
128
-
129
- await asyncio.get_event_loop().run_in_executor(
130
- None,
131
- partial(
132
- create_repo,
133
- repo_name,
134
- private=is_private,
135
- repo_type=repo_type,
136
- exist_ok=True
137
- )
138
- )
139
-
140
- return f"Repository '{repo_name}' created successfully!"
141
- except Exception as e:
142
- logger.error(f"Failed to create repository: {e}")
143
- return f"Failed to create repository: {str(e)}"
144
-
145
- async def upload_file_worker(
146
- self,
147
- file_path: Path,
148
- relative_path: Path,
149
- repo_name: str,
150
- repo_type: str,
151
- progress_callback=None
152
- ) -> Optional[str]:
153
- """Upload a single file to repository"""
154
- try:
155
- await asyncio.get_event_loop().run_in_executor(
156
- None,
157
- partial(
158
- upload_file,
159
- path_or_fileobj=str(file_path),
160
- path_in_repo=str(relative_path),
161
- repo_id=repo_name,
162
- repo_type=repo_type,
163
- commit_message=f"Upload: {relative_path}"
164
- )
165
- )
166
- if progress_callback:
167
- progress_callback()
168
- return str(relative_path)
169
- except Exception as e:
170
- logger.error(f"Error uploading {relative_path}: {e}")
171
- return None
172
-
173
- async def upload_folder(
174
- self,
175
- folder_path: str,
176
- repo_name: str,
177
- repo_type: str,
178
- progress: Optional[gr.Progress] = None
179
- ) -> str:
180
- """Upload entire folder to repository"""
181
- if not self.token:
182
- return "Please login first!"
183
-
184
- folder_path = Path(folder_path)
185
- if not folder_path.exists():
186
- return f"Folder {folder_path} does not exist!"
187
-
188
- try:
189
- self.validate_repo_name(repo_name)
190
-
191
- # Collect files for upload
192
- files_to_upload = []
193
- for root, dirs, files in os.walk(folder_path):
194
- if '.git' in dirs:
195
- dirs.remove('.git')
196
-
197
- for file in files:
198
- file_path = Path(root) / file
199
- relative_path = file_path.relative_to(folder_path)
200
- files_to_upload.append((file_path, relative_path))
201
-
202
- if not files_to_upload:
203
- return "No files found to upload"
204
-
205
- if progress:
206
- progress(0, desc=f"Uploading {len(files_to_upload)} files...")
207
-
208
- # Track progress
209
- uploaded_count = 0
210
- def update_progress():
211
- nonlocal uploaded_count
212
- uploaded_count += 1
213
- if progress:
214
- progress(uploaded_count / len(files_to_upload))
215
-
216
- # Upload files in parallel
217
- tasks = [
218
- self.upload_file_worker(
219
- file_path,
220
- relative_path,
221
- repo_name,
222
- repo_type,
223
- update_progress
224
- )
225
- for file_path, relative_path in files_to_upload
226
- ]
227
-
228
- results = await asyncio.gather(*tasks, return_exceptions=True)
229
-
230
- successful = sum(1 for r in results if r is not None)
231
- failed = len(files_to_upload) - successful
232
-
233
- return f"Uploaded {successful} files successfully. Failed: {failed}"
234
-
235
- except Exception as e:
236
- logger.error(f"Upload failed: {e}")
237
- return f"Upload failed: {str(e)}"
238
-
239
- async def delete_files(
240
- self,
241
- folder_path: str,
242
- repo_name: str,
243
- repo_type: str,
244
- dry_run: bool = True,
245
- progress: Optional[gr.Progress] = None
246
- ) -> str:
247
- """Delete files from repository based on local folder structure"""
248
- if not self.token:
249
- return "Please login first!"
250
-
251
- try:
252
- self.validate_repo_name(repo_name)
253
-
254
- folder_path = Path(folder_path)
255
- if not folder_path.exists():
256
- return f"Folder {folder_path} does not exist!"
257
-
258
- # Get repository files
259
- existing_files = await asyncio.get_event_loop().run_in_executor(
260
- None,
261
- partial(self.api.list_repo_files, repo_id=repo_name, repo_type=repo_type)
262
- )
263
-
264
- # Find files to delete
265
- files_to_delete = []
266
- for root, dirs, files in os.walk(folder_path):
267
- if '.git' in dirs:
268
- dirs.remove('.git')
269
-
270
- for file in files:
271
- file_path = Path(root) / file
272
- relative_path = str(file_path.relative_to(folder_path))
273
- if relative_path in existing_files:
274
- files_to_delete.append(relative_path)
275
-
276
- if not files_to_delete:
277
- return "No matching files found to delete"
278
-
279
- if dry_run:
280
- return f"Dry run: Would delete {len(files_to_delete)} files"
281
-
282
- # Perform deletion
283
- if progress:
284
- progress(0, desc=f"Deleting {len(files_to_delete)} files...")
285
-
286
- deleted_count = 0
287
- for file_path in files_to_delete:
288
- try:
289
- await asyncio.get_event_loop().run_in_executor(
290
- None,
291
- partial(
292
- self.api.delete_file,
293
- repo_id=repo_name,
294
- path_in_repo=file_path,
295
- repo_type=repo_type
296
- )
297
- )
298
- deleted_count += 1
299
- if progress:
300
- progress(deleted_count / len(files_to_delete))
301
- except Exception as e:
302
- logger.error(f"Error deleting {file_path}: {e}")
303
-
304
- return f"Successfully deleted {deleted_count} out of {len(files_to_delete)} files"
305
-
306
- except Exception as e:
307
- logger.error(f"Delete operation failed: {e}")
308
- return f"Delete operation failed: {str(e)}"
309
-
310
- def create_interface() -> gr.Blocks:
311
- """Create Gradio interface"""
312
- manager = HuggingFaceManager()
313
-
314
- with gr.Blocks(title="Hugging Face Repository Manager") as app:
315
- gr.Markdown("# Hugging Face Repository Manager")
316
-
317
- # Login Tab
318
- with gr.Tab("Login"):
319
- token_input = gr.Textbox(
320
- label="Hugging Face Token",
321
- type="password",
322
- placeholder="Enter your Hugging Face token"
323
- )
324
- login_btn = gr.Button("Login", variant="primary")
325
- login_output = gr.Textbox(label="Login Status", interactive=False)
326
-
327
- login_btn.click(
328
- fn=lambda x: asyncio.run(manager.login_and_validate(x)),
329
- inputs=[token_input],
330
- outputs=[login_output]
331
- )
332
-
333
- # Download Tab
334
- with gr.Tab("Download"):
335
- download_url = gr.Textbox(
336
- label="URL",
337
- placeholder="Enter URL to download"
338
- )
339
- download_type = gr.Radio(
340
- choices=["wget", "git"],
341
- label="Download Type",
342
- value="wget"
343
- )
344
- download_btn = gr.Button("Download", variant="primary")
345
- download_output = gr.Textbox(label="Status", interactive=False)
346
- download_path = gr.Textbox(
347
- label="Download Path",
348
- interactive=False,
349
- visible=False
350
- )
351
-
352
- download_btn.click(
353
- fn=lambda x, y: asyncio.run(manager.download_from_url(x, y)),
354
- inputs=[download_url, download_type],
355
- outputs=[download_output, download_path]
356
- )
357
-
358
- # Create Repository Tab
359
- with gr.Tab("Create Repository"):
360
- repo_name = gr.Textbox(
361
- label="Repository Name",
362
- placeholder="username/repo-name"
363
- )
364
- repo_type = gr.Radio(
365
- choices=["model", "dataset", "space"],
366
- label="Repository Type",
367
- value="model"
368
- )
369
- is_private = gr.Checkbox(label="Private Repository", value=True)
370
- create_btn = gr.Button("Create Repository", variant="primary")
371
- create_output = gr.Textbox(label="Status", interactive=False)
372
-
373
- create_btn.click(
374
- fn=lambda x, y, z: asyncio.run(manager.create_repository(x, y, z)),
375
- inputs=[repo_name, repo_type, is_private],
376
- outputs=[create_output]
377
- )
378
-
379
- # Upload Tab
380
- with gr.Tab("Upload"):
381
- with gr.Row():
382
- upload_folder_path = gr.Textbox(
383
- label="Local Folder Path",
384
- placeholder="Path to local folder"
385
- )
386
- use_downloaded = gr.Checkbox(
387
- label="Use Downloaded Content",
388
- value=False
389
- )
390
-
391
- upload_repo_name = gr.Textbox(
392
- label="Repository Name",
393
- placeholder="username/repo-name"
394
- )
395
- upload_repo_type = gr.Radio(
396
- choices=["model", "dataset", "space"],
397
- label="Repository Type",
398
- value="model"
399
- )
400
- upload_btn = gr.Button("Upload Files", variant="primary")
401
- upload_output = gr.Textbox(label="Status", interactive=False)
402
-
403
- def prepare_upload_path(folder_path, use_downloaded, downloaded_path):
404
- return downloaded_path if use_downloaded and downloaded_path else folder_path
405
-
406
- upload_btn.click(
407
- fn=lambda *args: asyncio.run(
408
- manager.upload_folder(
409
- prepare_upload_path(args[0], args[1], args[2]),
410
- args[3],
411
- args[4]
412
- )
413
- ),
414
- inputs=[
415
- upload_folder_path,
416
- use_downloaded,
417
- download_path,
418
- upload_repo_name,
419
- upload_repo_type
420
- ],
421
- outputs=[upload_output]
422
- )
423
-
424
- # Delete Tab
425
- with gr.Tab("Delete"):
426
- delete_folder_path = gr.Textbox(
427
- label="Local Folder Path",
428
- placeholder="Path to local folder for reference"
429
- )
430
- delete_repo_name = gr.Textbox(
431
- label="Repository Name",
432
- placeholder="username/repo-name"
433
- )
434
- delete_repo_type = gr.Radio(
435
- choices=["model", "dataset", "space"],
436
- label="Repository Type",
437
- value="model"
438
- )
439
- dry_run = gr.Checkbox(
440
- label="Dry Run",
441
- value=True,
442
- info="Preview changes without making them"
443
- )
444
- delete_btn = gr.Button("Delete Files", variant="secondary")
445
- delete_output = gr.Textbox(label="Status", interactive=False)
446
-
447
- delete_btn.click(
448
- fn=lambda *args: asyncio.run(manager.delete_files(*args)),
449
- inputs=[
450
- delete_folder_path,
451
- delete_repo_name,
452
- delete_repo_type,
453
- dry_run
454
- ],
455
- outputs=[delete_output]
456
- )
457
-
458
- # Error handling
459
- gr.Error()
460
-
461
- # Footer information
462
- gr.Markdown("""
463
- ### Information
464
- - Get your token from [Hugging Face Settings](https://huggingface.co/settings/tokens)
465
- - Repository names must be in format: username/repository-name
466
- - For files larger than 5GB, use Git LFS
467
- - Repository types:
468
- - Model: For ML models and weights
469
- - Dataset: For datasets and data files
470
- - Space: For demos and applications
471
- """)
472
-
473
- return app
474
-
475
- def main():
476
- """Application entry point"""
477
- try:
478
- logger.info("Starting Hugging Face Repository Manager")
479
- app = create_interface()
480
-
481
- # Configure and launch the application
482
- app.queue()
483
- app.launch(
484
- server_name="0.0.0.0",
485
- server_port=7860,
486
- share=True,
487
- max_threads=2,
488
- # Security configurations
489
- auth=None,
490
- ssl_keyfile=None,
491
- ssl_certfile=None,
492
- ssl_verify=True
493
- )
494
- except Exception as e:
495
- logger.error(f"Application failed to start: {e}")
496
- raise
497
- finally:
498
- logger.info("Shutting down Hugging Face Repository Manager")
499
-
500
- if __name__ == "__main__":
501
- main()