diff --git a/DEPLOY.md b/DEPLOY.md index ded1444..0f1be84 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -202,6 +202,7 @@ redirect back to `huggingface.co`, which recent `huggingface_hub` rejects with | `BGFILTER_MAX_IMAGE_PIXELS` | `4194304` | Reject larger inputs with `413` (~4 MP) | | `BGFILTER_PRELOAD` | `1` | Load default models at startup (first request isn't cold) | | `BGFILTER_CROSS_CHECK` | config (`on`) | Force the cross-check veto on/off (`0` disables; needs `BiRefNet_HR-matting`) | +| `BGFILTER_AUTH_TOKEN` | — | If set, `/remove-background` requires header `X-Genarrative-Image-Token` to equal it (constant-time; `401` otherwise). Unset = **open** (auth left to a fronting proxy). `/healthz` stays open. See §10. | | `BGFILTER_WEIGHTS_DIR` | `models` | Where local weight folders are looked up (Option B) | | `HF_HOME` | — | HF cache location (Option A) | | `HF_HUB_OFFLINE` / `TRANSFORMERS_OFFLINE` | — | Set to `1` in production once weights are cached | @@ -233,6 +234,12 @@ Two model knobs live in the **config file** (`model:` section), not env vars: | `model.precision` | `fp32` | `fp32` or `bf16`. bf16 is used **only** on hardware with native kernels (CUDA, or a CPU with AVX512-BF16/AMX); otherwise it warns and falls back to fp32. Also settable per model under `segmentation:` / `cross_check:`. | | `model.attn_query_chunk` | `2048` | Query-row chunk for ViTMatte's global attention. Smaller (e.g. `512`) caps the O(N²) memory transient for a few % more compute; output is bit-for-bit identical. `0` disables chunking (stock one-shot attention). | +> **Despill is off by default** (all lanes, cpu-fast included). It pulls foreground +> chroma along the background-hue axis with no positional/semantic guard, so a subject +> sharing the background's hue (e.g. a blue suit on a blue backdrop) gets desaturated / +> hue-shifted (~ΔE 35). Re-enable per-config with `despill: {enabled: true}` only when +> edge-spill removal matters more than same-hue fidelity. + ## 7. Run the service ```bash @@ -308,13 +315,34 @@ curl -sS -F "file=@input.png" -F "screen_color=#CFEFFF" \ ## 10. Exposing the service The unit binds `127.0.0.1` — intended to be called by a co-located client (e.g. the -Genarrative Rust BFF via `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL`). The -service has **no authentication**. To reach it from other hosts: +Genarrative Rust BFF via `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL`). To reach +it from other hosts: - **Reverse proxy (recommended):** put nginx/caddy in front, terminate TLS, add - auth/rate-limiting, and forward to `127.0.0.1:18083`. + rate-limiting, and forward to `127.0.0.1:18083`. - **Direct:** change `--host` to `0.0.0.0` and restrict source IPs with a firewall. - Do not expose it unauthenticated to the public internet. + Do not expose it to the public internet without authentication (below). + +### Authentication + +App-level token auth is **opt-in** via `BGFILTER_AUTH_TOKEN`: + +- **Set it** → `/remove-background` requires header `X-Genarrative-Image-Token: ` + (constant-time compare); missing or wrong returns `401`. `/healthz` stays open. Use + this whenever the app is reachable directly — `--host 0.0.0.0`, or a cloud port + mapping with no proxy in front. +- **Leave it unset** → the app is **open** (fail-open) and logs a startup WARNING. + Correct only when a fronting proxy already authenticates — e.g. the production nginx + checks `X-Genarrative-Image-Token` itself, so the app behind it needs no token. + +The header name matches the nginx layer, so a caller only swaps the base URL + token +value — no request-shape change: + +```bash +curl -H "X-Genarrative-Image-Token: " \ + -F "file=@input.png" \ + https:///remove-background -o out.png +``` ## 11. Capacity & performance diff --git a/DEPLOY_ZH.md b/DEPLOY_ZH.md index 2789a66..ff6e20e 100644 --- a/DEPLOY_ZH.md +++ b/DEPLOY_ZH.md @@ -188,6 +188,7 @@ export HF_HUB_DISABLE_XET=1 # 这些 repo 是 Xet 存储;强 | `BGFILTER_MAX_IMAGE_PIXELS` | `4194304` | 超过则返回 `413`(约 4 MP)| | `BGFILTER_PRELOAD` | `1` | 启动时预加载默认模型(首个请求不用冷加载)| | `BGFILTER_CROSS_CHECK` | 配置(`on`)| 强制开/关 cross-check 否决(`0` 关闭;需 `BiRefNet_HR-matting`)| +| `BGFILTER_AUTH_TOKEN` | — | 若设置,`/remove-background` 要求 header `X-Genarrative-Image-Token` 等于它(常量时间比较;否则 `401`)。不设 = **开放**(鉴权交给前置代理)。`/healthz` 始终开放。见 §10。 | | `BGFILTER_WEIGHTS_DIR` | `models` | 本地权重文件夹的查找目录(方案 B)| | `HF_HOME` | — | HF 缓存位置(方案 A)| | `HF_HUB_OFFLINE` / `TRANSFORMERS_OFFLINE` | — | 权重缓存好后,生产设为 `1` | @@ -216,6 +217,8 @@ export HF_HUB_DISABLE_XET=1 # 这些 repo 是 Xet 存储;强 | `model.precision` | `fp32` | `fp32` 或 `bf16`。bf16 **仅**在有原生内核的硬件上启用(CUDA,或带 AVX512-BF16/AMX 的 CPU);否则告警并回退 fp32。也可在 `segmentation:` / `cross_check:` 下按模型单独设。 | | `model.attn_query_chunk` | `2048` | ViTMatte 全局注意力的 query 行分块。调小(如 `512`)以几个百分点的额外算力换掉 O(N²) 内存瞬时尖峰;输出逐比特相同。设 `0` 关闭分块(走原始一次性注意力)。 | +> **despill 默认关闭**(所有 lane,含 cpu-fast)。它沿背景色调方向压前景色度,没有位置/语义护栏,所以主体与背景**同色相**时(如蓝背景前的蓝西装)会被褪色/偏色(约 ΔE 35)。仅当"去边缘溢色"比"同色系保真"更重要时,才在配置里 `despill: {enabled: true}` 单独开启。 + ## 7. 运行服务 ```bash @@ -288,13 +291,31 @@ curl -sS -F "file=@input.png" -F "screen_color=#CFEFFF" \ ## 10. 对外暴露 单元里绑的是 `127.0.0.1`——面向同机调用方(例如 Genarrative Rust BFF,通过 -`GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL` 调用)。服务本身**没有鉴权**。 -要从其它主机访问: +`GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL` 调用)。要从其它主机访问: -- **反向代理(推荐):** 前面放 nginx/caddy,终止 TLS、加鉴权/限流,转发到 +- **反向代理(推荐):** 前面放 nginx/caddy,终止 TLS、加限流,转发到 `127.0.0.1:18083`。 - **直接暴露:** 把 `--host` 改成 `0.0.0.0`,并用防火墙限制来源 IP。 - 切勿把无鉴权的服务裸暴露到公网。 + 切勿把无鉴权的服务裸暴露到公网(见下方鉴权)。 + +### 鉴权 + +app 层 token 鉴权是**可选开启**,由 `BGFILTER_AUTH_TOKEN` 控制: + +- **设置它** → `/remove-background` 要求 header `X-Genarrative-Image-Token: ` + (常量时间比较);缺失或错误返回 `401`。`/healthz` 保持开放。**当 app 被直接暴露** + (`--host 0.0.0.0`、或云端端口映射无代理)时用这个。 +- **不设置** → app **开放**(fail-open),并在启动时打一条 WARNING。仅当前置代理 + 已经鉴权时才可这样——例如生产机 nginx 自己校验 `X-Genarrative-Image-Token`, + 其后的 app 就无需 token。 + +header 名和 nginx 层一致,所以调用方只换 base URL + token 值,请求结构不变: + +```bash +curl -H "X-Genarrative-Image-Token: " \ + -F "file=@input.png" \ + https:///remove-background -o out.png +``` ## 11. 容量与性能