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