Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Push to spaces #4033

Merged
merged 40 commits into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
616d259
changes
aliabid94 Apr 28, 2023
23e27ec
first commit
aliabid94 May 2, 2023
ebc5307
Update gradio/upload.py
aliabid94 May 9, 2023
17f4550
Update gradio/upload.py
aliabid94 May 9, 2023
9679c51
changes
aliabid94 May 12, 2023
b6bd159
Merge branch 'main' into push_to_spaces
aliabid94 May 12, 2023
8280da5
changes
aliabid94 May 12, 2023
482b580
Merge branch 'push_to_spaces' of https://github.com/gradio-app/gradio…
aliabid94 May 12, 2023
f19e150
changes
aliabid94 May 12, 2023
05bca13
changes
aliabid94 May 12, 2023
ed8147f
changes
aliabid94 May 12, 2023
f7858b9
changes
aliabid94 May 12, 2023
bf326a6
changes
aliabid94 May 12, 2023
17d5fff
chnages
aliabid94 May 12, 2023
bc1ff14
changes
aliabid94 May 12, 2023
c28867a
changes
aliabid94 May 12, 2023
dc6996d
changes
aliabid94 May 16, 2023
e1fa083
merge conflict
aliabid94 May 16, 2023
a64d34d
changes
aliabid94 May 16, 2023
188a869
chnages
aliabid94 May 16, 2023
1b43bb3
Update 03_sharing-your-app.md
aliabid94 May 16, 2023
d90815e
changes
aliabid94 May 16, 2023
764a173
Merge branch 'push_to_spaces' of https://github.com/gradio-app/gradio…
aliabid94 May 16, 2023
507a2aa
Merge branch 'main' into push_to_spaces
aliabid94 May 16, 2023
1b9d13c
Merge branch 'main' into push_to_spaces
aliabid94 May 17, 2023
65cfa57
Merge branch 'main' into push_to_spaces
abidlabs May 17, 2023
2aea05a
changes
aliabid94 May 17, 2023
a628ada
Merge branch 'main' into push_to_spaces
aliabid94 May 17, 2023
3b37451
merge
aliabid94 May 23, 2023
b6cd32d
change
aliabid94 May 26, 2023
355d9eb
changes
aliabid94 May 30, 2023
4403d5d
changes
aliabid94 May 30, 2023
11dbc38
changes
aliabid94 May 30, 2023
58e1f6b
changes
aliabid94 May 30, 2023
615ce72
Merge branch 'main' into push_to_spaces
abidlabs May 30, 2023
c3ea7d8
Update gradio/deploy_space.py
aliabid94 May 31, 2023
397d4a1
changes
aliabid94 May 31, 2023
efec556
Merge remote-tracking branch 'origin' into push_to_spaces
aliabid94 May 31, 2023
839d17a
changes
aliabid94 May 31, 2023
19ae624
changes
aliabid94 May 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## New Features:

No changes to highlight.
- Introduced `gradio --deploy` to launch a Gradio app to Spaces directly from your terminal (or `gr.deploy()` if running from a python script / notebook). By [@aliabid94](https://github.com/aliabid94) in [PR 4033](https://github.com/gradio-app/gradio/pull/4033).


## Bug Fixes:

Expand Down
1 change: 1 addition & 0 deletions gradio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
Video,
component,
)
from gradio.deploy_space import deploy
from gradio.events import SelectData
from gradio.exceptions import Error
from gradio.external import load
Expand Down
14 changes: 14 additions & 0 deletions gradio/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import sys

import gradio.deploy_space
import gradio.reload


def cli():
args = sys.argv[1:]
if len(args) == 0:
raise ValueError("No file specified.")
if args[0] == "--deploy":
aliabid94 marked this conversation as resolved.
Show resolved Hide resolved
gradio.deploy_space.deploy()
else:
gradio.reload.run_in_reload_mode(*args)
abidlabs marked this conversation as resolved.
Show resolved Hide resolved
183 changes: 183 additions & 0 deletions gradio/deploy_space.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
from __future__ import annotations

