mastari commited on
Commit
7c16a09
Β·
1 Parent(s): 42430a6

Fix GFPGAN weights URL (v1.3.0 release tag)

Browse files
Files changed (1) hide show
  1. handler.py +103 -140
handler.py CHANGED
@@ -1,174 +1,137 @@
1
- import os
2
  import io
3
- import base64
 
4
  import torch
 
 
5
  import requests
6
  import numpy as np
7
  from PIL import Image
8
  from gfpgan import GFPGANer
9
 
 
 
 
 
 
 
 
 
 
10
 
 
 
 
 
 
 
 
 
 
 
11
  class EndpointHandler:
12
  def __init__(self, path="."):
13
- print("πŸš€ [INIT] Starting GFPGAN EndpointHandler initialization...")
14
- print(f"πŸ“ Working directory: {os.getcwd()}")
15
- print(f"πŸ“‚ Handler path argument: {path}")
16
-
17
- # ----------------------------
18
- # MODEL DOWNLOAD
19
- # ----------------------------
20
- self.model_url = (
21
- "https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth"
22
- )
23
- self.model_path = os.path.join(path, "GFPGANv1.4.pth")
24
- print(f"πŸ”— [MODEL] Model URL: {self.model_url}")
25
- print(f"πŸ“¦ [MODEL] Local model path: {self.model_path}")
26
-
27
- if not os.path.exists(self.model_path):
28
- print("πŸ“₯ [DOWNLOAD] Model not found locally β€” starting download...")
29
  try:
30
- r = requests.get(self.model_url, timeout=60)
 
31
  r.raise_for_status()
32
- with open(self.model_path, "wb") as f:
33
- f.write(r.content)
34
- print(f"βœ… [DOWNLOAD] Model successfully saved to {self.model_path}")
 
 
35
  except Exception as e:
36
- print(f"πŸ’₯ [ERROR] Failed to download GFPGAN weights: {e}")
37
- raise e
38
- else:
39
- print("πŸ“š [CACHE] Found existing model file, skipping download.")
40
-
41
- # ----------------------------
42
- # INITIALIZE RESTORER
43
- # ----------------------------
44
- device = "cuda" if torch.cuda.is_available() else "cpu"
45
- print(f"πŸ’» [DEVICE] Using device: {device}")
46
 
 
 
 
47
  try:
48
- print("🧠 [MODEL INIT] Initializing GFPGANer...")
49
  self.restorer = GFPGANer(
50
- model_path=self.model_path,
51
- upscale=2,
52
  arch="clean",
53
  channel_multiplier=2,
54
  bg_upsampler=None,
55
- device=device,
56
  )
57
- print("βœ… [MODEL INIT] GFPGANer successfully initialized.")
58
  except Exception as e:
59
- print(f"πŸ’₯ [ERROR] Failed to initialize GFPGANer: {e}")
60
- raise e
61
 
62
- print("πŸŽ‰ [INIT DONE] GFPGAN model ready for inference!")
63
-
64
- # ----------------------------
65
- # CALLABLE ENTRY POINT
66
- # ----------------------------
67
  def __call__(self, data):
68
- print("\nπŸ›°οΈ [CALL] ======= Incoming request =======")
69
- print(f"πŸ” [CALL] Input type: {type(data)}")
70
- print(f"πŸ” [CALL] Raw preview: {str(data)[:300]}")
71
 
 
 
 
72
  try:
73
- image = self.preprocess(data)
74
- print(f"πŸ“Έ [PREPROCESS DONE] Type: {type(image)}, Size: {image.size}")
75
-
76
- restored = self.inference(image)
77
- print(f"🎨 [INFERENCE DONE] Output type: {type(restored)}, Size: {restored.size}")
78
-
79
- response = self.postprocess(restored)
80
- print(f"πŸ“¦ [POSTPROCESS DONE] Keys: {list(response.keys())}")
81
- print("βœ… [CALL COMPLETE] Successfully processed request.\n")
82
- return response
83
-
84
  except Exception as e:
