| from fastapi import FastAPI, HTTPException |
| from pydantic import BaseModel |
| from typing import Optional, List, Any, Dict |
| import numpy as np |
| import base64 |
| import zlib |
| import os |
| import sys |
|
|
| |
| current_dir = os.path.dirname(os.path.abspath(__file__)) |
| project_root = os.path.abspath(os.path.join(current_dir, "../../../")) |
| if project_root not in sys.path: |
| sys.path.insert(0, project_root) |
|
|
| from dataflow_agent.toolkits.imtool.sam_tool import run_sam_auto, free_sam_model |
|
|
| try: |
| import torch |
| except ImportError: |
| torch = None |
|
|
| app = FastAPI(title="SAM Model Server") |
|
|
| |
| @app.on_event("startup") |
| async def startup_event(): |
| print("SAM Server Startup Check:") |
| print(f"CUDA_VISIBLE_DEVICES: {os.environ.get('CUDA_VISIBLE_DEVICES', 'Not Set')}") |
| if torch and torch.cuda.is_available(): |
| print(f"Torch CUDA available: {torch.cuda.is_available()}") |
| print(f"Current Device Count: {torch.cuda.device_count()}") |
| print(f"Current Device Name: {torch.cuda.get_device_name(0)}") |
| else: |
| print("CUDA NOT AVAILABLE") |
|
|
| class SAMRequest(BaseModel): |
| image_path: str |
| checkpoint: str = "sam_b.pt" |
| device: str = "cuda" |
|
|
| class SAMItemResponse(BaseModel): |
| mask_b64: str |
| mask_shape: List[int] |
| bbox: List[float] |
| score: Optional[float] = None |
| area: int |
|
|
| class SAMResponse(BaseModel): |
| items: List[SAMItemResponse] |
|
|
| @app.post("/predict", response_model=SAMResponse) |
| async def predict(req: SAMRequest): |
| """ |
| Run SAM auto segmentation on the given image path. |
| """ |
| if not os.path.exists(req.image_path): |
| raise HTTPException(status_code=404, detail=f"Image path not found: {req.image_path}") |
|
|
| try: |
| |
| target_device = req.device |
| if target_device == "cuda": |
| target_device = "cuda:0" |
|
|
| |
| |
| |
| items = run_sam_auto( |
| image_path=req.image_path, |
| checkpoint=req.checkpoint, |
| device=target_device |
| ) |
| |
| |
| serialized_items = [] |
| for it in items: |
| mask = it.get("mask") |
| if mask is None: |
| continue |
| |
| |
| |
| if not isinstance(mask, np.ndarray): |
| mask = np.array(mask) |
| |
| |
| mask_bool = mask.astype(bool) |
| mask_bytes = mask_bool.tobytes() |
| |
| compressed_bytes = zlib.compress(mask_bytes) |
| mask_b64 = base64.b64encode(compressed_bytes).decode('utf-8') |
| |
| serialized_items.append(SAMItemResponse( |
| mask_b64=mask_b64, |
| mask_shape=list(mask.shape), |
| bbox=it.get("bbox", []), |
| score=it.get("score"), |
| area=it.get("area", 0) |
| )) |
| |
| return SAMResponse(items=serialized_items) |
|
|
| except Exception as e: |
| import traceback |
| traceback.print_exc() |
| raise HTTPException(status_code=500, detail=str(e)) |
| finally: |
| |
| if torch and torch.cuda.is_available(): |
| torch.cuda.empty_cache() |
|
|
| @app.post("/free_model") |
| async def free_model(checkpoint: str = "sam_b.pt"): |
| try: |
| free_sam_model(checkpoint) |
| return {"status": "ok", "message": f"Model {checkpoint} freed"} |
| except Exception as e: |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|
| @app.get("/health") |
| def health(): |
| return {"status": "ok"} |
|
|