mirror of
https://github.com/docling-project/docling-serve.git
synced 2025-11-29 08:33:50 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4fed2d965 | ||
|
|
b0360d723b | ||
|
|
4adc0dfa79 | ||
|
|
40c7f1bcd3 | ||
|
|
d64a2a974a | ||
|
|
0d4545a65a | ||
|
|
fe98338239 | ||
|
|
b844ce737e | ||
|
|
27fdd7b85a | ||
|
|
1df62adf01 | ||
|
|
e5449472b2 | ||
|
|
81f0a8ddf8 | ||
|
|
a69cc867f5 |
56
.github/scripts/release.sh
vendored
56
.github/scripts/release.sh
vendored
@@ -3,32 +3,68 @@
|
||||
set -e # trigger failure on error - do not remove!
|
||||
set -x # display command on output
|
||||
|
||||
## debug
|
||||
# TARGET_VERSION="1.2.x"
|
||||
|
||||
if [ -z "${TARGET_VERSION}" ]; then
|
||||
>&2 echo "No TARGET_VERSION specified"
|
||||
exit 1
|
||||
fi
|
||||
CHGLOG_FILE="${CHGLOG_FILE:-CHANGELOG.md}"
|
||||
|
||||
# update package version
|
||||
# Update package version
|
||||
uvx --from=toml-cli toml set --toml-path=pyproject.toml project.version "${TARGET_VERSION}"
|
||||
uv lock --upgrade-package docling-serve
|
||||
|
||||
# collect release notes
|
||||
# Extract all docling packages and versions from uv.lock
|
||||
DOCVERSIONS=$(uvx --with toml python3 - <<'PY'
|
||||
import toml
|
||||
data = toml.load("uv.lock")
|
||||
for pkg in data.get("package", []):
|
||||
if pkg["name"].startswith("docling"):
|
||||
print(f"{pkg['name']} {pkg['version']}")
|
||||
PY
|
||||
)
|
||||
|
||||
# Format docling versions list without trailing newline
|
||||
DOCLING_VERSIONS="### Docling libraries included in this release:"
|
||||
while IFS= read -r line; do
|
||||
DOCLING_VERSIONS+="
|
||||
- $line"
|
||||
done <<< "$DOCVERSIONS"
|
||||
|
||||
# Collect release notes
|
||||
REL_NOTES=$(mktemp)
|
||||
uv run --no-sync semantic-release changelog --unreleased >> "${REL_NOTES}"
|
||||
|
||||
# update changelog
|
||||
# Strip trailing blank lines from release notes and append docling versions
|
||||
{
|
||||
sed -e :a -e '/^\n*$/{$d;N;};/\n$/ba' "${REL_NOTES}"
|
||||
printf "\n"
|
||||
printf "%s" "${DOCLING_VERSIONS}"
|
||||
printf "\n"
|
||||
} > "${REL_NOTES}.tmp" && mv "${REL_NOTES}.tmp" "${REL_NOTES}"
|
||||
|
||||
# Update changelog
|
||||
TMP_CHGLOG=$(mktemp)
|
||||
TARGET_TAG_NAME="v${TARGET_VERSION}"
|
||||
RELEASE_URL="$(gh repo view --json url -q ".url")/releases/tag/${TARGET_TAG_NAME}"
|
||||
printf "## [${TARGET_TAG_NAME}](${RELEASE_URL}) - $(date -Idate)\n\n" >> "${TMP_CHGLOG}"
|
||||
cat "${REL_NOTES}" >> "${TMP_CHGLOG}"
|
||||
if [ -f "${CHGLOG_FILE}" ]; then
|
||||
printf "\n" | cat - "${CHGLOG_FILE}" >> "${TMP_CHGLOG}"
|
||||
fi
|
||||
## debug
|
||||
#RELEASE_URL="myrepo/releases/tag/${TARGET_TAG_NAME}"
|
||||
|
||||
# Strip leading blank lines from existing changelog to avoid multiple blank lines when appending
|
||||
EXISTING_CL=$(sed -e :a -e '/^\n*$/{$d;N;};/\n$/ba' "${CHGLOG_FILE}")
|
||||
|
||||
{
|
||||
printf "## [${TARGET_TAG_NAME}](${RELEASE_URL}) - $(date -Idate)\n\n"
|
||||
cat "${REL_NOTES}"
|
||||
printf "\n"
|
||||
printf "%s\n" "${EXISTING_CL}"
|
||||
} >> "${TMP_CHGLOG}"
|
||||
|
||||
mv "${TMP_CHGLOG}" "${CHGLOG_FILE}"
|
||||
|
||||
# push changes
|
||||
# Push changes
|
||||
git config --global user.name 'github-actions[bot]'
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
git add pyproject.toml uv.lock "${CHGLOG_FILE}"
|
||||
@@ -36,5 +72,5 @@ COMMIT_MSG="chore: bump version to ${TARGET_VERSION} [skip ci]"
|
||||
git commit -m "${COMMIT_MSG}"
|
||||
git push origin main
|
||||
|
||||
# create GitHub release (incl. Git tag)
|
||||
# Create GitHub release (incl. Git tag)
|
||||
gh release create "${TARGET_TAG_NAME}" -F "${REL_NOTES}"
|
||||
|
||||
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
actionlint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Download actionlint
|
||||
id: get_actionlint
|
||||
run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
|
||||
|
||||
4
.github/workflows/cd.yml
vendored
4
.github/workflows/cd.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
outputs:
|
||||
TARGET_TAG_V: ${{ steps.version_check.outputs.TRGT_VERSION }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for fetching tags, required for semantic-release
|
||||
- name: Install uv and set the python version
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
with:
|
||||
app-id: ${{ vars.CI_APP_ID }}
|
||||
private-key: ${{ secrets.CI_PRIVATE_KEY }}
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
fetch-depth: 0 # for fetching tags, required for semantic-release
|
||||
|
||||
2
.github/workflows/job-build.yml
vendored
2
.github/workflows/job-build.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
matrix:
|
||||
python-version: ['3.12']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Install uv and set the python version
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
|
||||
18
.github/workflows/job-checks.yml
vendored
18
.github/workflows/job-checks.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
matrix:
|
||||
python-version: ['3.12']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Install uv and set the python version
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
@@ -58,11 +58,11 @@ jobs:
|
||||
- name: Create the server
|
||||
run: .venv/bin/python -c 'from docling_serve.app import create_app; create_app()'
|
||||
|
||||
markdown-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: markdownlint-cli2-action
|
||||
uses: DavidAnson/markdownlint-cli2-action@v16
|
||||
with:
|
||||
globs: "**/*.md"
|
||||
# markdown-lint:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v5
|
||||
# - name: markdownlint-cli2-action
|
||||
# uses: DavidAnson/markdownlint-cli2-action@v16
|
||||
# with:
|
||||
# globs: "**/*.md"
|
||||
|
||||
109
.github/workflows/job-image.yml
vendored
109
.github/workflows/job-image.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
df -h
|
||||
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Log in to the GHCR container image registry
|
||||
if: ${{ inputs.publish }}
|
||||
@@ -88,19 +88,114 @@ jobs:
|
||||
with:
|
||||
images: ${{ env.GHCR_REGISTRY }}/${{ inputs.ghcr_image_name }}
|
||||
|
||||
# # Local test
|
||||
# - name: Set metadata outputs for local testing ## comment out Free up space, Log in to cr, Cache Docker, Extract metadata, and quay blocks and run act
|
||||
# id: ghcr_meta
|
||||
# run: |
|
||||
# echo "tags=ghcr.io/docling-project/docling-serve:pr-123" >> $GITHUB_OUTPUT
|
||||
# echo "labels=org.opencontainers.image.source=https://github.com/docling-project/docling-serve" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build and push image to ghcr.io
|
||||
id: ghcr_push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: ${{ inputs.publish }}
|
||||
push: ${{ inputs.publish }} # set 'false' for local test
|
||||
tags: ${{ steps.ghcr_meta.outputs.tags }}
|
||||
labels: ${{ steps.ghcr_meta.outputs.labels }}
|
||||
platforms: ${{ inputs.platforms}}
|
||||
platforms: ${{ inputs.platforms }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
file: Containerfile
|
||||
build-args: ${{ inputs.build_args }}
|
||||
##
|
||||
## This stage runs after the build, so it leverages all build cache
|
||||
##
|
||||
- name: Export built image for testing
|
||||
id: ghcr_export_built_image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
load: true
|
||||
tags: ${{ env.GHCR_REGISTRY }}/${{ inputs.ghcr_image_name }}:${{ github.sha }}-test
|
||||
labels: |
|
||||
org.opencontainers.image.title=docling-serve
|
||||
org.opencontainers.image.test=true
|
||||
platforms: linux/amd64 # when 'load' is true, we can't use a list ${{ inputs.platforms }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
file: Containerfile
|
||||
build-args: ${{ inputs.build_args }}
|
||||
|
||||
- name: Test image
|
||||
if: steps.ghcr_export_built_image.outcome == 'success'
|
||||
run: |
|
||||
set -e
|
||||
|
||||
IMAGE_TAG="${{ env.GHCR_REGISTRY }}/${{ inputs.ghcr_image_name }}:${{ github.sha }}-test"
|
||||
echo "Testing local image: $IMAGE_TAG"
|
||||
|
||||
# Remove existing container if any
|
||||
docker rm -f docling-serve-test-container 2>/dev/null || true
|
||||
|
||||
echo "Starting container..."
|
||||
docker run -d -p 5001:5001 --name docling-serve-test-container "$IMAGE_TAG"
|
||||
|
||||
echo "Waiting 15s for container to boot..."
|
||||
sleep 15
|
||||
|
||||
# Health check
|
||||
echo "Checking service health..."
|
||||
for i in {1..20}; do
|
||||
HEALTH_RESPONSE=$(curl -s http://localhost:5001/health || true)
|
||||
echo "Health check response [$i]: $HEALTH_RESPONSE"
|
||||
|
||||
if echo "$HEALTH_RESPONSE" | grep -q '"status":"ok"'; then
|
||||
echo "Service is healthy!"
|
||||
|
||||
# Install pytest and dependencies
|
||||
echo "Installing pytest and dependencies..."
|
||||
pip install uv
|
||||
uv venv --allow-existing
|
||||
source .venv/bin/activate
|
||||
uv sync --all-extras --no-extra flash-attn
|
||||
|
||||
# Run pytest tests
|
||||
echo "Running tests..."
|
||||
# Test import
|
||||
python -c 'from docling_serve.app import create_app; create_app()'
|
||||
|
||||
# Run pytest and check result directly
|
||||
if ! pytest -sv -k "test_convert_url" tests/test_1-url-async.py \
|
||||
--disable-warnings; then
|
||||
echo "Tests failed!"
|
||||
docker logs docling-serve-test-container
|
||||
docker rm -f docling-serve-test-container
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Tests passed successfully!"
|
||||
break
|
||||
else
|
||||
echo "Waiting for service... [$i/20]"
|
||||
sleep 3
|
||||
fi
|
||||
done
|
||||
|
||||
# Final health check if service didn't pass earlier
|
||||
if ! echo "$HEALTH_RESPONSE" | grep -q '"status":"ok"'; then
|
||||
echo "Service did not become healthy in time."
|
||||
docker logs docling-serve-test-container
|
||||
docker rm -f docling-serve-test-container
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
echo "Cleaning up test container..."
|
||||
docker rm -f docling-serve-test-container
|
||||
echo "Cleaning up test image..."
|
||||
docker rmi "$IMAGE_TAG"
|
||||
|
||||
- name: Generate artifact attestation
|
||||
if: ${{ inputs.publish }}
|
||||
@@ -120,7 +215,7 @@ jobs:
|
||||
- name: Build and push image to quay.io
|
||||
if: ${{ inputs.publish }}
|
||||
# id: push-serve-cpu-quay
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: ${{ inputs.publish }}
|
||||
@@ -131,10 +226,6 @@ jobs:
|
||||
cache-to: type=gha,mode=max
|
||||
file: Containerfile
|
||||
build-args: ${{ inputs.build_args }}
|
||||
|
||||
# - name: Inspect the image details
|
||||
# run: |
|
||||
# echo "${{ steps.ghcr_push.outputs.metadata }}"
|
||||
|
||||
- name: Remove Local Docker Images
|
||||
run: |
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -445,4 +445,7 @@ pip-selfcheck.json
|
||||
.action-lint
|
||||
.markdown-lint
|
||||
|
||||
cookies.txt
|
||||
cookies.txt
|
||||
|
||||
# Examples
|
||||
/examples/splitted_pdf/*
|
||||
@@ -7,12 +7,12 @@ repos:
|
||||
- id: ruff-format
|
||||
name: "Ruff formatter"
|
||||
args: [--config=pyproject.toml]
|
||||
files: '^(docling_serve|tests).*\.(py|ipynb)$'
|
||||
files: '^(docling_serve|tests|examples).*\.(py|ipynb)$'
|
||||
# Run the Ruff linter.
|
||||
- id: ruff
|
||||
name: "Ruff linter"
|
||||
args: [--exit-non-zero-on-fix, --fix, --config=pyproject.toml]
|
||||
files: '^(docling_serve|tests).*\.(py|ipynb)$'
|
||||
files: '^(docling_serve|tests|examples).*\.(py|ipynb)$'
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: system
|
||||
|
||||
43
CHANGELOG.md
43
CHANGELOG.md
@@ -1,3 +1,46 @@
|
||||
## [v1.4.1](https://github.com/docling-project/docling-serve/releases/tag/v1.4.1) - 2025-09-08
|
||||
|
||||
### Fix
|
||||
|
||||
* Trigger fix after ci fixes ([#355](https://github.com/docling-project/docling-serve/issues/355)) ([`b0360d7`](https://github.com/docling-project/docling-serve/commit/b0360d723bff202dcf44a25a3173ec1995945fc2))
|
||||
|
||||
### Docling libraries included in this release:
|
||||
- docling 2.46.0
|
||||
- docling 2.51.0
|
||||
- docling-core 2.47.0
|
||||
- docling-ibm-models 3.9.1
|
||||
- docling-jobkit 1.4.1
|
||||
- docling-mcp 1.2.0
|
||||
- docling-parse 4.4.0
|
||||
- docling-serve 1.4.1
|
||||
|
||||
## [v1.4.0](https://github.com/docling-project/docling-serve/releases/tag/v1.4.0) - 2025-09-05
|
||||
|
||||
### Feature
|
||||
|
||||
* **docling:** Perfomance improvements in parsing, new layout model, fixes in html processing ([#352](https://github.com/docling-project/docling-serve/issues/352)) ([`d64a2a9`](https://github.com/docling-project/docling-serve/commit/d64a2a974a276c7ae3b105c448fd79f77a653d20))
|
||||
|
||||
### Fix
|
||||
|
||||
* Upgrade to latest docling version with fixes ([#335](https://github.com/docling-project/docling-serve/issues/335)) ([`e544947`](https://github.com/docling-project/docling-serve/commit/e5449472b2a3e71796f41c8a58c251d8229305c1))
|
||||
|
||||
### Documentation
|
||||
|
||||
* Add split processing example ([#303](https://github.com/docling-project/docling-serve/issues/303)) ([`0d4545a`](https://github.com/docling-project/docling-serve/commit/0d4545a65a5a941fc1fdefda57e39cfb1ea106ab))
|
||||
* Document DOCLING_NUM_THREADS environment variable ([#341](https://github.com/docling-project/docling-serve/issues/341)) ([`27fdd7b`](https://github.com/docling-project/docling-serve/commit/27fdd7b85ab18b3eece428366f46dc5cf0995e38))
|
||||
* Fix parameters typo ([#333](https://github.com/docling-project/docling-serve/issues/333)) ([`81f0a8d`](https://github.com/docling-project/docling-serve/commit/81f0a8ddf80a532042d550ae4568f891458b45e7))
|
||||
* Describe how to use Docling MCP ([#332](https://github.com/docling-project/docling-serve/issues/332)) ([`a69cc86`](https://github.com/docling-project/docling-serve/commit/a69cc867f5a3fb76648803ca866d65cc3a75c6b8))
|
||||
|
||||
### Docling libraries included in this release:
|
||||
- docling 2.46.0
|
||||
- docling 2.51.0
|
||||
- docling-core 2.47.0
|
||||
- docling-ibm-models 3.9.1
|
||||
- docling-jobkit 1.4.1
|
||||
- docling-mcp 1.2.0
|
||||
- docling-parse 4.4.0
|
||||
- docling-serve 1.4.0
|
||||
|
||||
## [v1.3.1](https://github.com/docling-project/docling-serve/releases/tag/v1.3.1) - 2025-08-21
|
||||
|
||||
### Fix
|
||||
|
||||
@@ -6,5 +6,6 @@ This documentation pages explore the webserver configurations, runtime options,
|
||||
- [Handling models](./models.md)
|
||||
- [Usage](./usage.md)
|
||||
- [Deployment](./deployment.md)
|
||||
- [MCP](./mcp.md)
|
||||
- [Development](./development.md)
|
||||
- [`v1` migration](./v1_migration.md)
|
||||
|
||||
@@ -44,6 +44,7 @@ THe following table describes the options to configure the Docling Serve app.
|
||||
| | `DOCLING_SERVE_SINGLE_USE_RESULTS` | `true` | If true, results can be accessed only once. If false, the results accumulate in the scratch directory. |
|
||||
| | `DOCLING_SERVE_RESULT_REMOVAL_DELAY` | `300` | When `DOCLING_SERVE_SINGLE_USE_RESULTS` is active, this is the delay before results are removed from the task registry. |
|
||||
| | `DOCLING_SERVE_MAX_DOCUMENT_TIMEOUT` | `604800` (7 days) | The maximum time for processing a document. |
|
||||
| | `DOCLING_NUM_THREADS` | `4` | Number of concurrent threads for processing a document. |
|
||||
| | `DOCLING_SERVE_MAX_NUM_PAGES` | | The maximum number of pages for a document to be processed. |
|
||||
| | `DOCLING_SERVE_MAX_FILE_SIZE` | | The maximum file size for a document to be processed. |
|
||||
| | `DOCLING_SERVE_MAX_SYNC_WAIT` | `120` | Max number of seconds a synchronous endpoint is waiting for the task completion. |
|
||||
@@ -77,7 +78,7 @@ The following table describes the options to configure the Docling Serve RQ engi
|
||||
|-----|---------|-------------|
|
||||
| `DOCLING_SERVE_ENG_RQ_REDIS_URL` | (required) | The connection Redis url, e.g. `redis://localhost:6373/` |
|
||||
| `DOCLING_SERVE_ENG_RQ_RESULTS_PREFIX` | `docling:results` | The prefix used for storing the results in Redis. |
|
||||
| `DOCLING_SERVE_ENG_RQ_RESULTS_PREFIX` | `docling:updates` | The channel key name used for storing communicating updates between the workers and the orchestrator. |
|
||||
| `DOCLING_SERVE_ENG_RQ_SUB_CHANNEL` | `docling:updates` | The channel key name used for storing communicating updates between the workers and the orchestrator. |
|
||||
|
||||
#### KFP engine
|
||||
|
||||
|
||||
22
docs/examples.md
Normal file
22
docs/examples.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Examples
|
||||
|
||||
## Split processing
|
||||
|
||||
The example of provided of split processing demonstrates how to split a PDF into chunks of pages and send them for conversion. At the end, it concatenates all split pages into a single conversion `JSON`.
|
||||
|
||||
At beginning of file there's variables to be used (and modified) such as:
|
||||
| Variable | Description |
|
||||
| ---------|-------------|
|
||||
| `path_to_pdf`| Path to PDF file to be split |
|
||||
| `pages_per_file`| The number of pages per chunk to split PDF |
|
||||
| `base_url`| Base url of the `docling-serve` host |
|
||||
| `out_dir`| The output folder of each conversion `JSON` of split PDF and the final concatenated `JSON` |
|
||||
|
||||
The example follows the following logic:
|
||||
- Get the number of pages of the `PDF`
|
||||
- Based on the number of chunks of pages, send each chunk to conversion using `page_range` parameter
|
||||
- Wait all conversions to finish
|
||||
- Get all conversion results
|
||||
- Save each conversion `JSON` result into a `JSON` file
|
||||
- Concatenate all `JSONs` into a single `JSON` using `docling` concatenate method
|
||||
- Save concatenated `JSON` into a `JSON` file
|
||||
39
docs/mcp.md
Normal file
39
docs/mcp.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Docling MCP in Docling Serve
|
||||
|
||||
The `docling-serve` container image includes all MCP (Model Communication Protocol) features starting from version v1.1.0. To leverage these features, you simply need to use a different entrypoint—no custom image builds or additional installations are required. The image provides the `docling-mcp-server` executable, which enables MCP functionality out of the box as of version v1.1.0 ([changelog](https://github.com/docling-project/docling-serve/blob/624f65d41b734e8b39ff267bc8bf6e766c376d6d/CHANGELOG.md)).
|
||||
|
||||
Read more on [Docling MCP](https://github.com/docling-project/docling-mcp) in its dedicated repository.
|
||||
|
||||
## Launching the MCP Service
|
||||
|
||||
By default, the container runs `docling-serve run` and exposes port 5001. To start the MCP service, override the entrypoint and specify your desired port mapping. For example:
|
||||
|
||||
```sh
|
||||
podman run -p 8000:8000 quay.io/docling-project/docling-serve -- docling-mcp-server --transport streamable-http --port 8000 --host 0.0.0.0
|
||||
```
|
||||
|
||||
This command starts the MCP server on port 8000, accessible at `http://localhost:8000/mcp`. Adjust the port and host as needed. Key arguments for `docling-mcp-server` include `--transport streamable-http` (HTTP transport for client connections), `--port <PORT>`, and `--host <HOST>` (use `0.0.0.0` to accept connections from any interface).
|
||||
|
||||
## Configuring MCP Clients
|
||||
|
||||
Most MCP-compatible clients, such as LM Studio and Claude Desktop, allow you to specify custom MCP server endpoints. The standard configuration uses a JSON block to define available MCP servers. For example, to connect to the Docling MCP server running on port 8000:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"docling": {
|
||||
"url": "http://localhost:8000/mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Insert this configuration in your client's settings where MCP servers are defined. Update the URL if you use a different port.
|
||||
|
||||
### LM Studio and Claude Desktop
|
||||
|
||||
Both LM Studio and Claude Desktop support MCP endpoints via configuration files or UI settings. Paste the above JSON block into the appropriate configuration section. For Claude Desktop, add the MCP server in the "Custom Model" or "MCP Server" section. For LM Studio, refer to its documentation for the location of the MCP server configuration.
|
||||
|
||||
### Other MCP Clients
|
||||
|
||||
Other clients, such as Continue Coding Assistant, also support custom MCP endpoints. Use the same configuration pattern: provide the MCP server URL ending with `/mcp` and ensure the port matches your container setup. See the [Docling MCP docs](https://github.com/docling-project/docling-mcp/tree/main/docs/integrations) for more details.
|
||||
124
examples/split_processing.py
Normal file
124
examples/split_processing.py
Normal file
@@ -0,0 +1,124 @@
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
from pydantic import BaseModel
|
||||
from pypdf import PdfReader
|
||||
|
||||
from docling_core.types.doc.document import DoclingDocument
|
||||
|
||||
# Variables to use
|
||||
path_to_pdf = Path("./tests/2206.01062v1.pdf")
|
||||
pages_per_file = 4
|
||||
base_url = "http://localhost:5001/v1"
|
||||
out_dir = Path("examples/splitted_pdf/")
|
||||
|
||||
|
||||
class ConvertedSplittedPdf(BaseModel):
|
||||
task_id: str
|
||||
conversion_finished: bool = False
|
||||
result: dict | None = None
|
||||
|
||||
|
||||
def get_task_result(task_id: str):
|
||||
response = httpx.get(
|
||||
f"{base_url}/result/{task_id}",
|
||||
timeout=15,
|
||||
)
|
||||
return response.json()
|
||||
|
||||
|
||||
def check_task_status(task_id: str):
|
||||
response = httpx.get(f"{base_url}/status/poll/{task_id}", timeout=15)
|
||||
task = response.json()
|
||||
task_status = task["task_status"]
|
||||
|
||||
task_finished = False
|
||||
if task_status == "success":
|
||||
task_finished = True
|
||||
|
||||
if task_status in ("failure", "revoked"):
|
||||
raise RuntimeError("A conversion failed")
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
return task_finished
|
||||
|
||||
|
||||
def post_file(file_path: Path, start_page: int, end_page: int):
|
||||
payload = {
|
||||
"to_formats": ["json"],
|
||||
"image_export_mode": "placeholder",
|
||||
"ocr": False,
|
||||
"abort_on_error": False,
|
||||
"page_range": [start_page, end_page],
|
||||
}
|
||||
|
||||
files = {
|
||||
"files": (file_path.name, file_path.open("rb"), "application/pdf"),
|
||||
}
|
||||
response = httpx.post(
|
||||
f"{base_url}/convert/file/async",
|
||||
files=files,
|
||||
data=payload,
|
||||
timeout=15,
|
||||
)
|
||||
|
||||
task = response.json()
|
||||
|
||||
return task["task_id"]
|
||||
|
||||
|
||||
def main():
|
||||
filename = path_to_pdf
|
||||
|
||||
splitted_pdfs: list[ConvertedSplittedPdf] = []
|
||||
|
||||
with open(filename, "rb") as input_pdf_file:
|
||||
pdf_reader = PdfReader(input_pdf_file)
|
||||
total_pages = len(pdf_reader.pages)
|
||||
|
||||
for start_page in range(0, total_pages, pages_per_file):
|
||||
task_id = post_file(
|
||||
filename, start_page + 1, min(start_page + pages_per_file, total_pages)
|
||||
)
|
||||
splitted_pdfs.append(ConvertedSplittedPdf(task_id=task_id))
|
||||
|
||||
all_files_converted = False
|
||||
while not all_files_converted:
|
||||
found_conversion_running = False
|
||||
for splitted_pdf in splitted_pdfs:
|
||||
if not splitted_pdf.conversion_finished:
|
||||
found_conversion_running = True
|
||||
print("checking conversion status...")
|
||||
splitted_pdf.conversion_finished = check_task_status(
|
||||
splitted_pdf.task_id
|
||||
)
|
||||
if not found_conversion_running:
|
||||
all_files_converted = True
|
||||
|
||||
for splitted_pdf in splitted_pdfs:
|
||||
splitted_pdf.result = get_task_result(splitted_pdf.task_id)
|
||||
|
||||
files = []
|
||||
for i, splitted_pdf in enumerate(splitted_pdfs):
|
||||
json_content = json.dumps(
|
||||
splitted_pdf.result.get("document").get("json_content"), indent=2
|
||||
)
|
||||
doc = DoclingDocument.model_validate_json(json_content)
|
||||
filename = f"{out_dir}/splited_json_{i}.json"
|
||||
doc.save_as_json(filename=filename)
|
||||
files.append(filename)
|
||||
|
||||
docs = [DoclingDocument.load_from_json(filename=f) for f in files]
|
||||
concate_doc = DoclingDocument.concatenate(docs=docs)
|
||||
|
||||
exp_json_file = Path(f"{out_dir}/concatenated.json")
|
||||
concate_doc.save_as_json(exp_json_file)
|
||||
|
||||
print("Finished")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "docling-serve"
|
||||
version = "1.3.1" # DO NOT EDIT, updated automatically
|
||||
version = "1.4.1" # DO NOT EDIT, updated automatically
|
||||
description = "Running Docling as a service"
|
||||
license = {text = "MIT"}
|
||||
authors = [
|
||||
@@ -34,7 +34,7 @@ classifiers = [
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"docling~=2.38",
|
||||
"docling-core>=2.44.1",
|
||||
"docling-core>=2.45.0",
|
||||
"docling-jobkit[kfp,rq,vlm]>=1.4.0,<2.0.0",
|
||||
"fastapi[standard]~=0.115",
|
||||
"httpx~=0.28",
|
||||
@@ -69,6 +69,7 @@ dev = [
|
||||
"asgi-lifespan~=2.0",
|
||||
"mypy~=1.11",
|
||||
"pre-commit-uv~=4.1",
|
||||
"pypdf>=6.0.0",
|
||||
"pytest~=8.3",
|
||||
"pytest-asyncio~=0.24",
|
||||
"pytest-check~=2.4",
|
||||
@@ -87,24 +88,24 @@ cpu = [
|
||||
]
|
||||
|
||||
cu124 = [
|
||||
"torch>=2.6.0 ; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version < '3.13'",
|
||||
"torchvision>=0.21.0 ; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version < '3.13'",
|
||||
"torch>=2.6.0",
|
||||
"torchvision>=0.21.0",
|
||||
]
|
||||
|
||||
cu126 = [
|
||||
"torch>=2.7.1 ; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version < '3.13'",
|
||||
"torchvision>=0.22.1 ; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version < '3.13'",
|
||||
"torch>=2.7.1",
|
||||
"torchvision>=0.22.1",
|
||||
]
|
||||
|
||||
cu128 = [
|
||||
"torch>=2.7.1 ; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version < '3.13'",
|
||||
"torchvision>=0.22.1 ; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version < '3.13'",
|
||||
"torch>=2.7.1",
|
||||
"torchvision>=0.22.1",
|
||||
]
|
||||
|
||||
rocm = [
|
||||
"torch>=2.7.1 ; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version < '3.13'",
|
||||
"torchvision>=0.22.1 ; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version < '3.13'",
|
||||
"pytorch-triton-rocm>=3.3.1 ; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version < '3.13'",
|
||||
"torch>=2.7.1",
|
||||
"torchvision>=0.22.1",
|
||||
"pytorch-triton-rocm>=3.3.1 ; sys_platform == 'linux' and platform_machine == 'x86_64'",
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
|
||||
Reference in New Issue
Block a user