2023-01-16 00:54:20 +00:00
|
|
|
from os import path
|
2023-01-16 13:31:42 +00:00
|
|
|
from time import time
|
2023-01-16 01:47:57 +00:00
|
|
|
from struct import pack
|
|
|
|
from typing import Any, Dict, Tuple, Union
|
|
|
|
from hashlib import sha256
|
2023-01-16 00:54:20 +00:00
|
|
|
|
|
|
|
|
2023-01-16 01:47:57 +00:00
|
|
|
Param = Union[str, int, float]
|
2023-01-16 00:54:20 +00:00
|
|
|
Point = Tuple[int, int]
|
|
|
|
|
|
|
|
|
2023-01-16 01:14:58 +00:00
|
|
|
class BaseParams:
|
2023-01-16 13:31:42 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
model: str,
|
|
|
|
provider: str,
|
|
|
|
scheduler: Any,
|
|
|
|
prompt: str,
|
|
|
|
negative_prompt: Union[None, str],
|
|
|
|
cfg: float,
|
|
|
|
steps: int,
|
|
|
|
seed: int
|
|
|
|
) -> None:
|
2023-01-16 01:14:58 +00:00
|
|
|
self.model = model
|
|
|
|
self.provider = provider
|
|
|
|
self.scheduler = scheduler
|
|
|
|
self.prompt = prompt
|
|
|
|
self.negative_prompt = negative_prompt
|
|
|
|
self.cfg = cfg
|
|
|
|
self.steps = steps
|
|
|
|
self.seed = seed
|
2023-01-16 01:33:40 +00:00
|
|
|
|
2023-01-16 01:47:57 +00:00
|
|
|
def tojson(self) -> Dict[str, Param]:
|
2023-01-16 01:33:40 +00:00
|
|
|
return {
|
|
|
|
'model': self.model,
|
|
|
|
'provider': self.provider,
|
|
|
|
'scheduler': self.scheduler.__name__,
|
|
|
|
'seed': self.seed,
|
|
|
|
'prompt': self.prompt,
|
|
|
|
'cfg': self.cfg,
|
|
|
|
'negativePrompt': self.negative_prompt,
|
|
|
|
'steps': self.steps,
|
|
|
|
}
|
2023-01-16 01:14:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Border:
|
2023-01-16 13:31:42 +00:00
|
|
|
def __init__(self, left: int, right: int, top: int, bottom: int) -> None:
|
2023-01-16 01:14:58 +00:00
|
|
|
self.left = left
|
|
|
|
self.right = right
|
|
|
|
self.top = top
|
|
|
|
self.bottom = bottom
|
|
|
|
|
|
|
|
|
2023-01-16 13:31:42 +00:00
|
|
|
class OutputPath:
|
|
|
|
'''
|
|
|
|
TODO: .path is only used in one place, can probably just be a str
|
|
|
|
'''
|
|
|
|
|
|
|
|
def __init__(self, path, file) -> None:
|
|
|
|
self.path = path
|
|
|
|
self.file = file
|
|
|
|
|
|
|
|
|
|
|
|
class ServerContext:
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
bundle_path: str,
|
|
|
|
model_path: str,
|
|
|
|
output_path: str,
|
|
|
|
params_path: str
|
|
|
|
) -> None:
|
|
|
|
self.bundle_path = bundle_path
|
|
|
|
self.model_path = model_path
|
|
|
|
self.output_path = output_path
|
|
|
|
self.params_path = params_path
|
|
|
|
|
|
|
|
|
2023-01-16 01:14:58 +00:00
|
|
|
class Size:
|
2023-01-16 13:31:42 +00:00
|
|
|
def __init__(self, width: int, height: int) -> None:
|
2023-01-16 01:14:58 +00:00
|
|
|
self.width = width
|
|
|
|
self.height = height
|
2023-01-16 01:33:40 +00:00
|
|
|
|
2023-01-16 01:47:57 +00:00
|
|
|
def tojson(self) -> Dict[str, int]:
|
2023-01-16 01:33:40 +00:00
|
|
|
return {
|
|
|
|
'height': self.height,
|
|
|
|
'width': self.width,
|
|
|
|
}
|
2023-01-16 01:47:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_and_clamp_float(args: Any, key: str, default_value: float, max_value: float, min_value=0.0) -> float:
|
|
|
|
return min(max(float(args.get(key, default_value)), min_value), max_value)
|
|
|
|
|
|
|
|
|
|
|
|
def get_and_clamp_int(args: Any, key: str, default_value: int, max_value: int, min_value=1) -> int:
|
|
|
|
return min(max(int(args.get(key, default_value)), min_value), max_value)
|
|
|
|
|
|
|
|
|
|
|
|
def get_from_map(args: Any, key: str, values: Dict[str, Any], default: Any):
|
|
|
|
selected = args.get(key, default)
|
|
|
|
if selected in values:
|
|
|
|
return values[selected]
|
|
|
|
else:
|
|
|
|
return values[default]
|
|
|
|
|
|
|
|
|
|
|
|
def safer_join(base: str, tail: str) -> str:
|
|
|
|
safer_path = path.relpath(path.normpath(path.join('/', tail)), '/')
|
|
|
|
return path.join(base, safer_path)
|
|
|
|
|
|
|
|
|
|
|
|
def hash_value(sha, param: Param):
|
|
|
|
if param is None:
|
|
|
|
return
|
|
|
|
elif isinstance(param, float):
|
|
|
|
sha.update(bytearray(pack('!f', param)))
|
|
|
|
elif isinstance(param, int):
|
|
|
|
sha.update(bytearray(pack('!I', param)))
|
|
|
|
elif isinstance(param, str):
|
|
|
|
sha.update(param.encode('utf-8'))
|
|
|
|
else:
|
|
|
|
print('cannot hash param: %s, %s' % (param, type(param)))
|
|
|
|
|
|
|
|
|
|
|
|
def make_output_path(
|
|
|
|
root: str,
|
|
|
|
mode: str,
|
|
|
|
params: BaseParams,
|
|
|
|
size: Size,
|
|
|
|
extras: Union[None, Tuple[Param]] = None
|
|
|
|
) -> OutputPath:
|
2023-01-16 13:31:42 +00:00
|
|
|
now = int(time())
|
2023-01-16 01:47:57 +00:00
|
|
|
sha = sha256()
|
|
|
|
|
2023-01-16 01:48:43 +00:00
|
|
|
hash_value(sha, mode)
|
|
|
|
hash_value(sha, params.model)
|
|
|
|
hash_value(sha, params.provider)
|
|
|
|
hash_value(sha, params.scheduler.__name__)
|
|
|
|
hash_value(sha, params.prompt)
|
|
|
|
hash_value(sha, params.negative_prompt)
|
|
|
|
hash_value(sha, params.cfg)
|
|
|
|
hash_value(sha, params.steps)
|
|
|
|
hash_value(sha, params.seed)
|
|
|
|
hash_value(sha, size.width)
|
|
|
|
hash_value(sha, size.height)
|
2023-01-16 01:47:57 +00:00
|
|
|
|
|
|
|
if extras is not None:
|
|
|
|
for param in extras:
|
|
|
|
hash_value(sha, param)
|
|
|
|
|
|
|
|
output_file = '%s_%s_%s_%s.png' % (mode, params.seed, sha.hexdigest(), now)
|
|
|
|
output_full = safer_join(root, output_file)
|
|
|
|
|
|
|
|
return OutputPath(output_full, output_file)
|