diff --git a/API.md b/API.md new file mode 100644 index 0000000..7ef8a7c --- /dev/null +++ b/API.md @@ -0,0 +1,108 @@ +# change_app.py API 文档 + +## 1. GET / + +返回主页静态文件 `index.html`。 + +--- + +## 2. POST /change_cloth + +**推荐入口**,带 Redis 队列排队,避免并发冲突。 + +### 请求参数(JSON) + +| 参数 | 类型 | 必选 | 说明 | +|------|------|------|------| +| human_url | string | 是 | 人物图片 URL | +| cloth_url | string | 是 | 服装图片 URL | +| output_format | string | 是 | 输出格式,包含 `"base64"` 则返回 base64,否则返回 URL | +| no2 | bool | 否 | true=跳过第一步(脱衣/生成写真),直接换衣;默认 false | +| tuodi | bool | 否 | true=使用拖地款工作流;默认 false | +| kuzi | bool | 否 | 是否同时换裤子(配合 kuzi_url);默认 false | +| cloth_len | string | 否 | 手动指定服装长度(如"膝盖""拖地"等),不传则 AI 自动判断 | +| suit | bool | 否 | true=使用 Gemini 模型换装(套装模式);默认 false | + +### 响应 + +```json +// 成功(URL 模式) +{ + "ret": 0, + "state": 0, + "msg": "success", + "url": "https://xiangsilian.oss-cn-beijing.aliyuncs.com/xxx.jpg", + "second_url": "换衣前中间步骤图 URL", + "first_url": "第一步(脱衣/写真)图 URL", + "is_girl": true +} + +// 成功(base64 模式) +{ + "ret": 0, + "state": 0, + "msg": "success", + "data": "data:image/jpeg;base64,...", + "second_step_data": "...", + "first_step_data": "...", + "is_girl": true +} + +// 失败 +{ "ret": -1, "state": -1, "msg": "错误信息" } +``` + +--- + +## 3. POST /change_cloth_base64 + +与 `/change_cloth` 功能相同,图片以 Base64 格式传入。 + +### 请求参数(JSON) + +| 参数 | 类型 | 必选 | 说明 | +|------|------|------|------| +| human_img | string | 是 | 人物图片 base64(带 data: 头,如 `data:image/jpeg;base64,...`) | +| cloth_img | string | 是 | 服装图片 base64 | +| output_format | string | 是 | 同上 | +| kuzi_img | string | 否 | 裤子图片 base64 | +| no2 | bool | 否 | 同上 | +| tuodi | bool | 否 | 同上 | +| suit | bool | 否 | 同上 | +| cloth_len | string | 否 | 同上 | + +### 响应 + +同 `/change_cloth`。 + +--- + +## 4. POST /do_change_cloth + +**直接调用**,无队列保护,通常由内部或 `/change_cloth_base64` 调用,不建议外部直接使用。 + +### 请求参数(JSON) + +| 参数 | 类型 | 必选 | 说明 | +|------|------|------|------| +| human_url | string | 是 | 人物图片 URL | +| cloth_url | string | 是 | 服装图片 URL | +| output_format | string | 是 | 同上 | +| no2 | bool | 否 | 同上 | +| tuodi | bool | 否 | 同上 | +| kuzi_url | string | 否 | 裤子图片 URL | +| cloth_len | string | 否 | 同上 | +| suit | bool | 否 | 同上 | + +### 响应 + +同 `/change_cloth`。 + +--- + +## 备注 + +- `cloth_len` 可选值:`胸、腰、跨、大腿、膝盖、小腿、脚踝、拖地、裤子、难以辨认` +- 若服装图片中检测到人物,`cloth_len` 自动设为 `拖地` +- 结果图片同时上传至阿里云 OSS(bucket: `xiangsilian`,region: 北京) +- 服务默认监听端口由 `config.py` 中的 `base64_test_port` 决定 diff --git a/change_app.py b/change_app.py index dfbe0a8..ef99561 100644 --- a/change_app.py +++ b/change_app.py @@ -66,7 +66,9 @@ def get_redis_conn(): """获取 Redis 连接""" return redis.Redis(connection_pool=redis_pool) -app = Flask(__name__) +app = Flask(__name__, static_folder='static', static_url_path='/static') +from flask_cors import CORS +CORS(app) client = Ark( # 此为默认路径,您可根据业务所在地域进行配置 @@ -225,10 +227,16 @@ def generate_from_face(human_name, sex_girl): prompt["93"]["inputs"]["image"] = human_name + # if sex_girl: + # prompt["6"]["inputs"]["text"] = "asian girl,knee-length shot ,model pose,hands are at the sides of the body,smile,wearing black tube top and micro skirt,simple ,white background,32k,high detail,and face is illuminated by soft side light and natural light. The sunlight spills over the white wall behind." + # else: + # prompt["6"]["inputs"]["text"] = "asian man,tall,knee-length shot,model pose,hands are at the sides of the body,smile,wearing black short pants,simple white background,The sunlight spills over the white wall behind,32k." + if sex_girl: - prompt["6"]["inputs"]["text"] = "asian girl,knee-length shot ,model pose,hands are at the sides of the body,smile,wearing black tube top and micro skirt,simple ,white background,32k,high detail,and face is illuminated by soft side light and natural light. The sunlight spills over the white wall behind." + prompt["6"]["inputs"]["text"] = "asian girl,knee-length shot,model pose,hands are at the sides of the body,smile,wearing black tube top and micro skirt,solid very dark gray background,32k,high detail,and face is illuminated by soft side light and natural light." else: - prompt["6"]["inputs"]["text"] = "asian man,tall,knee-length shot,model pose,hands are at the sides of the body,smile,wearing black short pants,simple white background,The sunlight spills over the white wall behind,32k." + prompt["6"]["inputs"]["text"] = "asian man,tall,knee-length shot,model pose,hands are at the sides of the body,smile,shirtless,wearing black short pants,very dark gray background,solid dark gray background,32k," + #out put name out_img_name = str(uuid.uuid4())[:8] @@ -639,9 +647,61 @@ def process_change_banana(human_filename, cloth_filename, output_format): "msg":"failure" }) -def process_change_cloth(human_filename, cloth_filename, output_format, img_url, human_url, no2, tuodi, kuzi_url, cloth_len): +def process_change_cloth(human_filename, cloth_filename, output_format, img_url, human_url, no2, tuodi, kuzi_url, cloth_len, kuzi_img=None): w,h = get_image_dimensions(f'{APP_ROOT}/../input/{human_filename}') + if kuzi_url: + print(f'换裤子 kuzi_url:{kuzi_url}') + + human_json_str = GetHumanDesDesc(human_url) + print(f"human_json_str {human_json_str}") + human_json_data = json.loads(human_json_str) + sex_type = human_json_data['性别'] + sex_girl = True + if '男' in sex_type: + sex_girl = False + + new_data = { + "model_image": image_to_base64(f'{APP_ROOT}/../input/{human_filename}', False), + "shirt_image": image_to_base64(f'{APP_ROOT}/../input/{cloth_filename}', False), + "pants_image": kuzi_img if kuzi_img else image_to_base64(save_image_from_url(kuzi_url), False), + } + response = requests.post(f'http://117.50.44.174:47698/try-on', json=new_data) + result_image_data = response.json().get("result_image", "") + if result_image_data: + print(f"result_image_data: {result_image_data[:30]}...") # 打印前30个字符以验证数据格式 + if 'base64' in output_format: + return jsonify({ + "ret":0, + "state": 0, + "msg":"success", + "is_girl":sex_girl, + "second_step_data":new_data["model_image"], + "first_step_data":new_data["model_image"], + "data":result_image_data + }) + else: + result_image_bytes = base64.b64decode(result_image_data.split(',')[1]) + result_image_stream = BytesIO(result_image_bytes) + image = Image.open(result_image_stream) + jpg_name = f"{uuid.uuid4()}.png" + jpg_path_name = f'{APP_ROOT}/static/imgs/{jpg_name}' + image.save(jpg_path_name, quality=90) + upload_to_oss(jpg_path_name, jpg_name) + https_url = f'https://xiangsilian.oss-cn-beijing.aliyuncs.com/{jpg_name}' + + return jsonify({ + "ret":0, + "state": 0, + "msg":"success", + "second_url":https_url, + "first_url":https_url, + "is_girl":sex_girl, + "url":https_url + }) + + + out_put_name, out_human_name, is_girl, msg = change(human_filename, cloth_filename, w, h, img_url, human_url, no2, tuodi, cloth_len) if out_put_name == None: print(f'Failed to change cloth {msg}') @@ -748,7 +808,13 @@ def save_image_from_url(image_url): except Exception as e: print(f"Error saving image from URL: {e}") return None - + + +@app.route('/') +def index(): + """返回主页""" + from flask import send_from_directory + return send_from_directory('static', 'index.html') @app.route('/do_change_cloth', methods=['POST']) def do_change_cloth(): @@ -801,7 +867,7 @@ def do_change_cloth(): if 'cloth_len' in data: cloth_len = data['cloth_len'] try: - return process_change_cloth(human_filename, cloth_filename, output_format, cloth_url, human_url, no2, tuodi, kuzi_url, cloth_len) + return process_change_cloth(human_filename, cloth_filename, output_format, cloth_url, human_url, no2, tuodi, kuzi_url, cloth_len, data.get("kuzi_img") ) except Exception as e: traceback.print_exc() print(f"错误详情:{e}") @@ -912,7 +978,7 @@ def change_cloth_base64(): return jsonify({"ret":-1, 'msg': 'Failed to save human image'}), 500 data['human_img'] = None - human_url = f"http://112.126.94.241:{base64_test_port}/static/imgs/{human_filename}" + human_url = f"http://117.50.44.174:{base64_test_port}/static/imgs/{human_filename}" # 保存服装图片 cloth_filename = save_base64_image(cloth_img, 'cloth') @@ -920,7 +986,7 @@ def change_cloth_base64(): return jsonify({"ret":-1, 'msg': 'Failed to save cloth image'}), 500 data['cloth_img'] = None - cloth_url = f"http://112.126.94.241:{base64_test_port}/static/imgs/{cloth_filename}" + cloth_url = f"http://117.50.44.174:{base64_test_port}/static/imgs/{cloth_filename}" data["human_url"] = human_url data["cloth_url"] = cloth_url @@ -928,8 +994,8 @@ def change_cloth_base64(): kuzi_img = data.get('kuzi_img') if kuzi_img: kuzi_filename = save_base64_image(kuzi_img, 'kuzi') - data['kuzi_img'] = None - kuzi_url = f"http://112.126.94.241:{base64_test_port}/static/imgs/{kuzi_filename}" + # data['kuzi_img'] = None + kuzi_url = f"http://117.50.44.174:{base64_test_port}/static/imgs/{kuzi_filename}" data['kuzi_url'] = kuzi_url no2 = data.get('no2') @@ -953,7 +1019,7 @@ def change_cloth_base64(): # 在内部调用第二个HTTP请求 try: # 调用第二个API(可以是外部服务或自己的另一个端点) - response = requests.post(f'http://112.126.94.241:{base64_test_port}/do_change_cloth', json=data) + response = requests.post(f'http://117.50.44.174:{base64_test_port}/do_change_cloth', json=data) return Response( response=response.content, @@ -967,4 +1033,4 @@ def change_cloth_base64(): if __name__ == '__main__': - app.run(host="0.0.0.0", port=8888, debug=True) \ No newline at end of file + app.run(host="0.0.0.0", port=base64_test_port, debug=True) \ No newline at end of file diff --git a/http_app.py b/http_app.py index c81ffed..e0a67e2 100644 --- a/http_app.py +++ b/http_app.py @@ -347,7 +347,7 @@ def change_cloth_base64(): if not cloth_filename: return jsonify({"ret":-1, 'msg': 'Failed to save cloth image'}), 500 - img_url = f"http://112.126.94.241:18888/static/imgs/{cloth_filename}" + img_url = f"http://117.50.44.174:18888/static/imgs/{cloth_filename}" return process_change_cloth(human_filename, cloth_filename, output_format, img_url, is_generated) diff --git a/static/cloth_long.png b/static/cloth_long.png new file mode 100644 index 0000000..631a627 Binary files /dev/null and b/static/cloth_long.png differ diff --git a/static/cloth_short.jpg b/static/cloth_short.jpg new file mode 100644 index 0000000..bae7fa7 Binary files /dev/null and b/static/cloth_short.jpg differ diff --git a/static/cloth_short_2.png b/static/cloth_short_2.png new file mode 100644 index 0000000..28c69de Binary files /dev/null and b/static/cloth_short_2.png differ diff --git a/static/img.html b/static/img.html index 370e13a..a30476a 100644 --- a/static/img.html +++ b/static/img.html @@ -92,12 +92,12 @@
URL图片预览: - URL图片预览
@@ -149,7 +149,7 @@ statusDiv.className = ""; const formData = new FormData(this); - const apiUrl = "http://47.94.244.112:19001/process-image"; + const apiUrl = "http://117.50.44.174:19001/process-image"; fetch(apiUrl, { method: 'POST', diff --git a/static/imgs/0dca1afa-6c07-42f3-b653-b3f3e5fbe75d.png b/static/imgs/0dca1afa-6c07-42f3-b653-b3f3e5fbe75d.png new file mode 100644 index 0000000..9006877 Binary files /dev/null and b/static/imgs/0dca1afa-6c07-42f3-b653-b3f3e5fbe75d.png differ diff --git a/static/imgs/1d19c73b-abf0-4a5d-b80f-3bf745b94e06.jpg b/static/imgs/1d19c73b-abf0-4a5d-b80f-3bf745b94e06.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/1d19c73b-abf0-4a5d-b80f-3bf745b94e06.jpg differ diff --git a/static/imgs/4975f8f0-c2bd-4b0a-8244-c6b280355cbb.jpg b/static/imgs/4975f8f0-c2bd-4b0a-8244-c6b280355cbb.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/4975f8f0-c2bd-4b0a-8244-c6b280355cbb.jpg differ diff --git a/static/imgs/4afc150a-367f-4ced-b39d-dafdc190c9a8.jpg b/static/imgs/4afc150a-367f-4ced-b39d-dafdc190c9a8.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/4afc150a-367f-4ced-b39d-dafdc190c9a8.jpg differ diff --git a/static/imgs/5876b5c9_00001_.jpg b/static/imgs/5876b5c9_00001_.jpg new file mode 100644 index 0000000..ec2ab71 Binary files /dev/null and b/static/imgs/5876b5c9_00001_.jpg differ diff --git a/static/imgs/680cdb31-fccd-4fc5-b96c-57ad14a96b03.jpg b/static/imgs/680cdb31-fccd-4fc5-b96c-57ad14a96b03.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/680cdb31-fccd-4fc5-b96c-57ad14a96b03.jpg differ diff --git a/static/imgs/690e77ab_00001_.jpg b/static/imgs/690e77ab_00001_.jpg new file mode 100644 index 0000000..ef01d96 Binary files /dev/null and b/static/imgs/690e77ab_00001_.jpg differ diff --git a/static/imgs/6971b192-f782-4723-9e71-ba6e3a98f281.jpg b/static/imgs/6971b192-f782-4723-9e71-ba6e3a98f281.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/6971b192-f782-4723-9e71-ba6e3a98f281.jpg differ diff --git a/static/imgs/6bc4d42d_00001_.jpg b/static/imgs/6bc4d42d_00001_.jpg new file mode 100644 index 0000000..809ca8f Binary files /dev/null and b/static/imgs/6bc4d42d_00001_.jpg differ diff --git a/static/imgs/8960cece-78df-47d4-a0f1-cfe353286d57.png b/static/imgs/8960cece-78df-47d4-a0f1-cfe353286d57.png new file mode 100644 index 0000000..9006877 Binary files /dev/null and b/static/imgs/8960cece-78df-47d4-a0f1-cfe353286d57.png differ diff --git a/static/imgs/9ee3e988-f0d9-4db6-b3f8-fc2ec4a642bb.jpg b/static/imgs/9ee3e988-f0d9-4db6-b3f8-fc2ec4a642bb.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/9ee3e988-f0d9-4db6-b3f8-fc2ec4a642bb.jpg differ diff --git a/static/imgs/9f91698e_00001_.jpg b/static/imgs/9f91698e_00001_.jpg new file mode 100644 index 0000000..e282ea0 Binary files /dev/null and b/static/imgs/9f91698e_00001_.jpg differ diff --git a/static/imgs/cbf9f8d5-f201-420c-974f-e3e6e45ae17e.jpg b/static/imgs/cbf9f8d5-f201-420c-974f-e3e6e45ae17e.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/cbf9f8d5-f201-420c-974f-e3e6e45ae17e.jpg differ diff --git a/static/imgs/cloth_20260308_155214_e5cef419.jpg b/static/imgs/cloth_20260308_155214_e5cef419.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/cloth_20260308_155214_e5cef419.jpg differ diff --git a/static/imgs/cloth_20260308_155621_b4618cd5.jpg b/static/imgs/cloth_20260308_155621_b4618cd5.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/cloth_20260308_155621_b4618cd5.jpg differ diff --git a/static/imgs/cloth_20260308_155808_1c668e1b.jpg b/static/imgs/cloth_20260308_155808_1c668e1b.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/cloth_20260308_155808_1c668e1b.jpg differ diff --git a/static/imgs/cloth_20260308_155922_e42ffe61.jpg b/static/imgs/cloth_20260308_155922_e42ffe61.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/cloth_20260308_155922_e42ffe61.jpg differ diff --git a/static/imgs/cloth_20260308_160045_3f378dd6.jpg b/static/imgs/cloth_20260308_160045_3f378dd6.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/cloth_20260308_160045_3f378dd6.jpg differ diff --git a/static/imgs/d1b3e77a-2487-48e2-8167-c20d03ebf378.jpg b/static/imgs/d1b3e77a-2487-48e2-8167-c20d03ebf378.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/d1b3e77a-2487-48e2-8167-c20d03ebf378.jpg differ diff --git a/static/imgs/e2ca1b41-1eff-4510-a68c-36c137f06016.jpg b/static/imgs/e2ca1b41-1eff-4510-a68c-36c137f06016.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/e2ca1b41-1eff-4510-a68c-36c137f06016.jpg differ diff --git a/static/imgs/e7b6b8b5-fe59-48f3-83dd-fe54f670c9c9.jpg b/static/imgs/e7b6b8b5-fe59-48f3-83dd-fe54f670c9c9.jpg new file mode 100644 index 0000000..0568a46 Binary files /dev/null and b/static/imgs/e7b6b8b5-fe59-48f3-83dd-fe54f670c9c9.jpg differ diff --git a/static/imgs/human_20260308_155214_c017e3f7.jpg b/static/imgs/human_20260308_155214_c017e3f7.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/human_20260308_155214_c017e3f7.jpg differ diff --git a/static/imgs/human_20260308_155621_1fe08bd8.jpg b/static/imgs/human_20260308_155621_1fe08bd8.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/human_20260308_155621_1fe08bd8.jpg differ diff --git a/static/imgs/human_20260308_155808_36af3294.jpg b/static/imgs/human_20260308_155808_36af3294.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/human_20260308_155808_36af3294.jpg differ diff --git a/static/imgs/human_20260308_155922_ac5de07a.jpg b/static/imgs/human_20260308_155922_ac5de07a.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/human_20260308_155922_ac5de07a.jpg differ diff --git a/static/imgs/human_20260308_160045_161e7d55.jpg b/static/imgs/human_20260308_160045_161e7d55.jpg new file mode 100644 index 0000000..744da63 Binary files /dev/null and b/static/imgs/human_20260308_160045_161e7d55.jpg differ diff --git a/static/imgs/kuzi_20260308_155214_24aa80fd.jpg b/static/imgs/kuzi_20260308_155214_24aa80fd.jpg new file mode 100644 index 0000000..f4abdc2 Binary files /dev/null and b/static/imgs/kuzi_20260308_155214_24aa80fd.jpg differ diff --git a/static/imgs/kuzi_20260308_155621_d75748f8.jpg b/static/imgs/kuzi_20260308_155621_d75748f8.jpg new file mode 100644 index 0000000..f4abdc2 Binary files /dev/null and b/static/imgs/kuzi_20260308_155621_d75748f8.jpg differ diff --git a/static/imgs/kuzi_20260308_155808_3b9f2756.jpg b/static/imgs/kuzi_20260308_155808_3b9f2756.jpg new file mode 100644 index 0000000..f4abdc2 Binary files /dev/null and b/static/imgs/kuzi_20260308_155808_3b9f2756.jpg differ diff --git a/static/index.html b/static/index.html index 32fdfed..c5033b3 100644 --- a/static/index.html +++ b/static/index.html @@ -257,7 +257,7 @@ console.log("准备发送的数据:", data); // 调试用 // 调用API - fetch('http://112.126.94.241:28888/change_cloth_base64', { + fetch('http://117.50.44.174:28888/change_cloth_base64', { method: 'POST', headers: { 'Content-Type': 'application/json' diff --git a/static/index_url.html b/static/index_url.html index a6db7fe..be26b0f 100644 --- a/static/index_url.html +++ b/static/index_url.html @@ -94,12 +94,12 @@
- +
- +
@@ -136,7 +136,7 @@ try { // 发送POST请求 - const response = await fetch('http://112.126.94.241:18888/change_cloth', { + const response = await fetch('http://117.50.44.174:18888/change_cloth', { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/static/monitor.html b/static/monitor.html index f45055a..b962fc6 100644 --- a/static/monitor.html +++ b/static/monitor.html @@ -246,7 +246,7 @@ // 获取服务器状态数据 async function fetchServerStatus() { try { - const response = await fetch('http://112.126.94.241:18018/get_server_state'); + const response = await fetch('http://117.50.44.174:18018/get_server_state'); if (!response.ok) throw new Error('网络响应不正常'); return await response.json(); } catch (error) { diff --git a/test_change_cloth_http.py b/test_change_cloth_http.py index 1b9d732..9e4b9f6 100644 --- a/test_change_cloth_http.py +++ b/test_change_cloth_http.py @@ -27,7 +27,7 @@ def image_to_base64(file_path, mime_type=None): return f"data:{mime_type};base64,{encoded_string}" if __name__ == '__main__': - url = 'http://112.126.94.241:18018/change_cloth_base64' + url = 'http://117.50.44.174:18018/change_cloth_base64' headers = {'Content-Type': 'application/json'} img64_human_str = image_to_base64("/home/xsl/code/ComfyUI/input/girl_full.jpg") data = {}