Spaces:
Sleeping
Sleeping
Resolve merge conflict in requirements.txt
Browse files- .dockerignore +0 -1
- Dockerfile +12 -27
- main.py +12 -2
- schemas.py +54 -24
.dockerignore
CHANGED
|
@@ -10,7 +10,6 @@ build/
|
|
| 10 |
venv/
|
| 11 |
env/
|
| 12 |
server/
|
| 13 |
-
.git
|
| 14 |
.gitignore
|
| 15 |
.env
|
| 16 |
.env.local
|
|
|
|
| 10 |
venv/
|
| 11 |
env/
|
| 12 |
server/
|
|
|
|
| 13 |
.gitignore
|
| 14 |
.env
|
| 15 |
.env.local
|
Dockerfile
CHANGED
|
@@ -1,11 +1,11 @@
|
|
| 1 |
-
# Use official Python runtime as base image
|
| 2 |
FROM python:3.11-slim
|
| 3 |
|
| 4 |
-
# Set working directory in container
|
| 5 |
WORKDIR /app
|
| 6 |
|
| 7 |
-
#
|
| 8 |
RUN apt-get update && apt-get install -y \
|
|
|
|
|
|
|
| 9 |
libsm6 \
|
| 10 |
libxext6 \
|
| 11 |
libxrender-dev \
|
|
@@ -13,35 +13,20 @@ RUN apt-get update && apt-get install -y \
|
|
| 13 |
pkg-config \
|
| 14 |
&& rm -rf /var/lib/apt/lists/*
|
| 15 |
|
| 16 |
-
#
|
| 17 |
-
|
| 18 |
|
| 19 |
-
#
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
# Copy application code
|
| 23 |
-
COPY main.py .
|
| 24 |
-
COPY model.py .
|
| 25 |
-
COPY schemas.py .
|
| 26 |
-
COPY inference/ ./inference/
|
| 27 |
|
| 28 |
-
#
|
| 29 |
-
|
| 30 |
|
| 31 |
-
#
|
| 32 |
-
RUN
|
| 33 |
|
| 34 |
-
#
|
| 35 |
EXPOSE 7860
|
| 36 |
-
|
| 37 |
-
# Set environment for production
|
| 38 |
ENV PYTHONUNBUFFERED=1
|
| 39 |
-
ENV PORT=7860
|
| 40 |
-
ENV HOST=0.0.0.0
|
| 41 |
-
|
| 42 |
-
# Health check
|
| 43 |
-
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
| 44 |
-
CMD python -c "import requests; requests.get('http://localhost:7860/health')" || exit 1
|
| 45 |
|
| 46 |
-
# Run FastAPI application with uvicorn
|
| 47 |
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
|
|
|
|
|
|
|
| 1 |
FROM python:3.11-slim
|
| 2 |
|
|
|
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
+
# --- System deps ---
|
| 6 |
RUN apt-get update && apt-get install -y \
|
| 7 |
+
git \
|
| 8 |
+
git-lfs \
|
| 9 |
libsm6 \
|
| 10 |
libxext6 \
|
| 11 |
libxrender-dev \
|
|
|
|
| 13 |
pkg-config \
|
| 14 |
&& rm -rf /var/lib/apt/lists/*
|
| 15 |
|
| 16 |
+
# --- Enable Git LFS ---
|
| 17 |
+
RUN git lfs install
|
| 18 |
|
| 19 |
+
# --- Copy repo ---
|
| 20 |
+
COPY . .
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
+
# --- Pull LFS files INSIDE container ---
|
| 23 |
+
RUN git lfs pull
|
| 24 |
|
| 25 |
+
# --- Install Python deps ---
|
| 26 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 27 |
|
| 28 |
+
# --- Runtime ---
|
| 29 |
EXPOSE 7860
|
|
|
|
|
|
|
| 30 |
ENV PYTHONUNBUFFERED=1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
|
|
|
| 32 |
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
|
main.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
# main.py
|
| 2 |
-
|
| 3 |
from fastapi import FastAPI, HTTPException, Request
|
| 4 |
from fastapi.responses import JSONResponse, HTMLResponse
|
| 5 |
import tensorflow as tf
|
|
@@ -207,11 +207,21 @@ def predict(payload: PredictRequest):
|
|
| 207 |
# ---------------------------------------------------------------------
|
| 208 |
# Run model (raw confidence)
|
| 209 |
# ---------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
model = tf.keras.models.load_model(
|
| 211 |
-
|
| 212 |
compile=False
|
| 213 |
)
|
| 214 |
|
|
|
|
|
|
|
| 215 |
confidence_map = model.predict(
|
| 216 |
input_tensor, verbose=0
|
| 217 |
)[0, :, :, 0]
|
|
|
|
| 1 |
# main.py
|
| 2 |
+
from huggingface_hub import hf_hub_download
|
| 3 |
from fastapi import FastAPI, HTTPException, Request
|
| 4 |
from fastapi.responses import JSONResponse, HTMLResponse
|
| 5 |
import tensorflow as tf
|
|
|
|
| 207 |
# ---------------------------------------------------------------------
|
| 208 |
# Run model (raw confidence)
|
| 209 |
# ---------------------------------------------------------------------
|
| 210 |
+
MODEL_REPO = "prshntdxt/Forest_Segmentation_Best"
|
| 211 |
+
MODEL_FILE = "Forest_Segmentation_Best.keras"
|
| 212 |
+
|
| 213 |
+
MODEL_PATH = hf_hub_download(
|
| 214 |
+
repo_id=MODEL_REPO,
|
| 215 |
+
filename=MODEL_FILE,
|
| 216 |
+
)
|
| 217 |
+
|
| 218 |
model = tf.keras.models.load_model(
|
| 219 |
+
MODEL_PATH,
|
| 220 |
compile=False
|
| 221 |
)
|
| 222 |
|
| 223 |
+
|
| 224 |
+
|
| 225 |
confidence_map = model.predict(
|
| 226 |
input_tensor, verbose=0
|
| 227 |
)[0, :, :, 0]
|
schemas.py
CHANGED
|
@@ -1,41 +1,71 @@
|
|
| 1 |
from pydantic import BaseModel
|
| 2 |
-
from typing import Dict, List, Optional, Union
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
class PredictRequest(BaseModel):
|
| 5 |
"""
|
| 6 |
-
Forest segmentation prediction request
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
-
|
| 11 |
-
-
|
| 12 |
-
|
| 13 |
-
Required
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
- Optical bands: [-0.2, 0.6]
|
| 23 |
-
- Indices: [-1, 1]
|
| 24 |
"""
|
|
|
|
| 25 |
model_name: str = "forest_segmentation"
|
| 26 |
model_version: str = "landsat8_v1"
|
| 27 |
-
bands: Dict[str, Union[str, List, int]] # Band data as base64 or array
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
| 32 |
|
| 33 |
class PredictResponse(BaseModel):
|
| 34 |
-
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
forest_percentage: float
|
| 37 |
forest_confidence: float
|
| 38 |
mean_prediction: float
|
|
|
|
|
|
|
| 39 |
classes: Dict[str, int]
|
|
|
|
|
|
|
| 40 |
model_info: Dict[str, Any]
|
|
|
|
|
|
|
| 41 |
debug: Optional[Dict[str, Any]] = None
|
|
|
|
| 1 |
from pydantic import BaseModel
|
| 2 |
+
from typing import Dict, List, Optional, Union, Any
|
| 3 |
+
|
| 4 |
+
# =============================================================================
|
| 5 |
+
# REQUEST SCHEMA
|
| 6 |
+
# =============================================================================
|
| 7 |
|
| 8 |
class PredictRequest(BaseModel):
|
| 9 |
"""
|
| 10 |
+
Forest segmentation prediction request.
|
| 11 |
+
|
| 12 |
+
This schema is intentionally flexible to support:
|
| 13 |
+
- Supabase Edge Functions
|
| 14 |
+
- Hugging Face remote inference
|
| 15 |
+
- Local inference scripts
|
| 16 |
+
|
| 17 |
+
Required:
|
| 18 |
+
- bands: Dict[str, Union[str, List[float]]]
|
| 19 |
+
|
| 20 |
+
Allowed extra fields (sent by Supabase):
|
| 21 |
+
- width, height
|
| 22 |
+
- bbox
|
| 23 |
+
- band_names
|
| 24 |
+
- preprocessing
|
| 25 |
+
- model_name, model_version
|
|
|
|
|
|
|
| 26 |
"""
|
| 27 |
+
|
| 28 |
model_name: str = "forest_segmentation"
|
| 29 |
model_version: str = "landsat8_v1"
|
|
|
|
| 30 |
|
| 31 |
+
# Band data:
|
| 32 |
+
# - base64-encoded float32 (remote calls)
|
| 33 |
+
# - list/array of floats (local calls)
|
| 34 |
+
bands: Dict[str, Union[str, List[float]]]
|
| 35 |
+
|
| 36 |
+
class Config:
|
| 37 |
+
# 🔑 CRITICAL FIX
|
| 38 |
+
# Allows Supabase to send extra metadata without 422 errors
|
| 39 |
+
extra = "allow"
|
| 40 |
|
| 41 |
+
|
| 42 |
+
# =============================================================================
|
| 43 |
+
# RESPONSE SCHEMA
|
| 44 |
+
# =============================================================================
|
| 45 |
|
| 46 |
class PredictResponse(BaseModel):
|
| 47 |
+
"""
|
| 48 |
+
Forest segmentation prediction response.
|
| 49 |
+
|
| 50 |
+
Mask values are CONTINUOUS (0–255) — NOT binary.
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
# Flattened mask (length = width * height)
|
| 54 |
+
mask: List[int]
|
| 55 |
+
|
| 56 |
+
# Inverted mask (optional utility)
|
| 57 |
+
inverted_mask: List[int]
|
| 58 |
+
|
| 59 |
+
# Statistics
|
| 60 |
forest_percentage: float
|
| 61 |
forest_confidence: float
|
| 62 |
mean_prediction: float
|
| 63 |
+
|
| 64 |
+
# Class mapping
|
| 65 |
classes: Dict[str, int]
|
| 66 |
+
|
| 67 |
+
# Model metadata
|
| 68 |
model_info: Dict[str, Any]
|
| 69 |
+
|
| 70 |
+
# Optional debug block
|
| 71 |
debug: Optional[Dict[str, Any]] = None
|