MacBook pro commited on
Commit
dc47447
·
1 Parent(s): 4c5554a

feat(pipeline): add performance stats method, improved CodeFormer import, debug logging

Browse files
Files changed (1) hide show
  1. swap_pipeline.py +51 -23
swap_pipeline.py CHANGED
@@ -63,6 +63,8 @@ class FaceSwapPipeline:
63
  self.codeformer = None
64
  self.codeformer_fidelity = float(os.getenv('MIRAGE_CODEFORMER_FIDELITY', '0.75'))
65
  self.codeformer_loaded = False
 
 
66
 
67
  def initialize(self):
68
  if self.initialized:
@@ -157,31 +159,40 @@ class FaceSwapPipeline:
157
  except Exception:
158
  logger.warning('Torch missing; cannot enable CodeFormer')
159
  return
160
- # Try import; if fails attempt auto-clone
161
- need_clone = False
 
162
  try:
163
- from codeformer.archs.codeformer_arch import CodeFormer # type: ignore
 
164
  except Exception:
165
- need_clone = True
166
- if need_clone and os.getenv('MIRAGE_CODEFORMER_AUTOCLONE', '1').lower() in ('1','true','yes','on'):
167
- # Clone into a writable path inside models (repo root may be read-only in some deploy envs)
168
- repo_dir = os.getenv('MIRAGE_CODEFORMER_REPO_DIR', os.path.join('models', '_codeformer_repo'))
169
- if self._ensure_repo_clone(repo_dir):
170
- import sys as _sys
171
- if repo_dir not in _sys.path:
172
- _sys.path.append(repo_dir)
173
- else:
174
- logger.warning('CodeFormer repo clone failed; enhancement disabled')
175
- return
176
  try:
177
- from codeformer.archs.codeformer_arch import CodeFormer # type: ignore
178
- except ModuleNotFoundError as e:
179
- # Likely missing dependencies such as facexlib / basicsr
180
- logger.warning(f"CodeFormer module import still failing after clone (dependency missing?): {e}")
181
- return
182
- except Exception as e: # still failing
183
- logger.warning(f"CodeFormer module import failed after clone attempt: {e}")
184
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  try:
186
  from basicsr.archs.rrdbnet_arch import RRDBNet # noqa: F401
187
  except Exception:
@@ -276,12 +287,20 @@ class FaceSwapPipeline:
276
  return pcm_bytes
277
 
278
  def process_frame(self, frame: np.ndarray) -> np.ndarray:
279
- if not self.initialized or self.swapper is None or self.app is None or self.source_face is None:
 
 
 
 
 
 
280
  return frame
281
  t0 = time.time()
282
  faces = self.app.get(frame)
283
  self._last_faces_cache = faces
284
  if not faces:
 
 
285
  self._record_latency(time.time() - t0)
286
  self._stats['swap_faces_last'] = 0
287
  return frame
@@ -298,6 +317,8 @@ class FaceSwapPipeline:
298
  count += 1
299
  except Exception as e:
300
  logger.debug(f"Swap failed for face: {e}")
 
 
301
  # CodeFormer stride / face-region logic