85
- print("πŸ’₯ [CALL ERROR] Exception occurred during inference!")
86
- print(f"❗ [TRACEBACK]: {repr(e)}")
87
- return {"error": str(e)}
88
-
89
- # ----------------------------
90
- # PREPROCESS STEP
91
- # ----------------------------
92
- def preprocess(self, data):
93
- print("πŸ”§ [PREPROCESS] Starting preprocessing step...")
94
- print(f"πŸ”§ [PREPROCESS] Received type: {type(data)}")
95
-
96
- # Case 1: raw bytes directly
97
- if isinstance(data, (bytes, bytearray)):
98
- print("πŸ“₯ [PREPROCESS] Detected raw bytes input.")
99
- img = Image.open(io.BytesIO(data)).convert("RGB")
100
- print(f"πŸ“Έ [PREPROCESS] Loaded image β€” size: {img.size}, mode: {img.mode}")
101
- return img
102
-
103
- # Case 2: dict payload (like {'inputs': base64_string})
104
- if isinstance(data, dict):
105
- print("πŸ“¦ [PREPROCESS] Detected dict input.")
106
- keys = list(data.keys())
107
- print(f"πŸ“¦ [PREPROCESS] Dict keys: {keys}")
108
- img_field = data.get("inputs") or data.get("image") or None
109
-
110
- if img_field is None:
111
- raise ValueError("Missing 'inputs' or 'image' key in JSON payload.")
112
-
113
- # Base64 string case
114
- if isinstance(img_field, str):
115
- print("🧬 [PREPROCESS] Input is a base64 string β€” decoding...")
116
- img_field = base64.b64decode(img_field)
117
-
118
- # Raw bytes inside dict
119
- if isinstance(img_field, (bytes, bytearray)):
120
- print("πŸ“₯ [PREPROCESS] Input is bytes inside dict β€” converting to image...")
121
- img = Image.open(io.BytesIO(img_field)).convert("RGB")
122
- print(f"πŸ“Έ [PREPROCESS] Image loaded from dict β€” size: {img.size}, mode: {img.mode}")
123
- return img
124
-
125
- raise ValueError("Unsupported input format β€” expected bytes or base64 data")
126
-
127
- # ----------------------------
128
- # INFERENCE STEP
129
- # ----------------------------
130
- def inference(self, image):
131
- print("🧠 [INFERENCE] Starting restoration process...")
132
- print(f"🧠 [INFERENCE] Input image type: {type(image)}, size: {image.size}, mode: {image.mode}")
133
 
 
 
 
134
  try:
135
- np_img = np.array(image)
136
- print(f"πŸ”’ [INFERENCE] NumPy array shape: {np_img.shape}, dtype: {np_img.dtype}")
137
-
138
- # Convert RGB β†’ BGR
139
- np_img = np_img[:, :, ::-1]
140
- print("🎨 [INFERENCE] Converted RGB to BGR for OpenCV-style processing.")
141
 
142
- # Run the GFPGAN restoration
143
- print("πŸš€ [INFERENCE] Running GFPGANer.enhance()...")
144
- _, _, restored_img = self.restorer.enhance(
145
- np_img, has_aligned=False, only_center_face=False, paste_back=True
 
 
 
 
 
146
  )
147
-
148
- if restored_img is None:
149
- raise RuntimeError("Restoration failed β€” GFPGAN returned None")
150
-
151
- print("βœ… [INFERENCE] Restoration successful, converting to PIL.Image...")
152
- restored_pil = Image.fromarray(restored_img[:, :, ::-1]) # Convert BGR β†’ RGB
153
- print(f"πŸ–ΌοΈ [INFERENCE] Restored image size: {restored_pil.size}, mode: {restored_pil.mode}")
154
- return restored_pil
155
-
156
  except Exception as e:
157
- print(f"πŸ’₯ [INFERENCE ERROR] {e}")
158
- raise e
159
-
160
- # ----------------------------
161
- # POSTPROCESS STEP
162
- # ----------------------------
163
- def postprocess(self, restored_img):
164
- print("πŸ“¦ [POSTPROCESS] Starting encoding...")
165
  try:
166
- buf = io.BytesIO()
167
- restored_img.save(buf, format="PNG")
168
- encoded = base64.b64encode(buf.getvalue()).decode("utf-8")
169
- print("βœ… [POSTPROCESS] Image successfully encoded to base64 (len=%d)" % len(encoded))
170
- return {"image": encoded}
171
  except Exception as e:
172
- print(f"πŸ’₯ [POSTPROCESS ERROR] {e}")
173
- raise e
174
 
 
 
1
  import io
2
+ import os
3
+ import cv2
4
  import torch
5
+ import base64
6
+ import logging
7
  import requests
8
  import numpy as np
9
  from PIL import Image
10
  from gfpgan import GFPGANer
11
 
12
+ # ======================================================
13
+ # LOGGING CONFIGURATION
14
+ # ======================================================
15
+ logging.basicConfig(level=logging.DEBUG)
16
+ logger = logging.getLogger(__name__)
17
+ logger.setLevel(logging.DEBUG)
18
+
19
+ logger.debug("πŸ“¦ [INIT] Importing GFPGAN handler module...")
20
+
21
 
22
+ # ======================================================
23
+ # GFPGAN MODEL DOWNLOAD CONFIG
24
+ # ======================================================
25
+ MODEL_URL = "https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth"
26
+ MODEL_NAME = "GFPGANv1.4.pth"
27
+
28
+
29
+ # ======================================================
30
+ # ENDPOINT HANDLER
31
+ # ======================================================
32
  class EndpointHandler:
33
  def __init__(self, path="."):
34
+ logger.debug("πŸš€ [INIT] Starting GFPGAN EndpointHandler initialization...")
35
+ logger.debug(f"πŸ“ Working directory: {os.getcwd()}")
36
+ logger.debug(f"πŸ“‚ Handler path argument: {path}")
37
+
38
+ model_path = os.path.join(path, MODEL_NAME)
39
+ logger.debug(f"πŸ”— [MODEL] Expected model path: {model_path}")
40
+
41
+ # ------------------------------------------------------
42
+ # Download model if not found
43
+ # ------------------------------------------------------
44
+ if not os.path.exists(model_path):
 
 
 
 
 
