File size: 13,118 Bytes
584da5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ab0f03
584da5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a025d94
584da5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
import os
import git
import shutil
import zipfile
from huggingface_hub import HfApi, create_repo
import gradio as gr
import requests

# Initialize Hugging Face API
api = HfApi()

def clone_repo(repo_url, repo_type=None, auth_token=None):
    try:
        print(f"Cloning repository from URL: {repo_url}")
        repo_name = repo_url.split('/')[-1]
        if os.path.exists(repo_name):
            print(f"Removing existing directory: {repo_name}")
            shutil.rmtree(repo_name)

        if "huggingface.co" in repo_url:
            repo_id = "/".join(repo_url.split("/")[-2:])
            if repo_type is None:
                repo_type = 'model'
            api.snapshot_download(repo_id=repo_id, repo_type=repo_type, token=auth_token, local_dir=repo_name)
        else:
            if auth_token:
                repo_url = repo_url.replace("https://", f"https://{auth_token}@")
            git.Repo.clone_from(repo_url, repo_name)

        print(f"Repository cloned successfully: {repo_name}")
        zip_file = f"{repo_name}.zip"
        shutil.make_archive(repo_name, 'zip', repo_name)
        print(f"Repository zipped successfully: {zip_file}")
        return zip_file
    except git.exc.GitCommandError as e:
        if "could not read Username" in str(e):
            return "Authentication error: Please provide a valid token for private repositories."
        return f"Git error: {str(e)}"
    except requests.exceptions.RequestException as e:
        return "Network error: Unable to connect to the repository."
    except Exception as e:
        return f"An error occurred: {str(e)}"

def zip_download_link(repo_type, repo_url, auth_token):
    result = clone_repo(repo_url, repo_type, auth_token)
    if isinstance(result, str) and result.endswith(".zip"):
        return gr.update(value=result), ""
    else:
        return gr.update(value=None), result

def push_to_huggingface(repo_type, repo_name, files_or_zip, hf_token):
    try:
        repo_name = repo_name.lstrip("/")
        if not "/" in repo_name:
            repo_name = f"{hf_token.split(':')[0]}/{repo_name}"
        target_dir = f"./{repo_name}"
        if os.path.exists(target_dir):
            shutil.rmtree(target_dir)
        os.makedirs(target_dir, exist_ok=True)

        if isinstance(files_or_zip, list):
            for file_obj in files_or_zip:
                if file_obj.endswith(".zip"):
                    with zipfile.ZipFile(file_obj, 'r') as zip_ref:
                        zip_ref.extractall(target_dir)
                else:
                    shutil.copy(file_obj, os.path.join(target_dir, os.path.basename(file_obj)))
        else:
            if files_or_zip.endswith(".zip"):
                with zipfile.ZipFile(files_or_zip, 'r') as zip_ref:
                    zip_ref.extractall(target_dir)
            else:
                shutil.copy(files_or_zip, os.path.join(target_dir, os.path.basename(files_or_zip)))

        if repo_type == "Space":
            api.upload_folder(folder_path=target_dir, path_in_repo="", repo_id=repo_name, repo_type="space", token=hf_token)
            return f"Files pushed to Hugging Face Space: {repo_name}"
        else:
            api.upload_folder(folder_path=target_dir, path_in_repo="", repo_id=repo_name, token=hf_token)
            return f"Files pushed to Hugging Face repository: {repo_name}"
    except Exception as e:
        return f"An error occurred: {str(e)}"

def create_huggingface_space(space_name, space_type, hardware, visibility, hf_token):
    try:
        if "/" not in space_name:
            space_name = f"{hf_token.split(':')[0]}/{space_name}"

        create_repo(repo_id=space_name, repo_type="space", space_sdk=space_type, token=hf_token, private=(visibility == "private"))
        return f"Successfully created Hugging Face Space: {space_name}"
    except Exception as e:
        return f"An error occurred while creating the Space: {str(e)}"

