Skip to content

Commit

Permalink
minor changes
Browse files Browse the repository at this point in the history
  • Loading branch information
FrancescoSaverioZuppichini committed Nov 21, 2022
1 parent 9e9ff16 commit 2ed46be
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 35 deletions.
34 changes: 28 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Under the hood we are using docker and [nvidia pytorch containers](https://catal

Since hugging face doesn't distribute the docker image used in their spaces, a lot of spaces won't work due to broken links or stuff like that.

This project aims to provide transparent and real open machine learning demo to the people.
This project aims to provide transparent and real open machine learning demo to the people. If something doesn't work please feel free to open an issue :)

Contributions are welcomed!

## Getting Started

Expand All @@ -22,17 +24,37 @@ TODO

## Run a space!

You need to get the hub token

### From a git repo url
```bash
my-spaces run https://huggingface.co/spaces/sabre-code/Flower-Classification
export HUGGING_FACE_HUB_TOKEN=<YOUR_HUGGING_FACE_HUB_TOKEN>
my-spaces run https://huggingface.co/spaces/Francesco/stable-diffusion
```
Output
```
INFO:root:🚀 Running ...
INFO:root:🐋 Log from container:
Downloading: 100%|██████████| 543/543 [00:00<00:00, 294kB/s]B/s]
Downloading: 100%|██████████| 342/342 [00:00<00:00, 277kB/s] ?it/s]
Downloading: 100%|██████████| 4.63k/4.63k [00:00<00:00, 3.51MB/s] 1.20s/it]
```
After a while, open up `http://localhost:7860/` if it was a gradio app, or `http://localhost:8501/` if it was a stremlit app

**The generated Dockerfiles will be inside `~/.my-spaces`**
![alt](demo.jpeg)

**The generated Dockerfile will be inside `~/.my-spaces/dockerfiles`**


For each space, we create an docker image, build and run a container

## Hub
All images use the `my-space` name and the repo name as `tag`. For example, using following space (that doesn't work on hugging face space gods only know why) `https://huggingface.co/spaces/Francesco/stable-diffusion` we will create an image named `my-spaces:stable-diffusion`.

### From Docker hub

I've personally build and distributed the following images
I've personally [built and distributed the following images](https://hub.docker.com/repository/docker/zuppif/my-spaces), you run them by

TODO table
```
export HUGGING_FACE_HUB_TOKEN=<YOUR_HUGGING_FACE_HUB_TOKEN>
my-spaces run zuppif/my-spaces:stable-diffusion
```
Binary file added demo.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 47 additions & 27 deletions my_spaces/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
logging.basicConfig(level=logging.INFO)

app = typer.Typer()
ORGANIZATION = "zuppif"


@dataclass
Expand All @@ -30,41 +31,40 @@ def __post_init__(self):
@dataclass
class LocalSpace:
client: docker.DockerClient
repo_url: str
image: str
tag: str

def __post_init__(self):
# get the name from the url
self.organizaion = "my-space"
self.name = Path(self.repo_url).parts[-1]
self.image = f"my-space:{self.name}"
self.container = self.maybe_find_container()

def maybe_find_container(self) -> Optional[Container]:
containers: List[Container] = self.client.containers.list(all=True)
for container in containers:
tags = container.image.tags
for tag in tags:
if tag == self.image:
if tag == f"{self.image}:{self.tag}":
return container

def build_dockerfile(self, template_path: Path, out_dir: Path) -> Path:
def build_dockerfile(
self, repo_url: str, template_path: Path, out_dir: Path
) -> Path:
with template_path.open("r") as f:
template = Template(f.read())
template_out_path = out_dir / f"Dockerfile.{self.name}"
template_out_path.write_text(template.render(dict(repo_url=self.repo_url)))
template_out_path = out_dir / f"Dockerfile.{self.tag}"
template_out_path.write_text(template.render(dict(repo_url=repo_url)))
return template_out_path

def build(self, template_path: Path, out_dir: Path):
dockerfile_path = self.build_dockerfile(template_path, out_dir)
def build(self, repo_url: str, template_path: Path, out_dir: Path):
dockerfile_path = self.build_dockerfile(repo_url, template_path, out_dir)
with dockerfile_path.open("rb") as f:
image, logs = self.client.images.build(
path=str(out_dir), fileobj=f, tag=self.image
path=str(out_dir), fileobj=f, tag=f"{self.image}:{self.tag}"
)
return self

def run(self):
container: Container = self.client.containers.run(
self.image,
f"{self.image}:{self.tag}",
detach=True,
environment={"HUGGING_FACE_HUB_TOKEN": environ["HUGGING_FACE_HUB_TOKEN"]},
ipc_mode="host",
Expand All @@ -89,6 +89,12 @@ def start(self, force_run: bool = False):
self.container = self.run()
return self.container

@classmethod
def from_repo_url(cls, repo_url: str, client: docker.DockerClient):
tag = Path(repo_url).parts[-1]
image = f"my-spaces"
return cls(client, image, tag)


@dataclass
class LocalSpaces:
Expand All @@ -105,17 +111,27 @@ def __post_init__(self):
)
self.client = docker.from_env()

def run(self, repo_url: str, force_run: bool = False):
self.space = LocalSpace(self.client, repo_url)
images: dict[str, Image] = {}
# let's check if we had build it before
for image in self.client.images.list():
for tag in image.tags:
images[tag] = image
if not self.space.image in images:
logging.info(f"🔨 Building {self.space.name} ...")
self.space.build(self.template_path, self.folder.dockerfiles_root)
logging.info("🔨 Done! ")
def run(self, idenfitier: str, force_run: bool = False):
is_image_link = "zuppif/" in idenfitier
if is_image_link:
# in this case, we just pull it
image, tag = idenfitier.split(":")
self.client.images.pull(image, tag=tag)
self.space = LocalSpace(self.client, image, tag)
else:
# identifier must be a link to a girhub repo, so we create the image
self.space = LocalSpace.from_repo_url(idenfitier, self.client)
images: dict[str, Image] = {}
# let's check if we had build it before
for image in self.client.images.list():
for tag in image.tags:
images[tag] = image
if not self.space.image in images:
logging.info(f"🔨 Building {self.space.image}:{self.space.tag} ...")
self.space.build(
idenfitier, self.template_path, self.folder.dockerfiles_root
)
logging.info("🔨 Done! ")
logging.info("🚀 Running ...")
container = self.space.start(force_run)
logging.info("🐋 Log from container: ")
Expand All @@ -128,7 +144,9 @@ def stop(self):
logging.info("👋 Done! ")

def list(self) -> List[str]:
images: List[Image] = self.client.images.list(name="my-space")
images: List[Image] = self.client.images.list(name=f"{ORGANIZATION}/my-spaces")
local_images: List[Image] = self.client.images.list(name=f"my-spaces")
images += local_images
# tags is my-space:asdsadsadas
return [image.tags[0].split(":")[-1] for image in images]

Expand All @@ -142,21 +160,23 @@ def list():

@app.command()
def run(
repo_url: str,
identifier: str,
force_run: bool = typer.Option(
default=False,
help="Will remove the previous container and re-run it from scratch. Useful if something went wrong (e.g. you hit ctrl+c while it was downloading stuff.",
),
):
try:
local_spaces = LocalSpaces(LocalSpaceFolder())
local_spaces.run(repo_url, force_run)
local_spaces.run(identifier, force_run)
except KeyboardInterrupt:
local_spaces.stop()
sys.exit()


def main():
app()


if __name__ == "__main__":
main()
6 changes: 4 additions & 2 deletions my_spaces/templates/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ EXPOSE 7860 8501
RUN apt update && apt install -y git-lfs ffmpeg libsm6 libxext6 cmake libgl1-mesa-glx \
&& rm -rf /var/lib/apt/lists/*
RUN git lfs install
WORKDIR /space
WORKDIR /home/user
WORKDIR /home/user/app
# we will reinstall pillow using pillow-smid, for better performances
RUN pip uninstall -y pillow \
&& pip install -U --force-reinstall pillow-simd
RUN pip install streamlit==1.10.0 "protobuf<4" "click<8.1" gradio==3.10.1 datasets huggingface_hub
RUN pip install "protobuf<4" "click<8.1" gradio datasets huggingface_hub ftfy GitPython
# clone user stuff
RUN git clone {{ repo_url }} .
RUN if [ -f "requirements.txt" ]; then pip install -r requirements.txt; fi;
RUN if [ -f "packages.txt" ]; then apt-get install $(grep -vE "^\s*#" packages.txt | tr "\n" " "); fi;
# some space had this error
# https://stackoverflow.com/questions/72706073/attributeerror-partially-initialized-module-cv2-has-no-attribute-gapi-wip-gs
# so we need to downgrade opencv
Expand Down

0 comments on commit 2ed46be

Please sign in to comment.