File size: 5,867 Bytes
870ab6b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
from __future__ import annotations

import argparse
import os
import re

import huggingface_hub

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") 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) as f:
            github_action_content = f.read()
        github_action_content = github_action_content.replace("$branch", track_branch)
        with open(github_action_file, "w") 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():
    if (
        os.getenv("SYSTEM") == "spaces"
    ):  # in case a repo with this function is uploaded to spaces
        return
    parser = argparse.ArgumentParser(description="Deploy to Spaces")
    parser.add_argument("deploy")
    parser.add_argument("--title", type=str, help="Spaces app title")
    parser.add_argument("--app-file", type=str, help="File containing the Gradio app")

    args = parser.parse_args()

    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(
            args.title,
            args.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}")