def remove_files_from_huggingface(repo_type, repo_name, file_paths, remove_all, hf_token):
    try:
        print(f"Removing files from {repo_type}: {repo_name}")
        repo_name = repo_name.lstrip("/")
        if not "/" in repo_name:
            repo_name = f"{hf_token.split(':')[0]}/{repo_name}"

        if remove_all:
            try:
                files = api.list_repo_files(repo_id=repo_name, repo_type=repo_type.lower(), token=hf_token)
                if not files:
                    return "No files found to remove."

                successful_removals = []
                failed_removals = []
                for file_path in files:
                    try:
                        api.delete_file(path_in_repo=file_path, repo_id=repo_name, repo_type=repo_type.lower(), token=hf_token)
                        successful_removals.append(file_path)
                    except Exception as e:
                        failed_removals.append((file_path, str(e)))

                result = []
                if successful_removals:
                    result.append(f"Successfully removed files: {', '.join(successful_removals)}")
                if failed_removals:
                    result.append("Failed to remove the following files:")
                    for path, error in failed_removals:
                        result.append(f"- {path}: {error}")

                return "\n".join(result)
            except Exception as e:
                return f"Error removing all files: {str(e)}"
        else:
            if isinstance(file_paths, str):
                file_paths = [path.strip() for path in file_paths.split(',') if path.strip()]

            if not file_paths:
                return "Error: No valid file paths provided."

            successful_removals = []
            failed_removals = []
            for file_path in file_paths:
                try:
                    api.delete_file(path_in_repo=file_path, repo_id=repo_name, repo_type=repo_type.lower(), token=hf_token)
                    successful_removals.append(file_path)
                except Exception as e:
                    failed_removals.append((file_path, str(e)))

            result = []
            if successful_removals:
                result.append(f"Successfully removed files: {', '.join(successful_removals)}")
            if failed_removals:
                result.append("Failed to remove the following files:")
                for path, error in failed_removals:
                    result.append(f"- {path}: {error}")

            return "\n".join(result)
    except Exception as e:
        return f"An error occurred during file removal: {str(e)}"

