From 0290c6fa17a53e289b6406a4486eb2b5a87a8b55 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Tue, 24 Feb 2026 19:31:57 -0800 Subject: [PATCH] feat: add Docker Compose stack with remote/cpu/single-gpu/dual-gpu profiles Co-Authored-By: Claude Sonnet 4.6 --- .dockerignore | 20 +++++++++ .env.example | 19 +++++++++ .gitignore | 1 + Dockerfile | 24 +++++++++++ compose.yml | 83 +++++++++++++++++++++++++++++++++++++ docker/ollama/entrypoint.sh | 10 +++++ docker/searxng/settings.yml | 8 ++++ requirements.txt | 63 ++++++++++++++++++++++++++++ 8 files changed, 228 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 compose.yml create mode 100755 docker/ollama/entrypoint.sh create mode 100644 docker/searxng/settings.yml create mode 100644 requirements.txt diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..be74e5c --- /dev/null +++ b/.dockerignore @@ -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/ diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..a9bfc0f --- /dev/null +++ b/.env.example @@ -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= diff --git a/.gitignore b/.gitignore index 75174d4..ab1ab8e 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ log/ unsloth_compiled_cache/ data/survey_screenshots/* !data/survey_screenshots/.gitkeep +config/user.yaml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..adc363b --- /dev/null +++ b/Dockerfile @@ -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"] diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..cbd347d --- /dev/null +++ b/compose.yml @@ -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 diff --git a/docker/ollama/entrypoint.sh b/docker/ollama/entrypoint.sh new file mode 100755 index 0000000..7dee3e2 --- /dev/null +++ b/docker/ollama/entrypoint.sh @@ -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 diff --git a/docker/searxng/settings.yml b/docker/searxng/settings.yml new file mode 100644 index 0000000..c416672 --- /dev/null +++ b/docker/searxng/settings.yml @@ -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" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..89158aa --- /dev/null +++ b/requirements.txt @@ -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