diff --git a/change2/nohup.out b/change2/nohup.out new file mode 100644 index 0000000..efa65e3 --- /dev/null +++ b/change2/nohup.out @@ -0,0 +1,6 @@ +/usr/local/miniconda3/envs/py312/lib/python3.12/site-packages/requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (7.0.1)/charset_normalizer (3.4.5) doesn't match a supported version! + warnings.warn( +INFO: Started server process [9669] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Uvicorn running on http://0.0.0.0:12222 (Press CTRL+C to quit) diff --git a/change2/service2.py b/change2/service2.py index 1967534..71b9386 100644 --- a/change2/service2.py +++ b/change2/service2.py @@ -10,6 +10,8 @@ import asyncio import base64 import io import json +import os +import tempfile import time import uuid from pathlib import Path @@ -21,6 +23,8 @@ from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from pydantic import BaseModel +import oss2 + COMFYUI_URL = "http://127.0.0.1:8188" # COMFYUI_URL = "http://117.50.80.187:47697" WORKFLOW_PATH = Path(__file__).parent / "change2_1_ex.json" @@ -40,6 +44,37 @@ app.add_middleware( allow_headers=["*"], ) +def upload_to_oss(image_path, object_name=None): + # 配置信息(替换为你的实际信息) + access_key_id = 'LTAI5tGp1sLzedqxihcNC1eb' + access_key_secret = 'IFZE1b8YYreCP6zfA6GaZ9uBT678qO' + endpoint = 'oss-cn-beijing.aliyuncs.com' # 替换为你的Endpoint + bucket_name = 'xiangsilian' + + # 创建Bucket实例 + auth = oss2.Auth(access_key_id, access_key_secret) + bucket = oss2.Bucket(auth, endpoint, bucket_name) + + # 如果没有指定OSS文件名,则使用本地文件名 + if object_name is None: + object_name = image_path.split('/')[-1] # 取本地文件名 + + try: + # 上传文件 + bucket.put_object_from_file(object_name, image_path) + + # 获取文件URL(有效期默认10年) + url = bucket.sign_url('GET', object_name, 3600 * 24 * 365 * 10) + + # 或者使用公共读Bucket的URL(如果Bucket是公共读权限) + # url = f"https://{bucket_name}.{endpoint}/{object_name}" + + print(f"文件上传成功,URL: {url}") + return url + except Exception as e: + print(f"上传失败: {str(e)}") + return None + class TryOnRequest(BaseModel): model_image: str # base64 模特图片 @@ -47,7 +82,7 @@ class TryOnRequest(BaseModel): class TryOnResponse(BaseModel): - result_image: str # base64 结果图片 + result_url: str # OSS 图片 URL def decode_base64_image(b64_str: str) -> bytes: @@ -96,14 +131,12 @@ async def wait_for_result(client: httpx.AsyncClient, prompt_id: str, timeout: in raise HTTPException(status_code=504, detail="等待 ComfyUI 超时(300秒)") -async def fetch_image_as_base64(client: httpx.AsyncClient, filename: str, subfolder: str = "", type_: str = "output") -> str: - """从 ComfyUI 下载图片并编码为 base64""" +async def fetch_image_bytes(client: httpx.AsyncClient, filename: str, subfolder: str = "", type_: str = "output") -> bytes: + """从 ComfyUI 下载图片,返回原始字节""" params = {"filename": filename, "subfolder": subfolder, "type": type_} resp = await client.get(f"{COMFYUI_URL}/view", params=params) resp.raise_for_status() - content_type = resp.headers.get("content-type", "image/png") - b64 = base64.b64encode(resp.content).decode() - return f"data:{content_type};base64,{b64}" + return resp.content @app.post("/try-on", response_model=TryOnResponse) @@ -173,9 +206,24 @@ async def try_on(req: TryOnRequest): # 下载结果图片 async with httpx.AsyncClient(timeout=30.0) as dl_client: - result_b64 = await fetch_image_as_base64(dl_client, filename, subfolder, type_) + result_bytes = await fetch_image_bytes(dl_client, filename, subfolder, type_) - return TryOnResponse(result_image=result_b64) + # 将图片保存到临时文件,上传到 OSS + suffix = Path(filename).suffix or ".png" + object_name = f"tryon/{uuid.uuid4().hex}{suffix}" + with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp: + tmp.write(result_bytes) + tmp_path = tmp.name + + try: + result_url = upload_to_oss(tmp_path, object_name) + finally: + os.unlink(tmp_path) + + if not result_url: + raise HTTPException(status_code=500, detail="上传结果图片到 OSS 失败") + + return TryOnResponse(result_url=result_url) @app.get("/health") diff --git a/change2/static/index.html b/change2/static/index.html index d2aeb53..e776112 100644 --- a/change2/static/index.html +++ b/change2/static/index.html @@ -309,15 +309,16 @@ } const data = await resp.json(); - resultImg.src = data.result_image; + resultImg.src = data.result_url; resultSection.classList.add('visible'); setStatus(`✅ 换装完成!耗时 ${elapsed(start)}`, 'success'); // 下载按钮 document.getElementById('btn-download').onclick = () => { const a = document.createElement('a'); - a.href = data.result_image; + a.href = data.result_url; a.download = `tryon_${Date.now()}.png`; + a.target = '_blank'; a.click(); }; } catch (err) { diff --git a/change3/nohup.out b/change3/nohup.out new file mode 100644 index 0000000..b5ceacc --- /dev/null +++ b/change3/nohup.out @@ -0,0 +1,10 @@ +/usr/local/miniconda3/envs/py312/lib/python3.12/site-packages/requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (7.0.1)/charset_normalizer (3.4.5) doesn't match a supported version! + warnings.warn( +INFO: Started server process [9612] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Uvicorn running on http://0.0.0.0:12223 (Press CTRL+C to quit) +静态文件目录: /root/change_cloth_server/change3/static +接收到换装请求,正在处理... +文件上传成功,URL: http://xiangsilian.oss-cn-beijing.aliyuncs.com/tryon%2F627bcee434384a7b847faf2dbbce90ae.png?OSSAccessKeyId=LTAI5tGp1sLzedqxihcNC1eb&Expires=2088730306&Signature=aATPXbjJCE3ArJnYfRyvSVSI8EE%3D +INFO: 127.0.0.1:39178 - "POST /try-on HTTP/1.1" 200 OK diff --git a/change3/service3.py b/change3/service3.py index 5c695e5..2490108 100644 --- a/change3/service3.py +++ b/change3/service3.py @@ -10,11 +10,14 @@ import asyncio import base64 import io import json +import os +import tempfile import time import uuid from pathlib import Path import httpx +import oss2 from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import FileResponse @@ -41,6 +44,28 @@ app.add_middleware( ) +def upload_to_oss(image_path, object_name=None): + access_key_id = 'LTAI5tGp1sLzedqxihcNC1eb' + access_key_secret = 'IFZE1b8YYreCP6zfA6GaZ9uBT678qO' + endpoint = 'oss-cn-beijing.aliyuncs.com' + bucket_name = 'xiangsilian' + + auth = oss2.Auth(access_key_id, access_key_secret) + bucket = oss2.Bucket(auth, endpoint, bucket_name) + + if object_name is None: + object_name = image_path.split('/')[-1] + + try: + bucket.put_object_from_file(object_name, image_path) + url = bucket.sign_url('GET', object_name, 3600 * 24 * 365 * 10) + print(f"文件上传成功,URL: {url}") + return url + except Exception as e: + print(f"上传失败: {str(e)}") + return None + + class TryOnRequest(BaseModel): model_image: str # base64 模特图片 shirt_image: str # base64 上衣图片 @@ -48,7 +73,7 @@ class TryOnRequest(BaseModel): class TryOnResponse(BaseModel): - result_image: str # base64 结果图片 + result_url: str # OSS 图片 URL def decode_base64_image(b64_str: str) -> bytes: @@ -97,14 +122,12 @@ async def wait_for_result(client: httpx.AsyncClient, prompt_id: str, timeout: in raise HTTPException(status_code=504, detail="等待 ComfyUI 超时(300秒)") -async def fetch_image_as_base64(client: httpx.AsyncClient, filename: str, subfolder: str = "", type_: str = "output") -> str: - """从 ComfyUI 下载图片并编码为 base64""" +async def fetch_image_bytes(client: httpx.AsyncClient, filename: str, subfolder: str = "", type_: str = "output") -> bytes: + """从 ComfyUI 下载图片,返回原始字节""" params = {"filename": filename, "subfolder": subfolder, "type": type_} resp = await client.get(f"{COMFYUI_URL}/view", params=params) resp.raise_for_status() - content_type = resp.headers.get("content-type", "image/png") - b64 = base64.b64encode(resp.content).decode() - return f"data:{content_type};base64,{b64}" + return resp.content @app.post("/try-on", response_model=TryOnResponse) @@ -116,6 +139,7 @@ async def try_on(req: TryOnRequest): - pants_image: 裤子图片 base64 返回 result_image: 换装结果 base64 """ + print(f"接收到换装请求,正在处理...") # 加载工作流模板 workflow = json.loads(WORKFLOW_PATH.read_text(encoding="utf-8")) @@ -175,9 +199,24 @@ async def try_on(req: TryOnRequest): # 下载结果图片 async with httpx.AsyncClient(timeout=30.0) as dl_client: - result_b64 = await fetch_image_as_base64(dl_client, filename, subfolder, type_) + result_bytes = await fetch_image_bytes(dl_client, filename, subfolder, type_) - return TryOnResponse(result_image=result_b64) + # 将图片保存到临时文件,上传到 OSS + suffix = Path(filename).suffix or ".png" + object_name = f"tryon/{uuid.uuid4().hex}{suffix}" + with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp: + tmp.write(result_bytes) + tmp_path = tmp.name + + try: + result_url = upload_to_oss(tmp_path, object_name) + finally: + os.unlink(tmp_path) + + if not result_url: + raise HTTPException(status_code=500, detail="上传结果图片到 OSS 失败") + + return TryOnResponse(result_url=result_url) @app.get("/health") diff --git a/change3/static/index.html b/change3/static/index.html index 45eeded..5d2f12f 100644 --- a/change3/static/index.html +++ b/change3/static/index.html @@ -320,15 +320,16 @@ } const data = await resp.json(); - resultImg.src = data.result_image; + resultImg.src = data.result_url; resultSection.classList.add('visible'); setStatus(`✅ 换装完成!耗时 ${elapsed(start)}`, 'success'); // 下载按钮 document.getElementById('btn-download').onclick = () => { const a = document.createElement('a'); - a.href = data.result_image; + a.href = data.result_url; a.download = `tryon_${Date.now()}.png`; + a.target = '_blank'; a.click(); }; } catch (err) { diff --git a/change_app.py b/change_app.py index cf037a4..f8bc938 100644 --- a/change_app.py +++ b/change_app.py @@ -47,7 +47,7 @@ def change_cloth_base64(): response.raise_for_status() result = response.json() - result_image = result.get('result_image') + result_image = result.get('result_url') if not result_image: return jsonify({"ret": -1, "state": -1, "msg": "Backend returned no image"}), 500 diff --git a/nohup.out b/nohup.out new file mode 100644 index 0000000..68b145f --- /dev/null +++ b/nohup.out @@ -0,0 +1,10 @@ +/usr/local/miniconda3/envs/py312/lib/python3.12/site-packages/requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (7.0.1)/charset_normalizer (3.4.5) doesn't match a supported version! + warnings.warn( + * Serving Flask app 'change_app' + * Debug mode: off +WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on all addresses (0.0.0.0) + * Running on http://127.0.0.1:28888 + * Running on http://10.60.190.115:28888 +Press CTRL+C to quit +1.202.76.38 - - [13/Mar/2026 02:51:46] "POST /change_cloth_base64 HTTP/1.1" 200 - diff --git a/static/index.html b/static/index.html index 1cfa4e4..76ad9eb 100644 --- a/static/index.html +++ b/static/index.html @@ -342,12 +342,8 @@ clearInterval(timer); const data = await resp.json(); - // 显示原始响应(data 字段截断) - const preview = { ...data }; - if (preview.data && preview.data.length > 80) { - preview.data = preview.data.slice(0, 80) + '…(已截断)'; - } - rawText.textContent = JSON.stringify(preview, null, 2); + // 显示原始响应 + rawText.textContent = JSON.stringify(data, null, 2); rawResp.classList.add('visible'); if (data.ret !== 0 || !data.data) { @@ -362,6 +358,7 @@ const a = document.createElement('a'); a.href = data.data; a.download = `tryon_${Date.now()}.png`; + a.target = '_blank'; a.click(); };