Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Deployment script for Trackio on Hugging Face Spaces | |
| Automates the process of creating and configuring a Trackio Space | |
| """ | |
| import os | |
| import json | |
| import requests | |
| import subprocess | |
| import sys | |
| import tempfile | |
| import shutil | |
| from pathlib import Path | |
| from typing import Dict, Any, Optional | |
| # Import Hugging Face Hub API | |
| try: | |
| from huggingface_hub import HfApi, create_repo | |
| HF_HUB_AVAILABLE = True | |
| except ImportError: | |
| HF_HUB_AVAILABLE = False | |
| print("Warning: huggingface_hub not available. Install with: pip install huggingface_hub") | |
| class TrackioSpaceDeployer: | |
| """Deployer for Trackio on Hugging Face Spaces""" | |
| def __init__(self, space_name: str, username: str, token: str, git_email: str = None, git_name: str = None): | |
| self.space_name = space_name | |
| self.username = username | |
| self.token = token | |
| self.space_url = f"https://huggingface.co/spaces/{username}/{space_name}" | |
| # Git configuration | |
| self.git_email = git_email or f"{username}@huggingface.co" | |
| self.git_name = git_name or username | |
| # Initialize HF API | |
| if HF_HUB_AVAILABLE: | |
| self.api = HfApi(token=self.token) | |
| else: | |
| self.api = None | |
| def create_space(self) -> bool: | |
| """Create a new Hugging Face Space using the latest API""" | |
| try: | |
| print(f"Creating Space: {self.space_name}") | |
| if not HF_HUB_AVAILABLE: | |
| print("β huggingface_hub not available, falling back to CLI") | |
| return self._create_space_cli() | |
| # Use the latest HF Hub API to create space | |
| repo_id = f"{self.username}/{self.space_name}" | |
| try: | |
| # Create the space using the API | |
| create_repo( | |
| repo_id=repo_id, | |
| token=self.token, | |
| repo_type="space", | |
| exist_ok=True, | |
| private=False, # Spaces are typically public | |
| space_sdk="gradio", # Specify Gradio SDK | |
| space_hardware="cpu-basic" # Use basic CPU | |
| ) | |
| print(f"β Space created successfully: {self.space_url}") | |
| return True | |
| except Exception as api_error: | |
| print(f"API creation failed: {api_error}") | |
| print("Falling back to CLI method...") | |
| return self._create_space_cli() | |
| except Exception as e: | |
| print(f"β Error creating space: {e}") | |
| return False | |
| def _create_space_cli(self) -> bool: | |
| """Fallback method using CLI commands""" | |
| try: | |
| print("Using CLI fallback method...") | |
| # Set HF token for CLI | |
| os.environ['HF_TOKEN'] = self.token | |
| # Create space using Hugging Face CLI | |
| cmd = [ | |
| "huggingface-cli", "repo", "create", | |
| f"{self.username}/{self.space_name}", | |
| "--type", "space" | |
| ] | |
| print(f"Running command: {' '.join(cmd)}") | |
| result = subprocess.run(cmd, capture_output=True, text=True) | |
| if result.returncode != 0: | |
| print(f"First attempt failed: {result.stderr}") | |
| # Try alternative approach without space-specific flags | |
| print("Retrying with basic space creation...") | |
| cmd = [ | |
| "huggingface-cli", "repo", "create", | |
| f"{self.username}/{self.space_name}" | |
| ] | |
| result = subprocess.run(cmd, capture_output=True, text=True) | |
| if result.returncode == 0: | |
| print(f"β Space created successfully: {self.space_url}") | |
| return True | |
| else: | |
| print(f"β Failed to create space: {result.stderr}") | |
| return False | |
| except Exception as e: | |
| print(f"β Error creating space with CLI: {e}") | |
| return False | |
| def prepare_space_files(self) -> str: | |
| """Prepare all necessary files for the Space in a temporary directory""" | |
| try: | |
| print("Preparing Space files...") | |
| # Create temporary directory | |
| temp_dir = tempfile.mkdtemp() | |
| print(f"Created temporary directory: {temp_dir}") | |
| # Get the project root directory (3 levels up from this script) | |
| project_root = Path(__file__).parent.parent.parent | |
| templates_dir = project_root / "templates" / "spaces" | |
| # Files to copy from templates/spaces | |
| files_to_copy = [ | |
| "app.py", | |
| "requirements.txt", | |
| "README.md" | |
| ] | |
| # Copy files from templates/spaces to temp directory | |
| copied_files = [] | |
| for file_name in files_to_copy: | |
| source_path = templates_dir / file_name | |
| dest_path = Path(temp_dir) / file_name | |
| if source_path.exists(): | |
| shutil.copy2(source_path, dest_path) | |
| copied_files.append(file_name) | |
| print(f"β Copied {file_name} to temp directory") | |
| else: | |
| print(f"β οΈ File not found: {source_path}") | |
| # Update README.md with actual space URL | |
| readme_path = Path(temp_dir) / "README.md" | |
| if readme_path.exists(): | |
| with open(readme_path, 'r', encoding='utf-8') as f: | |
| readme_content = f.read() | |
| # Replace placeholder with actual space URL | |
| readme_content = readme_content.replace("{SPACE_URL}", self.space_url) | |
| with open(readme_path, 'w', encoding='utf-8') as f: | |
| f.write(readme_content) | |
| print(f"β Updated README.md with space URL") | |
| print(f"β Prepared {len(copied_files)} files in temporary directory") | |
| return temp_dir | |
| except Exception as e: | |
| print(f"β Error preparing files: {e}") | |
| return None | |
| def upload_files_to_space(self, temp_dir: str) -> bool: | |
| """Upload files to the Space using git""" | |
| try: | |
| print("Uploading files to Space...") | |
| # Change to temp directory | |
| original_dir = os.getcwd() | |
| os.chdir(temp_dir) | |
| # Initialize git repository | |
| subprocess.run(["git", "init"], check=True, capture_output=True) | |
| subprocess.run(["git", "remote", "add", "origin", f"https://huggingface.co/spaces/{self.username}/{self.space_name}"], check=True, capture_output=True) | |
| # Configure git user identity for this repository | |
| # Get git config from the original directory or use defaults | |
| try: | |
| # Try to get existing git config | |
| result = subprocess.run(["git", "config", "--global", "user.email"], capture_output=True, text=True) | |
| if result.returncode == 0 and result.stdout.strip(): | |
| git_email = result.stdout.strip() | |
| else: | |
| git_email = self.git_email | |
| result = subprocess.run(["git", "config", "--global", "user.name"], capture_output=True, text=True) | |
| if result.returncode == 0 and result.stdout.strip(): | |
| git_name = result.stdout.strip() | |
| else: | |
| git_name = self.git_name | |
| except Exception: | |
| # Fallback to default values | |
| git_email = self.git_email | |
| git_name = self.git_name | |
| # Set git config for this repository | |
| subprocess.run(["git", "config", "user.email", git_email], check=True, capture_output=True) | |
| subprocess.run(["git", "config", "user.name", git_name], check=True, capture_output=True) | |
| print(f"β Configured git with email: {git_email}, name: {git_name}") | |
| # Add all files | |
| subprocess.run(["git", "add", "."], check=True, capture_output=True) | |
| subprocess.run(["git", "commit", "-m", "Initial Trackio Space setup"], check=True, capture_output=True) | |
| # Push to the space | |
| try: | |
| subprocess.run(["git", "push", "origin", "main"], check=True, capture_output=True) | |
| print("β Pushed to main branch") | |
| except subprocess.CalledProcessError: | |
| # Try pushing to master branch if main doesn't exist | |
| subprocess.run(["git", "push", "origin", "master"], check=True, capture_output=True) | |
| print("β Pushed to master branch") | |
| # Return to original directory | |
| os.chdir(original_dir) | |
| return True | |
| except Exception as e: | |
| print(f"β Error uploading files: {e}") | |
| # Return to original directory | |
| os.chdir(original_dir) | |
| return False | |
| def test_space(self) -> bool: | |
| """Test if the Space is working correctly""" | |
| try: | |
| print("Testing Space...") | |
| # Wait a bit for the space to build | |
| import time | |
| print("Waiting 180 seconds for Space to build...") | |
| time.sleep(180) | |
| # Try to access the space | |
| response = requests.get(self.space_url, timeout=30) | |
| if response.status_code == 200: | |
| print(f"β Space is accessible: {self.space_url}") | |
| return True | |
| else: | |
| print(f"β οΈ Space returned status code: {response.status_code}") | |
| print(f"Response: {response.text[:500]}...") | |
| return False | |
| except Exception as e: | |
| print(f"β Error testing space: {e}") | |
| return False | |
| def deploy(self) -> bool: | |
| """Complete deployment process""" | |
| print("π Starting Trackio Space deployment...") | |
| # Step 1: Create space | |
| if not self.create_space(): | |
| return False | |
| # Step 2: Prepare files | |
| temp_dir = self.prepare_space_files() | |
| if not temp_dir: | |
| return False | |
| # Step 3: Upload files | |
| if not self.upload_files_to_space(temp_dir): | |
| return False | |
| # Step 4: Clean up temp directory | |
| try: | |
| shutil.rmtree(temp_dir) | |
| print("β Cleaned up temporary directory") | |
| except Exception as e: | |
| print(f"β οΈ Warning: Could not clean up temp directory: {e}") | |
| # Step 5: Test space | |
| if not self.test_space(): | |
| print("β οΈ Space created but may need more time to build") | |
| print("Please check the Space manually in a few minutes") | |
| print(f"π Deployment completed!") | |
| print(f"π Trackio Space URL: {self.space_url}") | |
| print(f"π§ Space configuration: {self.space_url}/settings") | |
| return True | |
| def main(): | |
| """Main deployment function""" | |
| print("Trackio Space Deployment Script") | |
| print("=" * 40) | |
| # Get user input | |
| username = input("Enter your Hugging Face username: ").strip() | |
| space_name = input("Enter Space name (e.g., trackio-monitoring): ").strip() | |
| token = input("Enter your Hugging Face token: ").strip() | |
| # Get git configuration (optional) | |
| git_email = input("Enter your git email (optional, press Enter for default): ").strip() | |
| git_name = input("Enter your git name (optional, press Enter for default): ").strip() | |
| if not username or not space_name or not token: | |
| print("β Username, Space name, and token are required") | |
| sys.exit(1) | |
| # Use empty strings if not provided | |
| if not git_email: | |
| git_email = None | |
| if not git_name: | |
| git_name = None | |
| # Create deployer | |
| deployer = TrackioSpaceDeployer(space_name, username, token, git_email, git_name) | |
| # Run deployment | |
| success = deployer.deploy() | |
| if success: | |
| print("\nβ Deployment successful!") | |
| print(f"π Your Trackio Space: {deployer.space_url}") | |
| print("\nNext steps:") | |
| print("1. Wait for the Space to build (usually 2-5 minutes)") | |
| print("2. Test the interface by visiting the Space URL") | |
| print("3. Use the Space URL in your training scripts") | |
| print("\nIf the Space doesn't work immediately, check:") | |
| print("- The Space logs at the Space URL") | |
| print("- That all files were uploaded correctly") | |
| print("- That the HF token has write permissions") | |
| else: | |
| print("\nβ Deployment failed!") | |
| print("Check the error messages above and try again.") | |
| print("\nTroubleshooting:") | |
| print("1. Verify your HF token has write permissions") | |
| print("2. Check that the space name is available") | |
| print("3. Try creating the space manually on HF first") | |
| if __name__ == "__main__": | |
| main() |