# Define the Gradio interface using Blocks API
with gr.Blocks(css="footer {display:none;}.title {color: blue; font-size: 36px;}") as app:
    gr.Markdown("""
# πŸš€ Hugging Face Repo & Space Manager

Welcome to the best tool for effortlessly managing your Hugging Face ecosystem! Whether you're a seasoned ML engineer or just getting started with AI, this all-in-one interface streamlines your workflow and boosts productivity.

## 🌟 Key Features & Why Use This Tool?

- **Seamless File Management**: Push, pull, and organize your files across Spaces and Repos with drag-and-drop simplicity.
- **Git Integration**: Clone repositories from GitHub or Hugging Face with a single click, and download them as ready-to-use ZIP files.
- **Smart File Removal**: Selectively clean up your Spaces and Repos, or perform a total reset with our bulk file removal option.
- **Time-Saver**: Automate repetitive tasks and focus on what matters - your AI projects.
- **User-Friendly**: No more command-line headaches. Our GUI makes complex operations a breeze.
- **Versatile**: From creating Spaces to managing large datasets, handle it all in one place.
- **Secure**: Built-in token management ensures your credentials stay safe while you work.

## πŸ”§ How to Use This Tool

1. **Create a New Space**: Start by creating a fresh Hugging Face Space for your project.
2. **Manage Existing Spaces**: Remove Files" tab to clean up your Space or Repository.
3. **Push Your Content**: Upload your files or a ZIP archive to your Space or Repository. 
4. **Clone and Modify**: Modify the files locally, then push them back using the "Push to Hugging Face" feature.

Let's innovate together! πŸ€—βœ¨
---
Created with ❀️ by MoBenTa | Empowering AI enthusiasts worldwide
    """)

    with gr.Tabs():
        with gr.Tab("🌟 Manage Hugging Face Space/Repo"):
            with gr.Tabs():
                with gr.TabItem("Create Space"):
                    space_name = gr.Textbox(label="Space Name (format: username/space-name)")
                    space_type = gr.Dropdown(["streamlit", "gradio", "static", "docker"], label="Space Type")
                    hardware = gr.Textbox(label="Hardware (optional)")
                    visibility = gr.Radio(choices=["public", "private"], label="Visibility")
                    create_hf_token = gr.Textbox(label="Hugging Face Token", type="password")
                    create_space_button = gr.Button("Create Space", variant="primary")
                    create_space_output = gr.Textbox(label="Creation Result")

                    create_space_button.click(
                        fn=create_huggingface_space,
                        inputs=[space_name, space_type, hardware, visibility, create_hf_token],
                        outputs=create_space_output
                    )

                with gr.TabItem("Remove Files"):
                    remove_type = gr.Dropdown(["Space", "Repository"], label="Remove from")
                    remove_repo_name = gr.Textbox(label="Repository/Space Name")
                    remove_all_checkbox = gr.Checkbox(label="Remove All Files", info="Warning: This will remove all files from the repository!")
                    remove_file_paths = gr.Textbox(label="File Paths to Remove (comma-separated)", interactive=True)
                    remove_hf_token = gr.Textbox(label="Hugging Face Token", type="password")
                    remove_button = gr.Button("Remove Files", variant="primary")
                    remove_output = gr.Textbox(label="Removal Result")

                    def update_file_paths_interactivity(remove_all):
                        return gr.update(interactive=not remove_all)

                    remove_all_checkbox.change(
                        fn=update_file_paths_interactivity,
                        inputs=remove_all_checkbox,
                        outputs=remove_file_paths
                    )

                    remove_button.click(
                        fn=remove_files_from_huggingface,
                        inputs=[remove_type, remove_repo_name, remove_file_paths, remove_all_checkbox, remove_hf_token],
                        outputs=remove_output
                    )

        with gr.Tab("☁️ Push to Hugging Face"):
            push_type = gr.Dropdown(["Space", "Repository"], label="Push to")
            repo_name = gr.Textbox(label="Repository/Space Name")
            files_upload = gr.File(label="Upload File(s) or Zip", file_count="multiple", type="filepath")
            hf_token = gr.Textbox(label="Hugging Face Token", type="password")
            push_button = gr.Button("Push to Hugging Face", variant="primary")
            push_output = gr.Textbox(label="Push Result")

            push_button.click(
                fn=push_to_huggingface,
                inputs=[push_type, repo_name, files_upload, hf_token],
                outputs=push_output
            )

        with gr.Tab("πŸ” Clone Repository"):
            repo_type_input = gr.Radio(choices=["GitHub", "Hugging Face Model", "Hugging Face Dataset", "Hugging Face Space"], label="Repository Type")
            repo_url_input = gr.Textbox(label="Repository URL")
            auth_token_input = gr.Textbox(label="Authentication Token (optional)", type="password")
            clone_button = gr.Button("Clone and Download", variant="primary")
            output_zip = gr.File(label="Downloaded Repository")
            clone_error_output = gr.Textbox(label="Cloning Result", visible=False)

            def handle_clone_result(repo_type_input, repo_url, auth_token):
                if repo_type_input == "GitHub":
                    repo_type = None
                elif repo_type_input == "Hugging Face Model":
                    repo_type = "model"
                elif repo_type_input == "Hugging Face Dataset":
                    repo_type = "dataset"
                elif repo_type_input == "Hugging Face Space":
                    repo_type = "space"
                else:
                    repo_type = "model"

                file_output, error_message = zip_download_link(repo_type, repo_url, auth_token)
                return file_output, error_message, gr.update(visible=bool(error_message))

            clone_button.click(
                fn=handle_clone_result,
                inputs=[repo_type_input, repo_url_input, auth_token_input],
                outputs=[output_zip, clone_error_output, clone_error_output]
            )

if __name__ == "__main__":
    app.launch()