初始化换发型项目: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:
@@ -0,0 +1,3 @@
|
||||
# liveme_photo_service
|
||||
|
||||
liveme数字写真线上服务代码。依赖webui……
|
||||
@@ -0,0 +1,159 @@
|
||||
import os
|
||||
import sys
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os,sys
|
||||
from gevent import pywsgi, monkey
|
||||
|
||||
monkey.patch_all()
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
from flask import Flask, request, jsonify
|
||||
import global_variable as global_var
|
||||
import json
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route('/template/list', methods=['POST'])
|
||||
def get_template_list():
|
||||
import os
|
||||
import json
|
||||
try:
|
||||
# 读取data/template.json文件,并返回
|
||||
with open('data/template.json', 'r') as f:
|
||||
template_list = json.load(f)
|
||||
ret_dict = dict(code=0, message='success', data=template_list)
|
||||
# 返回结果作为 JSON 响应
|
||||
return jsonify(ret_dict)
|
||||
|
||||
except Exception as e:
|
||||
ret_dict = dict(code=-1, message=str(e), data=[])
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/user/list', methods=['POST'])
|
||||
def get_user_list():
|
||||
try:
|
||||
# 获取用户文件夹路径
|
||||
user_list_dir = os.path.join(global_var.service_data_dir, 'user_data')
|
||||
|
||||
ret_user_list = []
|
||||
|
||||
# 遍历查找user_list_dir目录下所有的cfg.json文件
|
||||
for root, dirs, files in os.walk(user_list_dir):
|
||||
for file in files:
|
||||
if file != 'cfg.json': continue
|
||||
json_path = os.path.join(root, file)
|
||||
lora_path = os.path.join(root, 'lora.safetensors')
|
||||
if not os.path.exists(lora_path): continue
|
||||
# 读取cfg.json文件
|
||||
with open(json_path, 'r') as f:
|
||||
user_info = json.load(f)
|
||||
user_dict = dict(user_id=user_info['user_id'], face_img_url=user_info['face_img_url'])
|
||||
ret_user_list.append(user_dict)
|
||||
|
||||
ret_dict = dict(code=0, message='success', data=ret_user_list)
|
||||
return jsonify(ret_dict)
|
||||
|
||||
except Exception as e:
|
||||
ret_dict = dict(code=-1, message='error', data=[])
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/user/generate', methods=['POST'])
|
||||
def generate_photo():
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
#判断'user_id'和'base_img'是否在请求参数中
|
||||
assert 'user_id' in request_data and 'base_img' in request_data, 'user_id and base_img is required'
|
||||
user_id = request_data['user_id']
|
||||
base_img_b64 = request_data['base_img']
|
||||
|
||||
user_path = os.path.join(global_var.service_data_dir, 'user_data', user_id)
|
||||
assert os.path.isdir(user_path), 'user_id not exist'
|
||||
user_lora = os.path.join(user_path, 'lora.safetensors')
|
||||
usr_config_path = os.path.join(user_path, 'cfg.json')
|
||||
assert os.path.exists(user_lora) and os.path.exists(usr_config_path), 'lora file or config not exist'
|
||||
|
||||
# 读取用户配置文件
|
||||
with open(usr_config_path, 'r') as f:
|
||||
user_info = json.load(f)
|
||||
lora_md5 = user_info['lora_md5']
|
||||
dst_lora_path = os.path.join(global_var.webui_lora_dir, lora_md5 + '.safetensors')
|
||||
if not os.path.exists(dst_lora_path):
|
||||
os.system(f'cp {user_lora} {dst_lora_path}')
|
||||
|
||||
#将模板图像转化为numpy数组
|
||||
prompt = f'<lora:{lora_md5}:0.8>,easyphoto_face, easyphoto, 1person,face,suit'
|
||||
neg_prompt = '(worst quality:2),(low quality:2),(normal quality:2),lowres,watermark'
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(base_img_b64), np.uint8)
|
||||
base_img = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
# base_img = cv2.resize(base_img, (512, 512))
|
||||
# cv2.imshow('image', base_img)
|
||||
# cv2.waitKey()
|
||||
|
||||
# 生成图片
|
||||
control_net = ControlnetRequestImg2Img(prompt, neg_prompt)
|
||||
control_net.build_body(dst_width=base_img.shape[1], dst_height=base_img.shape[0], cfg_scale=3.5, base_img=base_img)
|
||||
output = control_net.send_request()
|
||||
generate_photo = output['images'][0]
|
||||
|
||||
# 清理硬盘空间
|
||||
os.remove(dst_lora_path)
|
||||
|
||||
# # 将生成的图片转化为base64编码
|
||||
# retval, bytes = cv2.imencode('.png', generate_photo)
|
||||
# generate_photo = base64.b64encode(bytes).decode('utf-8')
|
||||
return jsonify(dict(code=0, message='success', generate_photo_b64=generate_photo))
|
||||
|
||||
except Exception as e:
|
||||
ret_dict = dict(code=-1, message=str(e), data=[])
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
def webd_service():
|
||||
# 用于启动webd的后台服务
|
||||
current_file_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
webd_path = os.path.join(current_file_dir, 'webd', 'webd')
|
||||
|
||||
print('webd server started...')
|
||||
cmd = f"{webd_path} -w {global_var.service_data_dir} -g rlT -l 10219"
|
||||
os.system(cmd)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 服务启动的数据目录
|
||||
global_var.service_data_dir = sys.argv[1]
|
||||
|
||||
# 本地webui的lora存储目录
|
||||
global_var.webui_lora_dir = sys.argv[2]
|
||||
|
||||
# webui_server_port
|
||||
global_var.webui_server_port = int(sys.argv[3])
|
||||
|
||||
# server_port
|
||||
global_var.server_port = int(sys.argv[4])
|
||||
|
||||
# 检查webui_lora_dir目录是否存在
|
||||
assert os.path.isdir(global_var.webui_lora_dir), 'webui_lora_dir should be a directory'
|
||||
|
||||
# 检查service_data_dir目录是否存在
|
||||
if not os.path.exists(global_var.service_data_dir):
|
||||
os.makedirs(global_var.service_data_dir, exist_ok=True)
|
||||
else:
|
||||
assert os.path.isdir(global_var.service_data_dir), 'service_data_dir should be a directory'
|
||||
|
||||
# 启动服务
|
||||
# app.run(debug=False, port=global_var.server_port, host='0.0.0.0')
|
||||
|
||||
server = pywsgi.WSGIServer(('0.0.0.0', global_var.server_port), app) # test port
|
||||
server.serve_forever()
|
||||
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
|
||||
if __name__ == '__main__':
|
||||
in_dir = "/mnt/database2/jiangqian/0808/online_orig_train_datas_2"
|
||||
out_dir = "/mnt/database2/jiangqian/0808/online_train_datas_2"
|
||||
|
||||
dirs = os.listdir(in_dir)
|
||||
|
||||
for single_dir in dirs:
|
||||
if "traindata" in single_dir:
|
||||
in_single_dir = os.path.join(in_dir, single_dir)
|
||||
out_single_dir = os.path.join(out_dir, single_dir)
|
||||
|
||||
if not os.path.exists(out_single_dir):
|
||||
os.makedirs(out_single_dir)
|
||||
|
||||
images_dir = os.path.join(out_single_dir, "images")
|
||||
if not os.path.exists(images_dir):
|
||||
os.makedirs(images_dir)
|
||||
|
||||
hairstyle_dir = os.path.join(images_dir, "1_hairstyle")
|
||||
if not os.path.exists(hairstyle_dir):
|
||||
os.makedirs(hairstyle_dir)
|
||||
|
||||
for root, dirs, files in os.walk(in_single_dir):
|
||||
for file in files:
|
||||
in_file = os.path.join(root, file)
|
||||
out_file = os.path.join(hairstyle_dir, file)
|
||||
os.system("cp %s %s" % (in_file, out_file))
|
||||
print("copy %s to %s" % (in_file, out_file))
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template01.png",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template02.png",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template03.jpg",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template04.jpg",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template05.png",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template06.png",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template07.png",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template08.jpg",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template09.png",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template10.png",
|
||||
"http://homenas.zhourunnan.cn:9212/zhourunnan/service_data/live_photo/template_data/template11.png"
|
||||
]
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
Executable
+247
@@ -0,0 +1,247 @@
|
||||
import cv2
|
||||
import os
|
||||
import numpy as np
|
||||
import tqdm
|
||||
|
||||
from utils import landmark_processor
|
||||
import base64
|
||||
import requests
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
def encode_numpy_to_base64(img):
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
|
||||
def webui_img2img(img, mask, prompt=''):
|
||||
url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
request_dict = {
|
||||
"prompt": prompt,
|
||||
"negative_prompt": '(nsfw:1.5), ng_deepnegative_v1_75t, (badhandv4:1.2), (worst quality:2), (low quality:2), (normal quality:2), lowres, bad anatomy, '
|
||||
'bad hands, ((monochrome)), ((grayscale)) watermark, large breast, big breast, bad_pictures,easynegative, faceless, no human, white background, simple background, ',
|
||||
"sampler_name": "DPM++ 2M Karras",
|
||||
"batch_size": 1,
|
||||
"steps": 20,
|
||||
"width": img.shape[1],
|
||||
"height": img.shape[0],
|
||||
"cfg_scale": 7.0,
|
||||
"seed": 123456789,
|
||||
"mask_blur": 11,
|
||||
"init_images": [
|
||||
encode_numpy_to_base64(img)
|
||||
],
|
||||
"inpaint_full_res": False,
|
||||
"inpainting_fill": 1,
|
||||
"inpainting_mask_invert": 0,
|
||||
"mask": encode_numpy_to_base64(mask),
|
||||
# "refiner_checkpoint":"majicmixRealistic_v7.safetensors",
|
||||
# "refiner_switch_at": 0.4,
|
||||
"denoising_strength": 0.7,
|
||||
"alwayson_scripts": {
|
||||
# "controlnet": {
|
||||
# "args": [
|
||||
# {
|
||||
# "enabled": True,
|
||||
# "module": "openpose_full",
|
||||
# "model": "openpose",
|
||||
# "weight": 1.0,
|
||||
# # "image": self.read_image(),
|
||||
# "resize_mode": "Crop and Resize",
|
||||
# "low_vram": False,
|
||||
# "processor_res": 512,
|
||||
# "guidance_start": 0.0,
|
||||
# "guidance_end": 1.0,
|
||||
# "control_mode": "Balanced",
|
||||
# "pixel_perfect": False
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
}
|
||||
}
|
||||
response = requests.post(url=url, json=request_dict)
|
||||
ret_json = response.json()
|
||||
result = ret_json['images'][0]
|
||||
img = cv2.imdecode(np.frombuffer(base64.b64decode(result.split(",", 1)[0]), np.uint8), cv2.IMREAD_COLOR)
|
||||
return img
|
||||
|
||||
def webui_super_res_img(img, ratio):
|
||||
url = "http://127.0.0.1:57860/sdapi/v1/extra-single-image"
|
||||
request_dict = {
|
||||
"resize_mode": 0,
|
||||
"show_extras_results": False,
|
||||
"gfpgan_visibility": 0,
|
||||
"codeformer_visibility": 1,
|
||||
"codeformer_weight": 1,
|
||||
"upscaling_resize": ratio,
|
||||
"upscaler_1": "8x_NMKD-Superscale_150000_G",
|
||||
"upscale_first": False,
|
||||
"image": encode_numpy_to_base64(img)
|
||||
}
|
||||
response = requests.post(url=url, json=request_dict)
|
||||
ret_json = response.json()
|
||||
result = ret_json['image']
|
||||
img = cv2.imdecode(np.frombuffer(base64.b64decode(result), np.uint8), cv2.IMREAD_COLOR)
|
||||
return img
|
||||
|
||||
|
||||
def webui_tag_by_clip(img):
|
||||
url = "http://127.0.0.1:57860/sdapi/v1/interrogate"
|
||||
request_dict = {
|
||||
"image": encode_numpy_to_base64(img),
|
||||
"model": "clip"
|
||||
}
|
||||
response = requests.post(url=url, json=request_dict)
|
||||
ret_json = response.json()
|
||||
return ret_json['caption']
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
hair_dir = '/mnt/database2/jiangqian/0808/exp2-data-zrn-0808/1816523294655647746'
|
||||
|
||||
data2process_list = []
|
||||
|
||||
# 遍历查找hair_dir下的所有npy文件
|
||||
for root, dirs, files in os.walk(hair_dir):
|
||||
for file in files:
|
||||
if file.endswith('.npy'):
|
||||
# 关键点路径
|
||||
pt1k_path = os.path.join(root, file)
|
||||
origin_img_path = pt1k_path[:-4] + '.png'
|
||||
origin_matting_path = pt1k_path[:-4] + '_origin_matting.png'
|
||||
new_matting_path = pt1k_path[:-4] + '_new_matting.png'
|
||||
result_img_path = pt1k_path[:-4] + '_res.png'
|
||||
# 判断上面的文件是否存在
|
||||
if (not os.path.exists(origin_img_path) or not os.path.exists(origin_matting_path)
|
||||
or not os.path.exists(new_matting_path) or not os.path.exists(result_img_path)):
|
||||
continue
|
||||
|
||||
ref_hair_path = pt1k_path[:-4] + '_orig_hair.png'
|
||||
# if not os.path.exists(ref_hair_path):
|
||||
# continue
|
||||
lora_model_path = pt1k_path[:-4] + '_hairstyle_lora.safetensors'
|
||||
# if not os.path.exists(lora_model_path):
|
||||
# continue
|
||||
data2process_list.append([pt1k_path, origin_img_path, origin_matting_path,
|
||||
new_matting_path, result_img_path, ref_hair_path, lora_model_path])
|
||||
|
||||
crop_size = 768
|
||||
|
||||
webui_lora_dir = '/home/student/Documents/workspace_cxt_tianjing_hair/miaoya/webui_home/stable-diffusion-webui/models/Lora'
|
||||
for pt1k_path, origin_img_path, origin_matting_path, new_matting_path, result_img_path, ref_hair_path, lora_model_path in tqdm.tqdm(data2process_list):
|
||||
# if '508417f3-2c71-45cf-a75b-969b27ec7d8f' not in pt1k_path: continue
|
||||
# 读取关键点
|
||||
pt1k = np.load(pt1k_path)
|
||||
# 读取原图
|
||||
origin_img = cv2.imread(origin_img_path)
|
||||
tmp_scale = 1920 / max(origin_img.shape[0], origin_img.shape[1])
|
||||
if tmp_scale < 1.0:
|
||||
origin_img = cv2.resize(origin_img, (0, 0), fx=tmp_scale, fy=tmp_scale, interpolation=cv2.INTER_LANCZOS4)
|
||||
|
||||
print("origin_img shape:", origin_img.shape)
|
||||
# cv2.imshow("origin_img", origin_img)
|
||||
|
||||
# 读取原图抠图
|
||||
origin_matting = cv2.imread(origin_matting_path, cv2.IMREAD_GRAYSCALE)
|
||||
# 读取新图抠图
|
||||
new_matting = cv2.imread(new_matting_path, cv2.IMREAD_GRAYSCALE)
|
||||
# 读取结果图
|
||||
result_img = cv2.imread(result_img_path)
|
||||
print("result_img shape:", result_img.shape)
|
||||
# cv2.imshow("result_img", result_img)
|
||||
# # 读取参考头发
|
||||
# ref_hair = cv2.imread(ref_hair_path)
|
||||
# if max(ref_hair.shape[:2]) < 300: continue
|
||||
|
||||
|
||||
# 如何图像不清晰,进行超分辨率处理
|
||||
# if max(origin_img.shape[:2]) < 1500:
|
||||
# scale_ratio = 2000 / max(origin_img.shape[:2])
|
||||
# result_img = webui_super_res_img(result_img, scale_ratio)
|
||||
# origin_img = cv2.resize(origin_img, (result_img.shape[1], result_img.shape[0]),
|
||||
# interpolation=cv2.INTER_LANCZOS4)
|
||||
# origin_matting = cv2.resize(origin_matting, (result_img.shape[1], result_img.shape[0]))
|
||||
# new_matting = cv2.resize(new_matting, (result_img.shape[1], result_img.shape[0]))
|
||||
# pt1k = pt1k * scale_ratio
|
||||
|
||||
# 获取头发处理的局部区域图像
|
||||
# M = landmark_processor.get_transform_mat_hair_ratio_v1(pt1k, crop_size, ratio=0.30, h_offset=0.32)
|
||||
|
||||
scale = 768 / max(origin_img.shape[0], origin_img.shape[1])
|
||||
M = cv2.getRotationMatrix2D((0, 0), 0, scale)
|
||||
|
||||
dst_size = (int(origin_img.shape[1] * scale), int(origin_img.shape[0] * scale))
|
||||
|
||||
# 高质量的从原图中截取头发区域
|
||||
crop_origin = landmark_processor.high_quality_warpAffine(origin_img, M, dst_size)
|
||||
cv2.imwrite("./crop_origin.png", crop_origin)
|
||||
|
||||
crop_result = landmark_processor.high_quality_warpAffine(result_img, M, dst_size)
|
||||
cv2.imwrite("./crop_result.png", crop_result)
|
||||
# tmp = cv2.warpAffine(origin_img, M, dst_size, flags=cv2.INTER_AREA)
|
||||
|
||||
# 构造重绘的mask
|
||||
matting_merge = np.concatenate([origin_matting[:,:, np.newaxis], new_matting[:,:, np.newaxis]], axis=2)
|
||||
matting_merge = np.max(matting_merge, axis=2)
|
||||
# matting_merge = new_matting
|
||||
crop_matting = cv2.warpAffine(matting_merge, M, dst_size)
|
||||
mask = (crop_matting > 10).astype(np.float32)
|
||||
mask_dilate = cv2.dilate(mask, np.ones((3, 11), np.uint8))
|
||||
final_img = crop_result
|
||||
|
||||
mask_dilate = np.clip(mask_dilate * 255, 0, 255).astype(np.uint8)
|
||||
|
||||
# file_name = os.path.basename(pt1k_path)[:-4]
|
||||
# save_dir = '/home/chinatszrn/Downloads/abc/ref_hair/dst_res/style3_tmp'
|
||||
# cv2.imwrite(os.path.join(save_dir, file_name + '.png'), final_img)
|
||||
# cv2.imwrite(os.path.join(save_dir, file_name + '_mask.png'), mask_dilate)
|
||||
# # cv2.imwrite(os.path.join(save_dir, file_name + '_ref_hair.png'), ref_hair)
|
||||
# continue
|
||||
|
||||
# # 拷贝lora模型
|
||||
# os.system('cp {} {}'.format(lora_model_path, webui_lora_dir))
|
||||
# # 构建prompt提示词
|
||||
# lora_model_name = os.path.basename(pt1k_path)[:-4]
|
||||
|
||||
# 对final_img进行打标
|
||||
# tag_result = webui_tag_by_clip(final_img)
|
||||
tag_result = ''
|
||||
|
||||
# 开始重绘
|
||||
prompt = f'<lora:1816523294655647746_hairstyle_lora:1> titor hairstyle, easyphoto, ' + tag_result
|
||||
# 对发型进行重绘
|
||||
|
||||
# cv2.imshow("final_img_0", final_img)
|
||||
# cv2.imshow("mask_dilate", mask_dilate)
|
||||
# cv2.waitKey(100)
|
||||
|
||||
sd_result = webui_img2img(final_img, mask_dilate, prompt)
|
||||
|
||||
final_img = origin_img.copy()
|
||||
# 将重绘结果恢复到原图
|
||||
M_inv = cv2.invertAffineTransform(M)
|
||||
cv2.warpAffine(sd_result, M_inv, (final_img.shape[1], final_img.shape[0]), dst=final_img,
|
||||
borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.INTER_LANCZOS4)
|
||||
|
||||
# cv2.imshow("final_img", final_img)
|
||||
# cv2.waitKey(0)
|
||||
cv2.imwrite(result_img_path[:-4] + '_sd.png', final_img)
|
||||
|
||||
# ref_hair_scale = final_img.shape[0] / ref_hair.shape[0]
|
||||
# ref_hair = cv2.resize(ref_hair, (0, 0), fx=ref_hair_scale, fy=ref_hair_scale, interpolation=cv2.INTER_LANCZOS4)
|
||||
# img2show = np.concatenate([origin_img, ref_hair, final_img], axis=1)
|
||||
#
|
||||
# # 显示结果
|
||||
# save_dir = '/home/chinatszrn/Downloads/exp'
|
||||
# cv2.imwrite(os.path.join(save_dir, lora_model_name + '.png'), img2show)
|
||||
# # cv2.imshow("origin_img", cv2.resize(img2show, (0, 0), fx=0.3, fy=0.3, interpolation=cv2.INTER_AREA))
|
||||
# cv2.imshow("sd_result", cv2.resize(sd_result, (0, 0), fx=0.3, fy=0.3, interpolation=cv2.INTER_AREA))
|
||||
# cv2.waitKey(1000)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# 服务数据目录
|
||||
service_data_dir = None
|
||||
|
||||
# 生成视频的thread_num
|
||||
video_generation_thread_num = None
|
||||
|
||||
# avatar训练的thread_num
|
||||
avatar_train_thread_num = None
|
||||
|
||||
# 视频生成的任务队列
|
||||
video_generation_task_sq = None
|
||||
|
||||
# avatar训练的任务队列
|
||||
avatar_train_task_sq = None
|
||||
|
||||
# webui的lora存储目录
|
||||
webui_lora_dir = None
|
||||
|
||||
# webui_server_port
|
||||
webui_server_port = None
|
||||
|
||||
# server ip address
|
||||
server_ip = None
|
||||
|
||||
# service port
|
||||
server_port = 10239
|
||||
|
||||
# 是否启动视频的硬件编码
|
||||
video_hardware_encode = True
|
||||
|
||||
#----------------------------------------------
|
||||
|
||||
# 发型lora训练队列
|
||||
hair_style_lora_train_task_sq = None
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
import base64
|
||||
import time
|
||||
|
||||
import requests
|
||||
import cv2
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
import tqdm
|
||||
|
||||
# OpenAI API Key
|
||||
api_key = "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"
|
||||
|
||||
# Function to encode the image
|
||||
def encode_image(image_path):
|
||||
img = cv2.imread(image_path)
|
||||
scale = 500.0 / min(img.shape[:2])
|
||||
img = cv2.resize(img, (0, 0), fx=scale, fy=scale)
|
||||
scaled_path = '/tmp/scaled_image.jpg'
|
||||
cv2.imwrite(scaled_path, img)
|
||||
with open(scaled_path, "rb") as image_file:
|
||||
return base64.b64encode(image_file.read()).decode('utf-8')
|
||||
|
||||
def caption_image(image_path):
|
||||
# Getting the base64 string
|
||||
base64_image = encode_image(image_path)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {api_key}"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"model": "gpt-4-vision-preview",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "As an AI image tagging expert, please provide precise tags for the hairstyle in the image, To enhance CLIP model's understanding of the content. Please provide a detailed description of the hairstyle in the image, including but not limited to the color, style, length, curliness, hairline, highlights, gradients, etc. Your tags should be accurate, non-duplicative, and within a 10-20 word count range. Tags should be comma-separated. No need to provide any safety statements or precautions."
|
||||
},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": f"data:image/jpeg;base64,{base64_image}",
|
||||
"detail": "low"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"max_tokens": 300
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
|
||||
tmp_json = response.json()
|
||||
return tmp_json['choices'][0]['message']['content']
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return ""
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
prompt = caption_image('/home/chinatszrn/Downloads/abc/train_data/style1/07ebac82-4c0f-4dd2-84bd-bc34a059bd9b.png')
|
||||
print(prompt)
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
import gradio as gr
|
||||
import os,re
|
||||
import numpy as np
|
||||
import requests
|
||||
import cv2
|
||||
import base64
|
||||
import json
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
api_service_url = 'http://127.0.0.1:1234'
|
||||
# api_service_url = 'http://i-2.gpushare.com:53412'
|
||||
|
||||
class ChangeFaceGui():
|
||||
def __init__(self):
|
||||
self.template_list = self.get_template_list()
|
||||
self.user_dict = self.get_user_dict()
|
||||
# self.tmp_dir = './tmp'
|
||||
# if not os.path.exists(self.tmp_dir): os.makedirs(self.tmp_dir)
|
||||
self.user_img_list = []
|
||||
# 获取户图片
|
||||
for item in self.user_dict:
|
||||
response = requests.get(item['face_img_url'])
|
||||
image_data = BytesIO(response.content)
|
||||
user_face_img = cv2.imdecode(np.frombuffer(image_data.read(), np.uint8), cv2.IMREAD_COLOR)
|
||||
self.user_img_list.append(user_face_img)
|
||||
item['face_img'] = user_face_img
|
||||
|
||||
# img_path = f'{self.tmp_dir}/{item["user_id"]}.jpg'
|
||||
# if not os.path.exists(img_path):
|
||||
# cv2.imwrite(f'{self.tmp_dir}/{item["user_id"]}.jpg', user_face_img)
|
||||
|
||||
|
||||
#请求得到模板图片的url
|
||||
def get_template_list(self):
|
||||
url = f"{api_service_url}/template/list"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print('请求模板照片成功!!')
|
||||
return(response.json()['data'])
|
||||
|
||||
|
||||
#请求得到用户图片及ID
|
||||
def get_user_dict(self):
|
||||
url = f"{api_service_url}/user/list"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
user_dict = response.json()['data']
|
||||
print('请求用户照片成功!!')
|
||||
return(user_dict)
|
||||
|
||||
|
||||
#获取用户ID
|
||||
def get_user_id(self, user_img):
|
||||
user_small_img = cv2.resize(user_img, (100, 100))
|
||||
mse = []
|
||||
for item in self.user_dict:
|
||||
user_face_img = item['face_img']
|
||||
# cv2.imwrite(f'{self.tmp_dir}/{item["user_id"]}_list.jpg', user_face_img)
|
||||
user_face_img = cv2.resize(user_face_img, (100, 100))
|
||||
# 计算均方误差
|
||||
mse.append(np.mean((user_small_img - user_face_img) ** 2))
|
||||
|
||||
# 找到均方差最小值对应的ID
|
||||
user_id = mse.index(min(mse))
|
||||
user_id = self.user_dict[user_id]['user_id']
|
||||
print('用户ID:', user_id)
|
||||
return user_id
|
||||
|
||||
|
||||
#虚拟试穿模块,输入是模特图和衣服图,输出是虚拟试穿的结果
|
||||
def take_photo(self, template_img, user_img):
|
||||
# if not os.path.exists(self.tmp_dir):os.makedirs(self.tmp_dir)
|
||||
|
||||
if template_img is None or user_img is None:
|
||||
return None
|
||||
|
||||
# 使用 Pillow 加载图像
|
||||
template_img = Image.open(template_img)
|
||||
user_img = Image.open(user_img)
|
||||
|
||||
# 将 Pillow 图像转换为 OpenCV 格式(BGR)
|
||||
template_img = cv2.cvtColor(np.array(template_img), cv2.COLOR_RGB2BGR)
|
||||
user_img = cv2.cvtColor(np.array(user_img), cv2.COLOR_RGB2BGR)
|
||||
|
||||
# 将模板图片转换为base64格式
|
||||
retval, template_bytes = cv2.imencode('.jpg', template_img)
|
||||
encoded_image = base64.b64encode(template_bytes).decode('utf-8')
|
||||
user_id = self.get_user_id(user_img)
|
||||
url = f"{api_service_url}/user/generate"
|
||||
payload = json.dumps({
|
||||
"user_id": user_id,
|
||||
"base_img": encoded_image
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
print('请求api_service.py发送请求!!')
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print('请求api_service.py发送请求成功!!')
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(f"Failed to send request to API service. Status code: {response.status_code}")
|
||||
|
||||
ret_image_b64 = response.json().get('generate_photo_b64')
|
||||
|
||||
if ret_image_b64 is None:
|
||||
raise RuntimeError(f"ret image failed!")
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(ret_image_b64), np.uint8)
|
||||
result_image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
result_image = cv2.cvtColor(result_image, cv2.COLOR_BGR2RGB)
|
||||
return result_image
|
||||
|
||||
|
||||
def start_gui(self):
|
||||
user_img_list = []
|
||||
for item in self.user_img_list:
|
||||
img = cv2.cvtColor(item, cv2.COLOR_BGR2RGB)
|
||||
user_img_list.append(img)
|
||||
|
||||
with gr.Blocks() as demo:
|
||||
with gr.Row():
|
||||
gr.Markdown("# 数字力场效果展示")
|
||||
|
||||
# 换脸
|
||||
with gr.Tab("数字写真"):
|
||||
with gr.Row():
|
||||
gr.Markdown("# 数字写真")
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
#选择模板
|
||||
template_img = gr.Image(label="模版", sources='upload', min_width=384, width=384, height=384, type="filepath", value=self.template_list[0],interactive=True)
|
||||
example_template = gr.Examples(
|
||||
inputs=template_img,
|
||||
examples_per_page=12,
|
||||
examples= self.template_list)
|
||||
with gr.Column():
|
||||
# 选择用户
|
||||
user_img = gr.Image(label="用户", sources='upload', min_width=384, width=384, height=384, type="filepath", value= user_img_list[0],interactive=False)
|
||||
example_user = gr.Examples(
|
||||
inputs=user_img,
|
||||
examples_per_page=12,
|
||||
examples=user_img_list)
|
||||
|
||||
with gr.Column():
|
||||
output_img = gr.Image(label="结果展示", type="numpy", height=576, width=384)
|
||||
with gr.Column():
|
||||
run_button = gr.Button(value="提交")
|
||||
run_button.click(self.take_photo, inputs=[template_img, user_img], outputs=[output_img])
|
||||
|
||||
# #换衣服
|
||||
# with gr.Tab("换衣"):
|
||||
# with gr.Row():
|
||||
# gr.Markdown("# 换衣")
|
||||
# text_button = gr.Button("提交")
|
||||
# # 换发型
|
||||
# with gr.Tab("换发型"):
|
||||
# with gr.Row():
|
||||
# gr.Markdown("# 换发型")
|
||||
# text_button = gr.Button("提交")
|
||||
|
||||
demo.launch(server_name='0.0.0.0', server_port=8080)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
demo = ChangeFaceGui()
|
||||
demo.start_gui()
|
||||
@@ -0,0 +1,102 @@
|
||||
import gradio as gr
|
||||
import os,re
|
||||
import numpy as np
|
||||
import requests
|
||||
import cv2
|
||||
import base64
|
||||
import json
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
# api_service_url = 'http://127.0.0.1:1234'
|
||||
# api_service_url = 'http://i-2.gpushare.com:53412'
|
||||
api_service_url = 'http://service.aicloud.fit:7393/api/hairStyle/v1'
|
||||
|
||||
class ChangeHairGui():
|
||||
# def __init__(self):
|
||||
# a = 1
|
||||
def change_hair(self, user_img, hair_img):
|
||||
|
||||
if user_img is None or user_img is None:
|
||||
return None
|
||||
#
|
||||
# if user_img.shape != hair_img.shape:
|
||||
# hair_img = cv2.resize(hair_img, (user_img.shape[1], user_img.shape[0]))
|
||||
#
|
||||
# alpha = 0.5 # 图像1的权重
|
||||
# beta = 0.5 # 图像2的权重
|
||||
# gamma = 0 # 亮度调整常量(通常为0)
|
||||
#
|
||||
# result_image = cv2.addWeighted(user_img, alpha, hair_img, beta, gamma)
|
||||
|
||||
|
||||
# 将 Pillow 图像转换为 OpenCV 格式(BGR)
|
||||
user_img = cv2.cvtColor(np.array(user_img), cv2.COLOR_RGB2BGR)
|
||||
hair_img = cv2.cvtColor(np.array(hair_img), cv2.COLOR_RGB2BGR)
|
||||
|
||||
# 将模板图片转换为base64格式
|
||||
retval, user_bytes = cv2.imencode('.jpg', user_img)
|
||||
encoded_user_image = base64.b64encode(user_bytes).decode('utf-8')
|
||||
retval, hair_bytes = cv2.imencode('.jpg', hair_img)
|
||||
encoded_hair_image = base64.b64encode(hair_bytes).decode('utf-8')
|
||||
|
||||
url = api_service_url
|
||||
|
||||
# 请求换发型接口
|
||||
payload = json.dumps({
|
||||
"user_img_base64": encoded_user_image,
|
||||
"hair_ref_img_base64": encoded_hair_image
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
print('请求api_service.py发送请求!!')
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print('请求api_service.py发送请求成功!!')
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(f"Failed to send request to API service. Status code: {response.status_code}")
|
||||
|
||||
ret_image_b64 = response.json().get('result')
|
||||
|
||||
if ret_image_b64 is None:
|
||||
raise RuntimeError(f"ret image failed!")
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(ret_image_b64), np.uint8)
|
||||
result_image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
result_image = cv2.cvtColor(result_image, cv2.COLOR_BGR2RGB)
|
||||
|
||||
dst_size = max(result_image.shape[0], result_image.shape[1])
|
||||
M = cv2.getRotationMatrix2D((result_image.shape[1] / 2, result_image.shape[0] / 2), 0, 1)
|
||||
M[:, 2] += np.float32([dst_size / 2 - result_image.shape[1] / 2, dst_size / 2 - result_image.shape[0] / 2])
|
||||
result_image = cv2.warpAffine(result_image, M, (dst_size, dst_size), borderValue=(255, 255, 255))
|
||||
|
||||
return result_image
|
||||
|
||||
|
||||
|
||||
def start_gui(self):
|
||||
with gr.Blocks() as demo:
|
||||
with gr.Row():
|
||||
gr.Markdown("# 数字力场换发型效果展示")
|
||||
|
||||
# 换脸
|
||||
with gr.Tab("换发型"):
|
||||
with gr.Row():
|
||||
gr.Markdown("#换发型")
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
user_img = gr.Image(label="请上传用户图片", type="numpy", height=384, width=384)
|
||||
with gr.Column():
|
||||
hair_img = gr.Image(label="请上传发型图片", type="numpy", height=384, width=384)
|
||||
with gr.Column():
|
||||
output_img = gr.Image(label="结果展示", type="numpy", height=384, width=384, format='png')
|
||||
with gr.Column():
|
||||
run_button = gr.Button(value="提交")
|
||||
run_button.click(self.change_hair, inputs=[user_img, hair_img], outputs=[output_img])
|
||||
|
||||
demo.launch(server_name='0.0.0.0', server_port=8080)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
demo = ChangeHairGui()
|
||||
demo.start_gui()
|
||||
@@ -0,0 +1,120 @@
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os, sys
|
||||
from gevent import pywsgi, monkey
|
||||
from multiprocessing import Process, Queue
|
||||
import glob
|
||||
|
||||
# from gpt4v_caption import caption_image
|
||||
|
||||
# monkey.patch_all()
|
||||
# sys.setrecursionlimit(20000)
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
|
||||
import global_variable as global_var
|
||||
import json
|
||||
|
||||
|
||||
|
||||
def train_hair_lora():
|
||||
import os
|
||||
import json
|
||||
|
||||
try:
|
||||
hair_train_dir = "/mnt/database2/jiangqian/0808/online_train_datas_2"
|
||||
hair_material_dir_list = os.listdir(hair_train_dir)
|
||||
|
||||
for single_hair_material in hair_material_dir_list:
|
||||
# 获取请求参数
|
||||
task_id = str(uuid.uuid4())
|
||||
|
||||
request_data = {}
|
||||
hair_material_dir = os.path.join(hair_train_dir, single_hair_material)
|
||||
print("--------------------hair_material_dir:", hair_material_dir)
|
||||
request_data['hair_material_dir'] = hair_material_dir
|
||||
|
||||
img_dir = os.path.join(hair_material_dir, 'images')
|
||||
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
if not os.path.exists(model_dir):
|
||||
os.makedirs(model_dir)
|
||||
|
||||
#判断img_dir下面是否只有一个文件夹
|
||||
img_dir_list = os.listdir(img_dir)
|
||||
train_image_dir = os.path.join(img_dir, img_dir_list[0])
|
||||
|
||||
#判断文件夹下面是否有图片
|
||||
request_data['train_image_dir'] = train_image_dir
|
||||
|
||||
# 将请求数据放入队列
|
||||
train_thread(request_data)
|
||||
|
||||
# 返回结果
|
||||
print("头发lora训练开始")
|
||||
print("\n\n\n\n")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def train_thread(task_dict):
|
||||
try:
|
||||
hair_material_dir = task_dict['hair_material_dir']
|
||||
images_dir = os.path.join(hair_material_dir, 'images')
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
train_image_dir = task_dict['train_image_dir']
|
||||
tag = ""
|
||||
|
||||
sample_dir = os.path.join(model_dir, 'sample')
|
||||
if not os.path.exists(sample_dir):
|
||||
os.makedirs(sample_dir)
|
||||
sample_txt = os.path.join(sample_dir, 'prompt.txt')
|
||||
with open(sample_txt, 'w') as f_s:
|
||||
f_s.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, '
|
||||
+ tag
|
||||
+ ' --n low quality, worst quality, bad anatomy, bad composition, poor, low effort --h 512 '
|
||||
'--w 512 --s 30 --l 7')
|
||||
|
||||
#训练头发lora
|
||||
cmd_train = (
|
||||
'docker run --rm --gpus all -v /home/student/Documents/workspace_cxt_tianjing_hair/miaoya/kohya_ss_home:/home/chinatszrn -v '
|
||||
'/mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
'--net=host chinatszrn/ubuntu:kohya_ss accelerate launch --num_cpu_threads_per_process=2 "./train_network.py" --enable_bucket '
|
||||
'--min_bucket_reso=256 --max_bucket_reso=1800 --pretrained_model_name_or_path="/mnt/nas_hdd/米亚像馆/models/Stable-diffusion/majicmixRealistic_v7.safetensors" '
|
||||
f'--train_data_dir={images_dir} --resolution="768,768" '
|
||||
f'--output_dir={model_dir} '
|
||||
'--network_alpha="64" --save_model_as=safetensors --network_module=networks.lora --text_encoder_lr=5e-05 '
|
||||
'--unet_lr=0.0001 --network_dim=128 --output_name="hairstyle_lora" --lr_scheduler_num_cycles="20" '
|
||||
'--no_half_vae --learning_rate="0.0001" --lr_scheduler="cosine" --lr_warmup_steps="650" --train_batch_size="1" '
|
||||
'--max_train_steps="2000" --save_every_n_epochs="100" --mixed_precision="fp16" --save_precision="fp16" '
|
||||
'--caption_extension=".txt" --sample_sampler=ddim '
|
||||
f'--sample_prompts={sample_txt} --sample_every_n_epochs="1" '
|
||||
'--seed="1234" --cache_latents --optimizer_type="AdamW8bit" --max_data_loader_n_workers="0" --bucket_reso_steps=64 '
|
||||
'--xformers --bucket_no_upscale --noise_offset=0.0 --tokenizer_cache_dir="/home/chinatszrn/.cache/clip"')
|
||||
print("cmd_train:", cmd_train)
|
||||
os.system(cmd_train)
|
||||
|
||||
lora_path = os.path.join(model_dir, 'hairstyle_lora.safetensors')
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
global_var.webui_lora_dir = '/home/student/Documents/workspace_cxt_tianjing_hair/miaoya/webui_home/stable-diffusion-webui/models/Lora'
|
||||
|
||||
train_hair_lora()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os, sys
|
||||
from gevent import pywsgi, monkey
|
||||
from multiprocessing import Process, Queue
|
||||
import glob
|
||||
|
||||
# from gpt4v_caption import caption_image
|
||||
|
||||
# monkey.patch_all()
|
||||
# sys.setrecursionlimit(20000)
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
from flask import Flask, request, jsonify
|
||||
import global_variable as global_var
|
||||
import json
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
def send_request(url, state, task_dict):
|
||||
import requests
|
||||
import json
|
||||
|
||||
msg = '头发lora训练失败' if state == -1 else '头发lora训练成功'
|
||||
payload = json.dumps({
|
||||
"task_id": task_dict['task_id'] if task_dict is not None else '',
|
||||
"hair_id": task_dict['hair_id'] if task_dict is not None else '',
|
||||
"state": state,
|
||||
"msg": msg,
|
||||
"is_tj": task_dict['is_tj']
|
||||
})
|
||||
|
||||
print("payload:", payload)
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
|
||||
@app.route('/api/hair/train', methods=['POST'])
|
||||
def train_hair_lora():
|
||||
import os
|
||||
import json
|
||||
task_id = ''
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
assert 'task_id' in request_data, 'task_id is required'
|
||||
task_id = request_data['task_id']
|
||||
assert 'hair_id' in request_data and 'hair_material_dir' in request_data, 'hair_id and hair_material_dir is required'
|
||||
hair_material_dir = request_data['hair_material_dir']
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
img_dir = os.path.join(hair_material_dir, 'images')
|
||||
assert os.path.exists(img_dir), f'{img_dir} not exists'
|
||||
assert os.path.exists(
|
||||
os.path.join(hair_material_dir, 'model')), f'{os.path.join(hair_material_dir, "model")} not exists'
|
||||
|
||||
#判断img_dir下面是否只有一个文件夹
|
||||
img_dir_list = os.listdir(img_dir)
|
||||
assert len(img_dir_list) == 1, f'{img_dir}下面只能有一个文件夹'
|
||||
train_image_dir = os.path.join(img_dir, img_dir_list[0])
|
||||
assert os.path.isdir(train_image_dir), f'{train_image_dir}不是文件夹'
|
||||
# 检查该文件夹是否以数字加下划线开头
|
||||
assert img_dir_list[0].split('_')[0].isdigit(), f'{img_dir_list[0]}不是数字开头'
|
||||
|
||||
#判断文件夹下面是否有图片
|
||||
img_list = glob.glob(train_image_dir + '/*.png')
|
||||
assert len(img_list) > 10, f'{os.path.join(img_dir, img_dir_list[0])}下面图片数量小于10张'
|
||||
request_data['train_image_dir'] = train_image_dir
|
||||
|
||||
# is tianjin company
|
||||
try:
|
||||
request_data['is_tj'] = request_data['is_tj']
|
||||
except Exception as e:
|
||||
print(e)
|
||||
request_data['is_tj'] = '0'
|
||||
|
||||
# 将请求数据放入队列
|
||||
global_var.hair_style_lora_train_task_sq.put(request_data)
|
||||
|
||||
# 返回结果
|
||||
ret_dict = dict(state=0, msg='头发lora训练开始', task_id=task_id)
|
||||
return jsonify(ret_dict)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e), task_id=task_id)
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/api/hair/inference', methods=['POST'])
|
||||
def inference_webui():
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
onediff_url = "http://127.0.0.1:9038/sdapi/v1/img2img"
|
||||
|
||||
try:
|
||||
t1 = time.time()
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
# hd_version_flag = request_data.get('hd_version_flag', False)
|
||||
hair_id = request_data['hair_id']
|
||||
selected_url = url
|
||||
if 'refiner_checkpoint' not in request_json:
|
||||
selected_url = onediff_url
|
||||
request_json['script_name'] = 'onediff_diffusion_model'
|
||||
print('user onediff')
|
||||
|
||||
|
||||
|
||||
# if hd_version_flag:
|
||||
# print('user hd version!!!!!')
|
||||
# lora_file_name = 'hairstyle_hd_lora.safetensors'
|
||||
# else:
|
||||
# lora_file_name = 'hairstyle_lora.safetensors'
|
||||
|
||||
hair_material_dir = request_data.get('hair_material_dir')
|
||||
print(hair_material_dir)
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
|
||||
hd_version_flag = True
|
||||
lora_file_name = 'hairstyle_hd_lora.safetensors'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', lora_file_name)
|
||||
if not os.path.exists(request_lora_path):
|
||||
print('use low resolution lora')
|
||||
hd_version_flag = False
|
||||
lora_file_name = 'hairstyle_lora.safetensors'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', lora_file_name)
|
||||
|
||||
assert os.path.exists(request_lora_path), f'{request_lora_path} not exists'
|
||||
|
||||
if hd_version_flag:
|
||||
tmp_lora_name = f'{hair_id}_hd'
|
||||
else:
|
||||
tmp_lora_name = f'{hair_id}'
|
||||
lora_dst_path = os.path.join(global_var.webui_lora_dir, f'{tmp_lora_name}.safetensors')
|
||||
if not os.path.exists(lora_dst_path):
|
||||
os.system('cp {} {}'.format(request_lora_path, lora_dst_path))
|
||||
request_json['prompt'] = f'<lora:{tmp_lora_name}:1.0>, titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
print('pre_stage cost:', time.time() - t1)
|
||||
|
||||
start_time = time.time()
|
||||
response = requests.post(url=selected_url, json=request_json)
|
||||
print('inference time:', time.time() - start_time)
|
||||
|
||||
ret_json = response.json()
|
||||
# if os.path.exists(lora_dst_path):
|
||||
# os.remove(lora_dst_path)
|
||||
# 返回结果
|
||||
return jsonify(ret_json)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e))
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/api/hair/inference_diy', methods=['POST'])
|
||||
def inference_diy_webui():
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
onediff_url = "http://127.0.0.1:9038/sdapi/v1/img2img"
|
||||
|
||||
try:
|
||||
t1 = time.time()
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
|
||||
selected_url = url
|
||||
if 'refiner_checkpoint' not in request_json:
|
||||
selected_url = onediff_url
|
||||
request_json['script_name'] = 'onediff_diffusion_model'
|
||||
print('user onediff')
|
||||
|
||||
request_json['prompt'] = f'titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
print('pre_stage cost:', time.time() - t1)
|
||||
|
||||
start_time = time.time()
|
||||
response = requests.post(url=selected_url, json=request_json)
|
||||
print('inference time:', time.time() - start_time)
|
||||
|
||||
ret_json = response.json()
|
||||
# if os.path.exists(lora_dst_path):
|
||||
# os.remove(lora_dst_path)
|
||||
# 返回结果
|
||||
return jsonify(ret_json)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e))
|
||||
return jsonify(ret_dict)
|
||||
|
||||
def train_thread(sq, gpu_id):
|
||||
while True:
|
||||
url = 'http://service.aicloud.fit:7393/api/hair/trainCallBack'
|
||||
task_dict = None
|
||||
try:
|
||||
task_dict = sq.get()
|
||||
hair_material_dir = task_dict['hair_material_dir']
|
||||
images_dir = os.path.join(hair_material_dir, 'images')
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
train_image_dir = task_dict['train_image_dir']
|
||||
# tag = task_dict['tag']
|
||||
tag = ""
|
||||
is_tj = task_dict['is_tj']
|
||||
|
||||
sample_dir = os.path.join(model_dir, 'sample')
|
||||
if not os.path.exists(sample_dir):
|
||||
os.makedirs(sample_dir)
|
||||
sample_txt = os.path.join(sample_dir, 'prompt.txt')
|
||||
with open(sample_txt, 'w') as f_s:
|
||||
f_s.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, '
|
||||
+ tag
|
||||
+ ' --n low quality, worst quality, bad anatomy, bad composition, poor, low effort --h 768 '
|
||||
'--w 768 --s 30 --l 7')
|
||||
|
||||
# 给训练图片打标签
|
||||
# cmd_caption = ('docker run --rm --gpus all -v /home/chinatszrn/Documents/miaoya/kohya_ss_home:/home/chinatszrn '
|
||||
# '-v /mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
# '--net=host chinatszrn/ubuntu:kohya_ss accelerate '
|
||||
# 'launch "./finetune/tag_images_by_wd14_tagger.py" --batch_size=2 '
|
||||
# '--general_threshold=0.5 --character_threshold=0.5 --caption_extension=".txt" '
|
||||
# '--model="SmilingWolf/wd-v1-4-convnextv2-tagger-v2" --max_data_loader_n_workers="2" '
|
||||
# '--debug --remove_underscore --frequency_tags --undesired_tags="1girl, 1boy" '
|
||||
# f'"{train_image_dir}"')
|
||||
# os.system(cmd_caption)
|
||||
|
||||
img_path_list = glob.glob(train_image_dir + '/*.png')
|
||||
# 给训练图片打标签, gpt
|
||||
for img_path in img_path_list:
|
||||
# print(img_path)
|
||||
txt_path = img_path[:-4] + '.txt'
|
||||
|
||||
print("tag img_path: ", img_path)
|
||||
# tags = caption_image(img_path)
|
||||
tags = tag
|
||||
with open(txt_path, 'w') as f:
|
||||
f.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, ' + tags)
|
||||
|
||||
#判断是否每个训练图片都有标签文件
|
||||
# for img_path in img_path_list:
|
||||
# assert os.path.exists(img_path[:-4]+'.txt'), f'{img_path}没有对应的标签文件'
|
||||
# with open(img_path[:-4]+'.txt', 'r') as f:
|
||||
# tags = f.readline()
|
||||
# with open(img_path[:-4]+'.txt', 'w') as f:
|
||||
# f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
|
||||
#训练头发lora
|
||||
cmd_train = (
|
||||
'docker run --rm --gpus "device=0" -v /home/student/Documents/workspace_cxt_tianjing_hair/miaoya/kohya_ss_home:/home/chinatszrn -v '
|
||||
'/mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
'--net=host chinatszrn/ubuntu:kohya_ss accelerate launch --num_cpu_threads_per_process=2 "./train_network.py" --enable_bucket '
|
||||
'--min_bucket_reso=256 --max_bucket_reso=2048 --pretrained_model_name_or_path="/mnt/nas_hdd/米亚像馆/models/Stable-diffusion/majicmixRealistic_v7.safetensors" '
|
||||
f'--train_data_dir={images_dir} --resolution="2000,2000" '
|
||||
f'--output_dir={model_dir} '
|
||||
'--network_alpha="64" --save_model_as=safetensors --network_module=networks.lora --text_encoder_lr=5e-05 '
|
||||
'--unet_lr=0.0001 --network_dim=128 --output_name="hairstyle_hd_lora" --lr_scheduler_num_cycles="20" '
|
||||
'--no_half_vae --learning_rate="0.0001" --lr_scheduler="cosine" --lr_warmup_steps="650" --train_batch_size="1" '
|
||||
'--max_train_steps="1500" --save_every_n_epochs="100" --mixed_precision="fp16" --save_precision="fp16" '
|
||||
'--caption_extension=".txt" --sample_sampler=ddim '
|
||||
f'--sample_prompts={sample_txt} --sample_every_n_epochs="1000" '
|
||||
'--seed="1234" --cache_latents --optimizer_type="AdamW8bit" --max_data_loader_n_workers="0" --bucket_reso_steps=64 '
|
||||
'--xformers --bucket_no_upscale --noise_offset=0.0 --tokenizer_cache_dir="/home/chinatszrn/.cache/clip"')
|
||||
print("cmd_train:", cmd_train)
|
||||
os.system(cmd_train)
|
||||
|
||||
lora_path = os.path.join(model_dir, 'hairstyle_hd_lora.safetensors')
|
||||
|
||||
# tianjin callback
|
||||
if is_tj == "1":
|
||||
url = 'http://service.aicloud.fit:7395/api/hair/trainCallBack'
|
||||
|
||||
if not os.path.exists(lora_path):
|
||||
send_request(url, -1, task_dict)
|
||||
else:
|
||||
send_request(url, 0, task_dict)
|
||||
|
||||
except Exception as e:
|
||||
send_request(url, -1, None)
|
||||
continue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
global_var.webui_lora_dir = '/gz-fs/models/Lora'
|
||||
|
||||
# avatar训练的任务队列
|
||||
global_var.hair_style_lora_train_task_sq = Queue()
|
||||
p = Process(target=train_thread, args=(
|
||||
global_var.hair_style_lora_train_task_sq, 0))
|
||||
p.start()
|
||||
|
||||
# # 启动服务
|
||||
# app.run(debug=True, port=32678, host='0.0.0.0')
|
||||
|
||||
server = pywsgi.WSGIServer(('0.0.0.0', 32678), app) # test port
|
||||
server.serve_forever()
|
||||
@@ -0,0 +1,357 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os, sys
|
||||
from gevent import pywsgi, monkey
|
||||
from multiprocessing import Process, Queue
|
||||
import glob
|
||||
import datetime
|
||||
# from gpt4v_caption import caption_image
|
||||
|
||||
# monkey.patch_all()
|
||||
# sys.setrecursionlimit(20000)
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
from flask import Flask, request, jsonify
|
||||
import global_variable as global_var
|
||||
import json
|
||||
#from common.logger import config
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
version = "online"
|
||||
if version == "local":
|
||||
current_url = 'http://service.aicloud.fit:7393/'
|
||||
kohya_ss_home_dir = '/home/chinatszrn/Documents/miaoya/kohya_ss_home'
|
||||
webui_lora_dir = '/home/chinatszrn/Documents/miaoya/webui_home/stable-diffusion-webui/models/Lora'
|
||||
inference_use_onediff = False
|
||||
callback_url = 'http://service.aicloud.fit:7395/api/hair/trainCallBack'
|
||||
else:
|
||||
current_url = 'http://0.0.0.0:7393/'
|
||||
kohya_ss_home_dir = os.path.join(BASE_DIR, 'kohya_ss_home')
|
||||
webui_lora_dir = os.path.join(BASE_DIR, 'stable-diffusion-webui', 'models', 'Lora')
|
||||
inference_use_onediff = False
|
||||
callback_url = 'http://0.0.0.0:8801/api/hair/trainCallBack'
|
||||
base_webui_port = '57860'
|
||||
base_onediff_port = '9038'
|
||||
base_webui_url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
def send_request(url, state, task_dict):
|
||||
import requests
|
||||
import json
|
||||
|
||||
msg = '头发lora训练失败' if state == -1 else '头发lora训练成功'
|
||||
payload = json.dumps({
|
||||
"task_id": task_dict['task_id'] if task_dict is not None else '',
|
||||
"hair_id": task_dict['hair_id'] if task_dict is not None else '',
|
||||
"state": state,
|
||||
"msg": msg,
|
||||
"is_tj": task_dict['is_tj']
|
||||
})
|
||||
|
||||
print("payload:", payload)
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
|
||||
@app.route('/api/hair/train', methods=['POST'])
|
||||
def train_hair_lora():
|
||||
import os
|
||||
import json
|
||||
task_id = ''
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
assert 'task_id' in request_data, 'task_id is required'
|
||||
task_id = request_data['task_id']
|
||||
assert 'hair_id' in request_data and 'hair_material_dir' in request_data, 'hair_id and hair_material_dir is required'
|
||||
hair_material_dir = request_data['hair_material_dir']
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
img_dir = os.path.join(hair_material_dir, 'images')
|
||||
assert os.path.exists(img_dir), f'{img_dir} not exists'
|
||||
assert os.path.exists(
|
||||
os.path.join(hair_material_dir, 'model')), f'{os.path.join(hair_material_dir, "model")} not exists'
|
||||
|
||||
#判断img_dir下面是否只有一个文件夹
|
||||
img_dir_list = os.listdir(img_dir)
|
||||
assert len(img_dir_list) == 1, f'{img_dir}下面只能有一个文件夹'
|
||||
train_image_dir = os.path.join(img_dir, img_dir_list[0])
|
||||
assert os.path.isdir(train_image_dir), f'{train_image_dir}不是文件夹'
|
||||
# 检查该文件夹是否以数字加下划线开头
|
||||
assert img_dir_list[0].split('_')[0].isdigit(), f'{img_dir_list[0]}不是数字开头'
|
||||
|
||||
#判断文件夹下面是否有图片
|
||||
img_list = glob.glob(train_image_dir + '/*.png')
|
||||
assert len(img_list) > 10, f'{os.path.join(img_dir, img_dir_list[0])}下面图片数量小于10张'
|
||||
request_data['train_image_dir'] = train_image_dir
|
||||
|
||||
# is tianjin company
|
||||
try:
|
||||
request_data['is_tj'] = request_data['is_tj']
|
||||
request_data['device_id'] = request_data['device_id']
|
||||
except Exception as e:
|
||||
print(e)
|
||||
request_data['is_tj'] = '0'
|
||||
request_data['device_id'] = '1'
|
||||
|
||||
# 将请求数据放入队列
|
||||
global_var.hair_style_lora_train_task_sq.put(request_data)
|
||||
|
||||
# 返回结果
|
||||
ret_dict = dict(state=0, msg='头发lora训练开始', task_id=task_id)
|
||||
return jsonify(ret_dict)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e), task_id=task_id)
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/api/hair/inference', methods=['POST'])
|
||||
def inference_webui():
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
|
||||
|
||||
try:
|
||||
t1 = time.time()
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
# hd_version_flag = request_data.get('hd_version_flag', False)
|
||||
hair_id = request_data['hair_id']
|
||||
inference_port = request_data['inference_port']
|
||||
|
||||
if inference_use_onediff and 'refiner_checkpoint' not in request_json:
|
||||
selected_url = base_webui_url.replace(base_webui_port, base_onediff_port)
|
||||
request_json['script_name'] = 'onediff_diffusion_model'
|
||||
print('user onediff')
|
||||
else:
|
||||
selected_url = base_webui_url.replace(base_webui_port, inference_port)
|
||||
|
||||
|
||||
|
||||
# if hd_version_flag:
|
||||
# print('user hd version!!!!!')
|
||||
# lora_file_name = 'hairstyle_hd_lora.safetensors'
|
||||
# else:
|
||||
# lora_file_name = 'hairstyle_lora.safetensors'
|
||||
|
||||
hair_material_dir = request_data.get('hair_material_dir')
|
||||
print(hair_material_dir)
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
|
||||
hd_version_flag = True
|
||||
lora_file_name = 'hairstyle_hd_lora.safetensors'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', lora_file_name)
|
||||
if not os.path.exists(request_lora_path):
|
||||
print('use low resolution lora')
|
||||
hd_version_flag = False
|
||||
lora_file_name = 'hairstyle_lora.safetensors'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', lora_file_name)
|
||||
|
||||
assert os.path.exists(request_lora_path), f'{request_lora_path} not exists'
|
||||
|
||||
if hd_version_flag:
|
||||
tmp_lora_name = f'{hair_id}_hd'
|
||||
else:
|
||||
tmp_lora_name = f'{hair_id}'
|
||||
lora_dst_path = os.path.join(global_var.webui_lora_dir, f'{tmp_lora_name}.safetensors')
|
||||
if not os.path.exists(lora_dst_path):
|
||||
os.system('cp {} {}'.format(request_lora_path, lora_dst_path))
|
||||
request_json['prompt'] = f'<lora:{tmp_lora_name}:1.0>, titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
print('pre_stage cost:', time.time() - t1)
|
||||
|
||||
start_time = time.time()
|
||||
current_time = datetime.datetime.now()
|
||||
print("*********cxt log1, infer***************, {}:{}:{}, {}".format(current_time.hour, current_time.minute,
|
||||
current_time.second, selected_url))
|
||||
response = requests.post(url=selected_url, json=request_json)
|
||||
print('inference time:', time.time() - start_time)
|
||||
|
||||
ret_json = response.json()
|
||||
# if os.path.exists(lora_dst_path):
|
||||
# os.remove(lora_dst_path)
|
||||
# 返回结果
|
||||
return jsonify(ret_json)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e))
|
||||
return jsonify(ret_dict)
|
||||
|
||||
|
||||
@app.route('/api/hair/inference_diy', methods=['POST'])
|
||||
def inference_diy_webui():
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
|
||||
try:
|
||||
t1 = time.time()
|
||||
# 获取请求参数
|
||||
request_data = request.get_json()
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
inference_port = request_data['inference_port']
|
||||
|
||||
if inference_use_onediff and 'refiner_checkpoint' not in request_json:
|
||||
selected_url = base_webui_url.replace(base_webui_port, base_onediff_port)
|
||||
request_json['script_name'] = 'onediff_diffusion_model'
|
||||
print('user onediff')
|
||||
else:
|
||||
selected_url = base_webui_url.replace(base_webui_port, inference_port)
|
||||
|
||||
request_json['prompt'] = f'titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
print('pre_stage cost:', time.time() - t1)
|
||||
|
||||
start_time = time.time()
|
||||
current_time = datetime.datetime.now()
|
||||
print("*********cxt log1, diy***************, {}:{}:{}, {}".format(current_time.hour, current_time.minute,
|
||||
current_time.second, selected_url))
|
||||
response = requests.post(url=selected_url, json=request_json)
|
||||
print('inference time:', time.time() - start_time)
|
||||
|
||||
ret_json = response.json()
|
||||
# if os.path.exists(lora_dst_path):
|
||||
# os.remove(lora_dst_path)
|
||||
# 返回结果
|
||||
return jsonify(ret_json)
|
||||
except Exception as e:
|
||||
ret_dict = dict(state=-1, msg=str(e))
|
||||
return jsonify(ret_dict)
|
||||
|
||||
def train_thread(sq, gpu_id):
|
||||
while True:
|
||||
url = f'{current_url}api/hair/trainCallBack'
|
||||
task_dict = None
|
||||
try:
|
||||
task_dict = sq.get()
|
||||
hair_material_dir = task_dict['hair_material_dir']
|
||||
images_dir = os.path.join(hair_material_dir, 'images')
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
train_image_dir = task_dict['train_image_dir']
|
||||
# tag = task_dict['tag']
|
||||
tag = ""
|
||||
is_tj = task_dict['is_tj']
|
||||
device_id = task_dict['device_id']
|
||||
|
||||
sample_dir = os.path.join(model_dir, 'sample')
|
||||
if not os.path.exists(sample_dir):
|
||||
os.makedirs(sample_dir)
|
||||
sample_txt = os.path.join(sample_dir, 'prompt.txt')
|
||||
with open(sample_txt, 'w') as f_s:
|
||||
f_s.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, '
|
||||
+ tag
|
||||
+ ' --n low quality, worst quality, bad anatomy, bad composition, poor, low effort --h 768 '
|
||||
'--w 768 --s 30 --l 7')
|
||||
|
||||
# 给训练图片打标签
|
||||
# cmd_caption = ('docker run --rm --gpus all -v /home/chinatszrn/Documents/miaoya/kohya_ss_home:/home/chinatszrn '
|
||||
# '-v /mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
# '--net=host chinatszrn/ubuntu:kohya_ss accelerate '
|
||||
# 'launch "./finetune/tag_images_by_wd14_tagger.py" --batch_size=2 '
|
||||
# '--general_threshold=0.5 --character_threshold=0.5 --caption_extension=".txt" '
|
||||
# '--model="SmilingWolf/wd-v1-4-convnextv2-tagger-v2" --max_data_loader_n_workers="2" '
|
||||
# '--debug --remove_underscore --frequency_tags --undesired_tags="1girl, 1boy" '
|
||||
# f'"{train_image_dir}"')
|
||||
# os.system(cmd_caption)
|
||||
|
||||
img_path_list = glob.glob(train_image_dir + '/*.png')
|
||||
# 给训练图片打标签, gpt
|
||||
for img_path in img_path_list:
|
||||
# print(img_path)
|
||||
txt_path = img_path[:-4] + '.txt'
|
||||
|
||||
print("tag img_path: ", img_path)
|
||||
# tags = caption_image(img_path)
|
||||
tags = tag
|
||||
with open(txt_path, 'w') as f:
|
||||
f.write('titor hairstyle, easyphoto, faceless, no human, white background, simple background, ' + tags)
|
||||
|
||||
#判断是否每个训练图片都有标签文件
|
||||
# for img_path in img_path_list:
|
||||
# assert os.path.exists(img_path[:-4]+'.txt'), f'{img_path}没有对应的标签文件'
|
||||
# with open(img_path[:-4]+'.txt', 'r') as f:
|
||||
# tags = f.readline()
|
||||
# with open(img_path[:-4]+'.txt', 'w') as f:
|
||||
# f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
|
||||
os.system(f'chmod 777 {model_dir}')
|
||||
#训练头发lora
|
||||
sd_models_dir = os.path.join(BASE_DIR, 'stable-diffusion-webui', 'models', 'Stable-diffusion')
|
||||
container_images_dir = images_dir.replace(kohya_ss_home_dir, '/home/chinatszrn')
|
||||
container_model_dir = model_dir.replace(kohya_ss_home_dir, '/home/chinatszrn')
|
||||
cmd_train = (
|
||||
f'sudo docker run --rm --privileged=true --gpus "device=0" '
|
||||
f'-v {kohya_ss_home_dir}:/home/chinatszrn '
|
||||
f'-v {sd_models_dir}:/mnt/sd_models '
|
||||
'-e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
'--net=host chinatszrn/ubuntu:kohya_ss accelerate launch --num_cpu_threads_per_process=2 "./train_network.py" --enable_bucket '
|
||||
'--min_bucket_reso=256 --max_bucket_reso=2048 --pretrained_model_name_or_path="/mnt/sd_models/majicmixRealistic_v7.safetensors" '
|
||||
f'--train_data_dir={container_images_dir} --resolution="2000,2000" '
|
||||
f'--output_dir={container_model_dir} '
|
||||
'--network_alpha="64" --save_model_as=safetensors --network_module=networks.lora --text_encoder_lr=5e-05 '
|
||||
'--unet_lr=0.0001 --network_dim=128 --output_name="hairstyle_hd_lora" --lr_scheduler_num_cycles="20" '
|
||||
'--no_half_vae --learning_rate="0.0001" --lr_scheduler="cosine" --lr_warmup_steps="650" --train_batch_size="1" '
|
||||
'--max_train_steps="1500" --save_every_n_epochs="100" --mixed_precision="fp16" --save_precision="fp16" '
|
||||
'--caption_extension=".txt" --sample_sampler=ddim '
|
||||
f'--sample_prompts={sample_txt} --sample_every_n_epochs="1000" '
|
||||
'--seed="1234" --cache_latents --optimizer_type="AdamW8bit" --max_data_loader_n_workers="0" --bucket_reso_steps=64 '
|
||||
'--xformers --bucket_no_upscale --noise_offset=0.0 --tokenizer_cache_dir="/home/chinatszrn/.cache/clip"')
|
||||
print("cmd_train:", cmd_train)
|
||||
os.system(cmd_train)
|
||||
|
||||
lora_path = os.path.join(model_dir, 'hairstyle_hd_lora.safetensors')
|
||||
|
||||
# tianjin callback
|
||||
if is_tj == "1":
|
||||
url = f'{callback_url}'
|
||||
|
||||
if not os.path.exists(lora_path):
|
||||
send_request(url, -1, task_dict)
|
||||
else:
|
||||
send_request(url, 0, task_dict)
|
||||
|
||||
except Exception as e:
|
||||
send_request(url, -1, None)
|
||||
continue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
global_var.webui_lora_dir = webui_lora_dir
|
||||
|
||||
# avatar训练的任务队列
|
||||
global_var.hair_style_lora_train_task_sq = Queue()
|
||||
p = Process(target=train_thread, args=(
|
||||
global_var.hair_style_lora_train_task_sq, 0))
|
||||
p.start()
|
||||
|
||||
# # 启动服务
|
||||
# app.run(debug=True, port=32678, host='0.0.0.0')
|
||||
|
||||
server = pywsgi.WSGIServer(('0.0.0.0', 32678), app) # test port
|
||||
server.serve_forever()
|
||||
|
||||
p.join()
|
||||
@@ -0,0 +1,190 @@
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from webui_im2im import ControlnetRequestImg2Img
|
||||
import numpy as np
|
||||
import base64
|
||||
import cv2
|
||||
import os,sys
|
||||
from gevent import pywsgi, monkey
|
||||
from multiprocessing import Process, Queue
|
||||
import glob
|
||||
from gpt4v_caption import caption_image
|
||||
|
||||
|
||||
# 将当前工作目录切换到当前目录
|
||||
project_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(project_dir)
|
||||
sys.path.append(project_dir)
|
||||
|
||||
import json
|
||||
|
||||
def send_request(url, state, task_dict):
|
||||
import requests
|
||||
import json
|
||||
|
||||
msg = '头发lora训练失败' if state == -1 else '头发lora训练成功'
|
||||
payload = json.dumps({
|
||||
"task_id": task_dict['task_id'] if task_dict is not None else '',
|
||||
"hair_id": task_dict['hair_id'] if task_dict is not None else '',
|
||||
"state": state,
|
||||
"msg": msg
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
|
||||
|
||||
def train_hair_lora():
|
||||
import os
|
||||
import json
|
||||
task_id = ''
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = ""
|
||||
assert 'task_id' in request_data, 'task_id is required'
|
||||
task_id = request_data['task_id']
|
||||
assert 'hair_id' in request_data and 'hair_material_dir' in request_data, 'hair_id and hair_material_dir is required'
|
||||
hair_material_dir = request_data['hair_material_dir']
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
img_dir = os.path.join(hair_material_dir,'images')
|
||||
assert os.path.exists(img_dir), f'{img_dir} not exists'
|
||||
assert os.path.exists(os.path.join(hair_material_dir, 'model')), f'{os.path.join(hair_material_dir, "model")} not exists'
|
||||
|
||||
#判断img_dir下面是否只有一个文件夹
|
||||
img_dir_list = os.listdir(img_dir)
|
||||
assert len(img_dir_list) == 1, f'{img_dir}下面只能有一个文件夹'
|
||||
train_image_dir = os.path.join(img_dir,img_dir_list[0])
|
||||
assert os.path.isdir(train_image_dir), f'{train_image_dir}不是文件夹'
|
||||
# 检查该文件夹是否以数字加下划线开头
|
||||
assert img_dir_list[0].split('_')[0].isdigit(), f'{img_dir_list[0]}不是数字开头'
|
||||
|
||||
#判断文件夹下面是否有图片
|
||||
img_list = glob.glob(train_image_dir + '/*.png')
|
||||
assert len(img_list) > 10, f'{os.path.join(img_dir,img_dir_list[0])}下面图片数量小于10张'
|
||||
request_data['train_image_dir'] = train_image_dir
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def inference_webui():
|
||||
import os
|
||||
import requests
|
||||
url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
try:
|
||||
# 获取请求参数
|
||||
request_data = ""
|
||||
# with open('request_data.json', 'w') as f:
|
||||
# json.dump(request_data, f)
|
||||
request_json = request_data.get('request_json')
|
||||
hair_material_dir = request_data.get('hair_material_dir')
|
||||
assert os.path.exists(hair_material_dir), f'{hair_material_dir} not exists'
|
||||
request_lora_path = os.path.join(hair_material_dir, 'model', 'hairstyle_lora.safetensors')
|
||||
assert os.path.exists(request_lora_path), f'{request_lora_path} not exists'
|
||||
|
||||
tmp_lora_name = f'{uuid.uuid4()}'
|
||||
lora_dst_path = ""
|
||||
os.system('cp {} {}'.format(request_lora_path, lora_dst_path))
|
||||
request_json['prompt'] = f'<lora:{tmp_lora_name}:1.0>, titor hairstyle, ' + request_json['prompt']
|
||||
request_json['negative_prompt'] = request_json['negative_prompt'] + ', faceless, no human'
|
||||
response = requests.post(url=url, json=request_json)
|
||||
ret_json = response.json()
|
||||
|
||||
if os.path.exists(lora_dst_path):
|
||||
os.remove(lora_dst_path)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def tag(train_image_dir):
|
||||
img_path_list = glob.glob(train_image_dir + '/*.png')
|
||||
|
||||
# 给训练图片打标签, gpt
|
||||
for img_path in img_path_list:
|
||||
print(img_path)
|
||||
txt_path = img_path[:-4] + '.txt'
|
||||
# if not os.path.exists(txt_path):
|
||||
tags = caption_image(img_path)
|
||||
with open(txt_path, 'w') as f:
|
||||
f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
# else:
|
||||
# continue
|
||||
|
||||
|
||||
def train_thread(sq, gpu_id):
|
||||
while True:
|
||||
url = 'http://service.aicloud.fit:7393/api/hair/trainCallBack'
|
||||
task_dict = None
|
||||
try:
|
||||
task_dict = sq.get()
|
||||
hair_material_dir = task_dict['hair_material_dir']
|
||||
images_dir = os.path.join(hair_material_dir, 'images')
|
||||
model_dir = os.path.join(hair_material_dir, 'model')
|
||||
train_image_dir = task_dict['train_image_dir']
|
||||
# 给训练图片打标签
|
||||
# cmd_caption = ('docker run --rm --gpus all -v /home/chinatszrn/Documents/miaoya/kohya_ss_home:/home/chinatszrn '
|
||||
# '-v /mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
# '--net=host chinatszrn/ubuntu:kohya_ss accelerate '
|
||||
# 'launch "./finetune/tag_images_by_wd14_tagger.py" --batch_size=2 '
|
||||
# '--general_threshold=0.5 --character_threshold=0.5 --caption_extension=".txt" '
|
||||
# '--model="SmilingWolf/wd-v1-4-convnextv2-tagger-v2" --max_data_loader_n_workers="2" '
|
||||
# '--debug --remove_underscore --frequency_tags --undesired_tags="1girl, 1boy" '
|
||||
# f'"{train_image_dir}"')
|
||||
# os.system(cmd_caption)
|
||||
|
||||
img_path_list = glob.glob(train_image_dir + '/*.png')
|
||||
# 给训练图片打标签, gpt
|
||||
for img_path in img_path_list:
|
||||
tags = caption_image(img_path)
|
||||
txt_path = img_path[:-4]+'.txt'
|
||||
if not os.path.exists(txt_path):
|
||||
with open(txt_path, 'w') as f:
|
||||
f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
else:
|
||||
continue
|
||||
|
||||
|
||||
#判断是否每个训练图片都有标签文件
|
||||
# for img_path in img_path_list:
|
||||
# assert os.path.exists(img_path[:-4]+'.txt'), f'{img_path}没有对应的标签文件'
|
||||
# with open(img_path[:-4]+'.txt', 'r') as f:
|
||||
# tags = f.readline()
|
||||
# with open(img_path[:-4]+'.txt', 'w') as f:
|
||||
# f.write('titor hairstyle, faceless, no human, gray background, simple background, ' + tags)
|
||||
|
||||
#训练头发lora
|
||||
cmd_train = ('docker run --rm --gpus all -v /home/chinatszrn/Documents/miaoya/kohya_ss_home:/home/chinatszrn -v '
|
||||
'/mnt:/mnt -e PATH=/home/chinatszrn/.local/bin -w /home/chinatszrn/kohya_ss '
|
||||
'--net=host chinatszrn/ubuntu:kohya_ss accelerate launch --num_cpu_threads_per_process=2 "./train_network.py" --enable_bucket '
|
||||
'--min_bucket_reso=512 --max_bucket_reso=1800 --pretrained_model_name_or_path="/mnt/nas_hdd/米亚像馆/models/Stable-diffusion/majicmixRealistic_v7.safetensors" '
|
||||
f'--train_data_dir={images_dir} --resolution="1800,1800" '
|
||||
f'--output_dir={model_dir} '
|
||||
'--network_alpha="64" --save_model_as=safetensors --network_module=networks.lora --text_encoder_lr=5e-05 '
|
||||
'--unet_lr=0.0001 --network_dim=128 --output_name="hairstyle_lora" --lr_scheduler_num_cycles="12" '
|
||||
'--no_half_vae --learning_rate="0.0001" --lr_scheduler="cosine" --lr_warmup_steps="96" --train_batch_size="1" '
|
||||
'--max_train_steps="4000" --save_every_n_epochs="100" --mixed_precision="fp16" --save_precision="fp16" '
|
||||
'--seed="1234" --cache_latents --optimizer_type="AdamW8bit" --max_data_loader_n_workers="0" --bucket_reso_steps=64 '
|
||||
'--xformers --bucket_no_upscale --noise_offset=0.0 --tokenizer_cache_dir="/home/chinatszrn/.cache/clip"')
|
||||
os.system(cmd_train)
|
||||
|
||||
lora_path = os.path.join(model_dir, 'hairstyle_lora.safetensors')
|
||||
|
||||
|
||||
if not os.path.exists(lora_path):
|
||||
send_request(url, -1, task_dict)
|
||||
else:
|
||||
send_request(url, 0, task_dict)
|
||||
|
||||
except Exception as e:
|
||||
send_request(url, -1, None)
|
||||
continue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
tag("/mnt/database2/online-server/hair-online/hair_lora_train_material/AAVWGW1NN-0KC-33B-24-/images/1_hairstyle")
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,37 @@
|
||||
import requests
|
||||
import cv2
|
||||
import numpy as np
|
||||
import base64
|
||||
import sys
|
||||
import json
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = './data/template01.png'
|
||||
img = cv2.imread(path)
|
||||
retval, bytes = cv2.imencode('.jpg', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
user_id = '61AB9097'
|
||||
|
||||
#给api_service.py发送请求
|
||||
url = "http://i-2.gpushare.com:53412/user/generate"
|
||||
payload = json.dumps({
|
||||
"user_id": "61AB9097",
|
||||
"base_img": encoded_image
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(f"Failed to send request to API service. Status code: {response.status_code}")
|
||||
|
||||
ret_image_b64 = response.json().get('generate_photo_b64')
|
||||
|
||||
if ret_image_b64 is None:
|
||||
raise RuntimeError(f"ret image failed!")
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(ret_image_b64), np.uint8)
|
||||
image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
cv2.imshow('image', cv2.resize(image, (0, 0), fx=0.5, fy=0.5))
|
||||
cv2.waitKey()
|
||||
@@ -0,0 +1 @@
|
||||
python api_service.py /hy-tmp/photo_service/service_data /hy-tmp/stable-diffusion-webui/models/Lora 7860 1234
|
||||
@@ -0,0 +1,18 @@
|
||||
import cv2
|
||||
import os
|
||||
import json
|
||||
import base64
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
if __name__ == '__main__':
|
||||
with open('request_json.json', 'r') as f:
|
||||
request_data = json.load(f)
|
||||
request_json = request_data
|
||||
img_base64 = request_json['init_images'][0]
|
||||
mask_base64 = request_json['mask']
|
||||
image = Image.open(io.BytesIO(base64.b64decode(img_base64)))
|
||||
image.save('image.png')
|
||||
mask = Image.open(io.BytesIO(base64.b64decode(mask_base64)))
|
||||
mask.save('mask.png')
|
||||
|
||||
Executable
+1663
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
|
||||
2024/02/23
|
||||
Fix popup 127.0.0.1 instead of real ip in some situations.
|
||||
|
||||
2023/06/04
|
||||
Rename packages name with toolchains name.
|
||||
Fix some toolchain's misconfiguration, which lead to unusable binary.
|
||||
Add support for drag-drop upload and folder upload.
|
||||
|
||||
2022/05/12
|
||||
Fix a issue when rename a file's name with question mark(?).
|
||||
|
||||
2022/03/27
|
||||
Fix a potential security problem.
|
||||
Add support for platform armv6.
|
||||
|
||||
2022/01/27
|
||||
Fix unexpected quit when upload file to jffs2 filesystem.
|
||||
|
||||
2022/01/24
|
||||
Fix unexpected quit on windows.
|
||||
Add back web player, but not enabled by default.
|
||||
|
||||
2022/01/10
|
||||
Fix UI mess up when multiple files selected to upload at once.
|
||||
|
||||
2022/01/05
|
||||
Fix upload error when file > 4G, 64bits versions not affected. Thanks for Mover.
|
||||
|
||||
2021/12/02
|
||||
Some minor UI correction.
|
||||
Add installation script for Android.
|
||||
|
||||
2021/11/30
|
||||
Fix for __libc_start_main@@GLIBC_2.34
|
||||
Fix parameter "-c".
|
||||
|
||||
2021/11/29
|
||||
Try fix rename() error on Android.
|
||||
Fix guest's permission settings.
|
||||
@@ -0,0 +1 @@
|
||||
<!doctype html><html><head><meta charset=UTF-8><meta name=viewport content="width=device-width,user-scalable=no"><style>:root{--cl:#036;--clcut:#79C;--clev:#f5f8f3;--clod:#FFF;--cltbh:#dfe6f3;--hvacl:#C00;--hvcl:#FFA;--hvslct:#DFF;--bd:1px solid #a3b5da;--bdl:1px solid #DDE;--clup:#e9967a;--bdupld:1px dashed var(--clup);--fnt:'Microsoft Yahei'}body{font-family:var(--fnt);font-size:14px;color:var(--cl)}video#vd,audio#ado,img#image{display:none}video#vd,img#image{max-width:99%}audio#ado{width:96%}</style><script>"use strict";(function(){function a(b){return document.getElementById(b)}function b(){var c=(location.hash.substr(1)||"??").substr(1).split("?")[0],e=c.substring(c.lastIndexOf(".")+1,c.length).toLowerCase()||c,f=["wav","mp3","wma","ape","ogg","cda","opus"],l=["jpg","jpeg","gif","png","bmp","ico"];(e=-1<["wmv","asf","mp4","avi","mpg","mpeg","mkv","flv","webm"].indexOf(e)?k=j:-1<f.indexOf(e)?k=i:-1<l.indexOf(e)?g:null)&&(e.src=c,f=e.dataset,l=decodeURIComponent,c=c.substring(c.lastIndexOf("/")+1,c.length)||c,f.t=l(c),document.title=e.dataset.t,e.style.display="block",k&&(e.currentTime=o.get(e.dataset.t)))}let g,i,j,k=null;const o={};let f=[];o.get=function(c){for(const a in f=JSON.parse(localStorage.getItem("cTM"))||[],f)if(f[a][0]==c)return f[a][1];return 0},o.set=function(c,a){if(5<a){for(const a in f)f[a][0]==c&&f.splice(a,1);f.unshift([c,parseInt(a)-2]),localStorage.setItem("cTM",JSON.stringify(f.slice(0,25)))}},[["beforeunload",function(){k&&o.set(k.dataset.t,k.currentTime)}],["DOMContentLoaded",function(){g=a("image"),i=a("ado"),j=a("vd"),b()}],["hashchange",b]].forEach(function(b){window.addEventListener(b[0],b[1])})})();</script></head><body><center><img id=image><audio controls autoplay=autoplay id=ado></audio><video controls autoplay=autoplay id=vd></video></center></body></html>
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,74 @@
|
||||
# NOTE:
|
||||
# This file must be encoded in UTF-8.
|
||||
# Directives and variable definition in this file are case-insensitive.
|
||||
# Lines that begin with the hash character "#" are considered comments, and are ignored.
|
||||
|
||||
|
||||
# Webd.Root: The directory that webd share on network.
|
||||
|
||||
# Example for Linux:
|
||||
# Webd.Root /mnt/sdb1
|
||||
# Example for Windows:
|
||||
# Webd.Root "D:\my share"
|
||||
|
||||
|
||||
# Webd.Listen: Bind webd to specific IP and/or port.
|
||||
# Also, webd can bind to multiple addresses by use multiple "Webd.Listen" instructions.
|
||||
|
||||
# Bind to port 9212 with IPv4:
|
||||
# Webd.Listen 9212
|
||||
# Bind to port 9212 with both IPv4 and IPv6:
|
||||
# Webd.Listen [::]:9212
|
||||
|
||||
|
||||
# User's permissions tag, can be set via one or more tag combinations:
|
||||
# r: Access files.
|
||||
# l: List directories.
|
||||
# u: Upload file.
|
||||
# m: Delete, move, or rename files.
|
||||
# S: Show hidden files or directories.
|
||||
# T: Use webpage to play media files.
|
||||
# D: Add 'download' atrribute to file link.
|
||||
|
||||
# For now, webd supports only two users.
|
||||
# Each user may have it's own Username Password and Permissions.
|
||||
# But they share the same web directory.
|
||||
|
||||
# user1 has all permissions.
|
||||
# Webd.User rlumS user1 pass1
|
||||
|
||||
# user2 can download and list files.
|
||||
# Webd.User rl user2 pass2
|
||||
|
||||
# Guest can download and list files by default.
|
||||
# Uncomment to disable all permissions for guest.
|
||||
# Webd.Guest 0
|
||||
|
||||
|
||||
# Hide tray icon for Windows.
|
||||
# Webd.Hide
|
||||
|
||||
|
||||
# Specify the path of Browser for Windows if webd can not popup Browser by double clicking tray icon.
|
||||
# Webd.Browser "C:\Program Files\Mozilla Firefox\firefox.exe"
|
||||
# Or start Browser with extra paramters that set by a batch file.
|
||||
# Webd.Browser "C:\Program Files\Mozilla Firefox\myFirefox.cmd"
|
||||
|
||||
|
||||
# Envionment variables for webd.
|
||||
# These should be set in the command line or system configration.
|
||||
#
|
||||
# Write log files to /var/log/webd-YYYY-MM-DD.log
|
||||
# _LOG_DIR=/var/log/webd-
|
||||
#
|
||||
# Write log to syslog.
|
||||
# _syslog=1
|
||||
#
|
||||
# Set the maximum number of open file descriptors, linux only.
|
||||
# _FD_LIMIT=10240
|
||||
#
|
||||
# Switch to non-privileged user after startup, linux only.
|
||||
# _RUNAS=nobody
|
||||
#
|
||||
# chroot after startup, linux only.
|
||||
# _CHROOT_PATH=/mnt/sda1
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
# 本脚本用于向webd的服务器上传文件,需要提供两个参数: 1、上传的文件路径。 2、上传的地址
|
||||
# bash ./webd_upload.sh abc.png http://nas.zhourunnan.cn:9212/zhourunnan
|
||||
|
||||
b36enc() {
|
||||
local b36=$(echo {0..9} {a..z}); b36=${b36// /}
|
||||
awk \
|
||||
'BEGIN { b = split(ARGV[1], D, ""); n = ARGV[2]; do { d = int(n / b); i = D[n - b * d + 1]; r = i r; n = d } while(n != 0); print r}' \
|
||||
"${b36}" "$1"
|
||||
}
|
||||
|
||||
upload(){
|
||||
local def_url="http://aaanas.zhourunnan.cn:9212/"
|
||||
local def_cookie='AcMY8R290zo'
|
||||
|
||||
local file="${1}"
|
||||
local size=$(stat -c %s "${file}")
|
||||
local time=$(stat -c %Y "${file}")
|
||||
|
||||
local url="${2:-${def_url}}"; url="${url%/}/${file##*/}"
|
||||
local cookie="${3:-${def_cookie}}"
|
||||
|
||||
echo -e "\e[1;32mupload: ${url}\e[0m"
|
||||
|
||||
wget -vdt1 -O- "${url//#/%23}?N$(b36enc ${time})" \
|
||||
--header='Content-Type: application/octet-stream' \
|
||||
--header="Cookie: u=${cookie}" \
|
||||
--header="RaOff: bytes=0/$(b36enc ${size})" \
|
||||
--post-file="${file}"
|
||||
|
||||
echo -e "\n\e[1;32mfinish: ${url}\e[0m"
|
||||
|
||||
}; upload "$@"
|
||||
Executable
+106
@@ -0,0 +1,106 @@
|
||||
import io
|
||||
import cv2
|
||||
import base64
|
||||
import requests
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
|
||||
"""
|
||||
To use this example make sure you've done the following steps before executing:
|
||||
1. Ensure automatic1111 is running in api mode with the controlnet extension.
|
||||
Use the following command in your terminal to activate:
|
||||
./webui.sh --no-half --api
|
||||
2. Validate python environment meet package dependencies.
|
||||
If running in a local repo you'll likely need to pip install cv2, requests and PIL
|
||||
"""
|
||||
|
||||
|
||||
class ControlnetRequestImg2Img:
|
||||
def __init__(self, prompt, net_prompt):
|
||||
self.url = "http://127.0.0.1:7860/sdapi/v1/img2img"
|
||||
self.prompt = prompt
|
||||
self.neg_prompt = net_prompt
|
||||
self.body = None
|
||||
|
||||
def build_body(self, dst_width, dst_height, cfg_scale, base_img):
|
||||
|
||||
self.body = {
|
||||
"prompt": self.prompt,
|
||||
"negative_prompt": self.neg_prompt,
|
||||
"sampler_name": "Restart",
|
||||
"batch_size": 1,
|
||||
"steps": 30,
|
||||
"width": dst_width,
|
||||
"height": dst_height,
|
||||
"cfg_scale": cfg_scale,
|
||||
"seed": -1,
|
||||
"init_images": [
|
||||
self.encode_image_to_base64(base_img)
|
||||
],
|
||||
"denoising_strength": 0.4,
|
||||
"alwayson_scripts": {
|
||||
"controlnet": {
|
||||
"args": [
|
||||
{
|
||||
"enabled": True,
|
||||
"module": "openpose_full",
|
||||
"model": "openpose",
|
||||
"weight": 1.0,
|
||||
# "image": self.read_image(),
|
||||
"resize_mode": "Crop and Resize",
|
||||
"low_vram": False,
|
||||
"processor_res": 512,
|
||||
"guidance_start": 0.0,
|
||||
"guidance_end": 1.0,
|
||||
"control_mode": "Balanced",
|
||||
"pixel_perfect": True
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def send_request(self):
|
||||
response = requests.post(url=self.url, json=self.body)
|
||||
return response.json()
|
||||
|
||||
def encode_image_to_base64(self, img):
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
def read_image(self):
|
||||
img = cv2.imread(self.img_path)
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
def read_mask(self):
|
||||
img = cv2.imread(self.mask)
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
def encode_image_to_base64(img):
|
||||
retval, bytes = cv2.imencode('.jpg', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = '/home/chinatszrn/Downloads/photo_service/service_data/template_data/template01.png'
|
||||
img = cv2.imread(path)
|
||||
prompt = '<lora:5b05d5eeee0188f436d7131c4f0ff52b:0.8>,easyphoto_face, easyphoto, 1person,face,suit'
|
||||
neg_prompt = '(worst quality:2),(low quality:2),(normal quality:2),lowres,watermark'
|
||||
|
||||
|
||||
control_net = ControlnetRequestImg2Img(prompt, neg_prompt)
|
||||
control_net.build_body(dst_width=img.shape[1], dst_height=img.shape[0], cfg_scale=3.5, base_img=img)
|
||||
output = control_net.send_request()
|
||||
result = output['images'][0]
|
||||
|
||||
image_array = np.frombuffer(base64.b64decode(result.split(",", 1)[0]), np.uint8)
|
||||
image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
|
||||
cv2.imshow('image', image)
|
||||
cv2.waitKey()
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
import io
|
||||
import cv2
|
||||
import base64
|
||||
import requests
|
||||
from PIL import Image
|
||||
|
||||
class ControlnetRequestImg2Img:
|
||||
def __init__(self, prompt, net_prompt, path, mask):
|
||||
self.url = "http://127.0.0.1:57860/sdapi/v1/img2img"
|
||||
self.prompt = prompt
|
||||
self.neg_prompt = net_prompt
|
||||
self.img_path = path
|
||||
self.mask = mask
|
||||
self.body = None
|
||||
|
||||
def build_body(self):
|
||||
img = cv2.imread(self.img_path)
|
||||
self.body = {
|
||||
"prompt": self.prompt,
|
||||
"negative_prompt": self.neg_prompt,
|
||||
"sampler_name": "DPM++ 2M Karras",
|
||||
"batch_size": 1,
|
||||
"steps": 30,
|
||||
"width": img.shape[1],
|
||||
"height": img.shape[0],
|
||||
"cfg_scale": 7,
|
||||
"seed": -1,
|
||||
"mask_blur": 15,
|
||||
"init_images": [
|
||||
self.read_image()
|
||||
],
|
||||
"inpaint_full_res": True,
|
||||
"inpainting_fill": 1,
|
||||
"inpainting_mask_invert": 1,
|
||||
"mask": self.read_mask(),
|
||||
"denoising_strength": 0.4,
|
||||
"alwayson_scripts": {
|
||||
"controlnet": {
|
||||
"args": [
|
||||
{
|
||||
"enabled": True,
|
||||
"module": "openpose_full",
|
||||
"model": "openpose",
|
||||
"weight": 1.0,
|
||||
"resize_mode": 1,
|
||||
"lowvram": False,
|
||||
"processor_res": 512,
|
||||
"guidance_start": 0.0,
|
||||
"guidance_end": 1.0,
|
||||
"control_mode": 0,
|
||||
"pixel_perfect": True
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
def send_request(self):
|
||||
response = requests.post(url=self.url, json=self.body)
|
||||
return response.json()
|
||||
|
||||
def read_image(self):
|
||||
img = cv2.imread(self.img_path)
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
def read_mask(self):
|
||||
img = cv2.imread(self.mask)
|
||||
retval, bytes = cv2.imencode('.png', img)
|
||||
encoded_image = base64.b64encode(bytes).decode('utf-8')
|
||||
return encoded_image
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = '/home/chinatszrn/Downloads/user1_hr.png'
|
||||
mask_path = '/home/chinatszrn/Downloads/user1_hr_mask.png'
|
||||
prompt = 'a woman with long blonde hair and a blue shirt on a gray background with a gray background and a gray background, lyco art, An Gyeon, realistic face, a character portrait'
|
||||
neg_prompt = '(nsfw:1.5), ng_deepnegative_v1_75t, (badhandv4:1.2), (worst quality:2), (low quality:2), (normal quality:2), lowres, bad anatomy, bad hands, ((monochrome)), ((grayscale)) watermark, moles, large breast, big breast, bad_pictures,easynegative'
|
||||
|
||||
control_net = ControlnetRequestImg2Img(prompt, neg_prompt, path, mask_path)
|
||||
control_net.build_body()
|
||||
output = control_net.send_request()
|
||||
result = output['images'][0]
|
||||
image = Image.open(io.BytesIO(base64.b64decode(result.split(",", 1)[0])))
|
||||
image.save('save2.png')
|
||||
Reference in New Issue
Block a user