45
  try:
46
+ logger.debug(f"πŸ“₯ [DOWNLOAD] Model not found locally. Downloading from {MODEL_URL}")
47
+ r = requests.get(MODEL_URL, stream=True)
48
  r.raise_for_status()
49
+ with open(model_path, "wb") as f:
50
+ for chunk in r.iter_content(chunk_size=8192):
51
+ if chunk:
52
+ f.write(chunk)
53
+ logger.debug("βœ… [MODEL] Downloaded GFPGAN model successfully.")
54
  except Exception as e:
55
+ logger.error(f"πŸ’₯ [ERROR] Failed to download GFPGAN weights: {e}")
56
+ raise
 
 
 
 
 
 
 
 
57
 
58
+ # ------------------------------------------------------
59
+ # Initialize GFPGANer just like the official Gradio demo
60
+ # ------------------------------------------------------
61
  try:
62
+ logger.debug("🧠 [MODEL] Initializing GFPGANer (v1.4, upscale=2, no background upsampler)...")
63
  self.restorer = GFPGANer(
64
+ model_path=model_path,
65
+ upscale=2, # Matches Gradio demo β€œRescaling factor: 2”
66
  arch="clean",
67
  channel_multiplier=2,
68
  bg_upsampler=None,
69
+ version="1.4",
70
  )
71
+ logger.debug("βœ… [MODEL] GFPGAN model initialized successfully.")
72
  except Exception as e:
73
+ logger.error(f"πŸ’₯ [ERROR] Model initialization failed: {e}")
74
+ raise
75
 
76
+ # ======================================================
77
+ # INFERENCE CALL
78
+ # ======================================================
 
 
79
  def __call__(self, data):
80
+ logger.debug("βš™οΈ [INFER] Starting inference...")
81
+ logger.debug(f"πŸ“₯ Incoming data keys: {list(data.keys())}")
 
82
 
83
+ # ------------------------------------------------------
84
+ # Handle both raw bytes and JSON base64 inputs
85
+ # ------------------------------------------------------
86
  try:
87
+ if isinstance(data, dict) and "inputs" in data:
88
+ logger.debug("πŸ“¦ Detected JSON base64 input")
89
+ image_bytes = base64.b64decode(data["inputs"])
90
+ elif isinstance(data, (bytes, bytearray)):
91
+ logger.debug("πŸ“¦ Detected raw bytes input")
92
+ image_bytes = data
93
+ else:
94
+ raise ValueError("Unsupported input format β€” expected bytes or base64 data")
95
+
96
+ logger.debug(f"🧾 [BYTES] Received {len(image_bytes)} bytes")
 
97
  except Exception as e:
98
+ logger.error(f"πŸ’₯ [ERROR] Input parsing failed: {e}")
99
+ return {"error": f"Invalid input: {e}"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
+ # ------------------------------------------------------
102
+ # Load and convert image
103
+ # ------------------------------------------------------
104
  try:
105
+ img_np = np.array(Image.open(io.BytesIO(image_bytes)).convert("RGB"))
106
+ logger.debug(f"πŸ–ΌοΈ [IMAGE] Loaded image of shape: {img_np.shape}")
107
+ except Exception as e:
108
+ logger.error(f"πŸ’₯ [ERROR] Failed to load image: {e}")
109
+ return {"error": f"Image loading failed: {e}"}
 
110
 
111
+ # ------------------------------------------------------
112
+ # Perform face restoration
113
+ # ------------------------------------------------------
114
+ try:
115
+ cropped_faces, restored_faces, restored_img = self.restorer.enhance(
116
+ img_np,
117
+ has_aligned=False,
118
+ only_center_face=False,
119
+ paste_back=True, # ⬅️ Matches web demo behavior
120
  )
121
+ logger.debug("βœ… [RESTORE] Face restoration complete.")
 
 
 
 
 
 
 
 
122
  except Exception as e:
123
+ logger.error(f"πŸ’₯ [ERROR] GFPGAN enhancement failed: {e}")
124
+ return {"error": f"Enhancement failed: {e}"}
125
+
126
+ # ------------------------------------------------------
127
+ # Encode restored image to base64 for response
128
+ # ------------------------------------------------------
 
 
129
  try:
130
+ _, buffer = cv2.imencode(".png", restored_img[:, :, ::-1]) # BGR β†’ RGB
131
+ img_base64 = base64.b64encode(buffer).decode("utf-8")
132
+ logger.debug("πŸ“€ [ENCODE] Successfully encoded restored image.")
133
+ return {"image": img_base64}
 
134
  except Exception as e:
135
+ logger.error(f"πŸ’₯ [ERROR] Failed to encode restored image: {e}")
136
+ return {"error": f"Encoding failed: {e}"}
137