Melika Kheirieh commited on
Commit
3c2f1c5
·
1 Parent(s): dc45a1d

feat(docker): add full-stack setup with FastAPI + Gradio and healthcheck

Browse files
Files changed (3) hide show
  1. Dockerfile +31 -53
  2. README.md +3 -4
  3. demo/app.py +6 -2
Dockerfile CHANGED
@@ -1,63 +1,41 @@
1
- # ---------- Stage 1: Build wheels ----------
2
- FROM python:3.12-slim AS builder
3
-
4
- ENV PIP_NO_CACHE_DIR=1 \
5
- PYTHONDONTWRITEBYTECODE=1 \
6
- PYTHONUNBUFFERED=1
7
-
8
- WORKDIR /build
9
-
10
- # If you truly need to compile deps, keep build-essential.
11
- # If you use psycopg[binary], you can safely drop build-essential.
12
- RUN apt-get update && apt-get install -y --no-install-recommends \
13
- build-essential \
14
- && rm -rf /var/lib/apt/lists/*
15
-
16
- COPY requirements.txt .
17
- RUN pip install --upgrade pip && \
18
- pip wheel --wheel-dir /wheels -r requirements.txt
19
-
20
- # ---------- Stage 2: Runtime image ----------
21
- FROM python:3.12-slim AS runtime
22
-
23
- ENV PIP_NO_CACHE_DIR=1 \
24
- PYTHONDONTWRITEBYTECODE=1 \
25
- PYTHONUNBUFFERED=1 \
26
- PYTHONPATH=/app
27
 
28
  WORKDIR /app
 
 
29
 
30
- # HTTPS certs for outbound calls (LLM proxies, etc.)
31
- RUN apt-get update && apt-get install -y --no-install-recommends \
32
- ca-certificates \
33
- && rm -rf /var/lib/apt/lists/*
34
-
35
- # Create a non-root user
36
- RUN useradd -m appuser
37
-
38
- # Wheels
39
- COPY --from=builder /wheels /wheels
40
  COPY requirements.txt .
41
- RUN pip install --no-cache-dir --find-links=/wheels -r requirements.txt && \
42
- rm -rf /wheels
43
 
44
- # App code
45
  COPY . .
46
- # Allow non-root writes if app writes logs/db files
47
- RUN chown -R appuser:appuser /app
48
 
49
  # ---------- Metadata & Healthcheck ----------
50
- LABEL org.opencontainers.image.title="nl2sql-copilot" \
51
- org.opencontainers.image.description="Modular Text-to-SQL Copilot (FastAPI)" \
52
- org.opencontainers.image.source="https://github.com/melika-kheirieh/nl2sql-copilot" \
53
- org.opencontainers.image.authors="melika.kheirieh" \
54
- org.opencontainers.image.licenses="MIT"
55
-
56
- HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
57
- CMD python -c "import urllib.request, sys; \
58
- sys.exit(0) if urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=2).getcode() == 200 else sys.exit(1)"
59
-
60
- USER appuser
 
 
 
 
 
 
 
 
 
 
61
  EXPOSE 8000
62
 
63
- CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers --workers ${UVICORN_WORKERS:-1}"]
 
 
1
+ # ---------- Base ----------
2
+ FROM python:3.12-slim AS base
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
  WORKDIR /app
5
+ ENV PYTHONUNBUFFERED=1 \
6
+ PYTHONDONTWRITEBYTECODE=1
7
 
8
+ # ---------- Install dependencies ----------
 
 
 
 
 
 
 
 
 
9
  COPY requirements.txt .
10
+ RUN pip install --no-cache-dir -r requirements.txt \
11
+ && pip install --no-cache-dir supervisor
12
 
13
+ # ---------- Copy source ----------
14
  COPY . .
 
 
15
 
16
  # ---------- Metadata & Healthcheck ----------
17
+ LABEL maintainer="melika kheirieh"
18
+ LABEL description="NL2SQL Copilot full stack (FastAPI + Gradio)"
19
+
20
+ # lightweight healthcheck without curl
21
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
22
+ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/healthz')" || exit 1
23
+
24
+ # ---------- Supervisor config ----------
25
+ RUN echo "[supervisord]" > /etc/supervisord.conf \
26
+ && echo "nodaemon=true" >> /etc/supervisord.conf \
27
+ && echo "" >> /etc/supervisord.conf \
28
+ && echo "[program:fastapi]" >> /etc/supervisord.conf \
29
+ && echo "command=uvicorn main:app --host 0.0.0.0 --port 8000" >> /etc/supervisord.conf \
30
+ && echo "autostart=true" >> /etc/supervisord.conf \
31
+ && echo "" >> /etc/supervisord.conf \
32
+ && echo "[program:gradio]" >> /etc/supervisord.conf \
33
+ && echo "command=python app.py" >> /etc/supervisord.conf \
34
+ && echo "autostart=true" >> /etc/supervisord.conf
35
+
36
+ # ---------- Ports ----------
37
+ EXPOSE 7860
38
  EXPOSE 8000
39
 
40
+ # ---------- Entrypoint ----------
41
+ CMD ["supervisord", "-c", "/etc/supervisord.conf"]
README.md CHANGED
@@ -1,11 +1,10 @@
1
  ---
2
- title: NL2SQL Copilot — Mock Demo
3
  emoji: 🧩
4
  colorFrom: indigo
5
  colorTo: blue
6
- sdk: gradio
7
- app_file: app/main.py
8
- python_version: "3.10"
9
  pinned: false
10
  ---
11
  # 🧩 NL2SQL Copilot
 
1
  ---
2
+ title: NL2SQL Copilot — Full Stack Demo
3
  emoji: 🧩
4
  colorFrom: indigo
5
  colorTo: blue
6
+ sdk: docker
7
+ python_version: "3.12"
 
8
  pinned: false
9
  ---
10
  # 🧩 NL2SQL Copilot
demo/app.py CHANGED
@@ -4,9 +4,13 @@ import os
4
  import json
5
  from pathlib import Path
6
 
 
 
 
 
7
  USE_MOCK = os.environ.get("USE_MOCK", "0") == "1"
8
- API_UPLOAD = "http://localhost:8000/api/v1/nl2sql/upload_db"
9
- API_QUERY = "http://localhost:8000/api/v1/nl2sql"
10
 
11
  HARDCODED_MOCK = {
12
  "sql": "SELECT name, country FROM singer WHERE age > 20;",
 
4
  import json
5
  from pathlib import Path
6
 
7
+ # Prefer internal backend when running inside Docker
8
+ API_HOST = os.getenv("API_HOST", "localhost")
9
+ API_PORT = os.getenv("API_PORT", "8000")
10
+
11
  USE_MOCK = os.environ.get("USE_MOCK", "0") == "1"
12
+ API_UPLOAD = f"http://{API_HOST}:{API_PORT}/api/v1/nl2sql/upload_db"
13
+ API_QUERY = f"http://{API_HOST}:{API_PORT}/api/v1/nl2sql"
14
 
15
  HARDCODED_MOCK = {
16
  "sql": "SELECT name, country FROM singer WHERE age > 20;",