dreamlessx commited on
Commit
21efdcf
·
verified ·
1 Parent(s): 7a35f0a

Update landmarkdiff/api_client.py to v0.3.2

Browse files
Files changed (1) hide show
  1. landmarkdiff/api_client.py +103 -27
landmarkdiff/api_client.py CHANGED
@@ -34,6 +34,12 @@ import cv2
34
  import numpy as np
35
 
36
 
 
 
 
 
 
 
37
  @dataclass
38
  class PredictionResult:
39
  """Result from a single prediction."""
@@ -69,17 +75,16 @@ class LandmarkDiffClient:
69
  def __init__(self, base_url: str = "http://localhost:8000", timeout: float = 60.0) -> None:
70
  self.base_url = base_url.rstrip("/")
71
  self.timeout = timeout
72
- self._session: Any = None
73
 
74
  def _get_session(self) -> Any:
75
  """Lazy-initialize requests session."""
76
  if self._session is None:
77
  try:
78
  import requests
79
- except ImportError:
80
- raise ImportError("requests required. Install with: pip install requests") from None
81
  self._session = requests.Session()
82
- self._session.timeout = self.timeout
83
  return self._session
84
 
85
  def _read_image(self, image_path: str | Path) -> bytes:
@@ -107,22 +112,58 @@ class LandmarkDiffClient:
107
 
108
  Returns:
109
  Dict with status and version info.
 
 
 
110
  """
111
  session = self._get_session()
112
- resp = session.get(f"{self.base_url}/health")
113
- resp.raise_for_status()
114
- return resp.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  def procedures(self) -> list[str]:
117
  """List available surgical procedures.
118
 
119
  Returns:
120
  List of procedure names.
 
 
 
121
  """
122
  session = self._get_session()
123
- resp = session.get(f"{self.base_url}/procedures")
124
- resp.raise_for_status()
125
- return resp.json().get("procedures", [])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
  def predict(
128
  self,
@@ -152,21 +193,38 @@ class LandmarkDiffClient:
152
  "seed": str(seed),
153
  }
154
 
155
- resp = session.post(f"{self.base_url}/predict", files=files, data=data)
156
- resp.raise_for_status()
157
- result = resp.json()
158
-
159
- # Decode output image
160
- output_img = self._decode_base64_image(result["output_image"])
161
-
162
- return PredictionResult(
163
- output_image=output_img,
164
- procedure=procedure,
165
- intensity=intensity,
166
- confidence=result.get("confidence", 0.0),
167
- metrics=result.get("metrics", {}),
168
- metadata=result.get("metadata", {}),
169
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
  def analyze(self, image_path: str | Path) -> dict[str, Any]:
172
  """Analyze a face image without generating a prediction.
@@ -178,14 +236,32 @@ class LandmarkDiffClient:
178
 
179
  Returns:
180
  Dict with analysis results.
 
 
 
181
  """
182
  session = self._get_session()
183
  image_bytes = self._read_image(image_path)
184
 
185
  files = {"image": ("image.png", image_bytes, "image/png")}
186
- resp = session.post(f"{self.base_url}/analyze", files=files)
187
- resp.raise_for_status()
188
- return resp.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
  def batch_predict(
191
  self,
 
34
  import numpy as np
35
 
36
 
37
+ class LandmarkDiffAPIError(Exception):
38
+ """Base exception for LandmarkDiff API errors."""
39
+
40
+ pass
41
+
42
+
43
  @dataclass
44
  class PredictionResult:
45
  """Result from a single prediction."""
 
75
  def __init__(self, base_url: str = "http://localhost:8000", timeout: float = 60.0) -> None:
76
  self.base_url = base_url.rstrip("/")
77
  self.timeout = timeout
78
+ self._session = None
79
 
80
  def _get_session(self) -> Any:
81
  """Lazy-initialize requests session."""
82
  if self._session is None:
83
  try:
84
  import requests
85
+ except ImportError as e:
86
+ raise ImportError("requests required. Install with: pip install requests") from e
87
  self._session = requests.Session()
 
88
  return self._session
89
 
90
  def _read_image(self, image_path: str | Path) -> bytes:
 
112
 
113
  Returns:
114
  Dict with status and version info.
115
+
116
+ Raises:
117
+ LandmarkDiffAPIError: If server is unreachable or returns an error.
118
  """
119
  session = self._get_session()
