hf-train-frontend / update_space.py
George-API's picture
Upload folder using huggingface_hub
4a1fd53 verified
raw
history blame
8.53 kB
#!/usr/bin/env python
"""
Quick script to update your Hugging Face Space for phi-4-unsloth-bnb-4bit training.
This script handles the specific requirements for the 4-bit quantized Phi-4 model training,
including proper configuration and dependency management.
"""
import os
import sys
import json
import subprocess
import argparse
import logging
from pathlib import Path
from huggingface_hub import HfApi, login
import getpass
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger(__name__)
def load_env_variables():
"""Load environment variables from system or .env file."""
# First try to load from local .env file
try:
from dotenv import load_dotenv
env_path = Path(__file__).parent / ".env"
if env_path.exists():
# Load and explicitly set environment variables
with open(env_path) as f:
for line in f:
if line.strip() and not line.startswith('#'):
key, value = line.strip().split('=', 1)
os.environ[key] = value.strip()
logger.info(f"Loaded environment variables from {env_path}")
else:
logger.warning(f"No .env file found at {env_path}")
except ImportError:
logger.warning("python-dotenv not installed, skipping .env loading")
# Check if we're running in a Hugging Face Space
if os.environ.get("SPACE_ID"):
logger.info("Running in Hugging Face Space")
if "/" in os.environ.get("SPACE_ID", ""):
username = os.environ.get("SPACE_ID").split("/")[0]
os.environ["HF_USERNAME"] = username
logger.info(f"Set HF_USERNAME from SPACE_ID: {username}")
# Verify required variables
required_vars = {
"HF_TOKEN": os.environ.get("HF_TOKEN"),
"HF_USERNAME": os.environ.get("HF_USERNAME"),
"HF_SPACE_NAME": os.environ.get("HF_SPACE_NAME", "phi4training")
}
# Ensure the space name is set correctly
if "HF_SPACE_NAME" not in os.environ:
os.environ["HF_SPACE_NAME"] = "phi4training"
missing_vars = [k for k, v in required_vars.items() if not v]
if missing_vars:
raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}")
logger.info(f"Using environment variables: USERNAME={required_vars['HF_USERNAME']}, SPACE_NAME={required_vars['HF_SPACE_NAME']}")
return required_vars
def verify_configs():
"""Verify that all necessary configuration files exist and are valid."""
current_dir = Path(__file__).parent
required_files = [
"transformers_config.json",
"requirements.txt",
"run_transformers_training.py"
]
missing_files = []
for file in required_files:
if not (current_dir / file).exists():
missing_files.append(file)
if missing_files:
raise FileNotFoundError(f"Missing required files: {', '.join(missing_files)}")
# Verify JSON configs
json_files = [f for f in required_files if f.endswith('.json')]
for json_file in json_files:
try:
with open(current_dir / json_file) as f:
json.load(f)
logger.info(f"Verified {json_file} is valid JSON")
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON in {json_file}: {e}")
def update_requirements():
"""Update requirements.txt with necessary packages."""
current_dir = Path(__file__).parent
req_path = current_dir / "requirements.txt"
required_packages = {
"torch>=2.0.0",
"transformers>=4.36.0",
"accelerate>=0.27.0",
"bitsandbytes>=0.41.0",
"tensorboard>=2.15.0",
"gradio>=5.17.0",
"huggingface-hub>=0.19.0",
"datasets>=2.15.0"
}
# Read existing requirements
existing_requirements = set()
if req_path.exists():
with open(req_path) as f:
existing_requirements = {line.strip() for line in f if line.strip()}
# Add new requirements
updated_requirements = existing_requirements.union(required_packages)
# Write updated requirements
with open(req_path, 'w') as f:
for req in sorted(updated_requirements):
f.write(f"{req}\n")
logger.info("Updated requirements.txt with necessary packages")
def create_space(username, space_name):
"""Create or get a Hugging Face Space."""
try:
api = HfApi()
space_id = f"{username}/{space_name}"
logger.info(f"Checking Space {space_id}...")
# First try to get the space
try:
space_info = api.space_info(repo_id=space_id)
logger.info(f"Space {space_id} already exists")
return space_info
except Exception as e:
logger.info(f"Space {space_id} does not exist, creating new space...")
# Create new space
try:
api.create_repo(
repo_id=space_id,
private=False,
repo_type="space",
space_sdk="gradio"
)
logger.info(f"Created new space: {space_id}")
return api.space_info(repo_id=space_id)
except Exception as e:
logger.error(f"Failed to create space: {str(e)}")
raise
except Exception as e:
raise RuntimeError(f"Error with Space {space_id}: {str(e)}")
def main():
parser = argparse.ArgumentParser(description='Update Hugging Face Space for Phi-4 training')
parser.add_argument('--space_name', type=str, help='Space name (default: from env)')
parser.add_argument('--force', action='store_true', help='Skip confirmation')
args = parser.parse_args()
if not args.force:
print("\n" + "!"*80)
print("WARNING: Updating the Space will INTERRUPT any ongoing training!")
print("Make sure all checkpoints are saved before proceeding.")
print("!"*80 + "\n")
confirm = input("Type 'update' to confirm: ")
if confirm.lower() != 'update':
logger.info("Update cancelled")
return False
try:
# Load environment variables
env_vars = load_env_variables()
logger.info(f"Environment variables loaded: USERNAME={env_vars['HF_USERNAME']}, SPACE_NAME={env_vars['HF_SPACE_NAME']}")
# Verify configurations
verify_configs()
logger.info("All configuration files verified successfully")
# Update requirements
update_requirements()
logger.info("Requirements updated successfully")
# Get space name from args or env, prioritize args
space_name = args.space_name if args.space_name else env_vars["HF_SPACE_NAME"]
logger.info(f"Using space name: {space_name}")
# Login to Hugging Face
logger.info("Logging in to Hugging Face...")
login(token=env_vars["HF_TOKEN"])
logger.info("Successfully logged in to Hugging Face")
# Create/get space
space_info = create_space(env_vars["HF_USERNAME"], space_name)
logger.info(f"Space info: {space_info}")
# Upload files
current_dir = Path(__file__).parent
logger.info(f"Uploading files from {current_dir} to Space {env_vars['HF_USERNAME']}/{space_name}...")
# Create .gitignore
with open(current_dir / ".gitignore", "w") as f:
f.write(".env\n*.pyc\n__pycache__\n")
logger.info("Created .gitignore file")
api = HfApi()
api.upload_folder(
folder_path=str(current_dir),
repo_id=f"{env_vars['HF_USERNAME']}/{space_name}",
repo_type="space",
ignore_patterns=[".env", "*.pyc", "__pycache__", "TRAINING_IN_PROGRESS.lock"]
)
logger.info(f"Files uploaded successfully")
space_url = f"https://huggingface.co/spaces/{env_vars['HF_USERNAME']}/{space_name}"
logger.info(f"Space URL: {space_url}")
print(f"\nSpace created successfully! You can view it at:\n{space_url}")
return True
except Exception as e:
logger.error(f"Error updating Space: {str(e)}")
return False
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)