import json
import os
import random
import re

import huggingface_hub


def add_configuration_to_readme(repo_directory, readme_file) -> dict:
configuration = {}

dir_name = os.path.basename(repo_directory)
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

app_file = 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") and not file.endswith(".ipynb")
):
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.")
if app_file.endswith(".ipynb"):
configuration["notebook_file"] = app_file
app_file = "_" + configuration["notebook_file"].replace(".ipynb", ".py")
configuration["app_file"] = app_file

emoji_set = "🤯🤖🧠🐶👑💥🐮🎁🐙🦋"
default_emoji = random.choice(emoji_set)
configuration["emoji"] = (
input(f"Enter Spaces Card emoji [{default_emoji}]: ") or default_emoji
)

color_set = ["red", "yellow", "green", "blue", "indigo", "purple", "pink", "gray"]
default_color = random.choice(color_set)
color = input(f"Enter Spaces Card color [{default_color}]: ") or default_color
configuration["colorFrom"] = color
aliabid94 marked this conversation as resolved.
Show resolved Hide resolved
configuration["colorTo"] = color
configuration["sdk"] = "gradio"
huggingface_hub.metadata_save(readme_file, configuration)
Copy link
Member

@abidlabs abidlabs May 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throws an error on Windows: UnicodeEncodeError: 'charmap' codec can't encode character '\U0001f916' in position 46: character maps to <undefined>

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The huggingface_hub.metadata_save line? Can you file an issue on https://github.com/huggingface/huggingface_hub/

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks 🙏 Merging it :)


configuration["hardware"] = (
aliabid94 marked this conversation as resolved.
Show resolved Hide resolved
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"
):
input(
"Created requirements.txt file. Please add any dependencies to this file now. Press enter to continue. "
)

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 notebook_to_script(notebook_path, script_path):
aliabid94 marked this conversation as resolved.
Show resolved Hide resolved
print(f"Converting {notebook_path} to {script_path}.")
with open(notebook_path, encoding="utf-8") as f:
notebook = json.load(f)
import_subprocess = False
script_content = []

for cell in notebook["cells"]:
if cell["cell_type"] == "code":
for line in cell["source"]:
spaces = ""
if line.startswith(" ") or line.startswith("\t"):
spaces = line[: len(line) - len(line.lstrip())]
line = line.strip()
elif line.startswith("%"):
continue
elif line.startswith("!"):
command = line[1:].rstrip()
subprocess_call = f"subprocess.run('{command}', shell=True, check=True, text=True)"
script_content.append(spaces + subprocess_call)
import_subprocess = True
else:
script_content.append(spaces + line)

script_content.append("\n")

if import_subprocess:
script_content.insert(0, "import subprocess\n")

script = "".join(script_content)
with open(script_path, "w", encoding="utf-8") as f:
f.write(script)


def deploy():
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()

