umer1995 commited on
Commit
ed3c935
·
verified ·
1 Parent(s): 2229af1

Deploy NFA Track R FLUX.2 Fun CN ZeroGPU (real depth CN)

Browse files
Files changed (2) hide show
  1. README.md +1 -0
  2. app.py +44 -19
README.md CHANGED
@@ -24,6 +24,7 @@ Soft Flux2 `image=depth` is **banned forever** on this path.
24
  | Base | `black-forest-labs/FLUX.2-dev` |
25
  | GPU | `@spaces.GPU(duration=300, size="large")` = **48GB** @ **1×** Pro minutes |
26
  | Memory mode | VideoX-Fun **`model_cpu_offload_and_qfloat8`** (official low-VRAM Fun CN path) |
 
27
  | Escalation | If OOM → redeploy with `size="xlarge"` + `model_cpu_offload` (2× quota) |
28
 
29
  Requires Space secret **`HF_TOKEN`** (gated FLUX.2-dev license accepted on the account).
 
24
  | Base | `black-forest-labs/FLUX.2-dev` |
25
  | GPU | `@spaces.GPU(duration=300, size="large")` = **48GB** @ **1×** Pro minutes |
26
  | Memory mode | VideoX-Fun **`model_cpu_offload_and_qfloat8`** (official low-VRAM Fun CN path) |
27
+ | Weights | **HF Mount volumes** (not ephemeral download): `/data/FLUX.2-dev` + `/data/Fun-CN` |
28
  | Escalation | If OOM → redeploy with `size="xlarge"` + `model_cpu_offload` (2× quota) |
29
 
30
  Requires Space secret **`HF_TOKEN`** (gated FLUX.2-dev license accepted on the account).
