Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions sam2/backend.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ ADD https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_small.
ADD https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_base_plus.pt ${APP_ROOT}/checkpoints/sam2.1_hiera_base_plus.pt
ADD https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_large.pt ${APP_ROOT}/checkpoints/sam2.1_hiera_large.pt

# Create a non-root user and switch to it
RUN useradd -m nonrootuser
USER nonrootuser

WORKDIR ${APP_ROOT}/server

# https://pythonspeed.com/articles/gunicorn-in-docker/
Expand Down
26 changes: 26 additions & 0 deletions sam2/demo/backend/server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
from data.store import set_videos
from flask import Flask, make_response, Request, request, Response, send_from_directory
from flask_cors import CORS
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from flask_httpauth import HTTPBasicAuth
from flask_talisman import Talisman
from inference.data_types import PropagateDataResponse, PropagateInVideoRequest
from inference.multipart import MultipartResponseBuilder
from inference.predictor import InferenceAPI
Expand All @@ -28,19 +32,33 @@

app = Flask(__name__)
cors = CORS(app, supports_credentials=True)
limiter = Limiter(get_remote_address, app=app, default_limits=["200 per day", "50 per hour"])
auth = HTTPBasicAuth()
talisman = Talisman(app)

videos = preload_data()
set_videos(videos)

inference_api = InferenceAPI()

users = {
"admin": "secret"
}

@auth.get_password
def get_pw(username):
if username in users:
return users.get(username)
return None

@app.route("/healthy")
def healthy() -> Response:
return make_response("OK", 200)


@app.route(f"/{GALLERY_PREFIX}/<path:path>", methods=["GET"])
@auth.login_required
@limiter.limit("10 per minute")
def send_gallery_video(path: str) -> Response:
try:
return send_from_directory(
Expand All @@ -52,6 +70,8 @@ def send_gallery_video(path: str) -> Response:


@app.route(f"/{POSTERS_PREFIX}/<path:path>", methods=["GET"])
@auth.login_required
@limiter.limit("10 per minute")
def send_poster_image(path: str) -> Response:
try:
return send_from_directory(
Expand All @@ -63,6 +83,8 @@ def send_poster_image(path: str) -> Response:


@app.route(f"/{UPLOADS_PREFIX}/<path:path>", methods=["GET"])
@auth.login_required
@limiter.limit("10 per minute")
def send_uploaded_video(path: str):
try:
return send_from_directory(
Expand All @@ -75,8 +97,12 @@ def send_uploaded_video(path: str):

# TOOD: Protect route with ToS permission check
@app.route("/propagate_in_video", methods=["POST"])
@auth.login_required
@limiter.limit("5 per minute")
def propagate_in_video() -> Response:
data = request.json
if not data or "session_id" not in data or "start_frame_index" not in data:
return make_response("Invalid input", 400)
args = {
"session_id": data["session_id"],
"start_frame_index": data.get("start_frame_index", 0),
Expand Down