repo_directory = os.getcwd()
readme_file = os.path.join(repo_directory, "README.md")
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(repo_directory, readme_file)
if configuration.get("notebook_file"):
notebook_to_script(configuration["notebook_file"], configuration["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}")
9 changes: 1 addition & 8 deletions gradio/reload.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,13 @@
"""
import inspect
import os
import sys
from pathlib import Path

import gradio
from gradio import networking, utils


def run_in_reload_mode():
args = sys.argv[1:]
if len(args) == 0:
raise ValueError("No file specified.")
demo_name = "demo" if len(args) == 1 else args[1]

original_path = args[0]
def run_in_reload_mode(original_path, demo_name="demo"):
abs_original_path = utils.abspath(original_path)
path = os.path.normpath(original_path)
path = path.replace("/", ".")
Expand Down
2 changes: 1 addition & 1 deletion gradio/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"To turn off, set debug=False in launch().",
"COLAB_DEBUG_FALSE": "Colab notebook detected. To show errors in colab notebook, set debug=True in launch()",
"COLAB_WARNING": "Note: opening Chrome Inspector may crash demo inside Colab notebooks.",
"SHARE_LINK_MESSAGE": "\nThis share link expires in 72 hours. For free permanent hosting and GPU upgrades (NEW!), check out Spaces: https://huggingface.co/spaces",
"SHARE_LINK_MESSAGE": "\nThis share link expires in 72 hours. For free permanent hosting and GPU upgrades, run `gradio --deploy` to deploy to Spaces (https://huggingface.co/spaces)",
"INLINE_DISPLAY_BELOW": "Interface loading below...",
"TIPS": [
"You can add authentication to your app with the `auth=` kwarg in the `launch()` command; for example: `gr.Interface(...).launch(auth=('username', 'password'))`",
Expand Down
5 changes: 4 additions & 1 deletion guides/01_getting-started/03_sharing-your-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ Share links expire after 72 hours.

If you'd like to have a permanent link to your Gradio demo on the internet, use Hugging Face Spaces. [Hugging Face Spaces](http://huggingface.co/spaces/) provides the infrastructure to permanently host your machine learning model for free!

You can either drag and drop a folder containing your Gradio model and all related files, or you can point Spaces to your Git repository and Spaces will pull the Gradio app from there. See [this guide how to host on Hugging Face Spaces](https://huggingface.co/blog/gradio-spaces) for more information.
After you have [created a free Hugging Face account](https://huggingface.co/join), you have three methods to deploy your Gradio app to Hugging Face Spaces:
1. From terminal: run `gradio --deploy` in your app directory. The CLI will gather some basic metadata and then launch your app. (Use `gr.deploy()` from a python script or notebook instead.) Whenever you update your app, just run this command again.
2. From your browser: Drag and drop a folder containing your Gradio model and all related files [here](https://huggingface.co/new-space).
3. Connect Spaces with your Git repository and Spaces will pull the Gradio app from there. See [this guide how to host on Hugging Face Spaces](https://huggingface.co/blog/gradio-spaces) for more information.

<video autoplay muted loop>
<source src="/assets/guides/hf_demo.mp4" type="video/mp4" />
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ authors = [
keywords = ["machine learning", "reproducibility", "visualization"]

[project.scripts]
gradio = "gradio.reload:run_in_reload_mode"
gradio = "gradio.cli:cli"
upload_theme = "gradio.themes.upload_theme:main"

[project.urls]
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ fastapi
ffmpy
gradio_client>=0.2.4
httpx
huggingface_hub>=0.13.0
huggingface_hub>=0.14.0
Jinja2
markdown-it-py[linkify]>=2.0.0
pygments>=2.12.0
Expand Down
2 changes: 1 addition & 1 deletion test/requirements-37.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ httpx==0.23.0
# via
# -r requirements.in
# respx
huggingface-hub==0.13.0
huggingface-hub==0.14.0
# via
# -r requirements.in
# transformers
Expand Down
2 changes: 1 addition & 1 deletion test/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ httpx==0.23.0
# via
# -r requirements.in
# respx
huggingface-hub==0.13.0
huggingface-hub==0.14.0
# via
# -r requirements.in
# transformers
Expand Down
6 changes: 3 additions & 3 deletions test/test_reload.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
from unittest.mock import patch

import gradio
from gradio.reload import run_in_reload_mode
from gradio.cli import cli


@patch("gradio.reload.os.system")
@patch("gradio.reload.sys")
@patch("gradio.cli.sys")
def test_run_in_reload_mode(mock_sys, mock_system_call):

mock_sys.argv = ["gradio", "demo/calculator/run.py"]
run_in_reload_mode()
cli()
reload_command = mock_system_call.call_args[0][0]
gradio_dir = Path(gradio.__file__).parent
demo_dir = Path("demo/calculator/run.py").resolve().parent
Expand Down