|
|
|
""" |
|
Helper script to deploy to Hugging Face Spaces. |
|
This script will help you set environment variables and deploy your app. |
|
""" |
|
import os |
|
import sys |
|
import subprocess |
|
import time |
|
from getpass import getpass |
|
from huggingface_hub import HfApi, SpaceHardware, SpaceStage |
|
|
|
def setup_deployment(): |
|
"""Set up deployment environment variables and authenticate.""" |
|
print("="*50) |
|
print("Hugging Face Spaces Deployment Setup") |
|
print("="*50) |
|
|
|
|
|
username = os.environ.get("HF_USERNAME") |
|
token = os.environ.get("HF_TOKEN") |
|
space_name = os.environ.get("SPACE_NAME") |
|
|
|
|
|
if not (username and token and space_name): |
|
username = input("Enter your Hugging Face username: ") |
|
token = getpass("Enter your Hugging Face token (from https://huggingface.co/settings/tokens): ") |
|
space_name = input("Enter your Space name (default: personal-rag-assistant): ") or "personal-rag-assistant" |
|
|
|
|
|
os.environ["HF_USERNAME"] = username |
|
os.environ["HF_TOKEN"] = token |
|
os.environ["SPACE_NAME"] = space_name |
|
|
|
|
|
with open(".env", "w") as f: |
|
f.write(f"HF_API_KEY={token}\n") |
|
f.write(f"HF_USERNAME={username}\n") |
|
f.write(f"SPACE_NAME={space_name}\n") |
|
f.write("LLM_MODEL=distilgpt2\n") |
|
f.write("EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2\n") |
|
f.write("VECTOR_DB_PATH=./data/vector_db\n") |
|
f.write("COLLECTION_NAME=personal_assistant\n") |
|
f.write("DEFAULT_TEMPERATURE=0.7\n") |
|
f.write("CHUNK_SIZE=512\n") |
|
f.write("CHUNK_OVERLAP=128\n") |
|
f.write("MAX_TOKENS=256\n") |
|
|
|
|
|
try: |
|
|
|
subprocess.run(["git", "config", "--global", "credential.helper", "store"], check=True) |
|
|
|
|
|
home_dir = os.path.expanduser("~") |
|
credentials_path = os.path.join(home_dir, ".git-credentials") |
|
|
|
|
|
credentials_exist = os.path.exists(credentials_path) |
|
|
|
with open(credentials_path, "a" if credentials_exist else "w") as f: |
|
f.write(f"https://{username}:{token}@huggingface.co\n") |
|
|
|
|
|
if sys.platform != "win32": |
|
os.chmod(credentials_path, 0o600) |
|
|
|
print("Git credentials configured for Hugging Face.") |
|
except Exception as e: |
|
print(f"Warning: Could not set up git credentials: {e}") |
|
print("You may need to enter your credentials manually during push.") |
|
|
|
print(f"\nEnvironment variables set for {username}/{space_name}") |
|
return username, token, space_name |
|
|
|
def create_space(username, token, space_name): |
|
"""Create a Hugging Face Space directly using the HfApi.""" |
|
print("\nCreating Hugging Face Space...") |
|
|
|
try: |
|
|
|
api = HfApi(token=token) |
|
|
|
|
|
try: |
|
spaces = api.list_spaces(author=username) |
|
exists = any(space.id == f"{username}/{space_name}" for space in spaces) |
|
if exists: |
|
print(f"Space {username}/{space_name} exists.") |
|
|
|
|
|
try: |
|
print("Updating Space configuration to use Docker...") |
|
api.update_space( |
|
repo_id=f"{username}/{space_name}", |
|
private=False, |
|
sdk="docker", |
|
hardware=SpaceHardware.CPU_BASIC |
|
) |
|
print("Space configuration updated.") |
|
except Exception as e: |
|
print(f"Note: Could not update space configuration: {e}") |
|
else: |
|
print(f"Space {username}/{space_name} does not exist. Creating...") |
|
|
|
api.create_space( |
|
name=space_name, |
|
organization=None, |
|
private=False, |
|
sdk="docker", |
|
hardware=SpaceHardware.CPU_BASIC, |
|
storage=1, |
|
sleep_time=3600, |
|
status=SpaceStage.RUNNING, |
|
) |
|
print(f"Space created successfully.") |
|
except Exception as e: |
|
print(f"Error checking/creating space: {e}") |
|
print("You may need to create the Space manually in the Hugging Face UI.") |
|
print(f"Visit: https://huggingface.co/spaces") |
|
return False |
|
|
|
print(f"Space URL: https://huggingface.co/spaces/{username}/{space_name}") |
|
return True |
|
except Exception as e: |
|
print(f"Error creating space: {e}") |
|
print("\nTrying to proceed anyway, as the space might already exist.") |
|
return True |
|
|
|
def prepare_git_push(username, space_name): |
|
"""Prepare git for pushing to Hugging Face Space.""" |
|
print("\nPreparing to push code to Hugging Face Space...") |
|
|
|
try: |
|
|
|
if not os.path.exists(".git"): |
|
subprocess.run(["git", "init"], check=True) |
|
print("Git repository initialized.") |
|
|
|
|
|
remote_url = f"https://huggingface.co/spaces/{username}/{space_name}" |
|
|
|
|
|
result = subprocess.run(["git", "remote"], capture_output=True, text=True) |
|
remotes = result.stdout.strip().split('\n') if result.stdout else [] |
|
|
|
print(f"Existing remotes: {remotes}") |
|
|
|
|
|
if "hf" not in remotes: |
|
|
|
print("Adding 'hf' remote...") |
|
try: |
|
add_result = subprocess.run(["git", "remote", "add", "hf", remote_url], capture_output=True, text=True) |
|
if add_result.returncode != 0: |
|
print(f"Error adding remote: {add_result.stderr}") |
|
return False |
|
print("Successfully added 'hf' remote") |
|
except Exception as e: |
|
print(f"Error adding remote: {e}") |
|
return False |
|
else: |
|
|
|
print("Updating 'hf' remote...") |
|
try: |
|
update_result = subprocess.run(["git", "remote", "set-url", "hf", remote_url], capture_output=True, text=True) |
|
if update_result.returncode != 0: |
|
print(f"Error updating remote: {update_result.stderr}") |
|
return False |
|
print("Successfully updated 'hf' remote") |
|
except Exception as e: |
|
print(f"Error updating remote: {e}") |
|
return False |
|
|
|
|
|
verify_remote = subprocess.run(["git", "remote", "-v"], capture_output=True, text=True) |
|
print(f"Remote verification: {verify_remote.stdout}") |
|
|
|
|
|
try: |
|
user_name = subprocess.run(["git", "config", "user.name"], capture_output=True, text=True).stdout.strip() |
|
user_email = subprocess.run(["git", "config", "user.email"], capture_output=True, text=True).stdout.strip() |
|
|
|
if not user_name or not user_email: |
|
|
|
name = input("Enter your name for git config: ") or username |
|
email = input("Enter your email for git config: ") or f"{username}@example.com" |
|
|
|
subprocess.run(["git", "config", "--global", "user.name", name], check=True) |
|
subprocess.run(["git", "config", "--global", "user.email", email], check=True) |
|
print("Git user configuration updated.") |
|
except subprocess.CalledProcessError: |
|
print("Warning: Could not check git user configuration.") |
|
|
|
|
|
subprocess.run(["git", "add", "."], check=True) |
|
try: |
|
subprocess.run(["git", "commit", "-m", "Update for Hugging Face Space deployment"], check=True) |
|
except subprocess.CalledProcessError: |
|
|
|
status = subprocess.run(["git", "status", "--porcelain"], capture_output=True, text=True, check=True).stdout.strip() |
|
if not status: |
|
print("No changes to commit.") |
|
else: |
|
print("Error making commit. Check git configuration.") |
|
return False |
|
|
|
print("\nGit repository prepared for pushing") |
|
except Exception as e: |
|
print(f"Error preparing git: {e}") |
|
return False |
|
|
|
return True |
|
|
|
def push_to_space(username, token): |
|
"""Push code to Hugging Face Space.""" |
|
print("\nPushing code to Hugging Face Space...") |
|
print("This may take a few minutes...") |
|
|
|
try: |
|
|
|
env = os.environ.copy() |
|
env["GIT_USERNAME"] = username |
|
env["GIT_PASSWORD"] = token |
|
|
|
|
|
env["HUGGINGFACEHUB_API_TOKEN"] = token |
|
|
|
|
|
current_branch = subprocess.run( |
|
["git", "branch", "--show-current"], |
|
capture_output=True, text=True |
|
).stdout.strip() |
|
|
|
if not current_branch: |
|
current_branch = "master" |
|
if not os.path.exists(".git/refs/heads/master"): |
|
current_branch = "main" |
|
|
|
|
|
print(f"Pushing from branch {current_branch} to main...") |
|
cmd = ["git", "push", "-f", "hf", f"{current_branch}:main"] |
|
|
|
print("\nRunning git push command...") |
|
print(f"Pushing to Space as user: {username}") |
|
|
|
|
|
methods = [ |
|
|
|
lambda: subprocess.run(cmd, check=True, env=env), |
|
|
|
|
|
lambda: subprocess.run( |
|
["git", "push", "-f", f"https://{username}:{token}@huggingface.co/spaces/{username}/{os.environ.get('SPACE_NAME')}", f"{current_branch}:main"], |
|
check=True, env=env |
|
), |
|
|
|
|
|
lambda: subprocess.run( |
|
["git", "push", "-f", "hf", f"{current_branch}:main"], |
|
check=True, env={**env, "HUGGINGFACE_TOKEN": token, "HF_TOKEN": token} |
|
) |
|
] |
|
|
|
success = False |
|
for i, method in enumerate(methods, 1): |
|
try: |
|
print(f"\nTrying push method {i}...") |
|
method() |
|
print(f"Push method {i} succeeded!") |
|
success = True |
|
break |
|
except subprocess.CalledProcessError as e: |
|
print(f"Push method {i} failed: {e}") |
|
if i < len(methods): |
|
print("Trying next method...") |
|
time.sleep(2) |
|
|
|
if success: |
|
print("\nCode pushed to Hugging Face Space successfully!") |
|
else: |
|
raise Exception("All push methods failed") |
|
|
|
|
|
print("\nWaiting for Space to start building...") |
|
time.sleep(5) |
|
|
|
print(f"\nYour Space will be available at: https://huggingface.co/spaces/{username}/{os.environ.get('SPACE_NAME')}") |
|
print("It may take a few minutes for the Space to build and start.") |
|
return True |
|
|
|
except Exception as e: |
|
print(f"Error pushing code: {e}") |
|
print("\nTroubleshooting git push issues:") |
|
print("1. Ensure your Hugging Face token has write access") |
|
print("2. Try manually setting up git credentials:") |
|
print(f" git config --global credential.helper store") |
|
print(f" echo 'https://{username}:{token}@huggingface.co' > ~/.git-credentials") |
|
print("3. Try pushing directly with:") |
|
print(f" git push -f https://{username}:{token}@huggingface.co/spaces/{username}/{os.environ.get('SPACE_NAME')} main") |
|
return False |
|
|
|
return True |
|
|
|
def main(): |
|
"""Main entry point for the deployment script.""" |
|
print("Hugging Face Space Deployment Script") |
|
print("="*50) |
|
print("This script will help you deploy your app to Hugging Face Spaces.") |
|
|
|
try: |
|
|
|
username, token, space_name = setup_deployment() |
|
|
|
|
|
if not create_space(username, token, space_name): |
|
print("Error creating Space. Please check your credentials and try again.") |
|
sys.exit(1) |
|
|
|
|
|
if not prepare_git_push(username, space_name): |
|
print("Error preparing git repository. Please check your git configuration and try again.") |
|
sys.exit(1) |
|
|
|
|
|
if not push_to_space(username, token): |
|
print("Error pushing to Space. Please check the logs and try again.") |
|
sys.exit(1) |
|
|
|
print("\nDeployment complete!") |
|
print(f"Your app is now available at: https://huggingface.co/spaces/{username}/{space_name}") |
|
print("\nNote: It may take a few minutes for the Space to build and start.") |
|
print("If your app is not showing up properly, check the Space logs in the Hugging Face UI.") |
|
print("Common issues:") |
|
print("1. Permission errors - check that cache directories have proper permissions") |
|
print("2. Model loading errors - try using a smaller model") |
|
print("3. Port configuration - ensure app is running on port 7860") |
|
except KeyboardInterrupt: |
|
print("\nDeployment interrupted by user.") |
|
sys.exit(1) |
|
except Exception as e: |
|
print(f"\nUnexpected error: {e}") |
|
sys.exit(1) |
|
|
|
if __name__ == "__main__": |
|
main() |