初始化换发型项目:3个微服务代码 + 部署脚本
包含: - hair_service_sd: 换发型/换发色算法服务 (端口 8801) - photo_service: LoRA 训练调度服务 (端口 32678) - stable-diffusion-webui: SD WebUI 推理服务 (端口 57860) - kohya_ss_home: 训练环境代码 - meidaojia: 监控测试脚本 - setup.sh: 一键部署脚本 (conda环境恢复 + 配置生成 + 完整性检查) - start_all_services.sh: 启动3个服务 - configure.ini.template: 路径模板化 (BASE_DIR自动推导) - conda_envs/py310.yml: py310 环境定义 大文件 (weights/, models/, data/, conda_envs/*.tar.gz 等) 通过 .gitignore 排除, 由网盘单独上传。
This commit is contained in:
Executable
Executable
+36
@@ -0,0 +1,36 @@
|
||||
import base64
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
test_files_path = os.path.dirname(__file__) + "/test_files"
|
||||
test_outputs_path = os.path.dirname(__file__) + "/test_outputs"
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
# We don't want to fail on Py.test command line arguments being
|
||||
# parsed by webui:
|
||||
os.environ.setdefault("IGNORE_CMD_ARGS_ERRORS", "1")
|
||||
|
||||
|
||||
def file_to_base64(filename):
|
||||
with open(filename, "rb") as file:
|
||||
data = file.read()
|
||||
|
||||
base64_str = str(base64.b64encode(data), "utf-8")
|
||||
return "data:image/png;base64," + base64_str
|
||||
|
||||
|
||||
@pytest.fixture(scope="session") # session so we don't read this over and over
|
||||
def img2img_basic_image_base64() -> str:
|
||||
return file_to_base64(os.path.join(test_files_path, "img2img_basic.png"))
|
||||
|
||||
|
||||
@pytest.fixture(scope="session") # session so we don't read this over and over
|
||||
def mask_basic_image_base64() -> str:
|
||||
return file_to_base64(os.path.join(test_files_path, "mask_basic.png"))
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def initialize() -> None:
|
||||
import webui # noqa: F401
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
import requests
|
||||
|
||||
|
||||
def test_simple_upscaling_performed(base_url, img2img_basic_image_base64):
|
||||
payload = {
|
||||
"resize_mode": 0,
|
||||
"show_extras_results": True,
|
||||
"gfpgan_visibility": 0,
|
||||
"codeformer_visibility": 0,
|
||||
"codeformer_weight": 0,
|
||||
"upscaling_resize": 2,
|
||||
"upscaling_resize_w": 128,
|
||||
"upscaling_resize_h": 128,
|
||||
"upscaling_crop": True,
|
||||
"upscaler_1": "Lanczos",
|
||||
"upscaler_2": "None",
|
||||
"extras_upscaler_2_visibility": 0,
|
||||
"image": img2img_basic_image_base64,
|
||||
}
|
||||
assert requests.post(f"{base_url}/sdapi/v1/extra-single-image", json=payload).status_code == 200
|
||||
|
||||
|
||||
def test_png_info_performed(base_url, img2img_basic_image_base64):
|
||||
payload = {
|
||||
"image": img2img_basic_image_base64,
|
||||
}
|
||||
assert requests.post(f"{base_url}/sdapi/v1/extra-single-image", json=payload).status_code == 200
|
||||
|
||||
|
||||
def test_interrogate_performed(base_url, img2img_basic_image_base64):
|
||||
payload = {
|
||||
"image": img2img_basic_image_base64,
|
||||
"model": "clip",
|
||||
}
|
||||
assert requests.post(f"{base_url}/sdapi/v1/extra-single-image", json=payload).status_code == 200
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import os
|
||||
from test.conftest import test_files_path, test_outputs_path
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("initialize")
|
||||
@pytest.mark.parametrize("restorer_name", ["gfpgan", "codeformer"])
|
||||
def test_face_restorers(restorer_name):
|
||||
from modules import shared
|
||||
|
||||
if restorer_name == "gfpgan":
|
||||
from modules import gfpgan_model
|
||||
gfpgan_model.setup_model(shared.cmd_opts.gfpgan_models_path)
|
||||
restorer = gfpgan_model.gfpgan_fix_faces
|
||||
elif restorer_name == "codeformer":
|
||||
from modules import codeformer_model
|
||||
codeformer_model.setup_model(shared.cmd_opts.codeformer_models_path)
|
||||
restorer = codeformer_model.codeformer.restore
|
||||
else:
|
||||
raise NotImplementedError("...")
|
||||
img = Image.open(os.path.join(test_files_path, "two-faces.jpg"))
|
||||
np_img = np.array(img, dtype=np.uint8)
|
||||
fixed_image = restorer(np_img)
|
||||
assert fixed_image.shape == np_img.shape
|
||||
assert not np.allclose(fixed_image, np_img) # should have visibly changed
|
||||
Image.fromarray(fixed_image).save(os.path.join(test_outputs_path, f"{restorer_name}.png"))
|
||||
BIN
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 9.7 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 362 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Executable
+68
@@ -0,0 +1,68 @@
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def url_img2img(base_url):
|
||||
return f"{base_url}/sdapi/v1/img2img"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def simple_img2img_request(img2img_basic_image_base64):
|
||||
return {
|
||||
"batch_size": 1,
|
||||
"cfg_scale": 7,
|
||||
"denoising_strength": 0.75,
|
||||
"eta": 0,
|
||||
"height": 64,
|
||||
"include_init_images": False,
|
||||
"init_images": [img2img_basic_image_base64],
|
||||
"inpaint_full_res": False,
|
||||
"inpaint_full_res_padding": 0,
|
||||
"inpainting_fill": 0,
|
||||
"inpainting_mask_invert": False,
|
||||
"mask": None,
|
||||
"mask_blur": 4,
|
||||
"n_iter": 1,
|
||||
"negative_prompt": "",
|
||||
"override_settings": {},
|
||||
"prompt": "example prompt",
|
||||
"resize_mode": 0,
|
||||
"restore_faces": False,
|
||||
"s_churn": 0,
|
||||
"s_noise": 1,
|
||||
"s_tmax": 0,
|
||||
"s_tmin": 0,
|
||||
"sampler_index": "Euler a",
|
||||
"seed": -1,
|
||||
"seed_resize_from_h": -1,
|
||||
"seed_resize_from_w": -1,
|
||||
"steps": 3,
|
||||
"styles": [],
|
||||
"subseed": -1,
|
||||
"subseed_strength": 0,
|
||||
"tiling": False,
|
||||
"width": 64,
|
||||
}
|
||||
|
||||
|
||||
def test_img2img_simple_performed(url_img2img, simple_img2img_request):
|
||||
assert requests.post(url_img2img, json=simple_img2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_inpainting_masked_performed(url_img2img, simple_img2img_request, mask_basic_image_base64):
|
||||
simple_img2img_request["mask"] = mask_basic_image_base64
|
||||
assert requests.post(url_img2img, json=simple_img2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_inpainting_with_inverted_masked_performed(url_img2img, simple_img2img_request, mask_basic_image_base64):
|
||||
simple_img2img_request["mask"] = mask_basic_image_base64
|
||||
simple_img2img_request["inpainting_mask_invert"] = True
|
||||
assert requests.post(url_img2img, json=simple_img2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_img2img_sd_upscale_performed(url_img2img, simple_img2img_request):
|
||||
simple_img2img_request["script_name"] = "sd upscale"
|
||||
simple_img2img_request["script_args"] = ["", 8, "Lanczos", 2.0]
|
||||
assert requests.post(url_img2img, json=simple_img2img_request).status_code == 200
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import types
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
from modules import torch_utils
|
||||
|
||||
|
||||
@pytest.mark.parametrize("wrapped", [True, False])
|
||||
def test_get_param(wrapped):
|
||||
mod = torch.nn.Linear(1, 1)
|
||||
cpu = torch.device("cpu")
|
||||
mod.to(dtype=torch.float16, device=cpu)
|
||||
if wrapped:
|
||||
# more or less how spandrel wraps a thing
|
||||
mod = types.SimpleNamespace(model=mod)
|
||||
p = torch_utils.get_param(mod)
|
||||
assert p.dtype == torch.float16
|
||||
assert p.device == cpu
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def url_txt2img(base_url):
|
||||
return f"{base_url}/sdapi/v1/txt2img"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def simple_txt2img_request():
|
||||
return {
|
||||
"batch_size": 1,
|
||||
"cfg_scale": 7,
|
||||
"denoising_strength": 0,
|
||||
"enable_hr": False,
|
||||
"eta": 0,
|
||||
"firstphase_height": 0,
|
||||
"firstphase_width": 0,
|
||||
"height": 64,
|
||||
"n_iter": 1,
|
||||
"negative_prompt": "",
|
||||
"prompt": "example prompt",
|
||||
"restore_faces": False,
|
||||
"s_churn": 0,
|
||||
"s_noise": 1,
|
||||
"s_tmax": 0,
|
||||
"s_tmin": 0,
|
||||
"sampler_index": "Euler a",
|
||||
"seed": -1,
|
||||
"seed_resize_from_h": -1,
|
||||
"seed_resize_from_w": -1,
|
||||
"steps": 3,
|
||||
"styles": [],
|
||||
"subseed": -1,
|
||||
"subseed_strength": 0,
|
||||
"tiling": False,
|
||||
"width": 64,
|
||||
}
|
||||
|
||||
|
||||
def test_txt2img_simple_performed(url_txt2img, simple_txt2img_request):
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_txt2img_with_negative_prompt_performed(url_txt2img, simple_txt2img_request):
|
||||
simple_txt2img_request["negative_prompt"] = "example negative prompt"
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_txt2img_with_complex_prompt_performed(url_txt2img, simple_txt2img_request):
|
||||
simple_txt2img_request["prompt"] = "((emphasis)), (emphasis1:1.1), [to:1], [from::2], [from:to:0.3], [alt|alt1]"
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_txt2img_not_square_image_performed(url_txt2img, simple_txt2img_request):
|
||||
simple_txt2img_request["height"] = 128
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_txt2img_with_hrfix_performed(url_txt2img, simple_txt2img_request):
|
||||
simple_txt2img_request["enable_hr"] = True
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_txt2img_with_tiling_performed(url_txt2img, simple_txt2img_request):
|
||||
simple_txt2img_request["tiling"] = True
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_txt2img_with_restore_faces_performed(url_txt2img, simple_txt2img_request):
|
||||
simple_txt2img_request["restore_faces"] = True
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sampler", ["PLMS", "DDIM", "UniPC"])
|
||||
def test_txt2img_with_vanilla_sampler_performed(url_txt2img, simple_txt2img_request, sampler):
|
||||
simple_txt2img_request["sampler_index"] = sampler
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_txt2img_multiple_batches_performed(url_txt2img, simple_txt2img_request):
|
||||
simple_txt2img_request["n_iter"] = 2
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
|
||||
|
||||
def test_txt2img_batch_performed(url_txt2img, simple_txt2img_request):
|
||||
simple_txt2img_request["batch_size"] = 2
|
||||
assert requests.post(url_txt2img, json=simple_txt2img_request).status_code == 200
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
|
||||
def test_options_write(base_url):
|
||||
url_options = f"{base_url}/sdapi/v1/options"
|
||||
response = requests.get(url_options)
|
||||
assert response.status_code == 200
|
||||
|
||||
pre_value = response.json()["send_seed"]
|
||||
|
||||
assert requests.post(url_options, json={'send_seed': (not pre_value)}).status_code == 200
|
||||
|
||||
response = requests.get(url_options)
|
||||
assert response.status_code == 200
|
||||
assert response.json()['send_seed'] == (not pre_value)
|
||||
|
||||
requests.post(url_options, json={"send_seed": pre_value})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("url", [
|
||||
"sdapi/v1/cmd-flags",
|
||||
"sdapi/v1/samplers",
|
||||
"sdapi/v1/upscalers",
|
||||
"sdapi/v1/sd-models",
|
||||
"sdapi/v1/hypernetworks",
|
||||
"sdapi/v1/face-restorers",
|
||||
"sdapi/v1/realesrgan-models",
|
||||
"sdapi/v1/prompt-styles",
|
||||
"sdapi/v1/embeddings",
|
||||
])
|
||||
def test_get_api_url(base_url, url):
|
||||
assert requests.get(f"{base_url}/{url}").status_code == 200
|
||||
Reference in New Issue
Block a user