feature: script for running imaginairy in the modal.com cloud
parent
76b6fa8b65
commit
9c48b749d8
@ -0,0 +1,117 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pathspec
|
||||||
|
|
||||||
|
|
||||||
|
def find_project_root(start_path):
|
||||||
|
"""
|
||||||
|
Traverse up from a starting path to find the project root.
|
||||||
|
|
||||||
|
The project root is identified by the presence of a '.git' directory inside it.
|
||||||
|
"""
|
||||||
|
current_path = Path(start_path)
|
||||||
|
|
||||||
|
while current_path != current_path.root:
|
||||||
|
if (current_path / ".git").is_dir():
|
||||||
|
return str(current_path)
|
||||||
|
|
||||||
|
if (current_path / ".hg").is_dir():
|
||||||
|
return current_path
|
||||||
|
|
||||||
|
if (current_path / "pyproject.toml").is_file():
|
||||||
|
return current_path
|
||||||
|
|
||||||
|
if (current_path / "setup.py").is_file():
|
||||||
|
return current_path
|
||||||
|
|
||||||
|
current_path = current_path.parent
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
ALWAYS_IGNORE = """
|
||||||
|
.git
|
||||||
|
__pycache__
|
||||||
|
.direnv
|
||||||
|
.eggs
|
||||||
|
.git
|
||||||
|
.hg
|
||||||
|
.mypy_cache
|
||||||
|
.nox
|
||||||
|
.tox
|
||||||
|
.venv
|
||||||
|
venv
|
||||||
|
.svn
|
||||||
|
.ipynb_checkpoints
|
||||||
|
_build
|
||||||
|
buck-out
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
__pypackages__
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def load_gitignore_spec_at_path(path):
|
||||||
|
gitignore_path = os.path.join(path, ".gitignore")
|
||||||
|
|
||||||
|
if os.path.exists(gitignore_path):
|
||||||
|
with open(gitignore_path, encoding="utf-8") as f:
|
||||||
|
patterns = f.read().split("\n")
|
||||||
|
patterns.extend(ALWAYS_IGNORE.split("\n"))
|
||||||
|
ignore_spec = pathspec.PathSpec.from_lines("gitwildmatch", patterns)
|
||||||
|
else:
|
||||||
|
ignore_spec = pathspec.PathSpec.from_lines("gitwildmatch", [])
|
||||||
|
return ignore_spec
|
||||||
|
|
||||||
|
|
||||||
|
def get_nonignored_file_paths(directory, gitignore_dict=None, extensions=()):
|
||||||
|
return_relative = False
|
||||||
|
if gitignore_dict is None:
|
||||||
|
gitignore_dict = {}
|
||||||
|
return_relative = True
|
||||||
|
gitignore_dict = {
|
||||||
|
**gitignore_dict,
|
||||||
|
directory: load_gitignore_spec_at_path(directory),
|
||||||
|
}
|
||||||
|
|
||||||
|
file_paths = []
|
||||||
|
|
||||||
|
for entry in os.scandir(directory):
|
||||||
|
if path_is_ignored(Path(entry.path), gitignore_dict):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if entry.is_file():
|
||||||
|
if any(entry.path.endswith(ext) for ext in extensions):
|
||||||
|
continue
|
||||||
|
|
||||||
|
file_paths.append(entry.path)
|
||||||
|
|
||||||
|
elif entry.is_dir():
|
||||||
|
subdir_file_paths = get_nonignored_file_paths(
|
||||||
|
entry.path, gitignore_dict=gitignore_dict
|
||||||
|
)
|
||||||
|
file_paths.extend(subdir_file_paths)
|
||||||
|
if return_relative:
|
||||||
|
file_paths = [os.path.relpath(f, directory) for f in file_paths]
|
||||||
|
file_paths.sort(key=lambda p: ("/" in p, p))
|
||||||
|
|
||||||
|
return file_paths
|
||||||
|
|
||||||
|
|
||||||
|
def path_is_ignored(path: Path, gitignore_dict) -> bool:
|
||||||
|
for gitignore_path, pattern in gitignore_dict.items():
|
||||||
|
try:
|
||||||
|
abspath = path if path.is_absolute() else Path.cwd() / path
|
||||||
|
normalized_path = abspath.resolve()
|
||||||
|
try:
|
||||||
|
relative_path = normalized_path.relative_to(gitignore_path).as_posix()
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if pattern.match_file(relative_path):
|
||||||
|
return True
|
||||||
|
return False
|
@ -0,0 +1,211 @@
|
|||||||
|
import os.path
|
||||||
|
from functools import lru_cache
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from modal import (
|
||||||
|
Image,
|
||||||
|
Mount,
|
||||||
|
Stub,
|
||||||
|
Volume,
|
||||||
|
gpu,
|
||||||
|
)
|
||||||
|
|
||||||
|
os.environ["MODAL_AUTOMOUNT"] = "0"
|
||||||
|
|
||||||
|
# find project root that is two levels up from __file__
|
||||||
|
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||||
|
requirements_path = os.path.join(project_root, "requirements-dev.txt")
|
||||||
|
|
||||||
|
|
||||||
|
def file_filter(path: str):
|
||||||
|
# print(f"Checking {path}")
|
||||||
|
if "/tests/" in path:
|
||||||
|
return False
|
||||||
|
include = path in files_for_inclusion()
|
||||||
|
return include
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def files_for_inclusion():
|
||||||
|
from imaginairy.utils.gitignore import get_nonignored_file_paths
|
||||||
|
|
||||||
|
filepaths = get_nonignored_file_paths(project_root)
|
||||||
|
for f in filepaths:
|
||||||
|
print(f)
|
||||||
|
filepaths = [f"{project_root}/{f}" for f in filepaths if os.path.isfile(f)]
|
||||||
|
return set(filepaths)
|
||||||
|
|
||||||
|
|
||||||
|
local_mount = Mount.from_local_dir(
|
||||||
|
project_root, remote_path="/root/workspace/imaginairy", condition=file_filter
|
||||||
|
)
|
||||||
|
|
||||||
|
imaginairy_image = (
|
||||||
|
Image.debian_slim(python_version="3.10")
|
||||||
|
.apt_install(
|
||||||
|
"libglib2.0-0", "libsm6", "libxrender1", "libxext6", "ffmpeg", "libgl1"
|
||||||
|
)
|
||||||
|
.pip_install_from_requirements(requirements_path)
|
||||||
|
.workdir("/root/workspace")
|
||||||
|
.env({"PYTHONPATH": "/root/workspace/imaginairy"})
|
||||||
|
)
|
||||||
|
weights_cache_volume = Volume.from_name("ai-wights-cache", create_if_missing=True)
|
||||||
|
weights_cache_path = "/root/.cache/"
|
||||||
|
|
||||||
|
stub = Stub(
|
||||||
|
"imaginairy",
|
||||||
|
mounts=[local_mount],
|
||||||
|
volumes={weights_cache_path: weights_cache_volume},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@stub.function(gpu=gpu.A100(), container_idle_timeout=2, image=imaginairy_image)
|
||||||
|
def generate_image(imagine_prompt):
|
||||||
|
from imaginairy.api import imagine
|
||||||
|
from imaginairy.utils.log_utils import configure_logging
|
||||||
|
|
||||||
|
configure_logging()
|
||||||
|
|
||||||
|
results = list(imagine(imagine_prompt))
|
||||||
|
result = results[-1]
|
||||||
|
|
||||||
|
weights_cache_volume.commit()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
standard_prompts = [
|
||||||
|
"a flower",
|
||||||
|
"portrait photo of a woman with a few freckles. red hair",
|
||||||
|
"photo of a bowl of fruit",
|
||||||
|
"gold coins",
|
||||||
|
"a scenic landscape",
|
||||||
|
"old growth redwood forest with a stream meandering through it. award-winning photo, diffuse lighting, beautiful, high-resolution, 4k",
|
||||||
|
"abstract desktop background",
|
||||||
|
"highway system seen from above",
|
||||||
|
"the galaxy",
|
||||||
|
"a photo of the rainforest",
|
||||||
|
"the starry night painting",
|
||||||
|
"photo of flowers",
|
||||||
|
"girl with a pearl earring",
|
||||||
|
"a painting of 1920s luncheon on a boat",
|
||||||
|
"napolean crossing the alps",
|
||||||
|
"american gothic painting",
|
||||||
|
"the tower of babel",
|
||||||
|
"god creating the {universe|earth}",
|
||||||
|
"a fishing boat in a storm on the sea of galilee. oil painting",
|
||||||
|
"the american flag",
|
||||||
|
"the tree of life. oil painting",
|
||||||
|
"the last supper. oil painting",
|
||||||
|
"the statue of liberty",
|
||||||
|
"a maze",
|
||||||
|
"HD desktop wallpaper",
|
||||||
|
"a beautiful garden",
|
||||||
|
"the garden of eden",
|
||||||
|
"the circus. {photo|oil painting}",
|
||||||
|
"a futuristic city",
|
||||||
|
"a retro spaceship",
|
||||||
|
"yosemite national park. {photo|oil painting}",
|
||||||
|
"a seacliff with a lighthouse. giant ocean waves, {photo|oil painting}",
|
||||||
|
"blueberries",
|
||||||
|
"strawberries",
|
||||||
|
"a single giant diamond",
|
||||||
|
"disneyland thomas kinkade painting",
|
||||||
|
"ancient books in an ancient library. cinematic",
|
||||||
|
"mormon missionaries",
|
||||||
|
"salt lake city",
|
||||||
|
"oil painting of heaven",
|
||||||
|
"oil painting of hell",
|
||||||
|
"an x-wing. digital art",
|
||||||
|
"star trek uss enterprise",
|
||||||
|
"a giant pile of treasure",
|
||||||
|
"the white house",
|
||||||
|
"a grizzly bear. nature photography",
|
||||||
|
"a unicorn. nature photography",
|
||||||
|
"elon musk. normal rockwell painting",
|
||||||
|
"a cybertruck",
|
||||||
|
"elon musk with a halo dressed in greek robes. oil painting",
|
||||||
|
"a crowd of people",
|
||||||
|
"a stadium full of people",
|
||||||
|
"macro photography of a drop of water",
|
||||||
|
"macro photography of a leaf",
|
||||||
|
"macro photography of a spider",
|
||||||
|
"flames",
|
||||||
|
"a robot",
|
||||||
|
"the stars at night",
|
||||||
|
"a lovely sunset",
|
||||||
|
"an oil painting",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@stub.local_entrypoint()
|
||||||
|
def main(
|
||||||
|
prompt: str,
|
||||||
|
size: str = "fhd",
|
||||||
|
upscale: bool = False,
|
||||||
|
model_weights: str = "opendalle",
|
||||||
|
n_images: int = 1,
|
||||||
|
n_steps: int = 50,
|
||||||
|
seed=None,
|
||||||
|
):
|
||||||
|
from imaginairy.enhancers.prompt_expansion import expand_prompts
|
||||||
|
from imaginairy.schema import ImaginePrompt
|
||||||
|
from imaginairy.utils import get_next_filenumber
|
||||||
|
from imaginairy.utils.log_utils import configure_logging
|
||||||
|
|
||||||
|
configure_logging()
|
||||||
|
|
||||||
|
prompt_texts = expand_prompts(
|
||||||
|
n=n_images,
|
||||||
|
prompt_text=prompt,
|
||||||
|
)
|
||||||
|
# model_weights = ModelWeightsConfig(
|
||||||
|
# name="ProteusV0.4",
|
||||||
|
# aliases=["proteusv4"],
|
||||||
|
# architecture="sdxl",
|
||||||
|
# defaults={
|
||||||
|
# "negative_prompt": DEFAULT_NEGATIVE_PROMPT,
|
||||||
|
# "composition_strength": 0.6,
|
||||||
|
# },
|
||||||
|
# weights_location="https://huggingface.co/dataautogpt3/ProteusV0.4/tree/0dfa4101db540e7a4b2b6ba6f87d8d7219e84513",
|
||||||
|
# )
|
||||||
|
|
||||||
|
imagine_prompts = [
|
||||||
|
ImaginePrompt(
|
||||||
|
prompt_text,
|
||||||
|
steps=n_steps,
|
||||||
|
size=size,
|
||||||
|
upscale=upscale,
|
||||||
|
model_weights=model_weights,
|
||||||
|
seed=seed,
|
||||||
|
)
|
||||||
|
for prompt_text in prompt_texts
|
||||||
|
]
|
||||||
|
# imagine_prompts = []
|
||||||
|
# for sp in standard_prompts:
|
||||||
|
# imagine_prompts.append(
|
||||||
|
# ImaginePrompt(
|
||||||
|
# sp,
|
||||||
|
# steps=n_steps,
|
||||||
|
# size=size,
|
||||||
|
# upscale=upscale,
|
||||||
|
# model_weights=model_weights,
|
||||||
|
# seed=seed
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# imagine_prompts = imagine_prompts[:n_images]
|
||||||
|
|
||||||
|
outdir = Path("./outputs/modal-inference")
|
||||||
|
outdir.mkdir(exist_ok=True, parents=True)
|
||||||
|
file_num = get_next_filenumber(f"{outdir}/generated")
|
||||||
|
|
||||||
|
for result in generate_image.map(imagine_prompts):
|
||||||
|
from imaginairy.api.generate import save_image_result
|
||||||
|
|
||||||
|
save_image_result(
|
||||||
|
result=result,
|
||||||
|
base_count=file_num,
|
||||||
|
outdir=outdir,
|
||||||
|
output_file_extension="jpg",
|
||||||
|
primary_filename_type="generated",
|
||||||
|
)
|
||||||
|
file_num += 1
|
Loading…
Reference in New Issue