Update app.py
Browse files
app.py
CHANGED
|
@@ -5,7 +5,8 @@ import os
|
|
| 5 |
import uuid
|
| 6 |
import shutil
|
| 7 |
import tempfile
|
| 8 |
-
|
|
|
|
| 9 |
# --- State Management and API Client ---
|
| 10 |
|
| 11 |
def get_hf_api(token):
|
|
@@ -13,7 +14,29 @@ def get_hf_api(token):
|
|
| 13 |
return HfApi(token=token if token else None)
|
| 14 |
|
| 15 |
# --- Core Logic Functions ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
def handle_token_change(token):
|
| 18 |
"""
|
| 19 |
Called when the token is entered. Fetches user info, updates UI interactivity,
|
|
@@ -112,10 +135,9 @@ def archive_repo(token, repo_id, archive_repo, manage_repo_type_state):
|
|
| 112 |
# --- File Management Functions ---
|
| 113 |
|
| 114 |
def show_files_and_load_first(token, repo_id, repo_type):
|
| 115 |
-
"""Lists files
|
| 116 |
if not repo_id:
|
| 117 |
-
gr.
|
| 118 |
-
return gr.update(visible=False), gr.update(choices=[], value=None), gr.update(value="")
|
| 119 |
try:
|
| 120 |
api = get_hf_api(token)
|
| 121 |
repo_files = api.list_repo_files(repo_id=repo_id, repo_type=repo_type)
|
|
@@ -123,16 +145,23 @@ def show_files_and_load_first(token, repo_id, repo_type):
|
|
| 123 |
|
| 124 |
if not filtered_files:
|
| 125 |
return (gr.update(visible=True), gr.update(choices=[], value=None),
|
| 126 |
-
gr.update(value="##
|
| 127 |
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
except Exception as e:
|
| 134 |
-
gr.Error(f"
|
| 135 |
-
return gr.update(visible=False), gr.update(choices=[], value=None), gr.update(
|
| 136 |
|
| 137 |
def load_file_content_backend(token, repo_id, repo_type, filepath):
|
| 138 |
"""Backend logic to fetch and format file content."""
|
|
@@ -150,21 +179,43 @@ def load_file_content_backend(token, repo_id, repo_type, filepath):
|
|
| 150 |
return f"Error loading file: {e}", 'python'
|
| 151 |
|
| 152 |
def load_file_content_for_editor(token, repo_id, repo_type, filepath):
|
| 153 |
-
"""
|
| 154 |
-
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
|
| 157 |
-
def commit_file(token, repo_id, repo_type, filepath,
|
| 158 |
-
"""
|
| 159 |
-
if not token: gr.Error("
|
| 160 |
if not filepath: gr.Warning("No file selected."); return
|
| 161 |
-
|
| 162 |
try:
|
| 163 |
api = get_hf_api(token)
|
| 164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
repo_id=repo_id, repo_type=repo_type, commit_message=commit_message)
|
| 166 |
-
gr.Info(f"Successfully committed '{filepath}'
|
| 167 |
-
except Exception as e: gr.Error(f"Failed to commit
|
| 168 |
|
| 169 |
# --- Download Tab Functions ---
|
| 170 |
|
|
@@ -229,6 +280,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), title="Hugging Face Hub
|
|
| 229 |
gr.Markdown("### 3. Edit Files")
|
| 230 |
file_selector = gr.Dropdown(label="Select File", interactive=True)
|
| 231 |
code_editor = gr.Code(label="File Content", interactive=True)
|
|
|
|
| 232 |
commit_message_input = gr.Textbox(label="Commit Message", placeholder="e.g., Update README.md")
|
| 233 |
commit_btn = gr.Button("Commit Changes", variant="primary", interactive=False)
|
| 234 |
# Now, attach event handlers
|
|
@@ -261,7 +313,8 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), title="Hugging Face Hub
|
|
| 261 |
|
| 262 |
manage_files_btn.click(fn=show_files_and_load_first,
|
| 263 |
inputs=[hf_token_state, manage_repo_dropdown, manage_repo_type_state],
|
| 264 |
-
outputs=[editor_panel, file_selector, code_editor])
|
|
|
|
| 265 |
|
| 266 |
archive_repo_btn.click(fn=archive_repo, inputs=[hf_token_state, selected_repo, archive_repo_name, manage_repo_type_state],
|
| 267 |
outputs=[manage_repo_dropdown, action_panel, editor_panel],
|
|
@@ -274,10 +327,14 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), title="Hugging Face Hub
|
|
| 274 |
|
| 275 |
file_selector.change(fn=load_file_content_for_editor,
|
| 276 |
inputs=[hf_token_state, manage_repo_dropdown, manage_repo_type_state, file_selector],
|
| 277 |
-
outputs=code_editor)
|
|
|
|
| 278 |
|
| 279 |
commit_btn.click(fn=commit_file,
|
| 280 |
-
inputs=[hf_token_state, manage_repo_dropdown, manage_repo_type_state, file_selector,
|
|
|
|
|
|
|
|
|
|
| 281 |
|
| 282 |
download_btn.click(fn=download_repos_as_zip,
|
| 283 |
inputs=[hf_token_state, download_repo_dropdown, download_repo_type_state],
|
|
|
|
| 5 |
import uuid
|
| 6 |
import shutil
|
| 7 |
import tempfile
|
| 8 |
+
import pandas as pd
|
| 9 |
+
import io
|
| 10 |
# --- State Management and API Client ---
|
| 11 |
|
| 12 |
def get_hf_api(token):
|
|
|
|
| 14 |
return HfApi(token=token if token else None)
|
| 15 |
|
| 16 |
# --- Core Logic Functions ---
|
| 17 |
+
def is_tabular(filepath):
|
| 18 |
+
"""Checks if the file is a supported tabular dataset."""
|
| 19 |
+
if not filepath: return False
|
| 20 |
+
ext = os.path.splitext(filepath)[1].lower()
|
| 21 |
+
return ext in ['.csv', '.tsv', '.json', '.jsonl', '.parquet']
|
| 22 |
|
| 23 |
+
def load_tabular_content(token, repo_id, repo_type, filepath):
|
| 24 |
+
"""Loads a file into a Pandas DataFrame."""
|
| 25 |
+
try:
|
| 26 |
+
api = get_hf_api(token)
|
| 27 |
+
local_path = api.hf_hub_download(repo_id=repo_id, repo_type=repo_type, filename=filepath, token=token)
|
| 28 |
+
ext = os.path.splitext(filepath)[1].lower()
|
| 29 |
+
|
| 30 |
+
if ext == '.csv': return pd.read_csv(local_path)
|
| 31 |
+
if ext == '.tsv': return pd.read_csv(local_path, sep='\t')
|
| 32 |
+
if ext == '.parquet': return pd.read_parquet(local_path)
|
| 33 |
+
if ext == '.json':
|
| 34 |
+
try: return pd.read_json(local_path)
|
| 35 |
+
except: return pd.read_json(local_path, lines=True) # Try JSONL
|
| 36 |
+
if ext == '.jsonl': return pd.read_json(local_path, lines=True)
|
| 37 |
+
return None
|
| 38 |
+
except Exception as e:
|
| 39 |
+
return pd.DataFrame({"Error": [str(e)]})
|
| 40 |
def handle_token_change(token):
|
| 41 |
"""
|
| 42 |
Called when the token is entered. Fetches user info, updates UI interactivity,
|
|
|
|
| 135 |
# --- File Management Functions ---
|
| 136 |
|
| 137 |
def show_files_and_load_first(token, repo_id, repo_type):
|
| 138 |
+
"""Lists files and pre-loads the first one (Text OR DataFrame)."""
|
| 139 |
if not repo_id:
|
| 140 |
+
return gr.update(visible=False), gr.update(choices=[], value=None), gr.update(visible=False), gr.update(visible=False)
|
|
|
|
| 141 |
try:
|
| 142 |
api = get_hf_api(token)
|
| 143 |
repo_files = api.list_repo_files(repo_id=repo_id, repo_type=repo_type)
|
|
|
|
| 145 |
|
| 146 |
if not filtered_files:
|
| 147 |
return (gr.update(visible=True), gr.update(choices=[], value=None),
|
| 148 |
+
gr.update(value="## Empty Repo", visible=True), gr.update(visible=False))
|
| 149 |
|
| 150 |
+
first_file = filtered_files[0]
|
| 151 |
+
|
| 152 |
+
# Check type and load appropriately
|
| 153 |
+
if is_tabular(first_file):
|
| 154 |
+
df = load_tabular_content(token, repo_id, repo_type, first_file)
|
| 155 |
+
return (gr.update(visible=True), gr.update(choices=filtered_files, value=first_file),
|
| 156 |
+
gr.update(visible=False), gr.update(value=df, visible=True))
|
| 157 |
+
else:
|
| 158 |
+
content, lang = load_file_content_backend(token, repo_id, repo_type, first_file)
|
| 159 |
+
return (gr.update(visible=True), gr.update(choices=filtered_files, value=first_file),
|
| 160 |
+
gr.update(value=content, language=lang, visible=True), gr.update(visible=False))
|
| 161 |
+
|
| 162 |
except Exception as e:
|
| 163 |
+
gr.Error(f"Error: {e}")
|
| 164 |
+
return gr.update(visible=False), gr.update(choices=[], value=None), gr.update(visible=True), gr.update(visible=False)
|
| 165 |
|
| 166 |
def load_file_content_backend(token, repo_id, repo_type, filepath):
|
| 167 |
"""Backend logic to fetch and format file content."""
|
|
|
|
| 179 |
return f"Error loading file: {e}", 'python'
|
| 180 |
|
| 181 |
def load_file_content_for_editor(token, repo_id, repo_type, filepath):
|
| 182 |
+
"""Decides whether to show the Code Editor or the Data Editor."""
|
| 183 |
+
if is_tabular(filepath):
|
| 184 |
+
df = load_tabular_content(token, repo_id, repo_type, filepath)
|
| 185 |
+
# Hide Code, Show DF
|
| 186 |
+
return gr.update(visible=False), gr.update(value=df, visible=True)
|
| 187 |
+
else:
|
| 188 |
+
content, language = load_file_content_backend(token, repo_id, repo_type, filepath)
|
| 189 |
+
# Show Code, Hide DF
|
| 190 |
+
return gr.update(value=content, language=language, visible=True), gr.update(visible=False)
|
| 191 |
|
| 192 |
+
def commit_file(token, repo_id, repo_type, filepath, code_content, df_content, commit_message):
|
| 193 |
+
"""Smart commit: saves text OR dataframe based on file extension."""
|
| 194 |
+
if not token: gr.Error("Write-token required."); return
|
| 195 |
if not filepath: gr.Warning("No file selected."); return
|
| 196 |
+
|
| 197 |
try:
|
| 198 |
api = get_hf_api(token)
|
| 199 |
+
|
| 200 |
+
if is_tabular(filepath):
|
| 201 |
+
# Handle DataFrame Saving
|
| 202 |
+
buffer = io.BytesIO()
|
| 203 |
+
ext = os.path.splitext(filepath)[1].lower()
|
| 204 |
+
if ext == '.csv': df_content.to_csv(buffer, index=False)
|
| 205 |
+
elif ext == '.tsv': df_content.to_csv(buffer, sep='\t', index=False)
|
| 206 |
+
elif ext == '.parquet': df_content.to_parquet(buffer, index=False)
|
| 207 |
+
elif ext == '.json': df_content.to_json(buffer, orient='records')
|
| 208 |
+
elif ext == '.jsonl': df_content.to_json(buffer, orient='records', lines=True)
|
| 209 |
+
|
| 210 |
+
data_to_upload = buffer.getvalue()
|
| 211 |
+
else:
|
| 212 |
+
# Handle Text Saving
|
| 213 |
+
data_to_upload = bytes(code_content, 'utf-8')
|
| 214 |
+
|
| 215 |
+
api.upload_file(path_or_fileobj=data_to_upload, path_in_repo=filepath,
|
| 216 |
repo_id=repo_id, repo_type=repo_type, commit_message=commit_message)
|
| 217 |
+
gr.Info(f"Successfully committed '{filepath}'!")
|
| 218 |
+
except Exception as e: gr.Error(f"Failed to commit: {e}")
|
| 219 |
|
| 220 |
# --- Download Tab Functions ---
|
| 221 |
|
|
|
|
| 280 |
gr.Markdown("### 3. Edit Files")
|
| 281 |
file_selector = gr.Dropdown(label="Select File", interactive=True)
|
| 282 |
code_editor = gr.Code(label="File Content", interactive=True)
|
| 283 |
+
dataframe_editor = gr.Dataframe(label="Dataset Editor", interactive=True, visible=False, wrap=True)
|
| 284 |
commit_message_input = gr.Textbox(label="Commit Message", placeholder="e.g., Update README.md")
|
| 285 |
commit_btn = gr.Button("Commit Changes", variant="primary", interactive=False)
|
| 286 |
# Now, attach event handlers
|
|
|
|
| 313 |
|
| 314 |
manage_files_btn.click(fn=show_files_and_load_first,
|
| 315 |
inputs=[hf_token_state, manage_repo_dropdown, manage_repo_type_state],
|
| 316 |
+
outputs=[editor_panel, file_selector, code_editor, dataframe_editor]) # Added dataframe_editor
|
| 317 |
+
|
| 318 |
|
| 319 |
archive_repo_btn.click(fn=archive_repo, inputs=[hf_token_state, selected_repo, archive_repo_name, manage_repo_type_state],
|
| 320 |
outputs=[manage_repo_dropdown, action_panel, editor_panel],
|
|
|
|
| 327 |
|
| 328 |
file_selector.change(fn=load_file_content_for_editor,
|
| 329 |
inputs=[hf_token_state, manage_repo_dropdown, manage_repo_type_state, file_selector],
|
| 330 |
+
outputs=[code_editor, dataframe_editor]) # Added dataframe_editor
|
| 331 |
+
|
| 332 |
|
| 333 |
commit_btn.click(fn=commit_file,
|
| 334 |
+
inputs=[hf_token_state, manage_repo_dropdown, manage_repo_type_state, file_selector,
|
| 335 |
+
code_editor, dataframe_editor, # Added dataframe_editor
|
| 336 |
+
commit_message_input])
|
| 337 |
+
|
| 338 |
|
| 339 |
download_btn.click(fn=download_repos_as_zip,
|
| 340 |
inputs=[hf_token_state, download_repo_dropdown, download_repo_type_state],
|