fix: offline CodeFormer face-enhance (ship RealESRGAN_x2plus in upscale-enhance bundle) (#433)

* fix: ship RealESRGAN_x2plus.pth in the upscale-enhance bundle for offline CodeFormer

codeformer-pip 0.0.4 downloads RealESRGAN_x2plus.pth at import of
codeformer.app, unconditionally, even though enhance_faces calls
inference_app with background_enhance=False and never uses the background
upsampler. The weight was not bundled, so explicit CodeFormer face-enhance
(enhance-faces model=codeformer) failed in strict offline mode
(SNAPOTTER_ALLOW_MODEL_DOWNLOAD=0) on a host that had never cached it -- the
guard raised before the import could complete.

Add RealESRGAN_x2plus.pth to the upscale-enhance bundle manifest (only that
bundle uses codeformer-pip; photo-restoration uses the CodeFormer ONNX path)
and link it in prepare_codeformer_weights alongside the other three weights,
replacing the download-or-error guard. Once the bundle ships it, the import
resolves offline and strict mode works.

Archive SHA256s updated in a follow-up once the bundle is rebuilt.

Claude-Session: https://claude.ai/code/session_01XGB4pGvTvb7sUX4JN745U7

* fix: require face-detection bundle for enhance-faces + point manifest at the x2plus archives

enhance-faces runs MediaPipe face detection (blaze_face_short_range.tflite)
before CodeFormer/GFPGAN. That model ships in the face-detection bundle, not
the tool's primary upscale-enhance bundle, so a standalone upscale-enhance
install failed face detection (offline: hard error; online: a surprise
download) before reaching the codeformer path. Declare the dependency in
TOOL_EXTRA_BUNDLES like passport-photo does.

Update the upscale-enhance archive SHA256/sizes to the rebuilt bundles that
include RealESRGAN_x2plus.pth (amd64-gpu + arm64-cpu), verified to install and
run enhance-faces model=codeformer in strict offline mode with zero downloads.

Claude-Session: https://claude.ai/code/session_01XGB4pGvTvb7sUX4JN745U7
This commit is contained in:
SnapOtter
2026-07-04 16:30:08 +00:00
committed by GitHub
parent dadf766899
commit cf884b52cd
3 changed files with 25 additions and 15 deletions
+12 -6
View File
@@ -194,15 +194,15 @@
"archives": {
"amd64-gpu": {
"file": "v2.0.0/upscale-enhance-amd64-gpu.tar.gz",
"sha256": "37f0e7a62dcb83b2dc0760532fb41ac9d1c40d336abe1aea01d889ad039ebc65",
"compressedSize": 5314188723,
"extractedSize": 8412712960
"sha256": "089fdecbcd36090013ed4adf3a96650c757ce06871c2e1f1b155ccdd8487e413",
"compressedSize": 5376987856,
"extractedSize": 8455327174
},
"arm64-cpu": {
"file": "v2.0.0/upscale-enhance-arm64-cpu.tar.gz",
"sha256": "de65321f1cc5d5664c63e38e49cd39c36fe88e0569d666821e982ff6d6999bea",
"compressedSize": 2262502457,
"extractedSize": 0
"sha256": "b9e948c8308371ccb3defce4323a85884e46d5bde52791115d34d1c1f92e4f23",
"compressedSize": 2335658971,
"extractedSize": 3661453942
}
},
"packages": {
@@ -234,6 +234,12 @@
"path": "realesrgan/RealESRGAN_x4plus.pth",
"minSize": 60000000
},
{
"id": "realesrgan-x2plus",
"url": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth",
"path": "realesrgan/RealESRGAN_x2plus.pth",
"minSize": 60000000
},
{
"id": "gfpgan-v1.3",
"url": "https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth",
+8 -9
View File
@@ -82,11 +82,11 @@ def prepare_codeformer_weights(models_base):
"""Resolve codeformer-pip's cwd-relative weights offline.
codeformer-pip 0.0.4 downloads four weights into a cwd-relative
CodeFormer/weights/ tree at import time of codeformer.app. Three of them
ship in the feature bundles and are linked here so they never re-download;
RealESRGAN_x2plus.pth (a background-upscale helper this app never invokes)
is not bundled, so it downloads once on first use unless strict offline
mode blocks it.
CodeFormer/weights/ tree at import time of codeformer.app -- unconditionally,
even though this app calls inference_app with background_enhance=False and so
never uses the RealESRGAN background upsampler (RealESRGAN_x2plus.pth). All
four ship in the upscale-enhance bundle and are linked here from models_base
so the import never triggers a download; strict offline mode then works.
"""
expected = {
os.path.join("CodeFormer", "weights", "CodeFormer", "codeformer.pth"): os.path.join(
@@ -98,11 +98,10 @@ def prepare_codeformer_weights(models_base):
os.path.join("CodeFormer", "weights", "facelib", "parsing_parsenet.pth"): os.path.join(
models_base, "gfpgan", "facelib", "parsing_parsenet.pth"
),
os.path.join("CodeFormer", "weights", "realesrgan", "RealESRGAN_x2plus.pth"): os.path.join(
models_base, "realesrgan", "RealESRGAN_x2plus.pth"
),
}
for link, target in expected.items():
if not link_bundled_weight(link, target):
ensure_download_allowed(f"CodeFormer weight {os.path.basename(link)}")
x2plus = os.path.join("CodeFormer", "weights", "realesrgan", "RealESRGAN_x2plus.pth")
if not os.path.exists(x2plus):
ensure_download_allowed("CodeFormer helper weight RealESRGAN_x2plus.pth")
+5
View File
@@ -112,6 +112,11 @@ export function getToolsForBundle(bundleId: string): string[] {
*/
export const TOOL_EXTRA_BUNDLES: Record<string, string[]> = {
"passport-photo": ["face-detection"],
// enhance-faces runs MediaPipe face detection (blaze_face) before CodeFormer/
// GFPGAN; that model ships in face-detection, not its primary upscale-enhance
// bundle, so require both or it fails on a standalone install (offline: hard
// error; online: a surprise download).
"enhance-faces": ["face-detection"],
};
/**