120
+ try:
121
+ resp = session.get(f"{self.base_url}/health", timeout=self.timeout)
122
+ resp.raise_for_status()
123
+ return resp.json()
124
+ except Exception as e:
125
+ import requests
126
+
127
+ if isinstance(e, requests.ConnectionError):
128
+ raise LandmarkDiffAPIError(
129
+ f"Cannot connect to LandmarkDiff server at {self.base_url}. "
130
+ f"Make sure the server is running (python -m landmarkdiff serve)."
131
+ ) from None
132
+ elif isinstance(e, requests.HTTPError):
133
+ raise LandmarkDiffAPIError(
134
+ f"Server returned error {e.response.status_code}: {e.response.text[:200]}"
135
+ ) from None
136
+ else:
137
+ raise
138
 
139
  def procedures(self) -> list[str]:
140
  """List available surgical procedures.
141
 
142
  Returns:
143
  List of procedure names.
144
+
145
+ Raises:
146
+ LandmarkDiffAPIError: If server is unreachable or returns an error.
147
  """
148
  session = self._get_session()
149
+ try:
150
+ resp = session.get(f"{self.base_url}/procedures", timeout=self.timeout)
151
+ resp.raise_for_status()
152
+ return resp.json().get("procedures", [])
153
+ except Exception as e:
154
+ import requests
155
+
156
+ if isinstance(e, requests.ConnectionError):
157
+ raise LandmarkDiffAPIError(
158
+ f"Cannot connect to LandmarkDiff server at {self.base_url}. "
159
+ f"Make sure the server is running (python -m landmarkdiff serve)."
160
+ ) from None
161
+ elif isinstance(e, requests.HTTPError):
162
+ raise LandmarkDiffAPIError(
163
+ f"Server returned error {e.response.status_code}: {e.response.text[:200]}"
164
+ ) from None
165
+ else:
166
+ raise
167
 
168
  def predict(
169
  self,
 
193
  "seed": str(seed),
194
  }
195
 
196
+ resp = session.post(
197
+ f"{self.base_url}/predict", files=files, data=data, timeout=self.timeout
 
 
 
 
 
 
 
 
 
 
 
 
198
  )
199
+ try:
200
+ resp.raise_for_status()
201
+ result = resp.json()
202
+
203
+ # Decode output image
204
+ output_img = self._decode_base64_image(result["output_image"])
205
+
206
+ return PredictionResult(
207
+ output_image=output_img,
208
+ procedure=procedure,
209
+ intensity=intensity,
210
+ confidence=result.get("confidence", 0.0),
211
+ metrics=result.get("metrics", {}),
212
+ metadata=result.get("metadata", {}),
213
+ )
214
+ except Exception as e:
215
+ import requests
216
+
217
+ if isinstance(e, requests.ConnectionError):
218
+ raise LandmarkDiffAPIError(
219
+ f"Cannot connect to LandmarkDiff server at {self.base_url}. "
220
+ f"Make sure the server is running (python -m landmarkdiff serve)."
221
+ ) from None
222
+ elif isinstance(e, requests.HTTPError):
223
+ raise LandmarkDiffAPIError(
224
+ f"Server returned error {e.response.status_code}: {e.response.text[:200]}"
225
+ ) from None
226
+ else:
227
+ raise
228
 
229
  def analyze(self, image_path: str | Path) -> dict[str, Any]:
230
  """Analyze a face image without generating a prediction.
 
236
 
237
  Returns:
238
  Dict with analysis results.
239
+
240
+ Raises:
241
+ LandmarkDiffAPIError: If server is unreachable or returns an error.
242
  """
243
  session = self._get_session()
244
  image_bytes = self._read_image(image_path)
245
 
246
  files = {"image": ("image.png", image_bytes, "image/png")}
247
+ try:
248
+ resp = session.post(f"{self.base_url}/analyze", files=files, timeout=self.timeout)
249
+ resp.raise_for_status()
250
+ return resp.json()
251
+ except Exception as e:
252
+ import requests
253
+
254
+ if isinstance(e, requests.ConnectionError):
255
+ raise LandmarkDiffAPIError(
256
+ f"Cannot connect to LandmarkDiff server at {self.base_url}. "
257
+ f"Make sure the server is running (python -m landmarkdiff serve)."
258
+ ) from None
259
+ elif isinstance(e, requests.HTTPError):
260
+ raise LandmarkDiffAPIError(
261
+ f"Server returned error {e.response.status_code}: {e.response.text[:200]}"
262
+ ) from None
263
+ else:
264
+ raise
265
 
266
  def batch_predict(
267
  self,