diff --git a/.gitignore b/.gitignore index 06dd747..b373e0d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,9 @@ gateway/config.json # worker 配置(含鉴权密码,不入 git) worker_config.json +# ComfyUI Basic Auth 密码(不入 git) +password.txt + # worker 运行期文件(PID / 日志) worker.pid worker.log diff --git a/docs/实现说明.md b/docs/实现说明.md index c7e6953..a511b9d 100644 --- a/docs/实现说明.md +++ b/docs/实现说明.md @@ -84,7 +84,9 @@ - ⚠️ 本机 **RTX 5090(sm_120)**,pinned `torch 2.2.2(cu121)` 只到 sm_90 → GPU 算子报 "no kernel image", 代码已自动**回退 CPU**(BiSeNet/SegFormer CPU 推理可用)。要用 5090 GPU 需换 torch cu128(≥2.7)。 - 模型权重/字体见 [`../OFFLINE_ASSETS.md`](../OFFLINE_ASSETS.md);BiSeNet/SegFormer/face_landmarker.task 本地。 -- 生发接口依赖本机 **ComfyUI(8182)**(Flux-2,它自带支持 5090 的 torch);worker 只调其 HTTP API,不跑 Flux。 +- 生发接口依赖本机 **ComfyUI(8188)**(Flux-2,它自带支持 5090 的 torch);worker 只调其 HTTP API,不跑 Flux。 + ComfyUI 开了 **HTTP Basic Auth**(user `admin` + 密码);密码放 `password.txt`(不入 git) / + `worker_config.json.comfyui_password` / 环境变量 `COMFYUI_PASSWORD`,URL 用 `COMFYUI_URL`。 - `worker_config.json`(不入 git):`accept_passwords`(鉴权) + 鉴权头 `X-Internal-Token`。 **网关机** diff --git a/hairline/comfyui.py b/hairline/comfyui.py index e9422aa..f8c7422 100644 --- a/hairline/comfyui.py +++ b/hairline/comfyui.py @@ -1,7 +1,8 @@ """ComfyUI 客户端:用 add_hair.json 工作流跑生发图(Flux-2 inpaint)。 -worker 不跑 Flux,只把「划线图 + 遮罩」的 RGBA 上传到本机 ComfyUI(默认 8182), +worker 不跑 Flux,只把「划线图 + 遮罩」的 RGBA 上传到本机 ComfyUI(默认 8188), 替换工作流节点 26 的输入图、随机 seed,提交 /prompt,轮询 /history,取回 /view 输出。 +ComfyUI 开启了 HTTP Basic Auth(user `admin` + 密码),所有请求都带凭据。 """ from __future__ import annotations @@ -14,12 +15,13 @@ import uuid import httpx -COMFYUI_URL = os.getenv("COMFYUI_URL", "http://127.0.0.1:8182").rstrip("/") +COMFYUI_URL = os.getenv("COMFYUI_URL", "http://127.0.0.1:8188").rstrip("/") WORKFLOW_PATH = os.getenv( "ADD_HAIR_WORKFLOW", os.path.join(os.path.dirname(os.path.dirname(__file__)), "add_hair.json"), ) COMFY_TIMEOUT = float(os.getenv("COMFYUI_TIMEOUT", "600")) # 单张出图最长等待(秒) +_REPO = os.path.dirname(os.path.dirname(__file__)) _INPUT_NODE = "26" # LoadImage:外部输入图(含 alpha 遮罩) _SEED_NODE = "6" # RandomNoise @@ -28,6 +30,31 @@ _OUTPUT_NODE = "17" # SaveImage _workflow = None +def _comfy_auth(): + """ComfyUI Basic Auth 凭据 (user, password)。 + + user:环境变量 COMFYUI_USER,默认 admin。 + password:环境变量 COMFYUI_PASSWORD → worker_config.json.comfyui_password → password.txt。 + 无密码则返回 None(不带鉴权,兼容未开启 auth 的实例)。 + """ + user = os.getenv("COMFYUI_USER", "admin") + pw = os.getenv("COMFYUI_PASSWORD") + if not pw: + cfg = os.path.join(_REPO, "worker_config.json") + if os.path.isfile(cfg): + try: + with open(cfg, encoding="utf-8") as f: + pw = json.load(f).get("comfyui_password") + except Exception: # noqa: BLE001 + pw = None + if not pw: + pwfile = os.path.join(_REPO, "password.txt") + if os.path.isfile(pwfile): + with open(pwfile, encoding="utf-8") as f: + pw = f.read().strip() + return (user, pw) if pw else None + + def _load_workflow() -> dict: global _workflow if _workflow is None: @@ -39,7 +66,7 @@ def _load_workflow() -> dict: def run(rgba_png_bytes: bytes, timeout: float = COMFY_TIMEOUT) -> bytes: """提交一次生发任务,返回输出 PNG 字节。失败抛异常。""" client_id = uuid.uuid4().hex - with httpx.Client(base_url=COMFYUI_URL, timeout=30.0) as cli: + with httpx.Client(base_url=COMFYUI_URL, timeout=30.0, auth=_comfy_auth()) as cli: # 1. 上传输入图(含 alpha 遮罩)到 ComfyUI input 目录 fname = f"hair_{client_id}.png" r = cli.post("/upload/image", files={"image": (fname, rgba_png_bytes, "image/png")}, @@ -92,7 +119,7 @@ def run(rgba_png_bytes: bytes, timeout: float = COMFY_TIMEOUT) -> bytes: def ping() -> bool: """探测 ComfyUI 是否在线(/system_stats)。""" try: - with httpx.Client(base_url=COMFYUI_URL, timeout=3.0) as cli: + with httpx.Client(base_url=COMFYUI_URL, timeout=3.0, auth=_comfy_auth()) as cli: return cli.get("/system_stats").status_code == 200 except Exception: # noqa: BLE001 return False diff --git a/worker_config.example.json b/worker_config.example.json index 172af39..483fc13 100644 --- a/worker_config.example.json +++ b/worker_config.example.json @@ -1,5 +1,5 @@ { - "_comment": "复制为 worker_config.json(不入 git)。accept_passwords:worker 内网鉴权密码列表,网关带 X-Internal-Token: <其中之一>(也可用环境变量 WORKER_ACCEPT_PASSWORDS 覆盖)。ark_api_key:接口4 火山方舟豆包视觉模型的 API Key(也可用环境变量 ARK_API_KEY 覆盖)。", + "_comment": "复制为 worker_config.json(不入 git)。accept_passwords:worker 内网鉴权密码列表,网关带 X-Internal-Token: <其中之一>(也可用环境变量 WORKER_ACCEPT_PASSWORDS 覆盖)。comfyui_password:本机 ComfyUI(8188) Basic Auth 密码(user 默认 admin;也可放 password.txt 或环境变量 COMFYUI_PASSWORD)。注:接口4 火山方舟 ark_api_key 已迁到网关配置。", "accept_passwords": ["change-me-to-a-strong-secret"], - "ark_api_key": "your-volcengine-ark-api-key" + "comfyui_password": "your-comfyui-basic-auth-password" }