From 79d8c6d17f379ed34613f70354eef6db6612e7b5 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 6 Apr 2026 17:47:45 +0800 Subject: [PATCH] save code --- change2/service2.py | 6 +++- change2/static/index.html | 70 +++++++++++++++++++++++++++++++++++++++ change3/service3.py | 6 ++++ change3/static/index.html | 70 +++++++++++++++++++++++++++++++++++++++ change_app.py | 8 +++++ start_services.sh | 38 +++++++-------------- static/index.html | 70 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 241 insertions(+), 27 deletions(-) diff --git a/change2/service2.py b/change2/service2.py index 2691860..7a77a8c 100644 --- a/change2/service2.py +++ b/change2/service2.py @@ -37,6 +37,7 @@ NODE_MODEL = "11" # 模特 NODE_SHIRT = "10" # 上衣 # NODE_PANTS = "4" # 裤子 NODE_OUTPUT = "33" # 输出 +NODE_PROMPT = "31" # 文本提示(PrimitiveStringMultiline) app = FastAPI(title="ComfyUI 换装服务") @@ -82,6 +83,7 @@ def upload_to_oss(image_path, object_name=None): class TryOnRequest(BaseModel): model_image: str # base64 模特图片 shirt_image: str # base64 上衣图片 + change_desc: str = "" # 换装/编辑描述,可空;非空时替换节点 31 的 inputs class TryOnResponse(BaseModel): @@ -155,7 +157,9 @@ async def try_on(req: TryOnRequest): # 加载工作流模板 workflow = json.loads(WORKFLOW_PATH.read_text(encoding="utf-8")) - + desc = (req.change_desc or "").strip() + if desc: + workflow[NODE_PROMPT]["inputs"] = {"value": desc} async with httpx.AsyncClient(timeout=60.0) as client: # 解码两张图片 diff --git a/change2/static/index.html b/change2/static/index.html index e776112..fc41ccf 100644 --- a/change2/static/index.html +++ b/change2/static/index.html @@ -196,6 +196,49 @@ background: #7c3aed22; } + .prompt-panel { + width: 100%; + max-width: 900px; + margin-bottom: 24px; + background: #1a1a24; + border-radius: 16px; + padding: 20px; + border: 1px solid #2a2a3a; + } + .prompt-panel .prompt-title { + font-size: 0.85rem; + font-weight: 600; + color: #a78bfa; + margin-bottom: 12px; + } + .radio-row { + display: flex; + align-items: flex-start; + gap: 10px; + margin-bottom: 10px; + cursor: pointer; + font-size: 0.9rem; + color: #ccc; + } + .radio-row input { margin-top: 3px; accent-color: #7c3aed; flex-shrink: 0; } + .change-desc-input { + width: 100%; + margin-top: 4px; + padding: 12px; + border-radius: 10px; + border: 1px solid #333; + background: #12121a; + color: #e0e0e0; + font-family: inherit; + font-size: 0.88rem; + resize: vertical; + min-height: 88px; + } + .change-desc-input:disabled { + opacity: 0.45; + cursor: not-allowed; + } + @media (max-width: 640px) { .upload-grid { grid-template-columns: 1fr; } h1 { font-size: 1.5rem; } @@ -226,6 +269,19 @@ +
+
提示词(change_desc)
+ + + +
+
@@ -261,6 +317,19 @@ setupUpload('input-model', 'preview-model', 'card-model', 'model'); setupUpload('input-shirt', 'preview-shirt', 'card-shirt', 'shirt'); + const promptDefault = document.getElementById('prompt-default'); + const promptCustom = document.getElementById('prompt-custom'); + const changeDescEl = document.getElementById('change-desc'); + function syncPromptUi() { + changeDescEl.disabled = !promptCustom.checked; + } + promptDefault.addEventListener('change', syncPromptUi); + promptCustom.addEventListener('change', syncPromptUi); + + function getChangeDesc() { + return promptCustom.checked ? changeDescEl.value.trim() : ''; + } + function updateRunButton() { const btn = document.getElementById('btn-run'); btn.disabled = !(images.model && images.shirt); @@ -298,6 +367,7 @@ body: JSON.stringify({ model_image: images.model, shirt_image: images.shirt, + change_desc: getChangeDesc(), }), }); diff --git a/change3/service3.py b/change3/service3.py index f4fdd75..a251f90 100644 --- a/change3/service3.py +++ b/change3/service3.py @@ -36,6 +36,7 @@ NODE_MODEL = "11" # 模特 NODE_SHIRT = "10" # 上衣 NODE_PANTS = "4" # 裤子 NODE_OUTPUT = "33" # 输出 +NODE_PROMPT = "31" # 文本提示(PrimitiveStringMultiline) app = FastAPI(title="ComfyUI 换装服务") @@ -73,6 +74,7 @@ class TryOnRequest(BaseModel): model_image: str # base64 模特图片 shirt_image: str # base64 上衣图片 pants_image: str # base64 裤子图片 + change_desc: str = "" # 换装/编辑描述,可空;非空时替换节点 31 的 inputs class TryOnResponse(BaseModel): @@ -146,6 +148,10 @@ async def try_on(req: TryOnRequest): # 加载工作流模板 workflow = json.loads(WORKFLOW_PATH.read_text(encoding="utf-8")) + desc = (req.change_desc or "").strip() + if desc: + workflow[NODE_PROMPT]["inputs"] = {"value": desc} + async with httpx.AsyncClient(timeout=60.0) as client: # 解码三张图片 try: diff --git a/change3/static/index.html b/change3/static/index.html index 5d2f12f..4c69f46 100644 --- a/change3/static/index.html +++ b/change3/static/index.html @@ -196,6 +196,49 @@ background: #7c3aed22; } + .prompt-panel { + width: 100%; + max-width: 900px; + margin-bottom: 24px; + background: #1a1a24; + border-radius: 16px; + padding: 20px; + border: 1px solid #2a2a3a; + } + .prompt-panel .prompt-title { + font-size: 0.85rem; + font-weight: 600; + color: #a78bfa; + margin-bottom: 12px; + } + .radio-row { + display: flex; + align-items: flex-start; + gap: 10px; + margin-bottom: 10px; + cursor: pointer; + font-size: 0.9rem; + color: #ccc; + } + .radio-row input { margin-top: 3px; accent-color: #7c3aed; flex-shrink: 0; } + .change-desc-input { + width: 100%; + margin-top: 4px; + padding: 12px; + border-radius: 10px; + border: 1px solid #333; + background: #12121a; + color: #e0e0e0; + font-family: inherit; + font-size: 0.88rem; + resize: vertical; + min-height: 88px; + } + .change-desc-input:disabled { + opacity: 0.45; + cursor: not-allowed; + } + @media (max-width: 640px) { .upload-grid { grid-template-columns: 1fr; } h1 { font-size: 1.5rem; } @@ -235,6 +278,19 @@ +
+
提示词(change_desc)
+ + + +
+
@@ -271,6 +327,19 @@ setupUpload('input-shirt', 'preview-shirt', 'card-shirt', 'shirt'); setupUpload('input-pants', 'preview-pants', 'card-pants', 'pants'); + const promptDefault = document.getElementById('prompt-default'); + const promptCustom = document.getElementById('prompt-custom'); + const changeDescEl = document.getElementById('change-desc'); + function syncPromptUi() { + changeDescEl.disabled = !promptCustom.checked; + } + promptDefault.addEventListener('change', syncPromptUi); + promptCustom.addEventListener('change', syncPromptUi); + + function getChangeDesc() { + return promptCustom.checked ? changeDescEl.value.trim() : ''; + } + function updateRunButton() { const btn = document.getElementById('btn-run'); btn.disabled = !(images.model && images.shirt && images.pants); @@ -309,6 +378,7 @@ model_image: images.model, shirt_image: images.shirt, pants_image: images.pants, + change_desc: getChangeDesc(), }), }); diff --git a/change_app.py b/change_app.py index 4b29bfa..5e2033f 100644 --- a/change_app.py +++ b/change_app.py @@ -31,18 +31,26 @@ def change_cloth_base64(): kuzi_img = data.get('kuzi_img') + change_desc = data.get('change_desc') + if change_desc is None: + change_desc = '' + elif not isinstance(change_desc, str): + return jsonify({"ret": -1, "state": -1, "msg": "change_desc must be a string"}), 400 + try: if kuzi_img: payload = { 'model_image': human_img, 'shirt_image': cloth_img, 'pants_image': kuzi_img, + 'change_desc': change_desc, } response = requests.post('http://127.0.0.1:12223/try-on', json=payload, timeout=360) else: payload = { 'model_image': human_img, 'shirt_image': cloth_img, + 'change_desc': change_desc, } response = requests.post('http://127.0.0.1:12222/try-on', json=payload, timeout=360) diff --git a/start_services.sh b/start_services.sh index da82372..a7f2872 100755 --- a/start_services.sh +++ b/start_services.sh @@ -1,45 +1,31 @@ #!/bin/bash +# 启动本机换装网关与 service2 / service3。 +# ComfyUI 在其它机器运行;service2/service3 内已配置远端 COMFYUI_URL。 +ROOT="/home/ubuntu/change_cloth_server" LOG_DIR="/home/ubuntu/log" mkdir -p "$LOG_DIR" echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始停止旧进程..." -# 杀掉已有进程 -pkill -f "main.py" 2>/dev/null && echo " 已停止 ComfyUI" || echo " ComfyUI 未在运行" -pkill -f "change_cloth_server/change2/service2.py" 2>/dev/null && echo " 已停止 service2" || echo " service2 未在运行" -pkill -f "change_cloth_server/change3/service3.py" 2>/dev/null && echo " 已停止 service3" || echo " service3 未在运行" -pkill -f "change_cloth_server/change_app.py" 2>/dev/null && echo " 已停止 change_app" || echo " change_app 未在运行" +# 按命令行中的脚本绝对路径结束旧实例(与下方 nohup 路径一致) +pkill -f "${ROOT}/change2/service2.py" 2>/dev/null && echo " 已停止 service2" || echo " service2 未在运行" +pkill -f "${ROOT}/change3/service3.py" 2>/dev/null && echo " 已停止 service3" || echo " service3 未在运行" +pkill -f "${ROOT}/change_app.py" 2>/dev/null && echo " 已停止 change_app" || echo " change_app 未在运行" -# 等待进程退出 sleep 2 echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始启动服务..." -# 启动 ComfyUI(使用项目 venv) -COMFYUI_PYTHON="/home/ubuntu/ComfyUI/.venv/bin/python" -if [ -x "$COMFYUI_PYTHON" ]; then - cd /home/ubuntu/ComfyUI - nohup "$COMFYUI_PYTHON" main.py >> "$LOG_DIR/comfyui.log" 2>&1 & - echo " ComfyUI 已启动 (PID: $!)" -else - cd /home/ubuntu/ComfyUI - nohup python3 main.py >> "$LOG_DIR/comfyui.log" 2>&1 & - echo " ComfyUI 已启动 (PID: $!)" -fi - -# 启动 service2 / service3 / change_app(使用 python3,依赖已 pip install --user) export PATH="/home/ubuntu/.local/bin:$PATH" -cd /home/ubuntu/change_cloth_server/change2 -nohup python3 service2.py >> "$LOG_DIR/service2.log" 2>&1 & + +nohup python3 "${ROOT}/change2/service2.py" >> "$LOG_DIR/service2.log" 2>&1 & echo " service2 已启动 (PID: $!)" -cd /home/ubuntu/change_cloth_server/change3 -nohup python3 service3.py >> "$LOG_DIR/service3.log" 2>&1 & +nohup python3 "${ROOT}/change3/service3.py" >> "$LOG_DIR/service3.log" 2>&1 & echo " service3 已启动 (PID: $!)" -cd /home/ubuntu/change_cloth_server -nohup python3 change_app.py >> "$LOG_DIR/change_app.log" 2>&1 & +nohup python3 "${ROOT}/change_app.py" >> "$LOG_DIR/change_app.log" 2>&1 & echo " change_app 已启动 (PID: $!)" -echo "[$(date '+%Y-%m-%d %H:%M:%S')] 所有服务启动完毕,日志目录: $LOG_DIR" +echo "[$(date '+%Y-%m-%d %H:%M:%S')] 启动完毕(ComfyUI 请在外部机器保证可用)。日志目录: $LOG_DIR" diff --git a/static/index.html b/static/index.html index 76ad9eb..9d1216e 100644 --- a/static/index.html +++ b/static/index.html @@ -198,6 +198,49 @@ .raw-resp.visible { display: block; } .raw-resp pre { white-space: pre-wrap; } + .prompt-panel { + width: 100%; + max-width: 960px; + margin-bottom: 24px; + background: #1a1a24; + border-radius: 16px; + padding: 20px; + border: 1px solid #2a2a3a; + } + .prompt-panel .prompt-title { + font-size: 0.85rem; + font-weight: 600; + color: #a78bfa; + margin-bottom: 12px; + } + .radio-row { + display: flex; + align-items: flex-start; + gap: 10px; + margin-bottom: 10px; + cursor: pointer; + font-size: 0.9rem; + color: #ccc; + } + .radio-row input { margin-top: 3px; accent-color: #7c3aed; flex-shrink: 0; } + .change-desc-input { + width: 100%; + margin-top: 4px; + padding: 12px; + border-radius: 10px; + border: 1px solid #333; + background: #12121a; + color: #e0e0e0; + font-family: inherit; + font-size: 0.88rem; + resize: vertical; + min-height: 88px; + } + .change-desc-input:disabled { + opacity: 0.45; + cursor: not-allowed; + } + @media (max-width: 640px) { .upload-grid { grid-template-columns: 1fr; } h1 { font-size: 1.5rem; } @@ -241,6 +284,19 @@ +
+
提示词(change_desc)
+ + + +
+
@@ -295,6 +351,19 @@ setupUpload('input-cloth', 'preview-cloth', 'card-cloth', 'clear-cloth', 'cloth'); setupUpload('input-kuzi', 'preview-kuzi', 'card-kuzi', 'clear-kuzi', 'kuzi'); + const promptDefault = document.getElementById('prompt-default'); + const promptCustom = document.getElementById('prompt-custom'); + const changeDescEl = document.getElementById('change-desc'); + function syncPromptUi() { + changeDescEl.disabled = !promptCustom.checked; + } + promptDefault.addEventListener('change', syncPromptUi); + promptCustom.addEventListener('change', syncPromptUi); + + function getChangeDesc() { + return promptCustom.checked ? changeDescEl.value.trim() : ''; + } + function updateRunButton() { document.getElementById('btn-run').disabled = !(images.human && images.cloth); } @@ -329,6 +398,7 @@ const body = { human_img: images.human, cloth_img: images.cloth, + change_desc: getChangeDesc(), }; if (images.kuzi) body.kuzi_img = images.kuzi;