Spaces:
Sleeping
Sleeping
| """ | |
| Integration Example: How to replace SAM predictor calls with HF Space calls | |
| This shows you how to modify your app.py to use the HuggingFace Space | |
| """ | |
| import requests | |
| import json | |
| import base64 | |
| from io import BytesIO | |
| from PIL import Image | |
| import numpy as np | |
| from typing import Tuple, Optional | |
| # Your Space URL (update after deployment) | |
| MEDSAM_SPACE_URL = "https://YOUR_USERNAME-medsam-inference.hf.space/api/predict" | |
| class MedSAMSpacePredictor: | |
| """ | |
| Drop-in replacement for SamPredictor that calls HuggingFace Space | |
| Usage: | |
| # OLD CODE: | |
| from segment_anything import SamPredictor | |
| predictor = SamPredictor(sam) | |
| predictor.set_image(image_array) | |
| masks, scores, _ = predictor.predict(point_coords=..., point_labels=...) | |
| # NEW CODE: | |
| predictor = MedSAMSpacePredictor(MEDSAM_SPACE_URL) | |
| predictor.set_image(image_array) | |
| masks, scores, _ = predictor.predict(point_coords=..., point_labels=...) | |
| """ | |
| def __init__(self, space_url: str): | |
| self.space_url = space_url | |
| self.image_array = None | |
| print(f"✓ MedSAM Space Predictor initialized: {space_url}") | |
| def set_image(self, image: np.ndarray): | |
| """Set the image for segmentation (matches SAM interface)""" | |
| self.image_array = image | |
| def predict( | |
| self, | |
| point_coords: np.ndarray, | |
| point_labels: np.ndarray, | |
| multimask_output: bool = True, | |
| return_logits: bool = False | |
| ) -> Tuple[np.ndarray, np.ndarray, Optional[np.ndarray]]: | |
| """ | |
| Predict masks using HuggingFace Space (matches SAM interface) | |
| Args: | |
| point_coords: nx2 array of point coordinates [[x, y], ...] | |
| point_labels: n array of point labels [1, 0, ...] | |
| multimask_output: whether to return multiple masks | |
| return_logits: (ignored) kept for compatibility | |
| Returns: | |
| masks: (N, H, W) array of boolean masks | |
| scores: (N,) array of confidence scores | |
| logits: None (not supported via API) | |
| """ | |
| if self.image_array is None: | |
| raise ValueError("Must call set_image() before predict()") | |
| try: | |
| # Convert numpy array to base64 | |
| image = Image.fromarray(self.image_array) | |
| buffered = BytesIO() | |
| image.save(buffered, format="PNG") | |
| img_base64 = base64.b64encode(buffered.getvalue()).decode() | |
| # Prepare points JSON | |
| points_json = json.dumps({ | |
| "coords": point_coords.tolist(), | |
| "labels": point_labels.tolist(), | |
| "multimask_output": multimask_output | |
| }) | |
| # Call Space API | |
| response = requests.post( | |
| self.space_url, | |
| json={ | |
| "data": [ | |
| f"data:image/png;base64,{img_base64}", | |
| points_json | |
| ] | |
| }, | |
| timeout=120 # 2 minute timeout | |
| ) | |
| if response.status_code != 200: | |
| raise Exception(f"API returned status {response.status_code}: {response.text}") | |
| # Parse result | |
| result = response.json() | |
| # Gradio wraps output in data array | |
| if "data" in result and len(result["data"]) > 0: | |
| output_json = result["data"][0] | |
| else: | |
| raise Exception("Unexpected API response format") | |
| output = json.loads(output_json) | |
| if not output.get('success', False): | |
| raise Exception(output.get('error', 'Unknown error')) | |
| # Convert masks back to numpy arrays | |
| masks = [] | |
| for mask_data in output['masks']: | |
| mask = np.array(mask_data['mask_data'], dtype=bool) | |
| masks.append(mask) | |
| masks = np.array(masks) | |
| scores = np.array(output['scores']) | |
| return masks, scores, None | |
| except requests.exceptions.Timeout: | |
| raise Exception("MedSAM Space API timeout (>120s)") | |
| except requests.exceptions.RequestException as e: | |
| raise Exception(f"MedSAM Space API request failed: {str(e)}") | |
| except Exception as e: | |
| raise Exception(f"MedSAM Space API error: {str(e)}") | |
| # ============================================================================ | |
| # Example: How to modify your app.py | |
| # ============================================================================ | |
| def example_modification(): | |
| """ | |
| Shows how to modify your segment endpoint in app.py | |
| """ | |
| # At the top of app.py, add: | |
| print("# Add to imports:") | |
| print("from integration_example import MedSAMSpacePredictor") | |
| print() | |
| # Replace SAM initialization: | |
| print("# Replace SAM initialization:") | |
| print(""" | |
| # OLD: | |
| sam = sam_model_registry["vit_b"](checkpoint="models/sam_vit_h_4b8939.pth") | |
| sam.to(device=device) | |
| sam_predictor = SamPredictor(sam) | |
| # NEW: | |
| sam_predictor = MedSAMSpacePredictor( | |
| "https://YOUR_USERNAME-medsam-inference.hf.space/api/predict" | |
| ) | |
| """) | |
| print() | |
| # Usage in endpoint: | |
| print("# Usage in endpoint (NO CHANGES NEEDED!):") | |
| print(""" | |
| @app.route('/api/segment', methods=['POST']) | |
| def segment_with_sam(): | |
| # ... your existing code ... | |
| # This works exactly the same! | |
| sam_predictor.set_image(image_array) | |
| masks, scores, _ = sam_predictor.predict( | |
| point_coords=np.array([[x, y]]), | |
| point_labels=np.array([1]), | |
| multimask_output=True | |
| ) | |
| # Get the best mask | |
| best_mask = masks[np.argmax(scores)] | |
| # ... rest of your code ... | |
| """) | |
| # ============================================================================ | |
| # Complete integration example | |
| # ============================================================================ | |
| def integrate_with_your_backend(space_url: str): | |
| """ | |
| Complete code snippet to add to your app.py | |
| Save this as: backend/medsam_space_client.py | |
| Then import in app.py | |
| """ | |
| code = f''' | |
| # File: backend/medsam_space_client.py | |
| """Client for MedSAM HuggingFace Space""" | |
| import requests | |
| import json | |
| import base64 | |
| from io import BytesIO | |
| from PIL import Image | |
| import numpy as np | |
| MEDSAM_SPACE_URL = "{space_url}" | |
| class MedSAMSpacePredictor: | |
| """Drop-in replacement for SAM predictor using HF Space""" | |
| def __init__(self, space_url): | |
| self.space_url = space_url | |
| self.image_array = None | |
| def set_image(self, image): | |
| self.image_array = image | |
| def predict(self, point_coords, point_labels, multimask_output=True, **kwargs): | |
| if self.image_array is None: | |
| raise ValueError("Must call set_image() first") | |
| # Convert to base64 | |
| img = Image.fromarray(self.image_array) | |
| buf = BytesIO() | |
| img.save(buf, format="PNG") | |
| img_b64 = base64.b64encode(buf.getvalue()).decode() | |
| # Call API | |
| points_json = json.dumps({{ | |
| "coords": point_coords.tolist(), | |
| "labels": point_labels.tolist(), | |
| "multimask_output": multimask_output | |
| }}) | |
| resp = requests.post( | |
| self.space_url, | |
| json={{"data": [f"data:image/png;base64,{{img_b64}}", points_json]}}, | |
| timeout=120 | |
| ) | |
| result = json.loads(resp.json()["data"][0]) | |
| if not result["success"]: | |
| raise Exception(result.get("error", "API error")) | |
| # Convert back to numpy | |
| masks = np.array([np.array(m["mask_data"], dtype=bool) for m in result["masks"]]) | |
| scores = np.array(result["scores"]) | |
| return masks, scores, None | |
| # Usage in app.py: | |
| # ---------------- | |
| # from medsam_space_client import MedSAMSpacePredictor | |
| # | |
| # # Replace: | |
| # # sam_predictor = SamPredictor(sam) | |
| # # With: | |
| # sam_predictor = MedSAMSpacePredictor(MEDSAM_SPACE_URL) | |
| # | |
| # # Everything else stays the same! | |
| ''' | |
| print(code) | |
| return code | |
| if __name__ == "__main__": | |
| print("=" * 80) | |
| print("MedSAM HuggingFace Space Integration Guide") | |
| print("=" * 80) | |
| print() | |
| example_modification() | |
| print() | |
| print("=" * 80) | |
| print("Complete Integration Code") | |
| print("=" * 80) | |
| print() | |
| integrate_with_your_backend("https://YOUR_USERNAME-medsam-inference.hf.space/api/predict") | |