save code
This commit is contained in:
+338
-6
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"3": {
|
"3": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"seed": 351739583278114,
|
"seed": 712463095845292,
|
||||||
"steps": 20,
|
"steps": 20,
|
||||||
"cfg": 1,
|
"cfg": 1,
|
||||||
"sampler_name": "euler",
|
"sampler_name": "euler",
|
||||||
@@ -432,6 +432,18 @@
|
|||||||
"title": "Image Concatenate"
|
"title": "Image Concatenate"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"45": {
|
||||||
|
"inputs": {
|
||||||
|
"images": [
|
||||||
|
"42",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewImage",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Image"
|
||||||
|
}
|
||||||
|
},
|
||||||
"57": {
|
"57": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"brightness": -1,
|
"brightness": -1,
|
||||||
@@ -474,7 +486,7 @@
|
|||||||
},
|
},
|
||||||
"61": {
|
"61": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"image": "girl_full_2.webp"
|
"image": "girl_full.jpg"
|
||||||
},
|
},
|
||||||
"class_type": "LoadImage",
|
"class_type": "LoadImage",
|
||||||
"_meta": {
|
"_meta": {
|
||||||
@@ -505,6 +517,126 @@
|
|||||||
"title": "Load Style Model"
|
"title": "Load Style Model"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"83": {
|
||||||
|
"inputs": {
|
||||||
|
"images": [
|
||||||
|
"29",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewImage",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Image"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"84": {
|
||||||
|
"inputs": {
|
||||||
|
"images": [
|
||||||
|
"43",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewImage",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Image"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"85": {
|
||||||
|
"inputs": {
|
||||||
|
"mask": [
|
||||||
|
"30",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "MaskPreview",
|
||||||
|
"_meta": {
|
||||||
|
"title": "MaskPreview"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"86": {
|
||||||
|
"inputs": {
|
||||||
|
"mask": [
|
||||||
|
"71:2",
|
||||||
|
1
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "MaskPreview+",
|
||||||
|
"_meta": {
|
||||||
|
"title": "🔧 Mask Preview"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"87": {
|
||||||
|
"inputs": {
|
||||||
|
"images": [
|
||||||
|
"38",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewImage",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Image"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"88": {
|
||||||
|
"inputs": {
|
||||||
|
"images": [
|
||||||
|
"37",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewImage",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Image"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"89": {
|
||||||
|
"inputs": {
|
||||||
|
"images": [
|
||||||
|
"57",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewImage",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Image"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"90": {
|
||||||
|
"inputs": {
|
||||||
|
"images": [
|
||||||
|
"59",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewImage",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Image"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"91": {
|
||||||
|
"inputs": {
|
||||||
|
"images": [
|
||||||
|
"27",
|
||||||
|
1
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewImage",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Image"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"93": {
|
||||||
|
"inputs": {
|
||||||
|
"mask": [
|
||||||
|
"27",
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "MaskPreview",
|
||||||
|
"_meta": {
|
||||||
|
"title": "MaskPreview"
|
||||||
|
}
|
||||||
|
},
|
||||||
"94": {
|
"94": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"value": 1024
|
"value": 1024
|
||||||
@@ -535,7 +667,8 @@
|
|||||||
},
|
},
|
||||||
"96": {
|
"96": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"changdu": "yao",
|
"cloth_len": "yao",
|
||||||
|
"line_len": 0.6000000000000001,
|
||||||
"kps": [
|
"kps": [
|
||||||
"95",
|
"95",
|
||||||
1
|
1
|
||||||
@@ -546,11 +679,44 @@
|
|||||||
"title": "My RenderPeopleKps Mask"
|
"title": "My RenderPeopleKps Mask"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"97": {
|
||||||
|
"inputs": {
|
||||||
|
"mask": [
|
||||||
|
"61",
|
||||||
|
1
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "MaskPreview",
|
||||||
|
"_meta": {
|
||||||
|
"title": "MaskPreview"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"98": {
|
||||||
|
"inputs": {
|
||||||
|
"mask": [
|
||||||
|
"96",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "MaskPreview",
|
||||||
|
"_meta": {
|
||||||
|
"title": "MaskPreview"
|
||||||
|
}
|
||||||
|
},
|
||||||
"99": {
|
"99": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"width": 600,
|
"width": [
|
||||||
"height": 1024,
|
"108",
|
||||||
"x": 700,
|
0
|
||||||
|
],
|
||||||
|
"height": [
|
||||||
|
"107",
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
"109",
|
||||||
|
0
|
||||||
|
],
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"image": [
|
"image": [
|
||||||
"34",
|
"34",
|
||||||
@@ -575,6 +741,172 @@
|
|||||||
"title": "Save Image"
|
"title": "Save Image"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"104": {
|
||||||
|
"inputs": {
|
||||||
|
"image": [
|
||||||
|
"61",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "GetImageSize",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Get Image Size"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"106": {
|
||||||
|
"inputs": {
|
||||||
|
"op": "Mul",
|
||||||
|
"a": [
|
||||||
|
"107",
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
"104",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "CM_IntBinaryOperation",
|
||||||
|
"_meta": {
|
||||||
|
"title": "IntBinaryOperation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"107": {
|
||||||
|
"inputs": {
|
||||||
|
"image": [
|
||||||
|
"34",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "GetImageSize",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Get Image Size"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"108": {
|
||||||
|
"inputs": {
|
||||||
|
"op": "Div",
|
||||||
|
"a": [
|
||||||
|
"106",
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
"104",
|
||||||
|
1
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "CM_IntBinaryOperation",
|
||||||
|
"_meta": {
|
||||||
|
"title": "IntBinaryOperation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"109": {
|
||||||
|
"inputs": {
|
||||||
|
"op": "Sub",
|
||||||
|
"a": [
|
||||||
|
"107",
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
"108",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "CM_IntBinaryOperation",
|
||||||
|
"_meta": {
|
||||||
|
"title": "IntBinaryOperation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"110": {
|
||||||
|
"inputs": {
|
||||||
|
"preview": "",
|
||||||
|
"source": [
|
||||||
|
"106",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewAny",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Any"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"111": {
|
||||||
|
"inputs": {
|
||||||
|
"preview": "",
|
||||||
|
"source": [
|
||||||
|
"108",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewAny",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Any"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"112": {
|
||||||
|
"inputs": {
|
||||||
|
"preview": "",
|
||||||
|
"source": [
|
||||||
|
"109",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewAny",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Any"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"113": {
|
||||||
|
"inputs": {
|
||||||
|
"preview": "",
|
||||||
|
"source": [
|
||||||
|
"107",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewAny",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Any"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"114": {
|
||||||
|
"inputs": {
|
||||||
|
"preview": "",
|
||||||
|
"source": [
|
||||||
|
"107",
|
||||||
|
1
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewAny",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Any"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"115": {
|
||||||
|
"inputs": {
|
||||||
|
"preview": "",
|
||||||
|
"source": [
|
||||||
|
"104",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewAny",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Any"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"116": {
|
||||||
|
"inputs": {
|
||||||
|
"preview": "",
|
||||||
|
"source": [
|
||||||
|
"104",
|
||||||
|
1
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"class_type": "PreviewAny",
|
||||||
|
"_meta": {
|
||||||
|
"title": "Preview Any"
|
||||||
|
}
|
||||||
|
},
|
||||||
"71:0": {
|
"71:0": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"model_name": "sam_vit_h (2.56GB)"
|
"model_name": "sam_vit_h (2.56GB)"
|
||||||
|
|||||||
+59
-69
@@ -3,83 +3,70 @@ import uuid
|
|||||||
import requests
|
import requests
|
||||||
from flask import Flask, request, jsonify
|
from flask import Flask, request, jsonify
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from volcenginesdkarkruntime import Ark
|
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
import time
|
import time
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from volcenginesdkarkruntime import Ark
|
||||||
|
import shutil
|
||||||
|
|
||||||
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
|
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||||
STATIC_FOLDER = os.path.join(APP_ROOT, 'static')
|
STATIC_FOLDER = os.path.join(APP_ROOT, 'static')
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
# 请确保您已将 API Key 存储在环境变量 ARK_API_KEY 中
|
|
||||||
# 初始化Ark客户端,从环境变量中读取您的API Key
|
|
||||||
client = Ark(
|
client = Ark(
|
||||||
# 此为默认路径,您可根据业务所在地域进行配置
|
# 此为默认路径,您可根据业务所在地域进行配置
|
||||||
base_url="https://ark.cn-beijing.volces.com/api/v3",
|
base_url="https://ark.cn-beijing.volces.com/api/v3",
|
||||||
# 从环境变量中获取您的 API Key。此为默认方式,您可根据需要进行修改
|
# 从环境变量中获取您的 API Key。此为默认方式,您可根据需要进行修改
|
||||||
# api_key=os.environ.get("ARK_API_KEY"),
|
# api_key=os.environ.get("ARK_API_KEY"),
|
||||||
api_key='14fc0280-fc65-462d-ac2d-50178c0212e3'
|
api_key='14fc0280-fc65-462d-ac2d-50178c0212e3'
|
||||||
)
|
)
|
||||||
|
|
||||||
def parse_facial_data(data_str):
|
|
||||||
print(f'原始字符串 {data_str}')
|
|
||||||
# 去除多余的标记和换行符
|
|
||||||
json_str_clean = data_str.strip('```json\n').strip('```').strip()
|
|
||||||
|
|
||||||
# 转换为Python字典
|
|
||||||
data = json.loads(json_str_clean)
|
|
||||||
s = data['面部年龄']
|
|
||||||
s = s.replace('岁', '')
|
|
||||||
parts = s.split('-')
|
|
||||||
start_age = int(parts[0])
|
|
||||||
end_age = int(parts[1])
|
|
||||||
data['start_age'] = start_age
|
|
||||||
data['end_age'] = end_age
|
|
||||||
return data
|
|
||||||
|
|
||||||
def GetPicDesc(img_url):
|
def GetPicDesc(img_url):
|
||||||
response = client.chat.completions.create(
|
response = client.chat.completions.create(
|
||||||
# 指定您创建的方舟推理接入点 ID,此处已帮您修改为您的推理接入点 ID
|
# 指定您创建的方舟推理接入点 ID,此处已帮您修改为您的推理接入点 ID
|
||||||
model="doubao-1.5-vision-pro-250328",
|
model="doubao-1.5-vision-pro-250328",
|
||||||
messages=[
|
messages=[
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"content": [
|
"content": [
|
||||||
{
|
{
|
||||||
"type": "image_url",
|
"type": "image_url",
|
||||||
"image_url": {
|
"image_url": {
|
||||||
"url": img_url
|
"url": img_url
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{"type": "text", "text": "图片是一件服装的照片,告诉我图片中的服装穿到正常人身上的长度会覆盖到人体的哪个部位, 只要答案, 选项有(胸、腰、跨、大腿、膝盖、小腿、脚踝、拖地、难以辨认)"},
|
||||||
{"type": "text", "text": "告诉我图片中的服装长度, 只要答案, 选项有(腰部以上、腰、跨、大腿上部1/3、大腿中部、膝盖、小腿、小腿上部1/3、脚踝、拖地、难以辨认)"},
|
],
|
||||||
],
|
}
|
||||||
}
|
],
|
||||||
],
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
text = response.choices[0].message.content
|
text = response.choices[0].message.content
|
||||||
result = {}
|
print(text)
|
||||||
|
return text
|
||||||
|
|
||||||
try:
|
def change(human_name, cloth_name, c_width, c_height, cloth_url):
|
||||||
result = parse_facial_data(text)
|
|
||||||
except:
|
|
||||||
print(f'Error {text}')
|
|
||||||
|
|
||||||
return result
|
cloth_len = GetPicDesc(cloth_url)
|
||||||
|
if cloth_len == '难以辨认':
|
||||||
|
return None, "get image type error"
|
||||||
|
|
||||||
|
queue = requests.get("http://localhost:8188/queue").json()
|
||||||
|
if queue["queue_running"] or queue["queue_pending"]:
|
||||||
|
return None, "cur gpu is busy"
|
||||||
|
|
||||||
def change(human_name, cloth_name, c_width, c_height):
|
|
||||||
with open('/home/szlc/code/ComfyUI/change_cloth/change_new.json', 'r', encoding='utf-8') as file:
|
with open('/home/szlc/code/ComfyUI/change_cloth/change_new.json', 'r', encoding='utf-8') as file:
|
||||||
prompt_text = file.read()
|
prompt_text = file.read()
|
||||||
|
|
||||||
prompt = json.loads(prompt_text)
|
prompt = json.loads(prompt_text)
|
||||||
|
|
||||||
prompt["99"]["inputs"]["width"] = int((c_width/c_height) * 1024)
|
prompt["96"]["inputs"]["cloth_len"] = cloth_len
|
||||||
|
|
||||||
|
# prompt["99"]["inputs"]["width"] = int((c_width/c_height) * 1024)
|
||||||
|
|
||||||
#input cloth img
|
#input cloth img
|
||||||
prompt["22"]["inputs"]["image"] = cloth_name
|
prompt["22"]["inputs"]["image"] = cloth_name
|
||||||
@@ -109,14 +96,16 @@ def change(human_name, cloth_name, c_width, c_height):
|
|||||||
|
|
||||||
# 3. 从历史记录中获取结果
|
# 3. 从历史记录中获取结果
|
||||||
history = requests.get("http://localhost:8188/history").json()
|
history = requests.get("http://localhost:8188/history").json()
|
||||||
print("History:", history)
|
# print("History:", history)
|
||||||
outputs = history[prompt_id]["outputs"]
|
outputs = history[prompt_id]["outputs"]
|
||||||
for out in outputs:
|
for out in outputs:
|
||||||
if 'images' in outputs[out]:
|
if 'images' in outputs[out]:
|
||||||
for out_img_name in outputs[out]['images']:
|
for out_img in outputs[out]['images']:
|
||||||
if 'filename' in out_img_name:
|
if 'filename' in out_img:
|
||||||
return out_img_name['filename']
|
out_img_file_name = out_img['filename']
|
||||||
return None
|
if out_img_name in out_img_file_name:
|
||||||
|
return out_img_file_name, "success"
|
||||||
|
return None, "can not find output image"
|
||||||
|
|
||||||
def save_base64_image(base64_str, prefix):
|
def save_base64_image(base64_str, prefix):
|
||||||
"""
|
"""
|
||||||
@@ -146,7 +135,7 @@ def save_base64_image(base64_str, prefix):
|
|||||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
unique_id = str(uuid.uuid4())[:8]
|
unique_id = str(uuid.uuid4())[:8]
|
||||||
filename = f"{prefix}_{timestamp}_{unique_id}{file_ext}"
|
filename = f"{prefix}_{timestamp}_{unique_id}{file_ext}"
|
||||||
filepath = os.path.join('/home/szlc/code/ComfyUI/change_cloth/static', filename)
|
filepath = os.path.join('/home/szlc/code/ComfyUI/change_cloth/static/imgs', filename)
|
||||||
|
|
||||||
# 解码并保存图片
|
# 解码并保存图片
|
||||||
with open(filepath, 'wb') as f:
|
with open(filepath, 'wb') as f:
|
||||||
@@ -192,16 +181,17 @@ def image_to_base64(file_path, mime_type=None):
|
|||||||
# 组合成Data URI格式
|
# 组合成Data URI格式
|
||||||
return f"data:{mime_type};base64,{encoded_string}"
|
return f"data:{mime_type};base64,{encoded_string}"
|
||||||
|
|
||||||
def process_change_cloth(human_filename, cloth_filename, output_format):
|
def process_change_cloth(human_filename, cloth_filename, output_format, img_url):
|
||||||
w,h = get_image_dimensions(f'/home/szlc/code/ComfyUI/input/{human_filename}')
|
w,h = get_image_dimensions(f'/home/szlc/code/ComfyUI/input/{human_filename}')
|
||||||
|
|
||||||
out_put_name = change(human_filename, cloth_filename, w, h)
|
out_put_name, msg = change(human_filename, cloth_filename, w, h, img_url)
|
||||||
if out_put_name == None:
|
if out_put_name == None:
|
||||||
return jsonify({"ret":-1, 'msg': 'Failed to change cloth'}), 500
|
print(f'Failed to change cloth {msg}')
|
||||||
|
return jsonify({"ret":-1, 'msg': f'Failed to change cloth {msg}'}), 200
|
||||||
|
|
||||||
image = Image.open(f'/home/szlc/code/ComfyUI/output/{out_put_name}')
|
image = Image.open(f'/home/szlc/code/ComfyUI/output/{out_put_name}')
|
||||||
jpg_name = out_put_name.replace(".png", ".jpg")
|
jpg_name = out_put_name.replace(".png", ".jpg")
|
||||||
jpg_path_name = f'/home/szlc/code/ComfyUI/change_cloth/static/{jpg_name}'
|
jpg_path_name = f'/home/szlc/code/ComfyUI/change_cloth/static/imgs/{jpg_name}'
|
||||||
image.save(jpg_path_name, quality=95)
|
image.save(jpg_path_name, quality=95)
|
||||||
|
|
||||||
if 'base64' in output_format:
|
if 'base64' in output_format:
|
||||||
@@ -214,7 +204,7 @@ def process_change_cloth(human_filename, cloth_filename, output_format):
|
|||||||
return jsonify({
|
return jsonify({
|
||||||
"ret":0,
|
"ret":0,
|
||||||
"msg":"success",
|
"msg":"success",
|
||||||
"url":f"http://112.126.94.241:18018/static/{jpg_name}"
|
"url":f"http://112.126.94.241:18888/static/imgs/{jpg_name}"
|
||||||
})
|
})
|
||||||
|
|
||||||
@app.route('/change_cloth_base64', methods=['POST'])
|
@app.route('/change_cloth_base64', methods=['POST'])
|
||||||
@@ -242,7 +232,9 @@ def change_cloth_base64():
|
|||||||
if not cloth_filename:
|
if not cloth_filename:
|
||||||
return jsonify({"ret":-1, 'msg': 'Failed to save cloth image'}), 500
|
return jsonify({"ret":-1, 'msg': 'Failed to save cloth image'}), 500
|
||||||
|
|
||||||
return process_change_cloth(human_filename, cloth_filename, output_format)
|
img_url = f"http://112.126.94.241:18888/static/imgs/{cloth_filename}"
|
||||||
|
|
||||||
|
return process_change_cloth(human_filename, cloth_filename, output_format, img_url)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({"ret":-1, 'error': str(e)}), 500
|
return jsonify({"ret":-1, 'error': str(e)}), 500
|
||||||
@@ -269,16 +261,14 @@ def save_image_from_url(image_url):
|
|||||||
# 获取原始图片格式
|
# 获取原始图片格式
|
||||||
ext = get_file_extension(image_url)
|
ext = get_file_extension(image_url)
|
||||||
filename = f"{uuid.uuid4()}{ext}"
|
filename = f"{uuid.uuid4()}{ext}"
|
||||||
filepath = os.path.join('/home/szlc/code/ComfyUI/change_cloth/static', filename)
|
filepath = os.path.join('/home/szlc/code/ComfyUI/change_cloth/static/imgs', filename)
|
||||||
|
|
||||||
with open(filepath, "wb") as f:
|
with open(filepath, "wb") as f:
|
||||||
for chunk in response.iter_content(1024):
|
for chunk in response.iter_content(1024):
|
||||||
f.write(chunk)
|
f.write(chunk)
|
||||||
|
|
||||||
input_filepath = os.path.join('/home/szlc/code/ComfyUI/input', filename)
|
input_filepath = os.path.join('/home/szlc/code/ComfyUI/input', filename)
|
||||||
with open(input_filepath, "wb") as f:
|
shutil.copy(filepath, input_filepath)
|
||||||
for chunk in response.iter_content(1024):
|
|
||||||
f.write(chunk)
|
|
||||||
|
|
||||||
return filename
|
return filename
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -309,7 +299,7 @@ def change_cloth():
|
|||||||
|
|
||||||
output_format = data.get('output_format')
|
output_format = data.get('output_format')
|
||||||
|
|
||||||
return process_change_cloth(human_filename, cloth_filename, output_format)
|
return process_change_cloth(human_filename, cloth_filename, output_format, cloth_url)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(host="0.0.0.0", port=8018, debug=True)
|
app.run(host="0.0.0.0", port=8888, debug=True)
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh-CN">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>服装更换工具</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 20px;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.image-upload-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.image-upload-box {
|
|
||||||
width: 48%;
|
|
||||||
border: 2px dashed #ccc;
|
|
||||||
padding: 15px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
.image-upload-box h3 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
.image-preview {
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 300px;
|
|
||||||
margin-top: 10px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background-color: #4CAF50;
|
|
||||||
color: white;
|
|
||||||
padding: 10px 15px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
display: block;
|
|
||||||
margin: 20px auto;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
background-color: #45a049;
|
|
||||||
}
|
|
||||||
#result {
|
|
||||||
margin-top: 20px;
|
|
||||||
padding: 15px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#loading {
|
|
||||||
text-align: center;
|
|
||||||
display: none;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
.spinner {
|
|
||||||
border: 5px solid #f3f3f3;
|
|
||||||
border-top: 5px solid #3498db;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
animation: spin 2s linear infinite;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
@keyframes spin {
|
|
||||||
0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
.error {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>服装更换工具</h1>
|
|
||||||
|
|
||||||
<div class="image-upload-container">
|
|
||||||
<div class="image-upload-box">
|
|
||||||
<h3>人体图片</h3>
|
|
||||||
<input type="file" id="humanInput" accept="image/*">
|
|
||||||
<img id="humanPreview" class="image-preview" alt="人体图片预览">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="image-upload-box">
|
|
||||||
<h3>衣服图片</h3>
|
|
||||||
<input type="file" id="clothInput" accept="image/*">
|
|
||||||
<img id="clothPreview" class="image-preview" alt="衣服图片预览">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button id="submitBtn">提交处理</button>
|
|
||||||
|
|
||||||
<div id="loading">
|
|
||||||
<div class="spinner"></div>
|
|
||||||
<p>正在处理中,请稍候...</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="result"></div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// 图片预览功能
|
|
||||||
document.getElementById('humanInput').addEventListener('change', function(e) {
|
|
||||||
const file = e.target.files[0];
|
|
||||||
if (file) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = function(event) {
|
|
||||||
const img = document.getElementById('humanPreview');
|
|
||||||
img.src = event.target.result;
|
|
||||||
img.style.display = 'block';
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('clothInput').addEventListener('change', function(e) {
|
|
||||||
const file = e.target.files[0];
|
|
||||||
if (file) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = function(event) {
|
|
||||||
const img = document.getElementById('clothPreview');
|
|
||||||
img.src = event.target.result;
|
|
||||||
img.style.display = 'block';
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 提交处理
|
|
||||||
document.getElementById('submitBtn').addEventListener('click', function() {
|
|
||||||
const humanFile = document.getElementById('humanInput').files[0];
|
|
||||||
const clothFile = document.getElementById('clothInput').files[0];
|
|
||||||
|
|
||||||
if (!humanFile || !clothFile) {
|
|
||||||
alert('请同时选择人体图片和衣服图片!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示加载动画
|
|
||||||
document.getElementById('loading').style.display = 'block';
|
|
||||||
document.getElementById('result').style.display = 'none';
|
|
||||||
|
|
||||||
// 读取图片并转换为Base64(包含完整前缀)
|
|
||||||
Promise.all([
|
|
||||||
readFileAsDataURL(humanFile),
|
|
||||||
readFileAsDataURL(clothFile)
|
|
||||||
]).then(([humanDataURL, clothDataURL]) => {
|
|
||||||
// 准备请求数据
|
|
||||||
const data = {
|
|
||||||
human_img: humanDataURL, // 包含完整前缀的Base64
|
|
||||||
cloth_img: clothDataURL, // 包含完整前缀的Base64
|
|
||||||
output_format: "url"
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log("准备发送的数据:", data); // 调试用
|
|
||||||
|
|
||||||
// 调用API
|
|
||||||
fetch('http://112.126.94.241:18888/change_cloth_base64', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data)
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP错误! 状态: ${response.status}`);
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then(data => {
|
|
||||||
// 隐藏加载动画
|
|
||||||
document.getElementById('loading').style.display = 'none';
|
|
||||||
|
|
||||||
// 显示结果
|
|
||||||
const resultDiv = document.getElementById('result');
|
|
||||||
if (data.url) {
|
|
||||||
resultDiv.innerHTML = `
|
|
||||||
<h3>处理结果</h3>
|
|
||||||
<p>处理成功!点击查看结果:</p>
|
|
||||||
<a href="${data.url}" target="_blank">${data.url}</a>
|
|
||||||
<p><img src="${data.url}" style="max-width: 100%; margin-top: 10px;"></p>
|
|
||||||
`;
|
|
||||||
} else {
|
|
||||||
resultDiv.innerHTML = `
|
|
||||||
<h3>处理结果</h3>
|
|
||||||
<p class="error">处理完成,但未返回预期的URL</p>
|
|
||||||
<p>返回数据:</p>
|
|
||||||
<pre>${JSON.stringify(data, null, 2)}</pre>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
resultDiv.style.display = 'block';
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error:', error);
|
|
||||||
document.getElementById('loading').style.display = 'none';
|
|
||||||
document.getElementById('result').innerHTML = `
|
|
||||||
<h3 class="error">错误</h3>
|
|
||||||
<p>处理过程中出现错误:${error.message}</p>
|
|
||||||
<p>请检查控制台获取更多信息</p>
|
|
||||||
`;
|
|
||||||
document.getElementById('result').style.display = 'block';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 辅助函数:读取文件为DataURL(包含完整前缀的Base64)
|
|
||||||
function readFileAsDataURL(file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = () => resolve(reader.result);
|
|
||||||
reader.onerror = (error) => reject(error);
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>人体换装工具</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
input[type="text"] {
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
padding: 10px 15px;
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background-color: #45a049;
|
||||||
|
}
|
||||||
|
button:disabled {
|
||||||
|
background-color: #cccccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.button-loading::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: auto;
|
||||||
|
border: 4px solid transparent;
|
||||||
|
border-top-color: #ffffff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: button-loading-spinner 1s ease infinite;
|
||||||
|
}
|
||||||
|
@keyframes button-loading-spinner {
|
||||||
|
from {
|
||||||
|
transform: rotate(0turn);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(1turn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.result {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.result-image {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-top: 10px;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
margin-top: 10px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>人体换装工具</h1>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="human-url">人体图片URL:</label>
|
||||||
|
<input type="text" id="human-url" value="http://112.126.94.241:18888/static/imgs/human_20250713_091718_fb1f8a05.jpg">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="cloth-url">衣服图片URL:</label>
|
||||||
|
<input type="text" id="cloth-url" value="http://112.126.94.241:18888/static/imgs/cloth_20250713_092536_279335d2.jpg">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="submit-btn">提交处理</button>
|
||||||
|
|
||||||
|
<div id="error-message" class="error"></div>
|
||||||
|
|
||||||
|
<div id="result" class="result">
|
||||||
|
<h3>处理结果:</h3>
|
||||||
|
<p>处理后的图片URL: <a id="result-url" href="" target="_blank"></a></p>
|
||||||
|
<img id="result-image" class="result-image" src="" alt="处理后的图片">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('submit-btn').addEventListener('click', async function() {
|
||||||
|
const humanUrl = document.getElementById('human-url').value;
|
||||||
|
const clothUrl = document.getElementById('cloth-url').value;
|
||||||
|
const submitBtn = document.getElementById('submit-btn');
|
||||||
|
|
||||||
|
// 隐藏之前的结果和错误
|
||||||
|
document.getElementById('result').style.display = 'none';
|
||||||
|
document.getElementById('error-message').style.display = 'none';
|
||||||
|
|
||||||
|
// 验证URL是否为空
|
||||||
|
if (!humanUrl || !clothUrl) {
|
||||||
|
showError('请输入人体图片和衣服图片的URL');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置按钮为加载状态
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.classList.add('button-loading');
|
||||||
|
submitBtn.textContent = '处理中...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 发送POST请求
|
||||||
|
const response = await fetch('http://112.126.94.241:18888/change_cloth', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
human_url: humanUrl,
|
||||||
|
cloth_url: clothUrl,
|
||||||
|
output_format: 'url'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.ret === 0 && data.url) {
|
||||||
|
// 显示处理结果
|
||||||
|
const resultUrl = document.getElementById('result-url');
|
||||||
|
const resultImage = document.getElementById('result-image');
|
||||||
|
|
||||||
|
resultUrl.href = data.url;
|
||||||
|
resultUrl.textContent = data.url;
|
||||||
|
resultImage.src = data.url;
|
||||||
|
|
||||||
|
document.getElementById('result').style.display = 'block';
|
||||||
|
} else {
|
||||||
|
showError('处理失败: ' + (data.message || '未知错误'));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError('请求出错: ' + error.message);
|
||||||
|
} finally {
|
||||||
|
// 恢复按钮状态
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
submitBtn.classList.remove('button-loading');
|
||||||
|
submitBtn.textContent = '提交处理';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function showError(message) {
|
||||||
|
const errorElement = document.getElementById('error-message');
|
||||||
|
errorElement.textContent = message;
|
||||||
|
errorElement.style.display = 'block';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user