初始化换发型项目: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:
colomi
2026-07-11 18:11:49 +08:00
commit 0eb61f3e60
628 changed files with 120882 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# liveme_photo_service
liveme数字写真线上服务代码。依赖webui……
+159
View File
@@ -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()
+32
View File
@@ -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))
+13
View 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

+247
View File
@@ -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)
+34
View File
@@ -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
+68
View File
@@ -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)
+169
View File
@@ -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()
+102
View File
@@ -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()
+120
View File
@@ -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()
+315
View File
@@ -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()
+357
View File
@@ -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()
+190
View File
@@ -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

+37
View File
@@ -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()
+1
View File
@@ -0,0 +1 @@
python api_service.py /hy-tmp/photo_service/service_data /hy-tmp/stable-diffusion-webui/models/Lora 7860 1234
+18
View File
@@ -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')
File diff suppressed because one or more lines are too long
+39
View File
@@ -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.
+1
View File
@@ -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>
BIN
View File
Binary file not shown.
+74
View File
@@ -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
+33
View File
@@ -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 "$@"
+106
View File
@@ -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()
+86
View File
@@ -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')