Skip to content

Latest commit

 

History

History
283 lines (195 loc) · 9.03 KB

File metadata and controls

283 lines (195 loc) · 9.03 KB

🐳 Deployment Environment - Docker, Hugging Face Spaces, and Runtime Configuration

Scope: this document explains how the project is containerized and deployed, based on the actual deployment files: Dockerfile, start.sh, requirements.txt, and .dockerignore. These files are present at the root level on HF Space so that the web-app is deployed.


🚢 Deployment Model

The application is packaged as a Docker container and deployed as a dual-service runtime:

  • FastAPI runs the classifier and GitHub automation endpoints on port 8000 inside the container.
  • Flask runs the browser-facing app on port 7860 by default, reading the Hugging Face Spaces PORT variable when present.

The container is designed for a Hugging Face Spaces style runtime where the container exposes a single public port while internally launching both services.

💡 NOTE: The deployment uses two processes in one container, not a separate sidecar architecture. The start.sh script launches both processes and exits if either one dies, which is a practical choice for Spaces-style hosting.


🧱 Container Build Configuration

Dockerfile

FROM python:3.11-slim

WORKDIR /app

RUN apt-get update && \
    apt-get install -y --no-install-recommends git-lfs build-essential && \
    rm -rf /var/lib/apt/lists/*

COPY . /app

RUN pip install --no-cache-dir -r requirements.txt

RUN chmod +x /app/start.sh

EXPOSE 7860

CMD ["/bin/bash", "/app/start.sh"]

What the image does

Step Meaning
Base image python:3.11-slim for a small Python runtime
Working directory /app
System packages Installs git-lfs and build-essential
Source copy Copies the full repository into the image
Python deps Installs requirements.txt
Entrypoint Runs /app/start.sh
Public port Exposes 7860

Why git-lfs is installed

The project stores model artifacts in the repository and the image prepares for Git LFS-backed assets if needed. That is a practical safeguard for Hugging Face-style deployment and larger model files.

⚠️ WARNING: The container copies the full repository into the image. Keep .dockerignore tight so notebooks, caches, and other unnecessary artifacts do not bloat the build context.


▶️ Startup Process

start.sh

#!/usr/bin/env bash
set -e

FRONTEND_PORT="${PORT:-7860}"
BACKEND_PORT=8000

uvicorn api.backend:app --host 0.0.0.0 --port ${BACKEND_PORT} &
UVICORN_PID=$!

gunicorn app:app --bind 0.0.0.0:${FRONTEND_PORT} --workers 1 &
GUNICORN_PID=$!

wait -n ${UVICORN_PID} ${GUNICORN_PID}
EXIT_CODE=$?
kill ${UVICORN_PID} ${GUNICORN_PID} 2>/dev/null || true
exit ${EXIT_CODE}

Runtime behavior

Process Command Port Role
Backend uvicorn api.backend:app 8000 FastAPI inference and GitHub automation
Frontend gunicorn app:app 7860 or PORT Flask UI host

Why this pattern works

The two-process startup lets the app serve a browser UI while also keeping the model API alive for local proxying, Hugging Face traffic, and workflow automation.

graph TD
    A[Container Start] --> B[start.sh]
    B --> C[uvicorn api.backend:app :8000]
    B --> D[gunicorn app:app :7860 or PORT]
    C --> E[FastAPI endpoints ready]
    D --> F[Flask UI ready]
    E --> G[Browser on Hugging Face Spaces]
    F --> G
Loading

📦 Python Dependencies

requirements.txt

Package Purpose
fastapi API server for inference and automation
flask Frontend app host
uvicorn[standard] ASGI server for FastAPI
httpx Async GitHub and API calls
requests Flask-side proxy requests
transformers DistilBERT model and tokenizer
torch Neural network runtime
numpy Numeric utilities for post-processing
gunicorn Production WSGI server for Flask
pydantic Request/response schema validation

Deployment implication

The dependency set is intentionally minimal and focused on serving, not training. That keeps the production container leaner than the notebook environment.


📁 Build Context Filtering

.dockerignore

__pycache__
*.pyc
*.pyo
*.pyd

venv/
.venv/
env/

.git/
.gitignore

.ipynb_checkpoints/

*.pt
!pr_classifier.pt
*.bin
*.h5
*.ckpt

node_modules/

dist/
build/

.cache/

Why these rules matter

Ignore rule Why it exists
venv/, .venv/, env/ Prevent local virtual environments from being copied into the image
.ipynb_checkpoints/ Remove notebook artifacts
*.pt with !pr_classifier.pt Exclude large checkpoints except the production model artifact
*.bin, *.h5, *.ckpt Exclude alternate model artifacts not used in deployment
node_modules/, dist/, build/ Exclude frontend build outputs and dependency trees that are not needed here

💡 NOTE: The exception !pr_classifier.pt is important. It keeps the production model checkpoint in the build context while excluding other large model files.


🔐 Environment Variables and Secrets

Project environment contract

The repository already exposes the local environment shape in src/.env.example, and the deployment runtime should extend that with any hosting-specific variables.

Required / recommended variables

Variable Required Used by Purpose Example
FLASK_SECRET_KEY Recommended Flask Session and cookie signing random secret
API_BASE Required for local proxying Flask Base URL of the FastAPI service http://localhost:8000
PORT Provided by host Hugging Face Spaces / container runtime External port for the Flask service 7860
GitHub token User-provided secret Frontend + FastAPI + n8n Read/write GitHub access for private repos and label write-back PAT or GitHub App token

Source-side environment example

FLASK_SECRET_KEY=<your-secret-key>
API_BASE=http://localhost:8000

Secret handling guidance

Secret Where to store Why
GitHub PAT / App token Browser session storage for interactive UI; n8n credentials for automation; never in source control Needed for private repo access and write-back
Flask secret key Environment variable Protects Flask session and signed cookies
n8n webhook secret n8n credentials or secrets manager Helps validate or protect the automation webhook

⚠️ WARNING: Never commit GitHub tokens into the repository or into the Docker image. Treat them as runtime secrets only.


🐳 Hugging Face Spaces Deployment

The repository README states that the app is deployed on Hugging Face Spaces, which is consistent with the Docker-based runtime and port 7860 exposure.

What Spaces needs from the container

Requirement How this repository satisfies it
Single public port EXPOSE 7860 and FRONTEND_PORT="${PORT:-7860}"
Deterministic startup CMD ["/bin/bash", "/app/start.sh"]
Model availability models/pr_classifier.pt included in the repo build context
API availability FastAPI started inside the same container
UI availability Flask started inside the same container

Operational implication

The Flask UI is the public entry point, but it depends on the FastAPI process running inside the same container. That means a failure in either process makes the full app unhealthy.


🔄 Deployment Topology

sequenceDiagram
    autonumber
    participant HF as Hugging Face Spaces
    participant C as Docker Container
    participant F as Flask :7860
    participant API as FastAPI :8000
    participant GH as GitHub API

    HF->>C: Start container from Dockerfile
    C->>F: Launch gunicorn app:app
    C->>API: Launch uvicorn api.backend:app
    UI->>F: Open web app in browser
    F->>API: Forward analysis request
    API->>GH: Fetch or write GitHub data when needed
    GH-->>API: JSON response
    API-->>F: Prediction / action result
    F-->>UI: Rendered UI update
Loading

🧪 Validation and Runtime Health

The backend exposes a health endpoint:

Field Value
Endpoint GET /health
Output status, device, token_loaded
Use case Container liveness check and quick service verification

This is useful during deployment checks because the application has two internal processes and a model that must load correctly before the UI is fully usable.


✅ Deployment Summary

The production deployment is a compact Dockerized two-process application:

  • Python 3.11 slim base image,
  • Flask UI on the public port,
  • FastAPI on an internal port,
  • a production model checkpoint copied into the image,
  • and runtime secrets provided through environment variables or credential stores.

That setup is practical for Hugging Face Spaces and consistent with the repository’s actual startup scripts.