Spaces:
Runtime error
Runtime error
from __future__ import annotations | |
import os | |
import re | |
from typing import Annotated, Optional | |
import huggingface_hub | |
from rich import print | |
from typer import Option | |
import gradio as gr | |
repo_directory = os.getcwd() | |
readme_file = os.path.join(repo_directory, "README.md") | |
github_action_template = os.path.join( | |
os.path.dirname(__file__), "deploy_space_action.yaml" | |
) | |
def add_configuration_to_readme( | |
title: str | None, | |
app_file: str | None, | |
) -> dict: | |
configuration = {} | |
dir_name = os.path.basename(repo_directory) | |
if title is None: | |
title = input(f"Enter Spaces app title [{dir_name}]: ") or dir_name | |
formatted_title = format_title(title) | |
if formatted_title != title: | |
print(f"Formatted to {formatted_title}. ") | |
configuration["title"] = formatted_title | |
if app_file is None: | |
for file in os.listdir(repo_directory): | |
file_path = os.path.join(repo_directory, file) | |
if not os.path.isfile(file_path) or not file.endswith(".py"): | |
continue | |
with open(file_path, encoding="utf-8", errors="ignore") as f: | |
content = f.read() | |
if "import gradio" in content: | |
app_file = file | |
break | |
app_file = ( | |
input(f"Enter Gradio app file {f'[{app_file}]' if app_file else ''}: ") | |
or app_file | |
) | |
if not app_file or not os.path.exists(app_file): | |
raise FileNotFoundError("Failed to find Gradio app file.") | |
configuration["app_file"] = app_file | |
configuration["sdk"] = "gradio" | |
configuration["sdk_version"] = gr.__version__ | |
huggingface_hub.metadata_save(readme_file, configuration) | |
configuration["hardware"] = ( | |
input( | |
f"Enter Spaces hardware ({', '.join(hardware.value for hardware in huggingface_hub.SpaceHardware)}) [cpu-basic]: " | |
) | |
or "cpu-basic" | |
) | |
secrets = {} | |
if input("Any Spaces secrets (y/n) [n]: ") == "y": | |
while True: | |
secret_name = input("Enter secret name (leave blank to end): ") | |
if not secret_name: | |
break | |
secret_value = input(f"Enter secret value for {secret_name}: ") | |
secrets[secret_name] = secret_value | |
configuration["secrets"] = secrets | |
requirements_file = os.path.join(repo_directory, "requirements.txt") | |
if ( | |
not os.path.exists(requirements_file) | |
and input("Create requirements.txt file? (y/n) [n]: ").lower() == "y" | |
): | |
while True: | |
requirement = input("Enter a dependency (leave blank to end): ") | |
if not requirement: | |
break | |
with open(requirements_file, "a", encoding="utf-8") as f: | |
f.write(requirement + "\n") | |
if ( | |
input( | |
"Create Github Action to automatically update Space on 'git push'? [n]: " | |
).lower() | |
== "y" | |
): | |
track_branch = input("Enter branch to track [main]: ") or "main" | |
github_action_file = os.path.join( | |
repo_directory, ".github/workflows/update_space.yml" | |
) | |
os.makedirs(os.path.dirname(github_action_file), exist_ok=True) | |
with open(github_action_template, encoding="utf-8") as f: | |
github_action_content = f.read() | |
github_action_content = github_action_content.replace("$branch", track_branch) | |
with open(github_action_file, "w", encoding="utf-8") as f: | |
f.write(github_action_content) | |
print( | |
"Github Action created. Add your Hugging Face write token (from https://huggingface.co/settings/tokens) as an Actions Secret named 'hf_token' to your GitHub repository. This can be set in your repository's settings page." | |
) | |
return configuration | |
def format_title(title: str): | |
title = title.replace(" ", "_") | |
title = re.sub(r"[^a-zA-Z0-9\-._]", "", title) | |
title = re.sub("-+", "-", title) | |
while title.startswith("."): | |
title = title[1:] | |
return title | |
def deploy( | |
title: Annotated[Optional[str], Option(help="Spaces app title")] = None, | |
app_file: Annotated[ | |
Optional[str], Option(help="File containing the Gradio app") | |
] = None, | |
): | |
if ( | |
os.getenv("SYSTEM") == "spaces" | |
): # in case a repo with this function is uploaded to spaces | |
return | |
hf_api = huggingface_hub.HfApi() | |
whoami = None | |
login = False | |
try: | |
whoami = hf_api.whoami() | |
if whoami["auth"]["accessToken"]["role"] != "write": | |
login = True | |
except OSError: | |
login = True | |
if login: | |
print("Need 'write' access token to create a Spaces repo.") | |
huggingface_hub.login(add_to_git_credential=False) | |
whoami = hf_api.whoami() | |
configuration: None | dict = None | |
if os.path.exists(readme_file): | |
try: | |
configuration = huggingface_hub.metadata_load(readme_file) | |
except ValueError: | |
pass | |
if configuration is None: | |
print( | |
f"Creating new Spaces Repo in '{repo_directory}'. Collecting metadata, press Enter to accept default value." | |
) | |
configuration = add_configuration_to_readme( | |
title, | |
app_file, | |
) | |
space_id = huggingface_hub.create_repo( | |
configuration["title"], | |
space_sdk="gradio", | |
repo_type="space", | |
exist_ok=True, | |
space_hardware=configuration.get("hardware"), | |
).repo_id | |
hf_api.upload_folder( | |
repo_id=space_id, | |
repo_type="space", | |
folder_path=repo_directory, | |
) | |
if configuration.get("secrets"): | |
for secret_name, secret_value in configuration["secrets"].items(): | |
huggingface_hub.add_space_secret(space_id, secret_name, secret_value) | |
print(f"Space available at https://huggingface.co/spaces/{space_id}") | |