Merge pull request #39 from scub-france/feature/docker-split-local-remote
Feature/docker split local remote
This commit is contained in:
commit
b34b56aba2
14 changed files with 207 additions and 58 deletions
10
.env.example
10
.env.example
|
|
@ -1,3 +1,13 @@
|
||||||
|
# Conversion engine: "local" (in-process Docling) or "remote" (Docling Serve)
|
||||||
|
# CONVERSION_ENGINE=local
|
||||||
|
|
||||||
|
# Docling Serve settings (remote mode only)
|
||||||
|
# DOCLING_SERVE_URL=http://localhost:5001
|
||||||
|
# DOCLING_SERVE_API_KEY=
|
||||||
|
|
||||||
|
# Max seconds per conversion (default: 600)
|
||||||
|
# CONVERSION_TIMEOUT=600
|
||||||
|
|
||||||
# CORS (comma-separated origins, only needed for custom deployments)
|
# CORS (comma-separated origins, only needed for custom deployments)
|
||||||
# CORS_ORIGINS=http://localhost:3000,https://your-domain.com
|
# CORS_ORIGINS=http://localhost:3000,https://your-domain.com
|
||||||
|
|
||||||
|
|
|
||||||
17
.github/workflows/release.yml
vendored
17
.github/workflows/release.yml
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
name: Release Docker Image
|
name: Release Docker Images
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|
@ -11,12 +11,16 @@ env:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Build & push Docker image
|
name: Build & push — ${{ matrix.target }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
target: [remote, local]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|
@ -28,15 +32,15 @@ jobs:
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Extract version from tag
|
- name: Docker metadata
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}},suffix=-${{ matrix.target }}
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}},suffix=-${{ matrix.target }}
|
||||||
type=raw,value=latest
|
type=raw,value=latest-${{ matrix.target }}
|
||||||
|
|
||||||
- name: Extract version from tag
|
- name: Extract version from tag
|
||||||
id: version
|
id: version
|
||||||
|
|
@ -45,6 +49,7 @@ jobs:
|
||||||
- uses: docker/build-push-action@v6
|
- uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
target: ${{ matrix.target }}
|
||||||
push: true
|
push: true
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
build-args: APP_VERSION=${{ steps.version.outputs.value }}
|
build-args: APP_VERSION=${{ steps.version.outputs.value }}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,13 @@ Thank you for your interest in contributing to Docling Studio! This guide will h
|
||||||
```bash
|
```bash
|
||||||
cd document-parser
|
cd document-parser
|
||||||
python -m venv .venv && source .venv/bin/activate
|
python -m venv .venv && source .venv/bin/activate
|
||||||
|
|
||||||
|
# Remote mode (lightweight — delegates to Docling Serve)
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Local mode (full — runs Docling in-process)
|
||||||
|
pip install -r requirements-local.txt
|
||||||
|
|
||||||
pip install ruff pytest pytest-asyncio httpx # dev tools
|
pip install ruff pytest pytest-asyncio httpx # dev tools
|
||||||
uvicorn main:app --reload --port 8000
|
uvicorn main:app --reload --port 8000
|
||||||
```
|
```
|
||||||
|
|
@ -129,11 +135,16 @@ We use [Semantic Versioning](https://semver.org/): `MAJOR.MINOR.PATCH`.
|
||||||
|
|
||||||
### Docker Image Tags
|
### Docker Image Tags
|
||||||
|
|
||||||
|
Each release produces two image variants:
|
||||||
|
|
||||||
| Tag | Description |
|
| Tag | Description |
|
||||||
|-----|-------------|
|
|-----|-------------|
|
||||||
| `X.Y.Z` | Exact version |
|
| `X.Y.Z-remote` | Exact version — lightweight (Docling Serve) |
|
||||||
| `X.Y` | Latest patch of this minor |
|
| `X.Y.Z-local` | Exact version — full (in-process Docling) |
|
||||||
| `latest` | Latest stable release |
|
| `X.Y-remote` | Latest patch of this minor — lightweight |
|
||||||
|
| `X.Y-local` | Latest patch of this minor — full |
|
||||||
|
| `latest-remote` | Latest stable — lightweight |
|
||||||
|
| `latest-local` | Latest stable — full |
|
||||||
|
|
||||||
### Hotfix
|
### Hotfix
|
||||||
|
|
||||||
|
|
|
||||||
37
Dockerfile
37
Dockerfile
|
|
@ -1,10 +1,10 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Docling Studio — single-image build (frontend + backend)
|
# Docling Studio — single-image build (frontend + backend, multi-target)
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# docker build -t docling-studio .
|
# docker build --target remote -t docling-studio:remote .
|
||||||
# docker run -p 3000:3000 docling-studio
|
# docker build --target local -t docling-studio:local .
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
# --- Stage 1: Build frontend assets ---
|
# --- Stage 1: Build frontend assets ---
|
||||||
|
|
@ -18,21 +18,19 @@ RUN npm ci
|
||||||
COPY frontend/ .
|
COPY frontend/ .
|
||||||
RUN VITE_APP_VERSION=${APP_VERSION} npm run build
|
RUN VITE_APP_VERSION=${APP_VERSION} npm run build
|
||||||
|
|
||||||
# --- Stage 2: Runtime (Python + Nginx) ---
|
# --- Stage 2: Base runtime (Python + Nginx) ---
|
||||||
FROM python:3.12-slim
|
FROM python:3.12-slim AS base
|
||||||
|
|
||||||
ARG APP_VERSION=dev
|
ARG APP_VERSION=dev
|
||||||
ENV APP_VERSION=${APP_VERSION}
|
ENV APP_VERSION=${APP_VERSION}
|
||||||
|
|
||||||
# System deps: poppler (pdf2image), nginx, and OpenCV runtime libs
|
# System deps: poppler (pdf2image), nginx
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
poppler-utils \
|
poppler-utils \
|
||||||
libgl1 \
|
|
||||||
libglib2.0-0 \
|
|
||||||
nginx \
|
nginx \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Python deps
|
# Python deps (common)
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY document-parser/requirements.txt .
|
COPY document-parser/requirements.txt .
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
@ -57,5 +55,24 @@ ENV DB_PATH=/app/data/docling_studio.db
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
# nginx needs to run as root for port binding, then drops to appuser for uvicorn
|
|
||||||
CMD ["sh", "-c", "nginx && exec su appuser -c 'uvicorn main:app --host 127.0.0.1 --port 8000'"]
|
CMD ["sh", "-c", "nginx && exec su appuser -c 'uvicorn main:app --host 127.0.0.1 --port 8000'"]
|
||||||
|
|
||||||
|
# --- Remote: lightweight, delegates to Docling Serve ---
|
||||||
|
FROM base AS remote
|
||||||
|
ENV CONVERSION_ENGINE=remote
|
||||||
|
|
||||||
|
# --- Local: full Docling in-process ---
|
||||||
|
FROM base AS local
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libgl1 \
|
||||||
|
libglib2.0-0 \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY document-parser/requirements-local.txt .
|
||||||
|
RUN pip install --no-cache-dir torch torchvision --index-url https://download.pytorch.org/whl/cpu \
|
||||||
|
&& pip install --no-cache-dir -r requirements-local.txt
|
||||||
|
|
||||||
|
RUN chown -R appuser:appuser /app \
|
||||||
|
&& chown -R appuser:appuser /usr/local/lib/python3.12/site-packages/rapidocr/models
|
||||||
|
ENV CONVERSION_ENGINE=local
|
||||||
|
|
|
||||||
48
README.md
48
README.md
|
|
@ -85,22 +85,42 @@ frontend/src/
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
### Docker (fastest)
|
Docling Studio ships two Docker image variants:
|
||||||
|
|
||||||
|
| Variant | Image tag | Size | Description |
|
||||||
|
|---------|-----------|------|-------------|
|
||||||
|
| **remote** | `latest-remote` | ~270 MB | Lightweight — delegates to an external [Docling Serve](https://github.com/DS4SD/docling-serve) instance |
|
||||||
|
| **local** | `latest-local` | ~1.9 GB | Full — runs Docling in-process, CPU-only (downloads ML models on first run) |
|
||||||
|
|
||||||
|
### Docker — remote mode (fastest)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -p 3000:3000 ghcr.io/scub-france/docling-studio:latest
|
docker run -p 3000:3000 \
|
||||||
|
-e DOCLING_SERVE_URL=http://your-docling-serve:5001 \
|
||||||
|
ghcr.io/scub-france/docling-studio:latest-remote
|
||||||
```
|
```
|
||||||
|
|
||||||
Open [http://localhost:3000](http://localhost:3000)
|
### Docker — local mode (self-contained)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 3000:3000 ghcr.io/scub-france/docling-studio:latest-local
|
||||||
|
```
|
||||||
|
|
||||||
> **Note:** The first analysis takes longer as Docling downloads its ML models (~400 MB). Subsequent runs are fast.
|
> **Note:** The first analysis takes longer as Docling downloads its ML models (~400 MB). Subsequent runs are fast.
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000)
|
||||||
|
|
||||||
### Docker Compose (for development)
|
### Docker Compose (for development)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/scub-france/Docling-Studio.git
|
git clone https://github.com/scub-france/Docling-Studio.git
|
||||||
cd Docling-Studio
|
cd Docling-Studio
|
||||||
|
|
||||||
|
# Local mode (default)
|
||||||
docker compose up --build
|
docker compose up --build
|
||||||
|
|
||||||
|
# Remote mode
|
||||||
|
CONVERSION_MODE=remote DOCLING_SERVE_URL=http://your-docling-serve:5001 docker compose up --build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Local Development
|
### Local Development
|
||||||
|
|
@ -109,7 +129,13 @@ docker compose up --build
|
||||||
```bash
|
```bash
|
||||||
cd document-parser
|
cd document-parser
|
||||||
python -m venv .venv && source .venv/bin/activate
|
python -m venv .venv && source .venv/bin/activate
|
||||||
|
|
||||||
|
# Remote mode (lightweight)
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Local mode (with Docling)
|
||||||
|
pip install -r requirements-local.txt
|
||||||
|
|
||||||
uvicorn main:app --reload --port 8000
|
uvicorn main:app --reload --port 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -156,6 +182,9 @@ All configuration is done via environment variables. See [`.env.example`](.env.e
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
|
| `CONVERSION_ENGINE` | `local` | `local` (in-process Docling) or `remote` (Docling Serve) |
|
||||||
|
| `DOCLING_SERVE_URL` | `http://localhost:5001` | Docling Serve endpoint (remote mode only) |
|
||||||
|
| `DOCLING_SERVE_API_KEY` | — | API key for Docling Serve (optional) |
|
||||||
| `CORS_ORIGINS` | `http://localhost:3000,...` | CORS allowed origins (comma-separated) |
|
| `CORS_ORIGINS` | `http://localhost:3000,...` | CORS allowed origins (comma-separated) |
|
||||||
| `UPLOAD_DIR` | `./uploads` | File storage directory |
|
| `UPLOAD_DIR` | `./uploads` | File storage directory |
|
||||||
| `DB_PATH` | `./data/docling_studio.db` | SQLite database path |
|
| `DB_PATH` | `./data/docling_studio.db` | SQLite database path |
|
||||||
|
|
@ -168,7 +197,7 @@ GitHub Actions pipelines (see [`.github/workflows/`](.github/workflows/)):
|
||||||
| Workflow | Trigger | What it does |
|
| Workflow | Trigger | What it does |
|
||||||
|----------|---------|--------------|
|
|----------|---------|--------------|
|
||||||
| **CI** | push to `main`, pull requests | Lint + type check + Backend tests + Frontend tests + build |
|
| **CI** | push to `main`, pull requests | Lint + type check + Backend tests + Frontend tests + build |
|
||||||
| **Release** | push tag `v*` | Build & push multi-arch Docker image to `ghcr.io` |
|
| **Release** | push tag `v*` | Build & push **two** multi-arch Docker images (`remote` + `local`) to `ghcr.io` |
|
||||||
| **Docs** | push to `main` (docs changes) | Build & deploy MkDocs to GitHub Pages |
|
| **Docs** | push to `main` (docs changes) | Build & deploy MkDocs to GitHub Pages |
|
||||||
|
|
||||||
We follow [Semantic Versioning](https://semver.org/) with a simplified Git Flow. See [CONTRIBUTING.md](CONTRIBUTING.md) for the full release process.
|
We follow [Semantic Versioning](https://semver.org/) with a simplified Git Flow. See [CONTRIBUTING.md](CONTRIBUTING.md) for the full release process.
|
||||||
|
|
@ -183,12 +212,11 @@ We follow [Semantic Versioning](https://semver.org/) with a simplified Git Flow.
|
||||||
|
|
||||||
### Docker Desktop settings
|
### Docker Desktop settings
|
||||||
|
|
||||||
The document parser needs **at least 4 GB of RAM**:
|
| | Remote image | Local image |
|
||||||
|
|---|---|---|
|
||||||
| Resource | Minimum | Recommended |
|
| **Image size** | ~270 MB | ~1.9 GB |
|
||||||
|----------|---------|-------------|
|
| **Memory** | 2 GB | 6 GB (recommended 8 GB+) |
|
||||||
| Memory | 6 GB | 8 GB+ |
|
| **CPUs** | 2 | 4 (recommended 8+) |
|
||||||
| CPUs | 4 | 8+ |
|
|
||||||
|
|
||||||
### Platform support
|
### Platform support
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ services:
|
||||||
document-parser:
|
document-parser:
|
||||||
build:
|
build:
|
||||||
context: ./document-parser
|
context: ./document-parser
|
||||||
|
target: ${CONVERSION_MODE:-local}
|
||||||
expose:
|
expose:
|
||||||
- "8000"
|
- "8000"
|
||||||
volumes:
|
volumes:
|
||||||
|
|
@ -9,6 +10,8 @@ services:
|
||||||
- db_data:/app/data
|
- db_data:/app/data
|
||||||
environment:
|
environment:
|
||||||
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000,http://localhost:5173}
|
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000,http://localhost:5173}
|
||||||
|
DOCLING_SERVE_URL: ${DOCLING_SERVE_URL:-}
|
||||||
|
DOCLING_SERVE_API_KEY: ${DOCLING_SERVE_API_KEY:-}
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,13 @@
|
||||||
```bash
|
```bash
|
||||||
cd document-parser
|
cd document-parser
|
||||||
python -m venv .venv && source .venv/bin/activate
|
python -m venv .venv && source .venv/bin/activate
|
||||||
|
|
||||||
|
# Remote mode (lightweight — delegates to Docling Serve)
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Local mode (full — runs Docling in-process)
|
||||||
|
pip install -r requirements-local.txt
|
||||||
|
|
||||||
pip install ruff pytest pytest-asyncio httpx
|
pip install ruff pytest pytest-asyncio httpx
|
||||||
uvicorn main:app --reload --port 8000
|
uvicorn main:app --reload --port 8000
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,67 @@
|
||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
## Docker Compose (recommended)
|
Docling Studio ships two Docker image variants:
|
||||||
|
|
||||||
|
| Variant | Image tag | Size | Description |
|
||||||
|
|---------|-----------|------|-------------|
|
||||||
|
| **remote** | `latest-remote` | ~270 MB | Lightweight — delegates to an external [Docling Serve](https://github.com/DS4SD/docling-serve) instance |
|
||||||
|
| **local** | `latest-local` | ~1.9 GB | Full — runs Docling in-process, CPU-only (downloads ML models on first run) |
|
||||||
|
|
||||||
|
## Docker — remote mode (fastest)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 3000:3000 \
|
||||||
|
-e DOCLING_SERVE_URL=http://your-docling-serve:5001 \
|
||||||
|
ghcr.io/scub-france/docling-studio:latest-remote
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker — local mode (self-contained)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 3000:3000 ghcr.io/scub-france/docling-studio:latest-local
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** The first analysis takes longer as Docling downloads its ML models (~400 MB). Subsequent runs are fast.
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000).
|
||||||
|
|
||||||
|
## Docker Compose (recommended for development)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/scub-france/Docling-Studio.git
|
git clone https://github.com/scub-france/Docling-Studio.git
|
||||||
cd Docling-Studio
|
cd Docling-Studio
|
||||||
docker compose up --build
|
|
||||||
```
|
|
||||||
|
|
||||||
Open [http://localhost:3000](http://localhost:3000).
|
# Local mode (default)
|
||||||
|
docker compose up --build
|
||||||
|
|
||||||
|
# Remote mode
|
||||||
|
CONVERSION_MODE=remote DOCLING_SERVE_URL=http://your-docling-serve:5001 docker compose up --build
|
||||||
|
```
|
||||||
|
|
||||||
## Local Development
|
## Local Development
|
||||||
|
|
||||||
### Backend (Python 3.12+)
|
=== "Backend (Python 3.12+)"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd document-parser
|
cd document-parser
|
||||||
python -m venv .venv && source .venv/bin/activate
|
python -m venv .venv && source .venv/bin/activate
|
||||||
pip install -r requirements.txt
|
|
||||||
uvicorn main:app --reload --port 8000
|
|
||||||
```
|
|
||||||
|
|
||||||
### Frontend (Node 20+)
|
# Remote mode (lightweight)
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
```bash
|
# Local mode (with Docling)
|
||||||
cd frontend
|
pip install -r requirements-local.txt
|
||||||
npm install
|
|
||||||
npm run dev
|
uvicorn main:app --reload --port 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
=== "Frontend (Node 20+)"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
The frontend runs on `http://localhost:3000` and proxies API calls to `http://localhost:8000`.
|
The frontend runs on `http://localhost:3000` and proxies API calls to `http://localhost:8000`.
|
||||||
|
|
||||||
|
|
@ -71,6 +105,9 @@ All configuration is done via environment variables:
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
|
| `CONVERSION_ENGINE` | `local` | `local` (in-process Docling) or `remote` (Docling Serve) |
|
||||||
|
| `DOCLING_SERVE_URL` | `http://localhost:5001` | Docling Serve endpoint (remote mode only) |
|
||||||
|
| `DOCLING_SERVE_API_KEY` | — | API key for Docling Serve (optional) |
|
||||||
| `CORS_ORIGINS` | `http://localhost:3000,...` | CORS allowed origins |
|
| `CORS_ORIGINS` | `http://localhost:3000,...` | CORS allowed origins |
|
||||||
| `UPLOAD_DIR` | `./uploads` | File storage directory |
|
| `UPLOAD_DIR` | `./uploads` | File storage directory |
|
||||||
| `DB_PATH` | `./data/docling_studio.db` | SQLite database path |
|
| `DB_PATH` | `./data/docling_studio.db` | SQLite database path |
|
||||||
|
|
@ -78,9 +115,10 @@ All configuration is done via environment variables:
|
||||||
|
|
||||||
## System Requirements
|
## System Requirements
|
||||||
|
|
||||||
| Resource | Minimum | Recommended |
|
| | Remote image | Local image |
|
||||||
|----------|---------|-------------|
|
|---|---|---|
|
||||||
| Memory | 6 GB | 8 GB+ |
|
| **Image size** | ~270 MB | ~1.9 GB |
|
||||||
| CPUs | 4 | 8+ |
|
| **Memory** | 2 GB | 6 GB (recommended 8 GB+) |
|
||||||
|
| **CPUs** | 2 | 4 (recommended 8+) |
|
||||||
|
|
||||||
All Docker images are multi-arch (`linux/amd64` + `linux/arm64`). No GPU required.
|
All Docker images are multi-arch (`linux/amd64` + `linux/arm64`). No GPU required.
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
FROM python:3.12-slim
|
# syntax=docker/dockerfile:1
|
||||||
|
# =============================================================================
|
||||||
|
# Docling Studio — backend image (multi-target: remote / local)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# docker build --target remote -t docling-studio-backend:remote .
|
||||||
|
# docker build --target local -t docling-studio-backend:local .
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# --- Base: common deps for both targets ---
|
||||||
|
FROM python:3.12-slim AS base
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
poppler-utils \
|
poppler-utils \
|
||||||
libgl1 \
|
|
||||||
libglib2.0-0 \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
@ -24,3 +32,25 @@ ENV DB_PATH=/app/data/docling_studio.db
|
||||||
|
|
||||||
USER appuser
|
USER appuser
|
||||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
|
|
||||||
|
# --- Remote: lightweight, delegates to Docling Serve ---
|
||||||
|
FROM base AS remote
|
||||||
|
ENV CONVERSION_ENGINE=remote
|
||||||
|
|
||||||
|
# --- Local: full Docling in-process ---
|
||||||
|
FROM base AS local
|
||||||
|
|
||||||
|
USER root
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libgl1 \
|
||||||
|
libglib2.0-0 \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY requirements-local.txt .
|
||||||
|
RUN pip install --no-cache-dir torch torchvision --index-url https://download.pytorch.org/whl/cpu \
|
||||||
|
&& pip install --no-cache-dir -r requirements-local.txt
|
||||||
|
|
||||||
|
RUN chown -R appuser:appuser /app \
|
||||||
|
&& chown -R appuser:appuser /usr/local/lib/python3.12/site-packages/rapidocr/models
|
||||||
|
USER appuser
|
||||||
|
ENV CONVERSION_ENGINE=local
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ app.include_router(documents_router)
|
||||||
app.include_router(analyses_router)
|
app.include_router(analyses_router)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/api/health")
|
||||||
def health():
|
def health():
|
||||||
"""Health check endpoint."""
|
"""Health check endpoint."""
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
3
document-parser/requirements-local.txt
Normal file
3
document-parser/requirements-local.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
-r requirements.txt
|
||||||
|
docling>=2.80.0,<3.0.0
|
||||||
|
docling-core>=2.0.0,<3.0.0
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
docling>=2.80.0,<3.0.0
|
|
||||||
docling-core>=2.0.0,<3.0.0
|
|
||||||
fastapi>=0.115.0,<1.0.0
|
fastapi>=0.115.0,<1.0.0
|
||||||
uvicorn[standard]>=0.32.0,<1.0.0
|
uvicorn[standard]>=0.32.0,<1.0.0
|
||||||
python-multipart>=0.0.12
|
python-multipart>=0.0.12
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ def mock_analysis_service(client):
|
||||||
|
|
||||||
class TestHealthEndpoint:
|
class TestHealthEndpoint:
|
||||||
def test_health(self, client):
|
def test_health(self, client):
|
||||||
resp = client.get("/health")
|
resp = client.get("/api/health")
|
||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
assert data["status"] == "ok"
|
assert data["status"] == "ok"
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ export const useFeatureFlagStore = defineStore('feature-flags', () => {
|
||||||
|
|
||||||
async function load(): Promise<void> {
|
async function load(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const data = await apiFetch<HealthResponse>('/health')
|
const data = await apiFetch<HealthResponse>('/api/health')
|
||||||
engine.value = data.engine
|
engine.value = data.engine
|
||||||
loaded.value = true
|
loaded.value = true
|
||||||
error.value = null
|
error.value = null
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue