antonioserra21 commited on
Commit
cd072ae
·
verified ·
1 Parent(s): 84c8d8a

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +23 -0
  2. app/main.py +41 -0
  3. app/processing.py +19 -0
  4. requirements.txt +4 -0
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use a lightweight Python base image
2
+ FROM python:3.11-slim
3
+
4
+ # Install system libraries required by Pillow (for JPG/PNG handling)
5
+ RUN apt-get update && apt-get install -y --no-install-recommends \
6
+ libjpeg62-turbo libpng16-16 && \
7
+ rm -rf /var/lib/apt/lists/*
8
+
9
+ # Set working directory
10
+ WORKDIR /app
11
+
12
+ # Copy and install Python dependencies
13
+ COPY requirements.txt /app/requirements.txt
14
+ RUN pip install --no-cache-dir -r requirements.txt
15
+
16
+ # Copy the app source code
17
+ COPY app /app/app
18
+
19
+ # Expose port (Hugging Face Spaces uses 7860 by default)
20
+ EXPOSE 7860
21
+
22
+ # Start the FastAPI app
23
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"]
app/main.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, UploadFile, File, Form, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import JSONResponse
4
+ from PIL import Image
5
+ from io import BytesIO
6
+ import base64
7
+
8
+ from .processing import increase_contrast, gaussian_smooth, to_png_b64
9
+
10
+ app = FastAPI(title="Surgical Planning Phase Simulator")
11
+
12
+ app.add_middleware(
13
+ CORSMiddleware,
14
+ allow_origins=["*"], # restrict later
15
+ allow_credentials=True,
16
+ allow_methods=["*"],
17
+ allow_headers=["*"],
18
+ )
19
+
20
+ @app.get("/health")
21
+ def health():
22
+ return {"ok": True}
23
+
24
+ @app.post("/process")
25
+ async def process(file: UploadFile = File(...), phase: str = Form(...)):
26
+ if phase not in {"arterial", "venous"}:
27
+ raise HTTPException(status_code=400, detail="phase must be 'arterial' or 'venous'")
28
+ if file.content_type not in {"image/png", "image/jpeg"}:
29
+ raise HTTPException(status_code=400, detail="file must be PNG or JPEG")
30
+
31
+ data = await file.read()
32
+ try:
33
+ img = Image.open(BytesIO(data)).convert("RGB")
34
+ except Exception as e:
35
+ raise HTTPException(status_code=400, detail=f"invalid image: {e}")
36
+
37
+ proc = increase_contrast(img) if phase == "arterial" else gaussian_smooth(img)
38
+
39
+ orig_b64 = to_png_b64(img)
40
+ proc_b64 = to_png_b64(proc)
41
+ return JSONResponse({"original_b64": orig_b64, "processed_b64": proc_b64})
app/processing.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from io import BytesIO
2
+ import base64
3
+ from PIL import Image, ImageEnhance, ImageFilter
4
+
5
+ def to_png_b64(img: Image.Image) -> str:
6
+ buf = BytesIO()
7
+ img.save(buf, format="PNG")
8
+ return base64.b64encode(buf.getvalue()).decode("utf-8")
9
+
10
+ def increase_contrast(img: Image.Image, factor: float = 1.6) -> Image.Image:
11
+ # Simulate arterial phase: boost contrast (and a touch of autocontrast)
12
+ img = img.convert("RGB")
13
+ enhanced = ImageEnhance.Contrast(img).enhance(factor)
14
+ return enhanced
15
+
16
+ def gaussian_smooth(img: Image.Image, sigma: float = 1.6) -> Image.Image:
17
+ # Simulate venous phase: gaussian blur
18
+ img = img.convert("RGB")
19
+ return img.filter(ImageFilter.GaussianBlur(radius=sigma))
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ fastapi==0.115.4
2
+ uvicorn==0.32.0
3
+ pillow==10.4.0
4
+ python-multipart==0.0.9