git-to-zip / app.py
soiz1's picture
Update app.py
68cab11 verified
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()