初始化:换发型/换发色/训练发型服务

包含:
- hair_service_sd: 主服务(换发型/换发色/生发,端口8801)
- photo_service: LoRA调度+训练(端口32678)
- hair_grow_service: 调试测试页(端口8888,含4个测试页)
- 批量训练脚本(batch_train_hairstyles.py)
- 发际线mask自动识别(hairline_mask.py,4种方案)
- 手绘mask换发型(hair_swap_manual.py)
- 文档:README.md + LARGE_FILES.md + docs/

大文件(模型权重200G、训练数据123G)已排除,见 LARGE_FILES.md
OSS/COS密钥已脱敏为环境变量,原文件备份在本地
This commit is contained in:
xsl
2026-07-07 13:53:52 +08:00
commit 443cfa298f
312 changed files with 67065 additions and 0 deletions
@@ -0,0 +1,46 @@
import requests
import json
callback_hairstyle_url = "https://puton.meidaojia.com/api/cloth/callBack"
def callback_color(color_id, cover_img, success):
url = "http://172.21.0.3:8080/ydapp/system/platform/complete_color_model"
payload = json.dumps({
"success": success,
"colorId": color_id,
"coverImg": cover_img
})
headers = {
'X-MZ-API-TOKEN': '98bcf37c942a2240ba2d907c96ed1137',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
return response
# print(response.text)
def callback_hairstyle(req_id, state, message, clothId):
url = callback_hairstyle_url
payload = json.dumps({
"taskId": req_id,
"status": state,
"clothId": clothId,
"msg": message
})
status = -1
print(f"url:{url},complete_hair_model payload:{payload}")
headers = {
'X-MZ-API-TOKEN': '98bcf37c942a2240ba2d907c96ed1137',
'Content-Type': 'application/json'
}
try:
response = requests.request("POST", url, headers=headers, data=payload)
print("response:", response.text)
status = 0
except Exception as e:
print(e)
return response.text, status
@@ -0,0 +1,27 @@
import pynvml
threshold = 0.9
def get_gpu(need_gpu_id):
used = get_gpu_threshold(need_gpu_id)
#小于一定的
if used > threshold:
need_use = get_use_gpu()
return need_use[0]
else:
return need_gpu_id
def get_use_gpu():
use=[]
for index in range(pynvml.nvmlDeviceGetCount()):
used = get_gpu_threshold(index)
if used > threshold:
use.append(index)
return use
def get_gpu_count():
return pynvml.nvmlDeviceGetCount()
def get_gpu_threshold(index):
handle = pynvml.nvmlDeviceGetHandleByIndex(index)
meminfo = pynvml.nvmlDeviceGetMemoryInfo(handle)
used = meminfo.used / meminfo.total
return used
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/python
# coding=utf-8
import os
from logging.handlers import TimedRotatingFileHandler
import logging
import configparser
config = configparser.ConfigParser() # 创建对象
config.read("config/configure.ini", encoding="utf-8") # 读取配置文件,如果配置文件不存在则创建
"""
自定义日志处理
"""
class LogFactory(object):
@staticmethod
def getLogger(log_name,log_level=None):
if log_level is None:
log_level = LogFactory.getLogLevel(getLevel())
logger = logging.getLogger(log_name)
path = getPath()
isExists=os.path.exists(path)
if not isExists:
os.makedirs(path)
log_file = os.path.join(path, '{}.log'.format(log_name))
if len(logger.handlers) <= 0:
handler = TimedRotatingFileHandler(log_file, when='D', interval=1)
else:
handler = logger.handlers[0]
formatter = logging.Formatter("%(asctime)s-%(thread)d-%(filename)s-%(levelname)s-%(message)s", "%Y-%m-%d %H:%M:%S")
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(log_level)
return logger
@staticmethod
def getLogLevel(log_level):
log_level = getattr(logging, log_level.upper(), None)
if log_level is None:
raise Exception("No such log level.")
return log_level
def getPath():
import sys
process_order = sys.argv[1] if len(sys.argv) > 1 else None
logpath = config.get('logger', "logpath")
logpath = logpath.rstrip("/")
if process_order is None:
return logpath
return logpath
def getLevel():
return config.get('logger', "level")