302
  apply_cf = (
303
  self.codeformer is not None and
@@ -364,6 +385,13 @@ class FaceSwapPipeline:
364
  pass
365
  return info
366
 
 
 
 
 
 
 
 
367
  # Backwards compatibility for earlier server expecting process_video_frame
368
  def process_video_frame(self, frame: np.ndarray, frame_idx: int | None = None) -> np.ndarray:
369
  return self.process_frame(frame)
 
63
  self.codeformer = None
64
  self.codeformer_fidelity = float(os.getenv('MIRAGE_CODEFORMER_FIDELITY', '0.75'))
65
  self.codeformer_loaded = False
66
+ # Debug verbosity for swap decisions
67
+ self.swap_debug = os.getenv('MIRAGE_SWAP_DEBUG', '0').lower() in ('1','true','yes','on')
68
 
69
  def initialize(self):
70
  if self.initialized:
 
159
  except Exception:
160
  logger.warning('Torch missing; cannot enable CodeFormer')
161
  return
162
+ # Direct import path used by upstream project (packaged when installed)
163
+ # Primary expected path: basicsr.archs.* (weights independent). Some forks use codeformer.archs
164
+ CodeFormer = None # type: ignore
165
  try:
166
+ from basicsr.archs.codeformer_arch import CodeFormer as _CF # type: ignore
167
+ CodeFormer = _CF # type: ignore
168
  except Exception:
 
 
 
 
 
 
 
 
 
 
 
169
  try:
170
+ from codeformer.archs.codeformer_arch import CodeFormer as _CF # type: ignore
171
+ CodeFormer = _CF # type: ignore
172
+ except Exception as e:
173
+ # Attempt repo clone only if autoclone enabled and both imports failed
174
+ if os.getenv('MIRAGE_CODEFORMER_AUTOCLONE', '1').lower() in ('1','true','yes','on'):
175
+ repo_dir = os.getenv('MIRAGE_CODEFORMER_REPO_DIR', os.path.join('models', '_codeformer_repo'))
176
+ if self._ensure_repo_clone(repo_dir):
177
+ import sys as _sys
178
+ if repo_dir not in _sys.path:
179
+ _sys.path.append(repo_dir)
180
+ try:
181
+ from basicsr.archs.codeformer_arch import CodeFormer as _CF2 # type: ignore
182
+ CodeFormer = _CF2 # type: ignore
183
+ except Exception:
184
+ try:
185
+ from codeformer.archs.codeformer_arch import CodeFormer as _CF3 # type: ignore
186
+ CodeFormer = _CF3 # type: ignore
187
+ except Exception as e2:
188
+ logger.warning(f"CodeFormer import failed after clone: {e2}")
189
+ return
190
+ else:
191
+ logger.warning(f"CodeFormer repo clone failed; enhancement disabled ({e})")
192
+ return
193
+ else:
194
+ logger.warning(f"CodeFormer import failed (no autoclone): {e}")
195
+ return
196
  try:
197
  from basicsr.archs.rrdbnet_arch import RRDBNet # noqa: F401
198
  except Exception:
 
287
  return pcm_bytes
288
 
289
  def process_frame(self, frame: np.ndarray) -> np.ndarray:
290
+ if not self.initialized or self.swapper is None or self.app is None:
291
+ if self.swap_debug:
292
+ logger.debug('process_frame: pipeline not fully initialized yet')
293
+ return frame
294
+ if self.source_face is None:
295
+ if self.swap_debug:
296
+ logger.debug('process_frame: no source_face set yet')
297
  return frame
298
  t0 = time.time()
299
  faces = self.app.get(frame)
300
  self._last_faces_cache = faces
301
  if not faces:
302
+ if self.swap_debug:
303
+ logger.debug('process_frame: no faces detected in incoming frame')
304
  self._record_latency(time.time() - t0)
305
  self._stats['swap_faces_last'] = 0
306
  return frame
 
317
  count += 1
318
  except Exception as e:
319
  logger.debug(f"Swap failed for face: {e}")
320
+ if self.swap_debug:
321
+ logger.debug(f'process_frame: detected={len(faces)} swapped={count} stride={self.codeformer_frame_stride} apply_cf={count>0 and (self._frame_index % self.codeformer_frame_stride == 0)}')
322
  # CodeFormer stride / face-region logic
323
  apply_cf = (
324
  self.codeformer is not None and
 
385
  pass
386
  return info
387
 
388
+ # Legacy interface used by webrtc_server data channel
389
+ def get_performance_stats(self) -> Dict[str, Any]: # pragma: no cover simple delegate
390
+ stats = self.get_stats()
391
+ # Provide alias field names expected historically (if any)
392
+ stats['frames_processed'] = stats.get('frames')
393
+ return stats
394
+
395
  # Backwards compatibility for earlier server expecting process_video_frame
396
  def process_video_frame(self, frame: np.ndarray, frame_idx: int | None = None) -> np.ndarray:
397
  return self.process_frame(frame)