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() | |