Spaces:
Sleeping
Sleeping
import gradio as gr | |
from huggingface_hub import snapshot_download | |
from github import Github | |
import shutil | |
import os | |
import base64 | |
def clone_hf_to_github( | |
space_url, github_token, repo_name, make_private, enable_sync, hf_token | |
): | |
# Sanitize inputs | |
if not space_url or not github_token or not repo_name: | |
return "Error: All fields must be filled out." | |
if enable_sync and not hf_token: | |
return "Error: A Hugging Face Token is required for continuous sync." | |
temp_dir = f"./temp_clone/{repo_name}" | |
os.makedirs(temp_dir, exist_ok=True) | |
try: | |
# Step 1: Clone Hugging Face Space | |
# Pass the token if sync is enabled (handles public/private spaces) | |
token_to_use = hf_token if enable_sync else None | |
snapshot_download(repo_id=space_url.split("spaces/")[1], local_dir=temp_dir, token=token_to_use) | |
# Step 2: Authenticate with GitHub | |
g = Github(github_token) | |
user = g.get_user() | |
# Check if repo already exists to prevent an error | |
try: | |
github_repo = user.get_repo(repo_name) | |
except: | |
# Create the new GitHub repository, using the user's preference | |
github_repo = user.create_repo(repo_name, private=make_private) | |
# Use git commands to push the cloned content | |
os.system(f"cd {temp_dir} && git init && git add . && git commit -m 'Initial commit from HF Space'") | |
os.system(f"cd {temp_dir} && git branch -M main") | |
os.system(f"cd {temp_dir} && git remote add origin {github_repo.clone_url.replace('https://', f'https://{github_token}@')}") | |
os.system(f"cd {temp_dir} && git push -u origin main") | |
# Step 3 (Optional): Add HF_TOKEN as a GitHub secret and create workflow file | |
if enable_sync: | |
github_repo.create_secret("HF_TOKEN", hf_token) | |
workflow_content = f""" | |
name: Sync with Hugging Face Hub | |
on: | |
push: | |
branches: [main] | |
jobs: | |
sync-to-hub: | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
lfs: true | |
- name: Push to Hugging Face Hub | |
uses: nateraw/huggingface-sync-action@v0.0.5 | |
with: | |
huggingface_repo_id: '{space_url.split("spaces/")[1]}' | |
hf_token: ${{ secrets.HF_TOKEN }} | |
""" | |
encoded_content = base64.b64encode(workflow_content.encode()).decode() | |
github_repo.create_file( | |
path=".github/workflows/sync-to-hf.yml", | |
message="Add GitHub Actions workflow to sync with Hugging Face", | |
content=encoded_content | |
) | |
final_url = github_repo.html_url | |
if enable_sync: | |
return f"Success! Space '{space_url}' cloned to GitHub repo '{final_url}'. Continuous sync workflow has been added." | |
else: | |
return f"Success! Space '{space_url}' cloned to GitHub repo '{final_url}'." | |
except Exception as e: | |
return f"An error occurred: {e}" | |
finally: | |
# Clean up the temporary directory | |
if os.path.exists(temp_dir): | |
shutil.rmtree(temp_dir) | |
def toggle_hf_token(enable_sync): | |
"""Conditionally shows/hides the HF_TOKEN textbox based on the checkbox state.""" | |
return gr.Textbox.update(visible=enable_sync) | |
# Create the Gradio interface | |
with gr.Blocks() as demo: | |
gr.Markdown("# Hugging Face Space to GitHub Cloner and Sync Setup") | |
gr.Markdown("Clone a Hugging Face Space and optionally set up a continuous sync with GitHub Actions.") | |
with gr.Row(): | |
hf_space_url = gr.Textbox(label="Hugging Face Space URL (e.g., user/space)") | |
github_token = gr.Textbox(label="GitHub Personal Access Token (with 'repo' and 'workflow' scopes)", type="password") | |
github_repo_name = gr.Textbox(label="New GitHub Repo Name") | |
with gr.Row(): | |
make_private = gr.Radio(choices=[True, False], value=False, label="Make GitHub Repo Private?") | |
enable_sync = gr.Checkbox(label="Enable Continuous Sync with Hugging Face Space") | |
hf_token = gr.Textbox( | |
label="Hugging Face User Access Token (with 'read' access for cloning)", | |
type="password", | |
visible=False # Initially hidden | |
) | |
# Event listener to control visibility of HF_TOKEN textbox | |
enable_sync.change( | |
fn=toggle_hf_token, | |
inputs=enable_sync, | |
outputs=hf_token | |
) | |
submit_btn = gr.Button("Clone and Set Up Sync") | |
output = gr.Textbox(label="Output") | |
submit_btn.click( | |
fn=clone_hf_to_github, | |
inputs=[hf_space_url, github_token, github_repo_name, make_private, enable_sync, hf_token], | |
outputs=output, | |
) | |
demo.launch() | |