feat: add Docker Compose stack with remote/cpu/single-gpu/dual-gpu profiles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
pyr0ball 2026-02-24 19:31:57 -08:00
parent a90be958f0
commit e22f233010
8 changed files with 228 additions and 0 deletions

20
.dockerignore Normal file
View file

@ -0,0 +1,20 @@
.git
__pycache__
*.pyc
*.pyo
staging.db
config/user.yaml
config/notion.yaml
config/email.yaml
config/tokens.yaml
config/craigslist.yaml
.streamlit.pid
.streamlit.log
aihawk/
docs/
tests/
.env
data/
log/
unsloth_compiled_cache/
resume_matcher/

19
.env.example Normal file
View file

@ -0,0 +1,19 @@
# .env.example — copy to .env
# Auto-generated by the setup wizard, or fill in manually.
# NEVER commit .env to git.
STREAMLIT_PORT=8501
OLLAMA_PORT=11434
VLLM_PORT=8000
SEARXNG_PORT=8888
DOCS_DIR=~/Documents/JobSearch
OLLAMA_MODELS_DIR=~/models/ollama
VLLM_MODELS_DIR=~/models/vllm
VLLM_MODEL=Ouro-1.4B
OLLAMA_DEFAULT_MODEL=llama3.2:3b
# API keys (required for remote profile)
ANTHROPIC_API_KEY=
OPENAI_COMPAT_URL=
OPENAI_COMPAT_KEY=

1
.gitignore vendored
View file

@ -18,3 +18,4 @@ log/
unsloth_compiled_cache/ unsloth_compiled_cache/
data/survey_screenshots/* data/survey_screenshots/*
!data/survey_screenshots/.gitkeep !data/survey_screenshots/.gitkeep
config/user.yaml

24
Dockerfile Normal file
View file

@ -0,0 +1,24 @@
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
# System deps for companyScraper (beautifulsoup4, fake-useragent, lxml) and PDF gen
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libffi-dev curl \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Bundle companyScraper (company research web scraper)
COPY scrapers/ /app/scrapers/
COPY . .
EXPOSE 8501
CMD ["streamlit", "run", "app/app.py", \
"--server.port=8501", \
"--server.headless=true", \
"--server.fileWatcherType=none"]

83
compose.yml Normal file
View file

@ -0,0 +1,83 @@
# compose.yml — Peregrine by Circuit Forge LLC
# Profiles: remote | cpu | single-gpu | dual-gpu
services:
app:
build: .
ports:
- "${STREAMLIT_PORT:-8501}:8501"
volumes:
- ./config:/app/config
- ./data:/app/data
- ${DOCS_DIR:-~/Documents/JobSearch}:/docs
environment:
- STAGING_DB=/app/data/staging.db
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
- OPENAI_COMPAT_URL=${OPENAI_COMPAT_URL:-}
- OPENAI_COMPAT_KEY=${OPENAI_COMPAT_KEY:-}
depends_on:
searxng:
condition: service_healthy
restart: unless-stopped
searxng:
image: searxng/searxng:latest
ports:
- "${SEARXNG_PORT:-8888}:8080"
volumes:
- ./docker/searxng:/etc/searxng:ro
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/"]
interval: 10s
timeout: 5s
retries: 3
restart: unless-stopped
ollama:
image: ollama/ollama:latest
ports:
- "${OLLAMA_PORT:-11434}:11434"
volumes:
- ${OLLAMA_MODELS_DIR:-~/models/ollama}:/root/.ollama
- ./docker/ollama/entrypoint.sh:/entrypoint.sh
environment:
- OLLAMA_MODELS=/root/.ollama
- DEFAULT_OLLAMA_MODEL=${OLLAMA_DEFAULT_MODEL:-llama3.2:3b}
entrypoint: ["/bin/bash", "/entrypoint.sh"]
profiles: [cpu, single-gpu, dual-gpu]
restart: unless-stopped
ollama-gpu:
extends:
service: ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
device_ids: ["0"]
capabilities: [gpu]
profiles: [single-gpu, dual-gpu]
vllm:
image: vllm/vllm-openai:latest
ports:
- "${VLLM_PORT:-8000}:8000"
volumes:
- ${VLLM_MODELS_DIR:-~/models/vllm}:/models
command: >
--model /models/${VLLM_MODEL:-Ouro-1.4B}
--trust-remote-code
--max-model-len 4096
--gpu-memory-utilization 0.75
--enforce-eager
--max-num-seqs 8
deploy:
resources:
reservations:
devices:
- driver: nvidia
device_ids: ["1"]
capabilities: [gpu]
profiles: [dual-gpu]
restart: unless-stopped

10
docker/ollama/entrypoint.sh Executable file
View file

@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Start Ollama server and pull a default model if none are present
ollama serve &
sleep 5
if [ -z "$(ollama list 2>/dev/null | tail -n +2)" ]; then
MODEL="${DEFAULT_OLLAMA_MODEL:-llama3.2:3b}"
echo "No models found — pulling $MODEL..."
ollama pull "$MODEL"
fi
wait

View file

@ -0,0 +1,8 @@
use_default_settings: true
search:
formats:
- html
- json
server:
secret_key: "change-me-in-production"
bind_address: "0.0.0.0:8080"

63
requirements.txt Normal file
View file

@ -0,0 +1,63 @@
# requirements.txt — Peregrine by Circuit Forge LLC
# Extracted from environment.yml for Docker pip installs
# Keep in sync with environment.yml
# ── Web UI ────────────────────────────────────────────────────────────────
streamlit>=1.35
watchdog
reportlab>=4.0
pandas>=2.0
pyarrow
streamlit-paste-button>=0.1.0
# ── Job scraping ──────────────────────────────────────────────────────────
python-jobspy>=1.1
playwright
selenium
undetected-chromedriver
webdriver-manager
beautifulsoup4
requests
curl_cffi
fake-useragent
# ── LLM / AI backends ─────────────────────────────────────────────────────
openai>=1.0
anthropic>=0.80
ollama
langchain>=0.2
langchain-openai
langchain-anthropic
langchain-ollama
langchain-community
langchain-google-genai
google-generativeai
tiktoken
# ── Resume matching ───────────────────────────────────────────────────────
scikit-learn>=1.3
rapidfuzz
lib-resume-builder-aihawk
# ── Notion integration ────────────────────────────────────────────────────
notion-client>=3.0
# ── Document handling ─────────────────────────────────────────────────────
pypdf
pdfminer-six
pyyaml>=6.0
python-dotenv
# ── Utilities ─────────────────────────────────────────────────────────────
sqlalchemy
tqdm
loguru
rich
tenacity
httpx
# ── Testing ───────────────────────────────────────────────────────────────
pytest>=9.0
pytest-cov
pytest-mock
lxml