SmolFactory / scripts /trackio_tonic /deploy_trackio_space.py
Tonic's picture
attempts spaces fix
93c5e53 verified
raw
history blame
13.6 kB
#!/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()