Files
opendan/src/aios_kernel/local_stability_node.py
T

206 lines
7.6 KiB
Python
Raw Normal View History

2023-09-20 22:31:33 +08:00
import os
import io
import asyncio
from asyncio import Queue
import logging
import base64
from PIL import Image
import requests
2023-09-23 10:44:57 +08:00
from typing import Tuple
2023-09-23 13:19:18 +08:00
from pathlib import Path
2023-09-20 22:31:33 +08:00
2023-09-27 19:37:13 +08:00
from .compute_task import ComputeTask, ComputeTaskResult, ComputeTaskState, ComputeTaskType, ComputeTaskResultCode
2023-09-20 22:31:33 +08:00
from .compute_node import ComputeNode
from .storage import AIStorage, UserConfig
logger = logging.getLogger(__name__)
class Local_Stability_ComputeNode(ComputeNode):
_instance = None
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = Local_Stability_ComputeNode()
return cls._instance
@classmethod
def declare_user_config(cls):
user_config = AIStorage.get_instance().get_user_config()
2023-09-23 13:19:18 +08:00
if os.getenv("LOCAL_STABILITY_URL") is None:
user_config.add_user_config(
"local_stability_url", "local stability url", True, None)
2023-09-23 13:19:18 +08:00
if os.getenv("TEXT2IMG_OUTPUT_DIR") is None:
home_dir = Path.home()
output_dir = Path.joinpath(home_dir, "text2img_output")
Path.mkdir(output_dir, exist_ok=True)
user_config.add_user_config(
"text2img_output_dir", "text2image output dir", True, output_dir)
if os.getenv("TEXT2IMG_DEFAULT_MODEL") is None:
user_config.add_user_config(
"text2img_default_model", "text2img default model", True, "v1-5-pruned-emaonly")
2023-09-20 22:31:33 +08:00
def __init__(self) -> None:
super().__init__()
self.is_start = False
self.node_id = "local_stability_node"
self.url = None
self.default_model = None
self.output_dir = None
self.task_queue = Queue()
async def initial(self):
if os.getenv("LOCAL_STABILITY_URL") is not None:
self.url = os.getenv("LOCAL_STABILITY_URL")
else:
self.url = AIStorage.get_instance(
).get_user_config().get_value("local_stability_url")
if os.getenv("TEXT2IMG_OUTPUT_DIR") is not None:
self.output_dir = os.getenv("TEXT2IMG_OUTPUT_DIR")
else:
self.output_dir = AIStorage.get_instance(
).get_user_config().get_value("text2img_output_dir")
if os.getenv("TEXT2IMG_DEFAULT_MODEL") is not None:
self.default_model = os.getenv("TEXT2IMG_DEFAULT_MODEL")
else:
self.default_model = AIStorage.get_instance(
).get_user_config().get_value("text2img_default_model")
if self.url is None:
logger.error("local stability url is None!")
return False
if self.default_model is None:
logger.error("local stability default model is None!")
return False
if self.output_dir is None:
self.output_dir = "./"
2023-09-23 10:44:57 +08:00
self.output_dir = os.path.abspath(self.output_dir)
2023-09-20 22:31:33 +08:00
self.start()
return True
async def push_task(self, task: ComputeTask, proiority: int = 0):
logger.info(f"stability_node push task: {task.display()}")
self.task_queue.put_nowait(task)
async def remove_task(self, task_id: str):
pass
2023-09-23 10:44:57 +08:00
def _make_post_request(self, url, json) -> Tuple[str, requests.Response]:
try:
response = requests.post(url, json=json)
if response.status_code != 200:
return f'{response.status_code}, {response.json()}', None
return None, response
except Exception as e:
return f"{e}", None
2023-09-20 22:31:33 +08:00
def _run_task(self, task: ComputeTask):
task.state = ComputeTaskState.RUNNING
2023-09-27 19:37:13 +08:00
result = ComputeTaskResult()
result.result_code = ComputeTaskResultCode.ERROR
result.set_from_task(task)
2023-09-20 22:31:33 +08:00
model_name = task.params["model_name"]
2023-09-23 10:44:57 +08:00
prompt = task.params["prompt"]
2023-09-27 19:37:13 +08:00
negative_prompt = task.params["negative_prompt"]
if negative_prompt == None or negative_prompt == "":
negative_prompt = "sketches, (worst quality:2), (low quality:2), (normal quality:2), lowres, duplicate, mutated hands, mutated legs, (blurry:1.3), (bad anatomy:1.2), bad proportions, extra limbs, more than 2 nipples, extra legs, fused fingers, missing fingers, jpeg artifacts, signature, watermark, username, artist name, heterochromia, muscular legs, monochrome, grayscale, skin spots, acnes, skin blemishes, age spot, skin spots, acnes, logo, badhandv4, easynegative, cropped image, patreon,lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, ng_deepnegative_v1_75t, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry,(Tiptoe:1.3),looking at viewer, Twisted eyes"
prompt += ",masterpiece, best quality:1.3"
2023-09-20 22:31:33 +08:00
2023-09-27 19:37:13 +08:00
logging.info(f"call local stability {model_name} prompts: {prompt}, nagative_prompt: {negative_prompt}")
2023-09-20 22:31:33 +08:00
if model_name is not None:
payload = {
"sd_model_checkpoint": model_name,
}
2023-09-23 10:44:57 +08:00
err, resp = self._make_post_request(f'{self.url}/sdapi/v1/options', payload)
if err is not None:
2023-09-20 22:31:33 +08:00
task.state = ComputeTaskState.ERROR
2023-09-23 10:44:57 +08:00
err_msg = f"Set local stability model failed. err:{err}"
logger.error(err_msg)
task.error_str = err_msg
2023-09-27 19:37:13 +08:00
result.error_str = err_msg
return result
2023-09-20 22:31:33 +08:00
2023-09-23 10:44:57 +08:00
logging.info(f"set local stability model {model_name} success")
2023-09-20 22:31:33 +08:00
payload = {
2023-09-23 10:44:57 +08:00
"prompt": prompt,
2023-09-27 19:37:13 +08:00
"negative_prompt": negative_prompt,
2023-09-20 22:31:33 +08:00
"steps": 20
}
2023-09-23 10:44:57 +08:00
err, resp = self._make_post_request(f'{self.url}/sdapi/v1/txt2img', payload)
if err is not None:
task.state = ComputeTaskState.ERROR
err_msg = f"Failed. err:{err}"
logger.error(err_msg)
task.error_str = err_msg
2023-09-27 19:37:13 +08:00
result.error_str = err_msg
return result
2023-09-23 10:44:57 +08:00
r = resp.json()
2023-09-20 22:31:33 +08:00
for i in r['images']:
image = Image.open(io.BytesIO(
base64.b64decode(i.split(",", 1)[0])))
file_name = os.path.join(self.output_dir, task.task_id + ".png")
image.save(file_name)
2023-09-27 19:37:13 +08:00
task.state = ComputeTaskState.DONE
result.result_code = ComputeTaskResultCode.OK
2023-09-20 22:31:33 +08:00
result.worker_id = self.node_id
result.result = {"file": file_name}
return result
2023-09-23 10:44:57 +08:00
task.error_str = "Unknown error!"
2023-09-27 19:37:13 +08:00
result.error_str = "Unknown error!"
2023-09-23 10:44:57 +08:00
task.state = ComputeTaskState.ERROR
2023-09-27 19:37:13 +08:00
return result
2023-09-20 22:31:33 +08:00
def start(self):
if self.is_start:
return
self.is_start = True
async def _run_task_loop():
while True:
logger.info("local_stability_node is waiting for task...")
task = await self.task_queue.get()
logger.info(f"stability_node get task: {task.display()}")
result = self._run_task(task)
2023-09-27 19:37:13 +08:00
# if result is not None:
# task.state = ComputeTaskState.DONE
# task.result = result
2023-09-20 22:31:33 +08:00
asyncio.create_task(_run_task_loop())
def display(self) -> str:
return f"Stability_ComputeNode: {self.node_id}"
def get_task_state(self, task_id: str):
pass
def get_capacity(self):
pass
def is_support(self, task: ComputeTask) -> bool:
return task.task_type == ComputeTaskType.TEXT_2_IMAGE
def is_local(self) -> bool:
return False