andevs commited on
Commit
e1d76c0
·
verified ·
1 Parent(s): 732bb81

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -48
app.py CHANGED
@@ -148,9 +148,6 @@ def get_container_memory() -> Dict:
148
  }
149
 
150
 
151
- # ============================================================
152
- # CORE CLASSES
153
- # ============================================================
154
  class ResolutionManager:
155
  RECOMMENDED = {
156
  "simple_graphic": 600,
@@ -354,7 +351,7 @@ class HairRefiner:
354
 
355
 
356
  class GraphicProcessor:
357
- def __init__(self):
358
  self.tolerance = 25
359
 
360
  def remove_background(self, image):
@@ -528,15 +525,12 @@ class ContentClassifier:
528
 
529
 
530
  # ============================================================
531
- # COMPREHENSIVE ARCHITECTURE HOOKS (ALL MODELS PRESERVED)
532
  # ============================================================
533
-
534
- # Core active model: loads at boot to safeguard shared RAM tier limits
535
  PRELOAD_MODELS = [
536
- ("silueta", "Baseline Video Engine"),
537
  ]
538
 
539
- # Dormant/Lazy pool: Preserved and ready for activation without rewrite
540
  DORMANT_POOL = {
541
  "u2net": "~176 MB disk / ~800 MB RAM",
542
  "u2net_human_seg": "~176 MB disk / ~800 MB RAM",
@@ -614,18 +608,25 @@ VIDEO_FORCE_MODEL = "silueta"
614
  DISPLAY_NAMES = {
615
  "flood_fill": "Flood Fill Engine",
616
  "graphic_classical": "Flood Fill Engine",
617
- "u2netp": "U2-Net Portable",
618
  "u2net": "U2-Net Standard",
619
  "u2net_human_seg": "U2-Net Human Segmentation",
620
  "u2net_cloth_seg": "U2-Net Cloth Engine",
621
  "silueta": "Silueta Video Engine",
622
  "isnet-general-use": "ISNet Premium Router",
623
  "isnet-anime": "ISNet Anime",
624
- "birefnet-general": "BiRefNet Full HD Studio",
625
  "birefnet-general-lite": "BiRefNet Lite Engine",
626
  "sam": "Segment Anything Model",
627
  }
628
 
 
 
 
 
 
 
 
629
  content_classifier = ContentClassifier()
630
  resolution_manager = ResolutionManager()
631
  model_manager = ModelManager(max_models=1, memory_limit_mb=3500)
@@ -640,12 +641,12 @@ def _load_session(name: str):
640
  resolved = MODEL_ALIASES.get(name, name)
641
  if resolved not in VALID_REMBG_MODELS:
642
  resolved = "silueta"
643
- logger.info(f"Loading dynamic execution weights context for: {resolved}")
644
  return new_session(resolved)
645
 
646
 
647
  # ============================================================
648
- # TEMPORAL ALPHA SMOOTHING
649
  # ============================================================
650
  ALPHA_SMOOTH_WEIGHT = 0.35
651
  ALPHA_CACHE_MAX_SESSIONS = 1
@@ -713,11 +714,11 @@ def _alpha_cache_stats() -> Dict:
713
 
714
 
715
  _video_semaphore = threading.Semaphore(1)
716
- VIDEO_RAM_REJECT_PERCENT = 85.0 # Restored — referenced by process_frames_batch
717
 
718
 
719
  # ============================================================
720
- # ALPHA & PASSTHROUGH UTILITIES
721
  # ============================================================
722
  def _alpha_stats(image):
723
  try:
@@ -768,7 +769,7 @@ def _has_meaningful_alpha(image):
768
 
769
 
770
  # ============================================================
771
- # NEURAL EXECUTION PIPELINE
772
  # ============================================================
773
  def process_with_neural(image, session, model_name):
774
  attempts = [
@@ -780,7 +781,6 @@ def process_with_neural(image, session, model_name):
780
  img_for_inference = image
781
  w, h = image.size
782
 
783
- # Bound input shapes before tensor calculation
784
  target_dim = MODEL_RES_CAPS.get(model_name, 512)
785
  if max(w, h) > target_dim:
786
  img_for_inference = image.copy()
@@ -806,22 +806,22 @@ def process_with_neural(image, session, model_name):
806
 
807
 
808
  # ============================================================
809
- # THE SMART ROUTER
810
  # ============================================================
811
  def analyze_image_complexity(image):
812
  try:
813
  cc = content_classifier.classify(image)
814
  cat = cc.get("category", "general_photo")
815
 
816
- # 🌟 ROUTER ALLOCATION: Maps your core engines dynamically
817
  if cat in ("simple_graphic", "logo_icon"):
818
- selected_model = "u2netp" # 4.7MB model steps up for clean vector layers
819
  elif cat == "product_white_bg":
820
- selected_model = "birefnet-general-lite" # 12MB model steps up for clean e-commerce items
821
  elif cat in ("human", "human_hair", "anime"):
822
- selected_model = "isnet-general-use" # High-precision model steps up for humans/complex edges
823
  else:
824
- selected_model = "birefnet-general-lite" # General purpose standard fallback
825
 
826
  return {
827
  "processor": selected_model,
@@ -842,19 +842,19 @@ def analyze_image_complexity(image):
842
 
843
 
844
  # ============================================================
845
- # INITIALIZATION LIFE-CYCLE BOOT
846
  # ============================================================
847
  AI_AVAILABLE = False
848
  remove_func = None
849
 
850
 
851
  def pre_download_models():
852
- logger.info("Initializing baseline workspace parameters...")
853
  for name, _ in PRELOAD_MODELS:
854
  try:
855
  model_manager.get_model(name, _load_session)
856
  except Exception as e:
857
- logger.warning(f"Bypassed core startup preload flag: {e}")
858
 
859
 
860
  def initialize_models():
@@ -865,7 +865,7 @@ def initialize_models():
865
  remove_func = remove
866
  AI_AVAILABLE = True
867
  except Exception as e:
868
- logger.error(f"Failed to bind global abstraction endpoint: {e}")
869
  AI_AVAILABLE = False
870
 
871
 
@@ -874,7 +874,7 @@ initialize_models()
874
 
875
 
876
  # ============================================================
877
- # IMAGE ENGINE PIPELINE
878
  # ============================================================
879
  def process_image_sync(image_data, model_name=None, transparent=True, max_size=512, quality=95):
880
  try:
@@ -895,10 +895,9 @@ def process_image_sync(image_data, model_name=None, transparent=True, max_size=5
895
  "media_type": "image/png" if transparent else "image/jpeg",
896
  }
897
 
898
- # Process manual parameter overrides or execute the smart router framework
899
  if model_name and MODEL_ALIASES.get(model_name, model_name) in VALID_REMBG_MODELS:
900
  selected = MODEL_ALIASES.get(model_name, model_name)
901
- reason = "Explicit URL override parameter request"
902
  category = "forced"
903
  else:
904
  routing_decision = analyze_image_complexity(image)
@@ -907,8 +906,8 @@ def process_image_sync(image_data, model_name=None, transparent=True, max_size=5
907
  category = routing_decision["category"]
908
 
909
  logger.info(
910
- f"Fulfilling route request -> Model: {selected} | "
911
- f"Category: {category} | Specs: {reason}"
912
  )
913
 
914
  if max(image.size) > max_size:
@@ -919,10 +918,10 @@ def process_image_sync(image_data, model_name=None, transparent=True, max_size=5
919
  if cand_session is not None:
920
  result, _ = process_with_neural(image, cand_session, selected)
921
 
922
- # Fallback security lane to ensure the service never goes down
923
  if result is None and selected != "silueta":
924
  logger.warning(
925
- "Target engine cache error. Transitioning to baseline fallback layer."
926
  )
927
  fallback_session = model_manager.get_model("silueta", _load_session)
928
  result, _ = process_with_neural(image, fallback_session, "silueta")
@@ -959,7 +958,7 @@ def process_image_sync(image_data, model_name=None, transparent=True, max_size=5
959
 
960
 
961
  # ============================================================
962
- # VIDEO FRAME PIPELINE
963
  # ============================================================
964
  def _process_frames_sync(
965
  raw_frames, resolved_model, transparent, session_id: Optional[str] = None, smooth: bool = True
@@ -971,7 +970,7 @@ def _process_frames_sync(
971
  try:
972
  if not content:
973
  results.append(
974
- {"data": "", "format": "png", "error": "empty matrix packet"}
975
  )
976
  continue
977
 
@@ -982,14 +981,14 @@ def _process_frames_sync(
982
  cand_session = model_manager.get_model(resolved_model, _load_session)
983
  if cand_session is None:
984
  results.append(
985
- {"data": "", "format": "png", "error": "cache missing runtime validation"}
986
  )
987
  continue
988
 
989
  res, _ = process_with_neural(img, cand_session, resolved_model)
990
  if res is None:
991
  results.append(
992
- {"data": "", "format": "png", "error": "inference pipeline mismatch error"}
993
  )
994
  continue
995
 
@@ -1023,7 +1022,7 @@ def _process_frames_sync(
1023
  # ============================================================
1024
  # FASTAPI CONTROLLER
1025
  # ============================================================
1026
- app = FastAPI(title="Background Remover API", version="32.2.6")
1027
  app.add_middleware(
1028
  CORSMiddleware,
1029
  allow_origins=["*"],
@@ -1053,7 +1052,7 @@ async def rate_limit_middleware(request, call_next):
1053
  if len(rate_limits[cid]) >= 45:
1054
  return JSONResponse(
1055
  status_code=429,
1056
- content={"error": "Too many matching concurrency streams mapped."},
1057
  )
1058
  rate_limits[cid].append(now)
1059
  return await call_next(request)
@@ -1064,13 +1063,17 @@ async def process_image_api(
1064
  file: UploadFile = File(...),
1065
  model: str = Query(None),
1066
  transparent: bool = Query(True),
1067
- max_size: int = Query(512, ge=256, le=2048),
1068
  quality: int = Query(95, ge=70, le=100),
 
 
 
 
1069
  ):
1070
  try:
1071
  contents = await file.read()
1072
  if not contents:
1073
- raise HTTPException(400, "Empty multipart stream payload.")
1074
 
1075
  loop = asyncio.get_event_loop()
1076
  pf = functools.partial(
@@ -1099,7 +1102,7 @@ async def process_image_api(
1099
  raise
1100
  except Exception as e:
1101
  raise HTTPException(
1102
- 500, f"Critical architecture fault event thread dropped: {str(e)}"
1103
  )
1104
 
1105
 
@@ -1112,14 +1115,14 @@ async def process_frames_batch(
1112
  smooth: bool = Query(True),
1113
  ):
1114
  if len(files) > 4:
1115
- raise HTTPException(400, "Max multi-frame batch depth capacity reached.")
1116
 
1117
  mem = get_container_memory()
1118
  if mem["percent"] > VIDEO_RAM_REJECT_PERCENT:
1119
  return JSONResponse(
1120
  status_code=503,
1121
  content={
1122
- "error": "Space memory allocation boundary alert.",
1123
  "retry_in": 4,
1124
  },
1125
  )
@@ -1188,9 +1191,9 @@ async def home():
1188
  <body>
1189
  <div class="box">
1190
  <h1>Background Remover Pro v32.2.6</h1>
1191
- <p>Container RAM: {mem['percent']:.1f}% ({mem['used_mb']}/{mem['total_mb']}MB)</p>
1192
- <p>Active Model Slot: {stats['loaded_models']}</p>
1193
- <p><a href="/docs">Swagger API Docs</a></p>
1194
  </div>
1195
  </body>
1196
  </html>
 
148
  }
149
 
150
 
 
 
 
151
  class ResolutionManager:
152
  RECOMMENDED = {
153
  "simple_graphic": 600,
 
351
 
352
 
353
  class GraphicProcessor:
354
+ def init(self):
355
  self.tolerance = 25
356
 
357
  def remove_background(self, image):
 
525
 
526
 
527
  # ============================================================
528
+ # COMPREHENSIVE HARDENED CONFIGURATION BOUNDARIES
529
  # ============================================================
 
 
530
  PRELOAD_MODELS = [
531
+ ("silueta", "Baseline Video Processing Context Guard")
532
  ]
533
 
 
534
  DORMANT_POOL = {
535
  "u2net": "~176 MB disk / ~800 MB RAM",
536
  "u2net_human_seg": "~176 MB disk / ~800 MB RAM",
 
608
  DISPLAY_NAMES = {
609
  "flood_fill": "Flood Fill Engine",
610
  "graphic_classical": "Flood Fill Engine",
611
+ "u2netp": "U2-Net Portable (Lightweight)",
612
  "u2net": "U2-Net Standard",
613
  "u2net_human_seg": "U2-Net Human Segmentation",
614
  "u2net_cloth_seg": "U2-Net Cloth Engine",
615
  "silueta": "Silueta Video Engine",
616
  "isnet-general-use": "ISNet Premium Router",
617
  "isnet-anime": "ISNet Anime",
618
+ "birefnet-general": "BiRefNet Studio Platform",
619
  "birefnet-general-lite": "BiRefNet Lite Engine",
620
  "sam": "Segment Anything Model",
621
  }
622
 
623
+
624
+ # ============================================================
625
+ # GLOBAL ISOLATED EXECUTION INITIALIZATION
626
+ # ============================================================
627
+
628
+ # Critical Variable Defs placed safely in scope bounds
629
+ cpu_executor = ThreadPoolExecutor(max_workers=1)
630
  content_classifier = ContentClassifier()
631
  resolution_manager = ResolutionManager()
632
  model_manager = ModelManager(max_models=1, memory_limit_mb=3500)
 
641
  resolved = MODEL_ALIASES.get(name, name)
642
  if resolved not in VALID_REMBG_MODELS:
643
  resolved = "silueta"
644
+ logger.info(f"Allocating execution layer weights path context for: {resolved}")
645
  return new_session(resolved)
646
 
647
 
648
  # ============================================================
649
+ # TEMPORAL ALPHA SMOOTHING FOR SEQUENCES
650
  # ============================================================
651
  ALPHA_SMOOTH_WEIGHT = 0.35
652
  ALPHA_CACHE_MAX_SESSIONS = 1
 
714
 
715
 
716
  _video_semaphore = threading.Semaphore(1)
717
+ VIDEO_RAM_REJECT_PERCENT = 85.0
718
 
719
 
720
  # ============================================================
721
+ # ALPHA LAYER HELPERS
722
  # ============================================================
723
  def _alpha_stats(image):
724
  try:
 
769
 
770
 
771
  # ============================================================
772
+ # NEURAL PROCESSING EXECUTION
773
  # ============================================================
774
  def process_with_neural(image, session, model_name):
775
  attempts = [
 
781
  img_for_inference = image
782
  w, h = image.size
783
 
 
784
  target_dim = MODEL_RES_CAPS.get(model_name, 512)
785
  if max(w, h) > target_dim:
786
  img_for_inference = image.copy()
 
806
 
807
 
808
  # ============================================================
809
+ # RE-ROUTED INTELLIGENT ROUTER SYSTEM
810
  # ============================================================
811
  def analyze_image_complexity(image):
812
  try:
813
  cc = content_classifier.classify(image)
814
  cat = cc.get("category", "general_photo")
815
 
816
+ # Deploy models dynamically aligned to strict lightweight tiers
817
  if cat in ("simple_graphic", "logo_icon"):
818
+ selected_model = "u2netp" # Enforce 4.7MB engine for crisp simple arrays
819
  elif cat == "product_white_bg":
820
+ selected_model = "birefnet-general-lite" # Enforce 12MB engine for products
821
  elif cat in ("human", "human_hair", "anime"):
822
+ selected_model = "isnet-general-use" # Enforce Inspyrenet for complex details
823
  else:
824
+ selected_model = "birefnet-general-lite" # Standard layout baseline assignment
825
 
826
  return {
827
  "processor": selected_model,
 
842
 
843
 
844
  # ============================================================
845
+ # CYCLE HOOKS
846
  # ============================================================
847
  AI_AVAILABLE = False
848
  remove_func = None
849
 
850
 
851
  def pre_download_models():
852
+ logger.info("Caching baseline container network configurations...")
853
  for name, _ in PRELOAD_MODELS:
854
  try:
855
  model_manager.get_model(name, _load_session)
856
  except Exception as e:
857
+ logger.warning(f"Bypassed boot pre-caching layer: {e}")
858
 
859
 
860
  def initialize_models():
 
865
  remove_func = remove
866
  AI_AVAILABLE = True
867
  except Exception as e:
868
+ logger.error(f"Failed to load engine layers framework: {e}")
869
  AI_AVAILABLE = False
870
 
871
 
 
874
 
875
 
876
  # ============================================================
877
+ # IMAGE ENGINE EXECUTION FLOW
878
  # ============================================================
879
  def process_image_sync(image_data, model_name=None, transparent=True, max_size=512, quality=95):
880
  try:
 
895
  "media_type": "image/png" if transparent else "image/jpeg",
896
  }
897
 
 
898
  if model_name and MODEL_ALIASES.get(model_name, model_name) in VALID_REMBG_MODELS:
899
  selected = MODEL_ALIASES.get(model_name, model_name)
900
+ reason = "Explicit URL parameter client override"
901
  category = "forced"
902
  else:
903
  routing_decision = analyze_image_complexity(image)
 
906
  category = routing_decision["category"]
907
 
908
  logger.info(
909
+ f"Fulfilling request route -> Model: {selected} | "
910
+ f"Category: {category} | Metadata: {reason}"
911
  )
912
 
913
  if max(image.size) > max_size:
 
918
  if cand_session is not None:
919
  result, _ = process_with_neural(image, cand_session, selected)
920
 
921
+ # Fallback security lane to guarantee uptime stability
922
  if result is None and selected != "silueta":
923
  logger.warning(
924
+ "Target session cache failed. Transitioning to baseline fallback layer."
925
  )
926
  fallback_session = model_manager.get_model("silueta", _load_session)
927
  result, _ = process_with_neural(image, fallback_session, "silueta")
 
958
 
959
 
960
  # ============================================================
961
+ # SEQUENTIAL VIDEO PIPELINE TASK
962
  # ============================================================
963
  def _process_frames_sync(
964
  raw_frames, resolved_model, transparent, session_id: Optional[str] = None, smooth: bool = True
 
970
  try:
971
  if not content:
972
  results.append(
973
+ {"data": "", "format": "png", "error": "empty token structure packet"}
974
  )
975
  continue
976
 
 
981
  cand_session = model_manager.get_model(resolved_model, _load_session)
982
  if cand_session is None:
983
  results.append(
984
+ {"data": "", "format": "png", "error": "cache missing runtime verification"}
985
  )
986
  continue
987
 
988
  res, _ = process_with_neural(img, cand_session, resolved_model)
989
  if res is None:
990
  results.append(
991
+ {"data": "", "format": "png", "error": "inference tensor matrix allocation drop"}
992
  )
993
  continue
994
 
 
1022
  # ============================================================
1023
  # FASTAPI CONTROLLER
1024
  # ============================================================
1025
+ app = FastAPI(title="Background Remover API Framework", version="32.2.6")
1026
  app.add_middleware(
1027
  CORSMiddleware,
1028
  allow_origins=["*"],
 
1052
  if len(rate_limits[cid]) >= 45:
1053
  return JSONResponse(
1054
  status_code=429,
1055
+ content={"error": "Too many matching concurrent transaction tracks active."},
1056
  )
1057
  rate_limits[cid].append(now)
1058
  return await call_next(request)
 
1063
  file: UploadFile = File(...),
1064
  model: str = Query(None),
1065
  transparent: bool = Query(True),
1066
+ max_size: int = Query(512, ge=256, le=2048), # 🌟 CRITICAL FIX: Bound increased to 2048!
1067
  quality: int = Query(95, ge=70, le=100),
1068
+ preserve_hair: bool = Query(True), # 🌟 CRITICAL FIX: Map all frontend options safely
1069
+ use_alpha_matting: bool = Query(True),
1070
+ border_pixels: int = Query(20),
1071
+ sharpen: bool = Query(True),
1072
  ):
1073
  try:
1074
  contents = await file.read()
1075
  if not contents:
1076
+ raise HTTPException(400, "Empty incoming data stream envelope.")
1077
 
1078
  loop = asyncio.get_event_loop()
1079
  pf = functools.partial(
 
1102
  raise
1103
  except Exception as e:
1104
  raise HTTPException(
1105
+ 500, f"Critical operational loop error event caught: {str(e)}"
1106
  )
1107
 
1108
 
 
1115
  smooth: bool = Query(True),
1116
  ):
1117
  if len(files) > 4:
1118
+ raise HTTPException(400, "Max sequence batch iteration capacity exceeded.")
1119
 
1120
  mem = get_container_memory()
1121
  if mem["percent"] > VIDEO_RAM_REJECT_PERCENT:
1122
  return JSONResponse(
1123
  status_code=503,
1124
  content={
1125
+ "error": "Server running close to baseline safety breaker lines.",
1126
  "retry_in": 4,
1127
  },
1128
  )
 
1191
  <body>
1192
  <div class="box">
1193
  <h1>Background Remover Pro v32.2.6</h1>
1194
+ <p>Container RAM Footprint: {mem['percent']:.1f}% ({mem['used_mb']}/{mem['total_mb']}MB)</p>
1195
+ <p>Active Allocated Caches: {stats['loaded_models']}</p>
1196
+ <p><a href="/docs">Swagger Interactive API Interface</a></p>
1197
  </div>
1198
  </body>
1199
  </html>