From cbc676c64050a499508e83d00854193537d3b982 Mon Sep 17 00:00:00 2001 From: Lilianxr <150981420+Lilianxr@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:04:04 -0800 Subject: [PATCH 1/4] Create modal_code update code for testing --- modal_code | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 modal_code diff --git a/modal_code b/modal_code new file mode 100644 index 0000000..3a2eaec --- /dev/null +++ b/modal_code @@ -0,0 +1,198 @@ +import io +from pathlib import Path +import random +import uuid +from fastapi import FastAPI, Request +from oxen import RemoteRepo + +from modal import Image, Mount, Stub, asgi_app, build, enter, gpu, method + +sdxl_image = ( + Image.debian_slim() + .apt_install( + "libglib2.0-0", "libsm6", "libxrender1", "libxext6", "ffmpeg", "libgl1" + ) + .pip_install( + "diffusers~=0.19", + "invisible_watermark~=0.1", + "transformers~=4.31", + "accelerate~=0.21", + "safetensors~=0.3", + "oxenai", + ) +) + +stub = Stub("oxen-stable-diffusion-test") + +with sdxl_image.imports(): + import fastapi.staticfiles + import torch + from diffusers import DiffusionPipeline + from fastapi import FastAPI, Request + from fastapi.responses import Response + from huggingface_hub import snapshot_download + +@stub.function(image=sdxl_image) +def generate_random_prompt(username): + ''' + generate the + ''' + adjectives = ["grand", "noble", "splendid", "majestic", "regal", "royal", + "stately", "august", "magnificent", "dignified", "imposing", + "sublime", "resplendent", "glorious", "impressive", "exalted", + "heroic", "grandiose", "epic", "monumental", "palatial", + "awesome", "breathtaking", "marvelous", "sumptuous", "funny" + "wonderful", "excellent", "terrific", "fantastic", "fabulous", + "charismatic"] + + colors = [ + "red", "orange", "yellow", "green", "blue", "purple", "brown", "black", "white", "gray" + ] + + locations = [ + "the clouds", "space", "the sky", "the ocean", "the sea", "the mountains", "the forest", "the desert", "the jungle", "the savannah", "the tundra", "the arctic", "the antarctic", "the moon", "the sun", "the stars", "the galaxy", "the universe", "the matrix" + ] + + styles = ["cartoon", "vibrant colors", "Geometric shapes", "Abstract patterns", "Movement and flow", "Texture and layers", "dreamlike", "surreal landscapes", "mystical creatures", "simplicity", "minimal", "negative space", "impressionist", "painted", "pastel colors", "digital art", "realistic portrait", "realistic landscape", "bold colors", "stylized portrait", "pop art still life", "black and white", "night time", "daylight", "street art", "fauvism", "graffiti art", "modernism", "abstract art", "action packed", "pop art", "neo-dada", "water color", "conceptual art", "fluxus", "cubism"] + + adjective = random.choice(adjectives) + color = random.choice(colors) + location = random.choice(locations) + style = random.choice(styles) + prompt = f"{username}, {adjective} {color} ox with wings flying through {location}, {style}" + # file_names = imagine(prompt) + + # commit_message = f"{username} gave an Ox it's wings" + # save_to_oxen("ox/FlyingOxen", "main", prompt, file_names, commit_message) + print(prompt) + return prompt + +@stub.function(image=sdxl_image) +def save_to_oxen(repo_name, branch_name, prompt, file_names, commit_message): + ''' + save the file to oxen repo + ''' + + repo = RemoteRepo(repo_name) + repo.checkout(branch_name) + + # Add all files in one commmit + paths = [] + for file_name in file_names: + repo.add(file_name, "images") + repo_path = f"images/{file_name}" + paths.append(repo_path) + repo.add_df_row("annotations.jsonl", {"prompt": prompt, "image": repo_path, "model": model_id}) + + commit = repo.commit(commit_message) + images = [] + for path in paths: + images.append({ + "path": path, + "content_url": f"https://hub.oxen.ai/api/repos/{repo_name}/file/{commit.commit_id}/{path}", + # https://www.oxen.ai/ox/GenerativeImagePlayground/file/edfdd2bc11396d86/images/a-white-fluffy-ox-427b3fa6-fed2-4379-b9a8-04babf476bc8.png + "view_url": f"https://oxen.ai/{repo_name}/file/{commit.commit_id}/{path}", + }) + print(f"Got Commit: {commit}") + os.remove(file_name) + return commit, images + + +@stub.cls(gpu=gpu.A10G(), container_idle_timeout=240, image=sdxl_image) +class Model: + @build() + def build(self): + ignore = [ + "*.bin", + "*.onnx_data", + "*/diffusion_pytorch_model.safetensors", + ] + snapshot_download( + "stabilityai/stable-diffusion-xl-base-1.0", ignore_patterns=ignore + ) + + @enter() + def enter(self): + load_options = dict( + torch_dtype=torch.float16, + use_safetensors=True, + variant="fp16", + device_map="auto", + ) + + # Load base model + self.pipe = DiffusionPipeline.from_pretrained( + "stabilityai/stable-diffusion-xl-base-1.0", **load_options + ) + + @method() + def imagine(self, prompt, num_images=1, num_steps=50, width=1024, height=1024): + file_base_name = str(prompt).split(" ")[:10] + print(f"Generating {str(prompt)}") + + images = self.pipe( + prompt, + height=height, + width=width, + num_images_per_prompt=num_images, + num_inference_steps=num_steps + ).images # type: ignore + print(images) + file_names = [] + + for image in images: + file_name = "-".join(file_base_name) + "-" + str(uuid.uuid4()) + ".png" + image.save(file_name) + file_names.append(file_name) + # print(file_names) + return file_names + + +app = FastAPI() + +@app.post("/") +async def generate_image( + request: Request +): + data = await request.json() + print(f"POST /imagine - received data={data}") + + if data['action'] == 'created': + data['prompt'] = generate_random_prompt.remote(data['sender']['login']) + + if data['prompt']: + prompt = data['prompt'] + file_names = Model().imagine.remote(prompt) + print("Saving to Oxen") + + commit_message = f"{prompt}" + namespace = "ox" + repo_name = "FlyingOxen" + branch_name = "main" + commit, images = save_to_oxen.remote(f"{namespace}/{repo_name}", branch_name, prompt, file_names, commit_message) + commit_id = commit.commit_id + return { + "status": "success", + "status_message": "Committed: " + commit.message, + "commit": { + "url": f"https://www.oxen.ai/{namespace}/{repo_name}/commit/{commit_id}", + "id": commit_id, + "message": commit.message + }, + "images": images + } + else: + return {"status": "error", "status_message": "Must supply 'prompt' field in json"} + + + +@app.post("/echo") +async def foo(request: Request): + data = await request.json() + return data + +@stub.function(image=sdxl_image) +@asgi_app() +def fastapi_app(): + return app + From 2bcd7a63e2ff7348bde87a18c5000d2880e0cd4e Mon Sep 17 00:00:00 2001 From: Lilianxr <150981420+Lilianxr@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:06:38 -0800 Subject: [PATCH 2/4] Update modal_code.py for testing --- modal_code.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/modal_code.py b/modal_code.py index 76cf7f5..3a2eaec 100644 --- a/modal_code.py +++ b/modal_code.py @@ -3,6 +3,7 @@ import random import uuid from fastapi import FastAPI, Request +from oxen import RemoteRepo from modal import Image, Mount, Stub, asgi_app, build, enter, gpu, method @@ -17,6 +18,7 @@ "transformers~=4.31", "accelerate~=0.21", "safetensors~=0.3", + "oxenai", ) ) @@ -30,7 +32,11 @@ from fastapi.responses import Response from huggingface_hub import snapshot_download +@stub.function(image=sdxl_image) def generate_random_prompt(username): + ''' + generate the + ''' adjectives = ["grand", "noble", "splendid", "majestic", "regal", "royal", "stately", "august", "magnificent", "dignified", "imposing", "sublime", "resplendent", "glorious", "impressive", "exalted", @@ -61,8 +67,12 @@ def generate_random_prompt(username): print(prompt) return prompt - +@stub.function(image=sdxl_image) def save_to_oxen(repo_name, branch_name, prompt, file_names, commit_message): + ''' + save the file to oxen repo + ''' + repo = RemoteRepo(repo_name) repo.checkout(branch_name) @@ -148,7 +158,7 @@ async def generate_image( print(f"POST /imagine - received data={data}") if data['action'] == 'created': - data['prompt'] = generate_random_prompt(data['sender']['login']) + data['prompt'] = generate_random_prompt.remote(data['sender']['login']) if data['prompt']: prompt = data['prompt'] @@ -157,9 +167,9 @@ async def generate_image( commit_message = f"{prompt}" namespace = "ox" - repo_name = "GenerativeImagePlayground" + repo_name = "FlyingOxen" branch_name = "main" - commit, images = save_to_oxen(f"{namespace}/{repo_name}", branch_name, prompt, file_names, commit_message) + commit, images = save_to_oxen.remote(f"{namespace}/{repo_name}", branch_name, prompt, file_names, commit_message) commit_id = commit.commit_id return { "status": "success", @@ -175,6 +185,7 @@ async def generate_image( return {"status": "error", "status_message": "Must supply 'prompt' field in json"} + @app.post("/echo") async def foo(request: Request): data = await request.json() From c7736d0e3093be2d2dbc8a4c6d7106a0e8b497db Mon Sep 17 00:00:00 2001 From: Lilianxr <150981420+Lilianxr@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:06:54 -0800 Subject: [PATCH 3/4] Delete modal_code --- modal_code | 198 ----------------------------------------------------- 1 file changed, 198 deletions(-) delete mode 100644 modal_code diff --git a/modal_code b/modal_code deleted file mode 100644 index 3a2eaec..0000000 --- a/modal_code +++ /dev/null @@ -1,198 +0,0 @@ -import io -from pathlib import Path -import random -import uuid -from fastapi import FastAPI, Request -from oxen import RemoteRepo - -from modal import Image, Mount, Stub, asgi_app, build, enter, gpu, method - -sdxl_image = ( - Image.debian_slim() - .apt_install( - "libglib2.0-0", "libsm6", "libxrender1", "libxext6", "ffmpeg", "libgl1" - ) - .pip_install( - "diffusers~=0.19", - "invisible_watermark~=0.1", - "transformers~=4.31", - "accelerate~=0.21", - "safetensors~=0.3", - "oxenai", - ) -) - -stub = Stub("oxen-stable-diffusion-test") - -with sdxl_image.imports(): - import fastapi.staticfiles - import torch - from diffusers import DiffusionPipeline - from fastapi import FastAPI, Request - from fastapi.responses import Response - from huggingface_hub import snapshot_download - -@stub.function(image=sdxl_image) -def generate_random_prompt(username): - ''' - generate the - ''' - adjectives = ["grand", "noble", "splendid", "majestic", "regal", "royal", - "stately", "august", "magnificent", "dignified", "imposing", - "sublime", "resplendent", "glorious", "impressive", "exalted", - "heroic", "grandiose", "epic", "monumental", "palatial", - "awesome", "breathtaking", "marvelous", "sumptuous", "funny" - "wonderful", "excellent", "terrific", "fantastic", "fabulous", - "charismatic"] - - colors = [ - "red", "orange", "yellow", "green", "blue", "purple", "brown", "black", "white", "gray" - ] - - locations = [ - "the clouds", "space", "the sky", "the ocean", "the sea", "the mountains", "the forest", "the desert", "the jungle", "the savannah", "the tundra", "the arctic", "the antarctic", "the moon", "the sun", "the stars", "the galaxy", "the universe", "the matrix" - ] - - styles = ["cartoon", "vibrant colors", "Geometric shapes", "Abstract patterns", "Movement and flow", "Texture and layers", "dreamlike", "surreal landscapes", "mystical creatures", "simplicity", "minimal", "negative space", "impressionist", "painted", "pastel colors", "digital art", "realistic portrait", "realistic landscape", "bold colors", "stylized portrait", "pop art still life", "black and white", "night time", "daylight", "street art", "fauvism", "graffiti art", "modernism", "abstract art", "action packed", "pop art", "neo-dada", "water color", "conceptual art", "fluxus", "cubism"] - - adjective = random.choice(adjectives) - color = random.choice(colors) - location = random.choice(locations) - style = random.choice(styles) - prompt = f"{username}, {adjective} {color} ox with wings flying through {location}, {style}" - # file_names = imagine(prompt) - - # commit_message = f"{username} gave an Ox it's wings" - # save_to_oxen("ox/FlyingOxen", "main", prompt, file_names, commit_message) - print(prompt) - return prompt - -@stub.function(image=sdxl_image) -def save_to_oxen(repo_name, branch_name, prompt, file_names, commit_message): - ''' - save the file to oxen repo - ''' - - repo = RemoteRepo(repo_name) - repo.checkout(branch_name) - - # Add all files in one commmit - paths = [] - for file_name in file_names: - repo.add(file_name, "images") - repo_path = f"images/{file_name}" - paths.append(repo_path) - repo.add_df_row("annotations.jsonl", {"prompt": prompt, "image": repo_path, "model": model_id}) - - commit = repo.commit(commit_message) - images = [] - for path in paths: - images.append({ - "path": path, - "content_url": f"https://hub.oxen.ai/api/repos/{repo_name}/file/{commit.commit_id}/{path}", - # https://www.oxen.ai/ox/GenerativeImagePlayground/file/edfdd2bc11396d86/images/a-white-fluffy-ox-427b3fa6-fed2-4379-b9a8-04babf476bc8.png - "view_url": f"https://oxen.ai/{repo_name}/file/{commit.commit_id}/{path}", - }) - print(f"Got Commit: {commit}") - os.remove(file_name) - return commit, images - - -@stub.cls(gpu=gpu.A10G(), container_idle_timeout=240, image=sdxl_image) -class Model: - @build() - def build(self): - ignore = [ - "*.bin", - "*.onnx_data", - "*/diffusion_pytorch_model.safetensors", - ] - snapshot_download( - "stabilityai/stable-diffusion-xl-base-1.0", ignore_patterns=ignore - ) - - @enter() - def enter(self): - load_options = dict( - torch_dtype=torch.float16, - use_safetensors=True, - variant="fp16", - device_map="auto", - ) - - # Load base model - self.pipe = DiffusionPipeline.from_pretrained( - "stabilityai/stable-diffusion-xl-base-1.0", **load_options - ) - - @method() - def imagine(self, prompt, num_images=1, num_steps=50, width=1024, height=1024): - file_base_name = str(prompt).split(" ")[:10] - print(f"Generating {str(prompt)}") - - images = self.pipe( - prompt, - height=height, - width=width, - num_images_per_prompt=num_images, - num_inference_steps=num_steps - ).images # type: ignore - print(images) - file_names = [] - - for image in images: - file_name = "-".join(file_base_name) + "-" + str(uuid.uuid4()) + ".png" - image.save(file_name) - file_names.append(file_name) - # print(file_names) - return file_names - - -app = FastAPI() - -@app.post("/") -async def generate_image( - request: Request -): - data = await request.json() - print(f"POST /imagine - received data={data}") - - if data['action'] == 'created': - data['prompt'] = generate_random_prompt.remote(data['sender']['login']) - - if data['prompt']: - prompt = data['prompt'] - file_names = Model().imagine.remote(prompt) - print("Saving to Oxen") - - commit_message = f"{prompt}" - namespace = "ox" - repo_name = "FlyingOxen" - branch_name = "main" - commit, images = save_to_oxen.remote(f"{namespace}/{repo_name}", branch_name, prompt, file_names, commit_message) - commit_id = commit.commit_id - return { - "status": "success", - "status_message": "Committed: " + commit.message, - "commit": { - "url": f"https://www.oxen.ai/{namespace}/{repo_name}/commit/{commit_id}", - "id": commit_id, - "message": commit.message - }, - "images": images - } - else: - return {"status": "error", "status_message": "Must supply 'prompt' field in json"} - - - -@app.post("/echo") -async def foo(request: Request): - data = await request.json() - return data - -@stub.function(image=sdxl_image) -@asgi_app() -def fastapi_app(): - return app - From 4570120aa5468b94c7471344859e4c66ca48d9f5 Mon Sep 17 00:00:00 2001 From: Greg Schoeninger Date: Mon, 22 Jan 2024 16:48:36 -0800 Subject: [PATCH 4/4] have modal example working --- modal_code.py | 72 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/modal_code.py b/modal_code.py index 3a2eaec..4c6c7b6 100644 --- a/modal_code.py +++ b/modal_code.py @@ -1,11 +1,13 @@ -import io +import os, io from pathlib import Path import random import uuid from fastapi import FastAPI, Request from oxen import RemoteRepo +import oxen +import modal -from modal import Image, Mount, Stub, asgi_app, build, enter, gpu, method +from modal import Image, Secret, Stub, asgi_app, build, enter, gpu, method sdxl_image = ( Image.debian_slim() @@ -67,7 +69,7 @@ def generate_random_prompt(username): print(prompt) return prompt -@stub.function(image=sdxl_image) +@stub.function(image=sdxl_image, secret=modal.Secret.from_name("oxenai-api-key")) def save_to_oxen(repo_name, branch_name, prompt, file_names, commit_message): ''' save the file to oxen repo @@ -75,6 +77,10 @@ def save_to_oxen(repo_name, branch_name, prompt, file_names, commit_message): repo = RemoteRepo(repo_name) repo.checkout(branch_name) + + api_key = os.environ["OXENAI_API_KEY"] + oxen.auth.config_auth(api_key) + oxen.user.config_user("Bessie", "ox@oxen.ai") # Add all files in one commmit paths = [] @@ -138,14 +144,16 @@ def imagine(self, prompt, num_images=1, num_steps=50, width=1024, height=1024): num_inference_steps=num_steps ).images # type: ignore print(images) - file_names = [] + image_byte_list = [] + os.makedirs("images", exist_ok=True) for image in images: - file_name = "-".join(file_base_name) + "-" + str(uuid.uuid4()) + ".png" - image.save(file_name) - file_names.append(file_name) - # print(file_names) - return file_names + byte_stream = io.BytesIO() + image.save(byte_stream, format="PNG") + image_bytes = byte_stream.getvalue() + image_byte_list.append(image_bytes) + + return image_byte_list app = FastAPI() @@ -157,19 +165,55 @@ async def generate_image( data = await request.json() print(f"POST /imagine - received data={data}") - if data['action'] == 'created': + if 'action' in data and data['action'] == 'created': data['prompt'] = generate_random_prompt.remote(data['sender']['login']) if data['prompt']: prompt = data['prompt'] - file_names = Model().imagine.remote(prompt) + image_byte_list = Model().imagine.remote(prompt) print("Saving to Oxen") commit_message = f"{prompt}" namespace = "ox" repo_name = "FlyingOxen" branch_name = "main" - commit, images = save_to_oxen.remote(f"{namespace}/{repo_name}", branch_name, prompt, file_names, commit_message) + + repo = RemoteRepo(f"{namespace}/{repo_name}") + repo.checkout(branch_name) + + api_key = os.environ["OXENAI_API_KEY"] + oxen.auth.config_auth(api_key) + oxen.user.config_user("Bessie", "ox@oxen.ai") + + # Add all files in one commmit + paths = [] + os.makedirs("images", exist_ok=True) + for image_bytes in image_byte_list: + file_base_name = str(prompt).split(" ")[:10] + basename = "-".join(file_base_name) + "-" + str(uuid.uuid4()) + ".png" + file_name = os.path.join("images", basename) + + print(f"Saving it to {file_name}") + with open(file_name, "wb") as f: + f.write(image_bytes) + + repo.add(file_name, "images") + repo_path = f"images/{file_name}" + paths.append(repo_path) + repo.add_df_row("annotations.jsonl", {"prompt": prompt, "image": repo_path, "model": "stable-diffusion-xl-base-1.0"}) + + commit = repo.commit(commit_message) + images = [] + for path in paths: + images.append({ + "path": path, + "content_url": f"https://hub.oxen.ai/api/repos/{namespace}/{repo_name}/file/{commit.commit_id}/{path}", + # https://www.oxen.ai/ox/GenerativeImagePlayground/file/edfdd2bc11396d86/images/a-white-fluffy-ox-427b3fa6-fed2-4379-b9a8-04babf476bc8.png + "view_url": f"https://oxen.ai/{namespace}/{repo_name}/file/{commit.commit_id}/{path}", + }) + print(f"Got Commit: {commit}") + os.remove(file_name) + commit_id = commit.commit_id return { "status": "success", @@ -184,14 +228,12 @@ async def generate_image( else: return {"status": "error", "status_message": "Must supply 'prompt' field in json"} - - @app.post("/echo") async def foo(request: Request): data = await request.json() return data -@stub.function(image=sdxl_image) +@stub.function(image=sdxl_image, secret=modal.Secret.from_name("oxenai-api-key")) @asgi_app() def fastapi_app(): return app