Spaces:
Runtime error
Runtime error
GPU speedup
Browse files- .env.example +7 -6
- Dockerfile +1 -1
- README.md +43 -29
- backend/tests/test_api_fetching.py +1 -1
- docker-compose.yml +8 -112
.env.example
CHANGED
|
@@ -3,12 +3,12 @@ API_BASE_URL=http://localhost:8000 # Vite proxy target (api)
|
|
| 3 |
VITE_API_BASE_URL= # empty = use Vite proxy (recommended for `npm run dev` + Docker)
|
| 4 |
VITE_PROXY_TARGET=http://api:8000 # used inside Docker (frontend -> api), ignored on host
|
| 5 |
VITE_API_KEY=replace-with-a-long-random-secret # must match PRECIS_API_KEY (baked into frontend)
|
| 6 |
-
OLLAMA_BASE_URL=http://127.0.0.1:11434 # Ollama's default — compose overrides to http://ollama:11434
|
| 7 |
|
| 8 |
-
#
|
| 9 |
-
#
|
| 10 |
-
#
|
| 11 |
-
|
|
|
|
| 12 |
PRECIS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:8000,http://localhost:7860 # Just front end + api, keep consistent
|
| 13 |
|
| 14 |
# Model addresses
|
|
@@ -19,8 +19,9 @@ DEFAULT_MODEL=phi4-mini:latest
|
|
| 19 |
AVAILABLE_MODELS=phi4-mini:latest,qwen3:4b # Only here so both front and backend have it
|
| 20 |
|
| 21 |
# API stuff
|
| 22 |
-
PRECIS_API_KEY=replace-with-a-long-random-secret # Once the API is actually up, this'll be needed
|
| 23 |
MAX_SUMMARY_TOKENS=120
|
| 24 |
TEMPERATURE=0.2 # Keep low for stability
|
| 25 |
PRECIS_MAX_UPLOAD_BYTES=10485760
|
| 26 |
PRECIS_MAX_TRANSCRIPT_CHARS=250000
|
|
|
|
|
|
| 3 |
VITE_API_BASE_URL= # empty = use Vite proxy (recommended for `npm run dev` + Docker)
|
| 4 |
VITE_PROXY_TARGET=http://api:8000 # used inside Docker (frontend -> api), ignored on host
|
| 5 |
VITE_API_KEY=replace-with-a-long-random-secret # must match PRECIS_API_KEY (baked into frontend)
|
|
|
|
| 6 |
|
| 7 |
+
# Ollama — HOST native (Option A, GPU fast). No Docker Ollama anymore.
|
| 8 |
+
# - For local `uvicorn` / `npm run dev` without Docker: http://127.0.0.1:11434 (host Ollama default)
|
| 9 |
+
# - Inside Docker, `docker-compose.yml` HARD-CODES `http://host.docker.internal:11434` so this value is IGNORED there.
|
| 10 |
+
OLLAMA_BASE_URL=http://127.0.0.1:11434 # Ollama host — keep 127.0.0.1 for local dev
|
| 11 |
+
|
| 12 |
PRECIS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:8000,http://localhost:7860 # Just front end + api, keep consistent
|
| 13 |
|
| 14 |
# Model addresses
|
|
|
|
| 19 |
AVAILABLE_MODELS=phi4-mini:latest,qwen3:4b # Only here so both front and backend have it
|
| 20 |
|
| 21 |
# API stuff
|
| 22 |
+
PRECIS_API_KEY=replace-with-a-long-random-secret # Once the API is actually up, this'll be needed — `openssl rand -hex 32`
|
| 23 |
MAX_SUMMARY_TOKENS=120
|
| 24 |
TEMPERATURE=0.2 # Keep low for stability
|
| 25 |
PRECIS_MAX_UPLOAD_BYTES=10485760
|
| 26 |
PRECIS_MAX_TRANSCRIPT_CHARS=250000
|
| 27 |
+
OLLAMA_KEEP_ALIVE=30m # How long Ollama keeps model in VRAM after use
|
Dockerfile
CHANGED
|
@@ -61,7 +61,7 @@ COPY --from=frontend-builder /app/frontend/dist ./frontend/dist
|
|
| 61 |
EXPOSE 8000 7860
|
| 62 |
|
| 63 |
ENV PORT=8000 \
|
| 64 |
-
OLLAMA_BASE_URL=http://
|
| 65 |
DEFAULT_MODEL=phi4-mini:latest \
|
| 66 |
AVAILABLE_MODELS=phi4-mini:latest \
|
| 67 |
PRECIS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:8000,http://localhost:7860,https://*.hf.space,https://*.huggingface.co
|
|
|
|
| 61 |
EXPOSE 8000 7860
|
| 62 |
|
| 63 |
ENV PORT=8000 \
|
| 64 |
+
OLLAMA_BASE_URL=http://host.docker.internal:11434 \
|
| 65 |
DEFAULT_MODEL=phi4-mini:latest \
|
| 66 |
AVAILABLE_MODELS=phi4-mini:latest \
|
| 67 |
PRECIS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:8000,http://localhost:7860,https://*.hf.space,https://*.huggingface.co
|
README.md
CHANGED
|
@@ -50,16 +50,23 @@ All `/summarize/*` endpoints accept an optional `model` field to override the de
|
|
| 50 |
|
| 51 |
---
|
| 52 |
|
| 53 |
-
## Quick Start (Docker)
|
| 54 |
|
| 55 |
-
**
|
| 56 |
|
| 57 |
> **Python runs inside the `precis` conda environment** — same as your local setup. The `Dockerfile` uses `continuumio/miniconda3` + `environment.yml` to create `conda env precis` (Python 3.11) and installs all deps there; the container's `PATH` points to `/opt/conda/envs/precis/bin`, so `uvicorn` runs from `precis`.
|
| 58 |
|
| 59 |
### 1. Prerequisites
|
| 60 |
|
| 61 |
- **Docker** + **Docker Compose** ([Install Docker Desktop](https://docs.docker.com/get-docker/))
|
| 62 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
### 2. Configure
|
| 65 |
|
|
@@ -71,39 +78,46 @@ cp .env.example .env
|
|
| 71 |
# VITE_API_KEY must match PRECIS_API_KEY so the baked frontend can auth
|
| 72 |
```
|
| 73 |
|
| 74 |
-
> **`.env.example` defaults for Docker:**
|
| 75 |
> ```ini
|
| 76 |
-
> OLLAMA_BASE_URL=http://127.0.0.1:11434 #
|
| 77 |
> DEFAULT_MODEL=phi4-mini:latest
|
| 78 |
-
> AVAILABLE_MODELS=phi4-mini:latest
|
| 79 |
> PRECIS_API_KEY=replace-with-a-long-random-secret
|
| 80 |
> VITE_API_KEY=replace-with-a-long-random-secret
|
| 81 |
> PRECIS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:8000
|
| 82 |
> VITE_API_BASE_URL= # empty = same origin (correct for Docker)
|
|
|
|
| 83 |
> ```
|
| 84 |
|
| 85 |
-
Manually update `.env.example` to match the block above if your copy is older.
|
| 86 |
-
|
| 87 |
### 3. Run
|
| 88 |
|
|
|
|
| 89 |
```bash
|
| 90 |
-
|
|
|
|
|
|
|
| 91 |
```
|
| 92 |
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
|
|
|
|
|
|
| 96 |
|
| 97 |
-
|
|
|
|
|
|
|
| 98 |
|
| 99 |
-
|
|
|
|
|
|
|
| 100 |
|
| 101 |
```bash
|
| 102 |
-
|
| 103 |
# optional extras:
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
docker exec -it precis-ollama ollama list
|
| 107 |
```
|
| 108 |
|
| 109 |
Then refresh http://localhost:5173 — the model selector populates automatically (`GET /models` proxied to `:8000`).
|
|
@@ -112,19 +126,18 @@ Then refresh http://localhost:5173 — the model selector populates automaticall
|
|
| 112 |
|
| 113 |
```bash
|
| 114 |
docker compose up --watch -d # detached with watch
|
| 115 |
-
docker compose logs -f api # tail API logs
|
| 116 |
-
docker compose logs -f ollama
|
| 117 |
docker compose logs -f frontend
|
| 118 |
-
docker compose down # stop
|
| 119 |
-
docker compose down -v # stop + wipe Ollama model cache (only if using named volume)
|
| 120 |
docker compose ps
|
| 121 |
curl http://localhost:8000/health
|
| 122 |
curl http://localhost:8000/status
|
|
|
|
| 123 |
# prod without watch/HMR (static frontend at 8000):
|
| 124 |
-
docker compose -f docker-compose.yml up --build
|
| 125 |
```
|
| 126 |
|
| 127 |
-
#### Single-image run (without compose
|
| 128 |
|
| 129 |
If you just want the API image and already run Ollama natively (`ollama serve` on host):
|
| 130 |
|
|
@@ -132,17 +145,18 @@ If you just want the API image and already run Ollama natively (`ollama serve` o
|
|
| 132 |
docker build -t precis .
|
| 133 |
docker run --rm -p 8000:8000 --env-file .env \
|
| 134 |
-e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
|
|
|
|
| 135 |
precis
|
| 136 |
-
# Windows/Mac: host.docker.internal resolves to host. Linux
|
| 137 |
```
|
| 138 |
|
| 139 |
#### Hugging Face Spaces
|
| 140 |
|
| 141 |
-
`sdk: docker` with `EXPOSE 8000 7860` + `ENV PORT=8000` + `CMD sh -c "uvicorn ... --port ${PORT:-8000}"` means the same image works everywhere: locally `http://localhost:8000` (compose sets `PORT=8000`), on HF Spaces Hugging Face sets `PORT=7860` automatically and the container listens on `7860` with no extra config.
|
| 142 |
|
| 143 |
---
|
| 144 |
|
| 145 |
-
## Manual Development
|
| 146 |
|
| 147 |
Use this if you want hot-reload for the frontend/backend separately. Docker remains the reproducible path.
|
| 148 |
|
|
@@ -151,14 +165,14 @@ Use this if you want hot-reload for the frontend/backend separately. Docker rema
|
|
| 151 |
- **Conda** (Miniconda/Anaconda/Mamba) with env **`precis`** (`conda env create -f environment.yml` / `conda activate precis`) — Python 3.11, same env the Docker image uses
|
| 152 |
- Alternative without conda: **Python** 3.11+ + `pip install -r requirements.txt`
|
| 153 |
- **Node.js** 18+
|
| 154 |
-
- **Ollama** (`ollama serve` to run) + at least one model: `ollama pull phi4-mini:latest`
|
| 155 |
|
| 156 |
### 1. Environment
|
| 157 |
|
| 158 |
```bash
|
| 159 |
cp .env.example .env
|
| 160 |
# set PRECIS_API_KEY, VITE_API_KEY (same value), and for local:
|
| 161 |
-
# OLLAMA_BASE_URL=http://127.0.0.1:11434
|
| 162 |
# VITE_API_BASE_URL=http://localhost:8000 # or leave empty and rely on Vite proxy
|
| 163 |
```
|
| 164 |
|
|
|
|
| 50 |
|
| 51 |
---
|
| 52 |
|
| 53 |
+
## Quick Start (Docker) — Host Ollama, GPU Fast
|
| 54 |
|
| 55 |
+
**Host Ollama (Option A) is now the ONLY supported Docker setup.** No Ollama container, no 2.5GB re-download, no 600% CPU. Docker only runs `api` (FastAPI + baked frontend) + `frontend` (Vite HMR). Ollama runs natively on the host for full GPU speed.
|
| 56 |
|
| 57 |
> **Python runs inside the `precis` conda environment** — same as your local setup. The `Dockerfile` uses `continuumio/miniconda3` + `environment.yml` to create `conda env precis` (Python 3.11) and installs all deps there; the container's `PATH` points to `/opt/conda/envs/precis/bin`, so `uvicorn` runs from `precis`.
|
| 58 |
|
| 59 |
### 1. Prerequisites
|
| 60 |
|
| 61 |
- **Docker** + **Docker Compose** ([Install Docker Desktop](https://docs.docker.com/get-docker/))
|
| 62 |
+
- **Ollama (host, native)** — [Install Ollama](https://ollama.com/download) + at least one model:
|
| 63 |
+
```bash
|
| 64 |
+
ollama pull phi4-mini:latest
|
| 65 |
+
# optional extras:
|
| 66 |
+
ollama pull qwen3:4b
|
| 67 |
+
ollama list
|
| 68 |
+
```
|
| 69 |
+
- That's it. Python (via `precis` conda env) and Node are inside the containers. No local conda/Python/Node needed for Docker path.
|
| 70 |
|
| 71 |
### 2. Configure
|
| 72 |
|
|
|
|
| 78 |
# VITE_API_KEY must match PRECIS_API_KEY so the baked frontend can auth
|
| 79 |
```
|
| 80 |
|
| 81 |
+
> **`.env.example` defaults for Docker (host Ollama):**
|
| 82 |
> ```ini
|
| 83 |
+
> OLLAMA_BASE_URL=http://127.0.0.1:11434 # for local `uvicorn` without Docker; Docker compose hard-codes http://host.docker.internal:11434 (host GPU)
|
| 84 |
> DEFAULT_MODEL=phi4-mini:latest
|
| 85 |
+
> AVAILABLE_MODELS=phi4-mini:latest,qwen3:4b
|
| 86 |
> PRECIS_API_KEY=replace-with-a-long-random-secret
|
| 87 |
> VITE_API_KEY=replace-with-a-long-random-secret
|
| 88 |
> PRECIS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:8000
|
| 89 |
> VITE_API_BASE_URL= # empty = same origin (correct for Docker)
|
| 90 |
+
> # NOTE: OLLAMA_HOST_DIR removed — no Docker Ollama container, no bind mount. Host Ollama uses its native store.
|
| 91 |
> ```
|
| 92 |
|
|
|
|
|
|
|
| 93 |
### 3. Run
|
| 94 |
|
| 95 |
+
**Terminal 1 — keep host Ollama running:**
|
| 96 |
```bash
|
| 97 |
+
# If Ollama was started with default 127.0.0.1 binding and api gets 503, restart host Ollama as:
|
| 98 |
+
# OLLAMA_HOST=0.0.0.0 ollama serve
|
| 99 |
+
ollama serve
|
| 100 |
```
|
| 101 |
|
| 102 |
+
**Terminal 2 — from repo root (use -d so terminal isn't blocked):**
|
| 103 |
+
```bash
|
| 104 |
+
docker compose up --watch -d
|
| 105 |
+
# or without -d if you want logs in this terminal (needs 2nd terminal for other commands)
|
| 106 |
+
```
|
| 107 |
|
| 108 |
+
- First build takes ~4-6 min (multi-stage: Node build + `conda env create -f environment.yml` for `precis` — cached after first build). Subsequent `up --watch -d` takes ~15s (no rebuild).
|
| 109 |
+
- Opens: **http://localhost:5173** (Vite HMR, host Ollama GPU) + API at **http://localhost:8000** (`/docs`, `/health`). With `--watch`, edits to `backend/` and `frontend/` hot-reload automatically.
|
| 110 |
+
- `GET /models` now proxies to **host** Ollama at `http://host.docker.internal:11434` — no `ollama-init` sidecar, no manifest pull. If host has no models, API 503s with `run ollama pull ...`.
|
| 111 |
|
| 112 |
+
#### Pull a model (on HOST, not in Docker)
|
| 113 |
+
|
| 114 |
+
The API will 503 until a model is installed. On **host**:
|
| 115 |
|
| 116 |
```bash
|
| 117 |
+
ollama pull phi4-mini:latest
|
| 118 |
# optional extras:
|
| 119 |
+
ollama pull qwen3:4b
|
| 120 |
+
ollama list
|
|
|
|
| 121 |
```
|
| 122 |
|
| 123 |
Then refresh http://localhost:5173 — the model selector populates automatically (`GET /models` proxied to `:8000`).
|
|
|
|
| 126 |
|
| 127 |
```bash
|
| 128 |
docker compose up --watch -d # detached with watch
|
| 129 |
+
docker compose logs -f api # tail API logs (no ollama container anymore)
|
|
|
|
| 130 |
docker compose logs -f frontend
|
| 131 |
+
docker compose down # stop api+frontend
|
|
|
|
| 132 |
docker compose ps
|
| 133 |
curl http://localhost:8000/health
|
| 134 |
curl http://localhost:8000/status
|
| 135 |
+
curl http://host.docker.internal:11434/api/tags # verify host Ollama reachable from Docker
|
| 136 |
# prod without watch/HMR (static frontend at 8000):
|
| 137 |
+
docker compose -f docker-compose.yml up --build -d
|
| 138 |
```
|
| 139 |
|
| 140 |
+
#### Single-image run (without compose)
|
| 141 |
|
| 142 |
If you just want the API image and already run Ollama natively (`ollama serve` on host):
|
| 143 |
|
|
|
|
| 145 |
docker build -t precis .
|
| 146 |
docker run --rm -p 8000:8000 --env-file .env \
|
| 147 |
-e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
|
| 148 |
+
--add-host=host.docker.internal:host-gateway \
|
| 149 |
precis
|
| 150 |
+
# Windows/Mac: host.docker.internal resolves to host. Linux already adds host-gateway above.
|
| 151 |
```
|
| 152 |
|
| 153 |
#### Hugging Face Spaces
|
| 154 |
|
| 155 |
+
`sdk: docker` with `EXPOSE 8000 7860` + `ENV PORT=8000` + `CMD sh -c "uvicorn ... --port ${PORT:-8000}"` means the same image works everywhere: locally `http://localhost:8000` (compose sets `PORT=8000`), on HF Spaces Hugging Face sets `PORT=7860` automatically and the container listens on `7860` with no extra config. HF Spaces will need its own Ollama or external `OLLAMA_BASE_URL`.
|
| 156 |
|
| 157 |
---
|
| 158 |
|
| 159 |
+
## Manual Development (without Docker)
|
| 160 |
|
| 161 |
Use this if you want hot-reload for the frontend/backend separately. Docker remains the reproducible path.
|
| 162 |
|
|
|
|
| 165 |
- **Conda** (Miniconda/Anaconda/Mamba) with env **`precis`** (`conda env create -f environment.yml` / `conda activate precis`) — Python 3.11, same env the Docker image uses
|
| 166 |
- Alternative without conda: **Python** 3.11+ + `pip install -r requirements.txt`
|
| 167 |
- **Node.js** 18+
|
| 168 |
+
- **Ollama (host, native)** (`ollama serve` to run) + at least one model: `ollama pull phi4-mini:latest`
|
| 169 |
|
| 170 |
### 1. Environment
|
| 171 |
|
| 172 |
```bash
|
| 173 |
cp .env.example .env
|
| 174 |
# set PRECIS_API_KEY, VITE_API_KEY (same value), and for local:
|
| 175 |
+
# OLLAMA_BASE_URL=http://127.0.0.1:11434 (host native)
|
| 176 |
# VITE_API_BASE_URL=http://localhost:8000 # or leave empty and rely on Vite proxy
|
| 177 |
```
|
| 178 |
|
backend/tests/test_api_fetching.py
CHANGED
|
@@ -11,7 +11,7 @@ from pathlib import Path
|
|
| 11 |
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
| 12 |
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "backend"))
|
| 13 |
|
| 14 |
-
os.environ.setdefault("OLLAMA_BASE_URL", "http://
|
| 15 |
os.environ.setdefault("DEFAULT_MODEL", "phi4-mini:latest")
|
| 16 |
os.environ.setdefault("PRECIS_API_KEY", "test-key")
|
| 17 |
os.environ.setdefault("AVAILABLE_MODELS", "phi4-mini:latest,qwen:4b")
|
|
|
|
| 11 |
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
| 12 |
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "backend"))
|
| 13 |
|
| 14 |
+
os.environ.setdefault("OLLAMA_BASE_URL", "http://127.0.0.1:11434")
|
| 15 |
os.environ.setdefault("DEFAULT_MODEL", "phi4-mini:latest")
|
| 16 |
os.environ.setdefault("PRECIS_API_KEY", "test-key")
|
| 17 |
os.environ.setdefault("AVAILABLE_MODELS", "phi4-mini:latest,qwen:4b")
|
docker-compose.yml
CHANGED
|
@@ -1,24 +1,4 @@
|
|
| 1 |
services:
|
| 2 |
-
ollama:
|
| 3 |
-
image: ollama/ollama:latest
|
| 4 |
-
container_name: precis-ollama
|
| 5 |
-
ports:
|
| 6 |
-
- "11434:11434"
|
| 7 |
-
volumes:
|
| 8 |
-
# Single copy — bind mount host Windows folder if OLLAMA_HOST_DIR is set in .env
|
| 9 |
-
# (e.g. OLLAMA_HOST_DIR=C:/Users/varak/.ollama). If unset/empty, falls back to
|
| 10 |
-
# named volume 'ollama_data' (isolated, but faster I/O than Windows bind).
|
| 11 |
-
# Short syntax with fallback: "${VAR:-default}:/target" — quoted for Windows paths.
|
| 12 |
-
- "${OLLAMA_HOST_DIR:-ollama_data}:/root/.ollama"
|
| 13 |
-
restart: unless-stopped
|
| 14 |
-
healthcheck:
|
| 15 |
-
test: ["CMD-SHELL", "ollama list >/dev/null 2>&1 || wget -qO- http://localhost:11434/api/tags >/dev/null 2>&1 || curl -fsS http://localhost:11434/api/tags >/dev/null 2>&1"]
|
| 16 |
-
interval: 15s
|
| 17 |
-
timeout: 5s
|
| 18 |
-
retries: 8
|
| 19 |
-
start_period: 20s
|
| 20 |
-
start_interval: 3s
|
| 21 |
-
|
| 22 |
api:
|
| 23 |
build:
|
| 24 |
context: .
|
|
@@ -35,20 +15,19 @@ services:
|
|
| 35 |
env_file:
|
| 36 |
- .env
|
| 37 |
environment:
|
| 38 |
-
#
|
| 39 |
-
#
|
| 40 |
-
#
|
| 41 |
-
#
|
| 42 |
PORT: ${PORT:-8000}
|
| 43 |
-
OLLAMA_BASE_URL: http://
|
| 44 |
DEFAULT_MODEL: ${DEFAULT_MODEL:-phi4-mini:latest}
|
| 45 |
AVAILABLE_MODELS: ${AVAILABLE_MODELS:-phi4-mini:latest}
|
| 46 |
PRECIS_ALLOWED_ORIGINS: ${PRECIS_ALLOWED_ORIGINS:-http://localhost:5173,http://localhost:8000,http://localhost:7860,https://*.hf.space,https://*.huggingface.co}
|
| 47 |
PRECIS_API_KEY: ${PRECIS_API_KEY:?PRECIS_API_KEY must be set in .env}
|
| 48 |
OLLAMA_KEEP_ALIVE: ${OLLAMA_KEEP_ALIVE:-30m}
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
condition: service_healthy
|
| 52 |
volumes:
|
| 53 |
# Mount .env read-only so config.py hot-reload isn't needed — container restarts pick up changes
|
| 54 |
- type: bind
|
|
@@ -63,87 +42,4 @@ services:
|
|
| 63 |
retries: 5
|
| 64 |
start_period: 20s
|
| 65 |
|
| 66 |
-
|
| 67 |
-
image: ollama/ollama:latest
|
| 68 |
-
container_name: precis-ollama-init
|
| 69 |
-
volumes:
|
| 70 |
-
- "${OLLAMA_HOST_DIR:-ollama_data}:/root/.ollama"
|
| 71 |
-
env_file:
|
| 72 |
-
- .env
|
| 73 |
-
environment:
|
| 74 |
-
OLLAMA_HOST: http://ollama:11434
|
| 75 |
-
depends_on:
|
| 76 |
-
ollama:
|
| 77 |
-
condition: service_healthy
|
| 78 |
-
entrypoint: sh
|
| 79 |
-
command:
|
| 80 |
-
- -c
|
| 81 |
-
- |
|
| 82 |
-
set -e
|
| 83 |
-
echo "ollama-init: checking local models (host bind: ${OLLAMA_HOST_DIR:-<named volume ollama_data>})"
|
| 84 |
-
echo "AVAILABLE_MODELS=$$AVAILABLE_MODELS DEFAULT_MODEL=$$DEFAULT_MODEL"
|
| 85 |
-
echo "OLLAMA_HOST=$$OLLAMA_HOST OLLAMA_HOST_DIR fallback: ${OLLAMA_HOST_DIR:-ollama_data}"
|
| 86 |
-
# Wait for Ollama API to actually be ready (healthcheck may pass earlier)
|
| 87 |
-
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
|
| 88 |
-
if curl -fsS http://ollama:11434/api/tags >/dev/null 2>&1; then
|
| 89 |
-
echo "ollama API ready after $$i tries"
|
| 90 |
-
break
|
| 91 |
-
fi
|
| 92 |
-
echo "waiting for ollama API... $$i"
|
| 93 |
-
sleep 2
|
| 94 |
-
done
|
| 95 |
-
echo "existing models (ollama list):"
|
| 96 |
-
ollama list || true
|
| 97 |
-
echo "existing models (API /api/tags):"
|
| 98 |
-
curl -fsS http://ollama:11434/api/tags 2>/dev/null || echo "API tags fetch failed"
|
| 99 |
-
# ── IDEMPOTENT PULL: only pull if not already present ──
|
| 100 |
-
# Fixes "pulling 2.5GB raw" when host bind already has models.
|
| 101 |
-
# We re-query inside the loop (not cached) because Ollama may still be
|
| 102 |
-
# importing the bind-mounted blobs on first start.
|
| 103 |
-
for m in $$(echo "$$AVAILABLE_MODELS,$$DEFAULT_MODEL" | tr ',' ' ' | tr -s ' ' '\n' | sort -u); do
|
| 104 |
-
m=$$(echo "$$m" | xargs)
|
| 105 |
-
[ -z "$$m" ] && continue
|
| 106 |
-
echo "--- checking $$m ---"
|
| 107 |
-
# Fresh check each iteration via both CLI and API (CLI may lag on Windows bind)
|
| 108 |
-
if ollama list 2>/dev/null | awk 'NR>1{print $$1}' | grep -qx "$$m"; then
|
| 109 |
-
echo "-> $$m already installed (ollama list exact) — skipping pull"
|
| 110 |
-
continue
|
| 111 |
-
fi
|
| 112 |
-
if ollama list 2>/dev/null | awk 'NR>1{print $$1}' | grep -q "^$${m%%:*}:"; then
|
| 113 |
-
echo "-> $$m already installed (ollama list prefix) — skipping pull"
|
| 114 |
-
continue
|
| 115 |
-
fi
|
| 116 |
-
if curl -fsS http://ollama:11434/api/tags 2>/dev/null | grep -q "\"name\":\"$$m\""; then
|
| 117 |
-
echo "-> $$m already installed (API exact) — skipping pull"
|
| 118 |
-
continue
|
| 119 |
-
fi
|
| 120 |
-
# Check without tag: "phi4-mini" should match "phi4-mini:latest"
|
| 121 |
-
base="$${m%%:*}"
|
| 122 |
-
if curl -fsS http://ollama:11434/api/tags 2>/dev/null | grep -q "\"name\":\"$$base:"; then
|
| 123 |
-
echo "-> $$m already installed (API prefix $$base) — skipping pull"
|
| 124 |
-
continue
|
| 125 |
-
fi
|
| 126 |
-
if ollama show "$$m" >/dev/null 2>&1; then
|
| 127 |
-
echo "-> $$m show succeeded — skipping pull"
|
| 128 |
-
continue
|
| 129 |
-
fi
|
| 130 |
-
# Also check filesystem directly (Windows bind may not be reflected in list yet)
|
| 131 |
-
# Ollama stores manifests at /root/.ollama/models/manifests/registry.ollama.ai/library/<name>/<tag>
|
| 132 |
-
manifest_path="/root/.ollama/models/manifests/registry.ollama.ai/library/$$base"
|
| 133 |
-
if [ -d "$$manifest_path" ]; then
|
| 134 |
-
echo "-> $$m manifest dir exists at $$manifest_path — skipping pull (filesystem hit)"
|
| 135 |
-
continue
|
| 136 |
-
fi
|
| 137 |
-
echo "-> ollama pull $$m (not found locally, will download)"
|
| 138 |
-
# If this still shows "pulling manifest 2.5GB", it means the model truly wasn't
|
| 139 |
-
# on the host bind. To use host's models, ensure .env has:
|
| 140 |
-
# OLLAMA_HOST_DIR=C:/Users/YOURNAME/.ollama (forward slashes, no trailing slash)
|
| 141 |
-
# and that host `ollama list` shows the model. Fallback named volume is empty on first run.
|
| 142 |
-
ollama pull "$$m" || echo "pull failed for $$m (may already exist or name wrong)"
|
| 143 |
-
done
|
| 144 |
-
echo "ollama-init done:"
|
| 145 |
-
ollama list || curl -fsS http://ollama:11434/api/tags || true
|
| 146 |
-
restart: "no"
|
| 147 |
-
|
| 148 |
-
volumes:
|
| 149 |
-
ollama_data: {}
|
|
|
|
| 1 |
services:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
api:
|
| 3 |
build:
|
| 4 |
context: .
|
|
|
|
| 15 |
env_file:
|
| 16 |
- .env
|
| 17 |
environment:
|
| 18 |
+
# Host Ollama (Option A) — blazing fast GPU, no 2.5GB re-download.
|
| 19 |
+
# api inside Docker talks to host via host.docker.internal:11434.
|
| 20 |
+
# Host must have `ollama serve` running (see README). On Windows Docker Desktop this resolves automatically.
|
| 21 |
+
# If host Ollama was started with default 127.0.0.1 binding, set OLLAMA_HOST=0.0.0.0 on host before `ollama serve`.
|
| 22 |
PORT: ${PORT:-8000}
|
| 23 |
+
OLLAMA_BASE_URL: http://host.docker.internal:11434
|
| 24 |
DEFAULT_MODEL: ${DEFAULT_MODEL:-phi4-mini:latest}
|
| 25 |
AVAILABLE_MODELS: ${AVAILABLE_MODELS:-phi4-mini:latest}
|
| 26 |
PRECIS_ALLOWED_ORIGINS: ${PRECIS_ALLOWED_ORIGINS:-http://localhost:5173,http://localhost:8000,http://localhost:7860,https://*.hf.space,https://*.huggingface.co}
|
| 27 |
PRECIS_API_KEY: ${PRECIS_API_KEY:?PRECIS_API_KEY must be set in .env}
|
| 28 |
OLLAMA_KEEP_ALIVE: ${OLLAMA_KEEP_ALIVE:-30m}
|
| 29 |
+
extra_hosts:
|
| 30 |
+
- "host.docker.internal:host-gateway"
|
|
|
|
| 31 |
volumes:
|
| 32 |
# Mount .env read-only so config.py hot-reload isn't needed — container restarts pick up changes
|
| 33 |
- type: bind
|
|
|
|
| 42 |
retries: 5
|
| 43 |
start_period: 20s
|
| 44 |
|
| 45 |
+
volumes: {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|