Skip to content
Merged
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
7 changes: 4 additions & 3 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ jobs:
with:
python-version: "3.11"

- name: Install uv
uses: astral-sh/setup-uv@v6

- name: Install linter
run: |
python -m pip install --upgrade pip
pip install ruff
run: uv pip install --system ruff

- name: Run linter
run: |
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ jobs:
with:
python-version: "3.11"

- name: Install uv
uses: astral-sh/setup-uv@v6

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
run: uv pip install --system -r requirements.txt

- name: Run tests
env:
Expand Down
36 changes: 23 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help init fireform build up down logs logs-app logs-ollama shell pull-model test clean super-clean migrate migration
.PHONY: help init fireform build up down logs logs-app logs-ollama shell pull-model test clean super-clean status ready-banner sync

COMPOSE = docker compose -f docker/dev/compose.yml --env-file docker/.env.dev
ENV_DEV = docker/.env.dev
Expand All @@ -22,6 +22,8 @@ help:
@echo "make build - Build Docker images"
@echo "make up - Start all containers (detached)"
@echo "make down - Stop all containers"
@echo "make sync - Fast-install new requirements.txt deps into running app (no rebuild)"
@echo "make status - Show compact container health summary"
@echo "make logs - Stream all container logs"
@echo "make logs-app - Stream app container logs"
@echo "make logs-ollama - Stream Ollama container logs"
Expand All @@ -46,30 +48,38 @@ init:
*) echo "Run 'make fireform' when ready." ;; \
esac

fireform: build up
@printf "Waiting for Ollama to be ready..."
@until $(COMPOSE) exec -T ollama ollama list > /dev/null 2>&1; do \
printf '.'; sleep 2; \
done
@echo " ready."
fireform:
@$(COMPOSE) up -d --build
@if $(COMPOSE) exec -T ollama ollama list 2>/dev/null | grep -q "^$(OLLAMA_MODEL)"; then \
echo " Model $(OLLAMA_MODEL) already pulled."; \
else \
echo " Pulling $(OLLAMA_MODEL)..."; \
$(COMPOSE) exec -T ollama ollama pull $(OLLAMA_MODEL); \
fi
@echo ""
@echo "FireForm is ready!"
@echo " API: http://localhost:8000"
@echo " API Docs: http://localhost:8000/docs"
@echo ""
@echo "Run 'make logs' to view live logs, 'make down' to stop."
@$(MAKE) --no-print-directory ready-banner

build:
@$(COMPOSE) build

up:
@$(COMPOSE) up -d
@$(MAKE) --no-print-directory ready-banner

# Fast path for "I added a package": install the delta into the running container
# (no image rebuild, no 1.6GB layer re-export). uv installs only what's missing in
sync:
@$(COMPOSE) exec -T app sh -c "UV_TORCH_BACKEND=cpu uv pip install --system -r requirements.txt"

status:
@$(COMPOSE) ps --format 'table {{.Service}}\t{{.Status}}'

ready-banner:
@echo ""
@echo "FireForm is ready!"
@echo " API: http://localhost:8000"
@echo " API Docs: http://localhost:8000/docs"
@echo ""
@echo "Run 'make logs' to view live logs, 'make down' to stop."

down:
@$(COMPOSE) down --remove-orphans
Expand Down
19 changes: 14 additions & 5 deletions docker/dev/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,30 @@ FROM python:3.11-slim

WORKDIR /app

# Use apt cache mount to speed up system package installation across builds
# apt cache mounts keep downloaded .debs across builds
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt \
apt-get update && apt-get install -y \
curl \
libgl1 \
libglib2.0-0 \
libxcb1
libxcb1 \
libpq-dev \
build-essential \
g++

COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv

COPY requirements.txt .

# Use pip cache mount so it remembers downloaded wheels
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
RUN --mount=type=cache,target=/root/.cache/uv \
UV_TORCH_BACKEND=cpu \
uv pip install --system -r requirements.txt

# Bake a hash of the deps the image was built with. The entrypoint compares this
# against the live (bind-mounted) requirements.txt to decide whether to reinstall.
RUN sha256sum requirements.txt | cut -d' ' -f1 > /opt/req_hash

ENV PYTHONPATH=/app

Expand Down
6 changes: 6 additions & 0 deletions docker/dev/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ services:
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
start_interval: 1s

ollama:
image: ollama/ollama:latest
Expand All @@ -33,6 +35,7 @@ services:
timeout: 5s
retries: 5
start_period: 30s
start_interval: 2s

whisper:
image: onerahmet/openai-whisper-asr-webservice:latest
Expand All @@ -53,6 +56,7 @@ services:
timeout: 5s
retries: 5
start_period: 60s
start_interval: 3s

redis:
image: redis:7-alpine
Expand All @@ -68,6 +72,8 @@ services:
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
start_interval: 1s

app:
build:
Expand Down
19 changes: 17 additions & 2 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
#!/bin/sh
set -e

# Ensure data directories exist (volumes may be empty on first run)
mkdir -p /data/uploads

# Run DB migrations / init before starting the server
# Reinstall deps only when the live requirements.txt differs from what the image
# was built with. The image bakes the hash at /opt/req_hash; in dev the live file
# comes from the bind mount. Matching hash => deps already baked in => skip (instant).
BAKED_HASH=$(cat /opt/req_hash 2>/dev/null || echo "none")
LIVE_HASH=$(sha256sum requirements.txt 2>/dev/null | cut -d' ' -f1 || echo "unknown")

if [ "$BAKED_HASH" = "$LIVE_HASH" ]; then
echo "[entrypoint] dependencies up to date — skipping install"
else
echo "[entrypoint] requirements.txt changed since image build — syncing deps..."
if command -v uv > /dev/null 2>&1; then
UV_TORCH_BACKEND=cpu uv pip install --system -r requirements.txt
else
pip install -r requirements.txt
fi
fi

python3 -m app.db.init_db

exec "$@"
26 changes: 19 additions & 7 deletions docker/prod/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
# ---- builder ----
FROM python:3.11-slim AS builder

WORKDIR /build
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential g++ libpq-dev && \
rm -rf /var/lib/apt/lists/*

COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv

WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

RUN --mount=type=cache,target=/root/.cache/uv \
UV_TORCH_BACKEND=cpu \
uv pip install --system -r requirements.txt

# ---- runtime ----
FROM python:3.11-slim

WORKDIR /app

RUN apt-get update && apt-get install -y \
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
libgl1 \
libglib2.0-0 \
libxcb1 \
&& rm -rf /var/lib/apt/lists/*
libpq5 && \
rm -rf /var/lib/apt/lists/*

COPY --from=builder /install /usr/local
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin

# Copy only app code, not data/ temp/ tests/ docs/ etc.
COPY app/ ./app/
COPY requirements.txt .
COPY docker/entrypoint.sh /entrypoint.sh

# Bake deps hash so the entrypoint can skip the redundant install when unchanged.
RUN sha256sum requirements.txt | cut -d' ' -f1 > /opt/req_hash

ENV PYTHONPATH=/app

# Data dirs created here; actual storage comes from mounted volumes at runtime.
RUN mkdir -p /data/db /data/uploads && chmod +x /entrypoint.sh

EXPOSE 8000
Expand Down
6 changes: 5 additions & 1 deletion scripts/setup-dockers-env.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#!/bin/bash

source venv/bin/activate
pip install -r requirements.txt
if command -v uv > /dev/null 2>&1; then
uv pip install -r requirements.txt
else
pip install -r requirements.txt
fi