Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import requests | |
| import subprocess | |
| import zipfile | |
| import os | |
| import shutil | |
| from huggingface_hub import snapshot_download, login, hf_hub_download | |
| def clean_workspace(): | |
| for item in os.listdir(): | |
| if os.path.isdir(item) or item.endswith(".zip"): | |
| try: | |
| if os.path.isdir(item): | |
| shutil.rmtree(item) | |
| else: | |
| os.remove(item) | |
| except Exception as e: | |
| print(f"削除失敗: {item} ({e})") | |
| def zip_path_from_folder(folder_path, zip_path): | |
| """指定フォルダをZIP化""" | |
| with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: | |
| if os.path.isdir(folder_path): | |
| for root, dirs, files in os.walk(folder_path): | |
| for file in files: | |
| file_path = os.path.join(root, file) | |
| zipf.write(file_path, os.path.relpath(file_path, folder_path)) | |
| elif os.path.isfile(folder_path): | |
| zipf.write(folder_path, os.path.basename(folder_path)) | |
| else: | |
| raise ValueError(f"指定フォルダが存在しません: {folder_path}") | |
| return zip_path | |
| def download_and_zip_git_clone(repo_url, target_folder=None): | |
| repo_name = repo_url.rstrip('/').split('/')[-1] | |
| subprocess.run(["git", "clone", repo_url], check=True) | |
| zip_name = f"{repo_name}.zip" if not target_folder else f"{repo_name}_{target_folder.replace('/', '_')}.zip" | |
| folder_to_zip = os.path.join(repo_name, target_folder) if target_folder else repo_name | |
| zip_path = zip_path_from_folder(folder_to_zip, zip_name) | |
| shutil.rmtree(repo_name) | |
| return zip_path | |
| def download_and_zip_github_api(repo_url, target_folder=None): | |
| repo_name = repo_url.rstrip('/').split('/')[-1] | |
| zip_url = f"{repo_url}/archive/refs/heads/main.zip" | |
| response = requests.get(zip_url) | |
| if response.status_code != 200: | |
| raise Exception(f"GitHub API ダウンロード失敗: ステータスコード {response.status_code}") | |
| temp_zip = f"{repo_name}_full.zip" | |
| with open(temp_zip, 'wb') as f: | |
| f.write(response.content) | |
| # ZIP展開して特定フォルダを再ZIP化 | |
| temp_dir = f"{repo_name}_temp" | |
| with zipfile.ZipFile(temp_zip, 'r') as zip_ref: | |
| zip_ref.extractall(temp_dir) | |
| os.remove(temp_zip) | |
| folder_to_zip = os.path.join(temp_dir, f"{repo_name}-main", target_folder) if target_folder else os.path.join(temp_dir, f"{repo_name}-main") | |
| zip_name = f"{repo_name}.zip" if not target_folder else f"{repo_name}_{target_folder.replace('/', '_')}.zip" | |
| zip_path = zip_path_from_folder(folder_to_zip, zip_name) | |
| shutil.rmtree(temp_dir) | |
| return zip_path | |
| def download_and_zip_huggingface_hub(repo_url, token=None, specific_file=None, target_folder=None): | |
| repo_id = '/'.join(repo_url.rstrip('/').split('/')[-2:]) | |
| if token: | |
| login(token=token) | |
| if specific_file: | |
| specific_path = hf_hub_download(repo_id=repo_id, filename=specific_file) | |
| zip_name = f"{repo_id.replace('/', '_')}_{specific_file.replace('/', '_')}.zip" | |
| zip_path = zip_path_from_folder(specific_path, zip_name) | |
| else: | |
| # 全体をsnapshot_downloadで取得してフォルダ指定でZIP化 | |
| folder_path = snapshot_download(repo_id=repo_id, use_auth_token=token) | |
| folder_to_zip = os.path.join(folder_path, target_folder) if target_folder else folder_path | |
| zip_name = f"{repo_id.replace('/', '_')}.zip" if not target_folder else f"{repo_id.replace('/', '_')}_{target_folder.replace('/', '_')}.zip" | |
| zip_path = zip_path_from_folder(folder_to_zip, zip_name) | |
| return zip_path | |
| def process_repo(repo_url, method, use_token, token, specific_file, download_type, target_folder): | |
| try: | |
| clean_workspace() | |
| token_value = token if use_token else None | |
| if method == "git clone": | |
| zip_path = download_and_zip_git_clone(repo_url, target_folder) | |
| elif method == "GitHub API": | |
| zip_path = download_and_zip_github_api(repo_url, target_folder) | |
| elif method == "Hugging Face Hub": | |
| if download_type == "特定のファイルのみ": | |
| zip_path = download_and_zip_huggingface_hub(repo_url, token_value, specific_file) | |
| else: | |
| zip_path = download_and_zip_huggingface_hub(repo_url, token_value, None, target_folder) | |
| else: | |
| return f"不明な方法: {method}", None, gr.update(visible=False) | |
| return f"成功: {zip_path}", zip_path, gr.update(visible=True) | |
| except Exception as e: | |
| return f"エラー: {str(e)}", None, gr.update(visible=False) | |
| # Gradio UI | |
| with gr.Blocks() as app: | |
| gr.Markdown("# リポジトリZIP変換ツール") | |
| repo_url_input = gr.Textbox(label="リポジトリURL") | |
| method_input = gr.Radio(["git clone", "GitHub API", "Hugging Face Hub"], label="ダウンロード方法") | |
| use_token_input = gr.Checkbox(label="トークンを使用") | |
| token_input = gr.Textbox(label="Hugging Faceトークン", visible=False) | |
| download_type_input = gr.Radio(["リポジトリ全体", "特定のファイルのみ"], label="ダウンロードタイプ", visible=False) | |
| specific_file_input = gr.Textbox(label="特定ファイルのパス", visible=False) | |
| target_folder_input = gr.Textbox(label="特定フォルダのみZIP化(任意)") | |
| output_text = gr.Textbox(label="結果") | |
| download_button = gr.Button("ZIPに変換してダウンロード") | |
| download_file = gr.File(label="ZIPファイル", visible=False) | |
| # 表示切替 | |
| use_token_input.change(lambda x: gr.update(visible=x), inputs=use_token_input, outputs=token_input) | |
| method_input.change(lambda x: gr.update(visible=(x=="Hugging Face Hub")), inputs=method_input, outputs=download_type_input) | |
| download_type_input.change(lambda x: gr.update(visible=(x=="特定のファイルのみ")), inputs=download_type_input, outputs=specific_file_input) | |
| download_button.click( | |
| fn=process_repo, | |
| inputs=[repo_url_input, method_input, use_token_input, token_input, specific_file_input, download_type_input, target_folder_input], | |
| outputs=[output_text, download_file, download_file], | |
| ) | |
| app.launch() | |