app.py CHANGED
@@ -59,11 +59,15 @@ MEM_MODE = (
59
 
60
  APP_DIR = Path(__file__).resolve().parent
61
  CONFIG_PATH = APP_DIR / "config" / "flux2_control.yaml"
 
 
 
 
 
62
  CACHE_ROOT = Path(
63
  os.environ.get("NFA_FUN_CN_CACHE")
64
  or (Path.home() / ".cache" / "nfa_fun_cn")
65
  )
66
- MODEL_DIR = CACHE_ROOT / "FLUX.2-dev"
67
 
68
  _PIPE = None
69
  _CN_FILE_PATH: Path | None = None
@@ -74,46 +78,67 @@ def _resolve_cn_path() -> Path:
74
  global _CN_FILE_PATH
75
  if _CN_FILE_PATH is not None and _CN_FILE_PATH.is_file():
76
  return _CN_FILE_PATH
77
- direct = CACHE_ROOT / CN_FILE
78
- if direct.is_file():
79
- _CN_FILE_PATH = direct
80
- return direct
81
- nested = list(CACHE_ROOT.rglob(CN_FILE))
82
- if nested:
83
- _CN_FILE_PATH = nested[0]
84
- return nested[0]
85
- raise FileNotFoundError(f"Fun CN weights missing: {CN_FILE}")
 
 
 
 
 
 
86
 
87
 
88
  def _ensure_weights() -> None:
89
- """Download on CPU (must run outside @spaces.GPU so quota is not burned)."""
90
- global _WEIGHTS_READY, _CN_FILE_PATH
91
- if _WEIGHTS_READY and MODEL_DIR.is_dir():
92
  try:
93
  _resolve_cn_path()
 
 
94
  return
95
  except FileNotFoundError:
96
  pass
 
 
 
 
 
 
 
 
97
  CACHE_ROOT.mkdir(parents=True, exist_ok=True)
98
  token = HF_TOKEN or None
99
- print(f"[nfa-fun-cn] snapshot {BASE_MODEL} -> {MODEL_DIR}", flush=True)
100
  snapshot_download(
101
  repo_id=BASE_MODEL,
102
- local_dir=str(MODEL_DIR),
103
- local_dir_use_symlinks=False,
104
  token=token,
 
 
 
 
 
 
 
 
105
  )
106
- print(f"[nfa-fun-cn] download {CN_REPO}/{CN_FILE}", flush=True)
107
  path = hf_hub_download(
108
  repo_id=CN_REPO,
109
  filename=CN_FILE,
110
  local_dir=str(CACHE_ROOT),
111
- local_dir_use_symlinks=False,
112
  token=token,
113
  )
 
114
  _CN_FILE_PATH = Path(path)
115
  _WEIGHTS_READY = True
116
- print(f"[nfa-fun-cn] weights ready cn={_CN_FILE_PATH}", flush=True)
117
 
118
 
119
  def _prep_depth(depth_image: Image.Image, width: int, height: int) -> Image.Image:
 
59
 
60
  APP_DIR = Path(__file__).resolve().parent
61
  CONFIG_PATH = APP_DIR / "config" / "flux2_control.yaml"
62
+ # Prefer HF Mount volumes (no 178GB ephemeral download). Fallback: cache download.
63
+ MODEL_DIR = Path(
64
+ os.environ.get("NFA_FLUX2_MOUNT") or "/data/FLUX.2-dev"
65
+ )
66
+ CN_MOUNT_DIR = Path(os.environ.get("NFA_FUN_CN_MOUNT") or "/data/Fun-CN")
67
  CACHE_ROOT = Path(
68
  os.environ.get("NFA_FUN_CN_CACHE")
69
  or (Path.home() / ".cache" / "nfa_fun_cn")
70
  )
 
71
 
72
  _PIPE = None
73
  _CN_FILE_PATH: Path | None = None
 
78
  global _CN_FILE_PATH
79
  if _CN_FILE_PATH is not None and _CN_FILE_PATH.is_file():
80
  return _CN_FILE_PATH
81
+ candidates = [
82
+ CN_MOUNT_DIR / CN_FILE,
83
+ CACHE_ROOT / CN_FILE,
84
+ ]
85
+ candidates.extend(CN_MOUNT_DIR.rglob(CN_FILE) if CN_MOUNT_DIR.is_dir() else [])
86
+ candidates.extend(CACHE_ROOT.rglob(CN_FILE) if CACHE_ROOT.is_dir() else [])
87
+ for c in candidates:
88
+ if c.is_file():
89
+ _CN_FILE_PATH = c
90
+ return c
91
+ raise FileNotFoundError(
92
+ f"Fun CN weights missing: {CN_FILE}. "
93
+ "Mount alibaba-pai/FLUX.2-dev-Fun-Controlnet-Union at /data/Fun-CN "
94
+ "or download into cache."
95
+ )
96
 
97
 
98
  def _ensure_weights() -> None:
99
+ """Resolve mounted Hub volumes, or (last resort) selective download."""
100
+ global _WEIGHTS_READY, MODEL_DIR
101
+ if MODEL_DIR.is_dir() and (MODEL_DIR / "model_index.json").is_file():
102
  try:
103
  _resolve_cn_path()
104
+ _WEIGHTS_READY = True
105
+ print(f"[nfa-fun-cn] using mounts model={MODEL_DIR} cn={_CN_FILE_PATH}", flush=True)
106
  return
107
  except FileNotFoundError:
108
  pass
109
+
110
+ # Fallback: selective download (may OOM disk on ZeroGPU — mounts preferred)
111
+ print(
112
+ "[nfa-fun-cn] WARN mounts missing; selective download fallback "
113
+ "(transformer+vae+tokenizer+text_encoder+scheduler only)",
114
+ flush=True,
115
+ )
116
+ cache_model = CACHE_ROOT / "FLUX.2-dev"
117
  CACHE_ROOT.mkdir(parents=True, exist_ok=True)
118
  token = HF_TOKEN or None
 
119
  snapshot_download(
120
  repo_id=BASE_MODEL,
121
+ local_dir=str(cache_model),
 
122
  token=token,
123
+ allow_patterns=[
124
+ "model_index.json",
125
+ "transformer/*",
126
+ "vae/*",
127
+ "tokenizer/*",
128
+ "text_encoder/*",
129
+ "scheduler/*",
130
+ ],
131
  )
 
132
  path = hf_hub_download(
133
  repo_id=CN_REPO,
134
  filename=CN_FILE,
135
  local_dir=str(CACHE_ROOT),
 
136
  token=token,
137
  )
138
+ MODEL_DIR = cache_model
139
  _CN_FILE_PATH = Path(path)
140
  _WEIGHTS_READY = True
141
+ print(f"[nfa-fun-cn] weights ready model={MODEL_DIR} cn={_CN_FILE_PATH}", flush=True)
142
 
143
 
144
  def _prep_depth(depth_image: Image.Image, width: int, height: int) -> Image.Image: