DeepFellow DOCS

Doc Chunker

Convert audio, video, PDFs, images, and Office documents into text chunks for your vector stores.

Doc Chunker is an optional DeepFellow component that turns diverse knowledge sources into clean, searchable text. It converts documents, presentations, spreadsheets, images, audio, and video into text and splits that text into chunks ready for embedding.

The connection between Doc Chunker and vector stores is still under development.

This integration is active by default: doc_chunker_use defaults to true, so DeepFellow Server sends vector store files to Doc Chunker unless you turn it off. If you don't accept the status of this integration, set doc_chunker_use to false to use the built-in text extraction. It reads pdf, docx, pptx, md, rtf, and plain text, and it returns flat text with no layout, no OCR, no image descriptions, and no transcription. See Doc Chunker Settings.

When Doc Chunker is active, DeepFellow converts your files, splits them into chunks, and embeds those chunks for search. Retrieve the original text of any chunk, its neighboring context, or the whole reconstructed file with the chunk fragment endpoint.

What You Can Convert

Doc Chunker handles a wide range of formats.

  • Documents and Markup: pdf, docx, pptx, xlsx, html, md. OCR is enabled by default and extracts text from scanned PDFs and images embedded in documents.
  • Legacy Office formats: doc, ppt, xls, odt, odp, ods, rtf. Doc Chunker converts these with LibreOffice before parsing.
  • Images: png, jpg, jpeg, tiff, bmp. OCR reads text from the image. Optional image description adds a natural-language summary of the picture.
  • Audio: mp3, wav, m4a, ogg, flac, opus, aac, wma. Doc Chunker transcribes speech to text through a speech-to-text model.
  • Video: mp4, mkv, mov, avi, webm. Doc Chunker extracts the audio track and transcribes it.

Doc Chunker handles any other file type in two steps. First it tries to read the file as plain text. If that succeeds, the text becomes a document whose paragraphs are split on blank lines. If it fails, Doc Chunker falls back to Apache Tika, which is what happens with a format such as epub.

A file that reads as plain text, such as csv, txt, json, or yaml, never reaches Apache Tika and never gets a structured layout. A csv file becomes flat text rather than a table, so its rows and columns carry no structure into the chunks.

Audio and video transcription requires a speech-to-text model. Image descriptions require a vision-language model. Both reach the model through an inference gateway that you configure on the container. See Inference Gateway.

Install Doc Chunker

Install Doc Chunker from the Infra Web Panel as a model of the custom service.

In the services view, locate the custom service and open model list.

Find the doc_chunker model and open its configuration form.

Set the required fields: endpoint prefix, hardware, and the inference gateway URL. The default prefix is doc_chunker, which exposes Doc Chunker at /custom/doc_chunker. The gateway URL, INFRA_API_URL, arrives prefilled with http://infra:8086, the address of the gateway in a standard deployment.

Set the environment variables you need, described in Container Configuration. The defaults work for every format. Image descriptions and audio transcription need one more value, INFRA_API_KEY, and only when your gateway requires a key.

Leave "Docker image version" empty to install the image DeepFellow ships with your Infra release. Set it to a tag to pin a different image.

Leave the proxy timeout empty to use the global standard_proxy_timeout_seconds, which is 600 seconds. Raise it for large files: a conversion that outlives the timeout fails even though Doc Chunker is still working on it. See Proxy Timeout.

Click "Install". DeepFellow selects the CPU or GPU image automatically based on your hardware.

After a while, the model will appear with the green "Installed" label.

The GPU image needs about 15 GB of disk space and runs much faster. The CPU image needs about 4 GB. The form declares 15 GB for both, so the figure it shows for the CPU image is too high.

doc_chunker_use defaults to true, so DeepFellow Server routes vector store files to Doc Chunker whether or not the model is installed. With no model behind it, the endpoint prefix resolves to nothing, and the Infra gateway answers 400 with {"error": {"message": "Given url is not supported", "type": "invalid_request_error"}}.

POST /v1/vector_stores/{vector_store_id}/files still answers 200, because it only queues the file. Ingestion runs in the background, so the failure surfaces on the file itself: its status becomes failed, and last_error carries the gateway's message. The synchronous paths, GET /v1/files/{file_id}/text and POST /text_converter/text, return the error directly.

Install Doc Chunker, or set doc_chunker_use to false.

Doc Chunker Settings

Installing the model exposes the Doc Chunker endpoint. DeepFellow Server reads the following settings to route vector store files through it.

Doc Chunker itself holds no model configuration, and every request names the model it needs. These settings are what DeepFellow Server puts into that request.

  • doc_chunker_use: Whether to send files to Doc Chunker when you add them to a vector store. Set it to false to keep the built-in text extraction. Default true.
  • doc_chunker_prefix: Endpoint prefix the server uses to reach Doc Chunker. It must match the prefix you set when you installed the model. Default doc_chunker.
  • doc_chunker_picture_description_model: Vision-language model the server sends as the model parameter when it asks Doc Chunker to describe pictures. Default granite3.2-vision:2b.

All three are dynamic settings, so a change applies immediately and never needs a restart:

deepfellow server config set doc_chunker_use=true doc_chunker_prefix=doc_chunker

The Doc Chunker section of the Server Web Panel holds the first two. To change doc_chunker_picture_description_model, use PUT /admin/config.

The matching environment variables, DF_DOC_CHUNKER_USE, DF_DOC_CHUNKER_PREFIX, and DF_DOC_CHUNKER_PICTURE_DESCRIPTION_MODEL, only seed these settings on the server's first start. After that the values live in the server's configuration file, and setting the environment variable will have no effect. Use the Server Web Panel or PUT /admin/config instead.

Container Configuration

Set these environment variables on the Doc Chunker model in the Infra Web Panel.

Configuration Options

The Doc Chunker installation form exposes the following fields.

Processing

VariableDescriptionDefault
MAX_CONCURRENTMaximum number of files Doc Chunker converts in parallel.2
DOCUMENT_TIMEOUTMaximum time in seconds for a single conversion.600
LIBREOFFICE_TIMEOUTMaximum time in seconds LibreOffice gets to convert one legacy Office file.120

The defaults work for every format listed in What You Can Convert. Doc Chunker holds further timeouts for its Apache Tika and Docling backends, and the form leaves them at their defaults.

Chunk Size

A chunk holds at most MAX_TOKEN_COUNT tokens, which is 512. The install form doesn't expose this variable, so every chunk keeps that budget.

Doc Chunker fills 70 percent of the budget, 358 tokens, with text unique to the chunk, and spends the remaining 30 percent on overlap. The overlap runs forward: Doc Chunker takes whole sentences from the start of a chunk and appends them to the chunk before it. The earlier chunk grows, and the later one stays as it was. Each overlap also stays within about 30 percent of the length of the chunk it extends, so a short chunk grows by far less than the 153-token ceiling.

Doc Chunker overlaps only consecutive chunks of running text, so a table never bleeds into its neighbors.

Chunk boundaries are measured with the sentence-transformers/all-MiniLM-L6-v2 tokenizer, which is Docling's own default. The tokenizer is fixed, so its token counts differ from the ones your embedding model counts. Matching the two is planned work.

The chunking_strategy parameter of the vector store endpoints applies only to the built-in token chunker. Chunking through Doc Chunker takes no per-request parameters, so MAX_TOKEN_COUNT and the tokenizer above decide every chunk boundary. Per-request control is planned work.

Inference Gateway

Image description and audio transcription both call an OpenAI-compatible inference gateway, so they share one address and one key. Point INFRA_API_URL at the gateway root, not at a specific endpoint. Doc Chunker appends /v1/chat/completions for image description and /v1/audio/transcriptions for transcription.

VariableDescriptionDefault
INFRA_API_URLGateway root, for example http://ollama:11434.
INFRA_API_KEYAPI key for the gateway, if it requires one.

Without INFRA_API_URL, neither feature is available, and Doc Chunker rejects a request that needs one rather than returning a document without it.

Image Descriptions

Image description is opt-in per request. Pass describe_images=true and name the vision-language model with model. Both are required together: a request that asks for descriptions without a model is rejected with 422, and so is a request naming a model the gateway doesn't offer.

Doc Chunker describes every picture the document holds. There is no size threshold, so icons and logos are described too.

VariableDescriptionDefault
PICTURE_DESCRIPTION_PROMPTPrompt that controls how the model describes each image.Describe this image in detail.
PICTURE_DESCRIPTION_API_MAX_TIMEMaximum wait time in seconds for a single gateway call.300
PICTURE_DESCRIPTION_CONCURRENCYNumber of pictures described in parallel within one document.4

PICTURE_DESCRIPTION_CONCURRENCY bounds a single document, and Doc Chunker converts MAX_CONCURRENT documents at a time. The gateway therefore sees up to the product of the two, which is 8 requests with both at their defaults. Raise it for a gateway that takes the load.

Audio Transcription

For audio and video, transcription is the conversion: the transcript becomes the document's text. Name the speech-to-text model per request with model. It is required, so uploading audio or video without it is rejected with 422.

Doc Chunker splits the transcript on silence, and every piece keeps the time span it was spoken in. A silence longer than AUDIO_SILENCE_THRESHOLD always ends a chunk, so no chunk ever spans a pause.

VariableDescriptionDefault
AUDIO_STT_MAX_TIMEMaximum wait time in seconds for a single speech-to-text call.600
AUDIO_SILENCE_THRESHOLDMinimum duration of silence in seconds that splits the transcript.2.0

Converted Documents

When Doc Chunker is active, adding a file to a vector store with POST /v1/vector_stores/{vector_store_id}/files converts the file through Doc Chunker first, and the vector store stores the chunks that come back.

DeepFellow keeps the converted document next to the file, under the path set by DF_FILESTORAGE_META_PATH, which defaults to storage/. Adding the same file again, or asking for its text later, reuses that document instead of converting the file a second time. A conversion that stopped halfway leaves nothing reusable behind, so the next request converts the file again.

POST /v1/metadata/expand, which extracts metadata fields from a document with an LLM, uses the same cache. When a requested field is not present in a document's embedded metadata, DeepFellow falls back to Doc Chunker to extract the document's text, converting the file if no conversion is cached yet. To have a vision model describe images during that fallback conversion, set image_processing_mode to description in the request body. The default value, ignore, skips image descriptions. The setting applies only when the fallback runs.

Because the conversion is shared, whichever feature converts a file first decides whether the cached conversion holds image descriptions. If a metadata expansion job asks for descriptions but an earlier conversion produced the cached document without them, DeepFellow reuses the existing cache as is and logs a warning instead of reconverting. The same warning covers the reverse case, and the case where Doc Chunker is disabled and the fallback produces no descriptions at all.

Both GET /v1/files/{file_id}/text and POST /text_converter/text take an image_mode parameter. It defaults to none on the first, and the second requires it. When it asks for descriptions, the server names the vision-language model from doc_chunker_picture_description_model.

Besides none and descriptions, image_mode accepts embedded, which inlines each image as a base64 data: URI. GET /v1/files/{file_id}/text also accepts referenced, which links each image to /v1/files/{file_id}/assets/{name}. An ad-hoc conversion keeps no assets to link to, so POST /text_converter/text doesn't offer that mode. Both modes need output_format=md and return 400 without it.

Image descriptions are written while the document is being converted, so a document converted without them never gains them. On GET /v1/files/{file_id}/text the converted document is kept and reused, so image_mode=descriptions produces descriptions on a file's first conversion only: a later call asking for them returns the document as it was converted. POST /text_converter/text keeps nothing, so it describes the images on every call that asks.

Call Doc Chunker Directly

For advanced use cases, call Doc Chunker through the /custom/doc_chunker endpoint without a vector store. The two operations are separate endpoints, and conversion never happens implicitly: POST /convert turns a file into a Docling document, and POST /chunk turns that document into chunks.

Address these calls to DeepFellow Server with your project API key. The server proxies them to Doc Chunker and supplies the Infra credentials itself, so your client never holds the Infra API key. See Custom Endpoints.

Your project's custom_endpoints must allow the exact path you call. It defaults to all, which allows every custom endpoint. If you restrict it, list full paths such as doc_chunker/convert. The prefix alone doesn't match, so a list holding only doc_chunker answers 403 for doc_chunker/convert. DeepFellow Server answers 403 before the request reaches Doc Chunker.

The list governs only the calls you address to /custom/doc_chunker/.... Vector store ingestion and GET /v1/files/{file_id}/text reach Doc Chunker from inside the server, which doesn't consult custom_endpoints. See Authorization.

Convert a File

POST /custom/doc_chunker/convert accepts multipart/form-data with the file in the file field, and returns a ZIP archive named after the uploaded file.

ParameterDescriptionDefault
describe_imagesWhether to describe the pictures found in the document. Requires model. Doc Chunker ignores it for audio and video.false
modelModel the inference gateway will use: the speech-to-text model for audio and video, the vision-language model for image description. A file needs at most one, so its type decides which.
chunkWhether to also chunk the document and add chunks.json to the archive, which saves a round trip through POST /chunk.false

The archive holds document.json always, assets/ when the document has pictures, and chunks.json when you pass chunk=true.

curl -X 'POST' \
  'https://deepfellow-server-host/custom/doc_chunker/convert?chunk=true' \
  -H 'Authorization: Bearer DEEPFELLOW-PROJECT-API-KEY' \
  -F 'file=@report.pdf;type=application/pdf' \
  -o report.zip
import io
import json
import zipfile

import requests

with open("report.pdf", "rb") as f:
    response = requests.post(
        "https://deepfellow-server-host/custom/doc_chunker/convert",
        params={"chunk": "true"},
        files={"file": ("report.pdf", f, "application/pdf")},
        headers={"Authorization": "Bearer DEEPFELLOW-PROJECT-API-KEY"},
    )

with zipfile.ZipFile(io.BytesIO(response.content)) as archive:
    chunks = json.loads(archive.read("chunks.json"))

print(chunks)
import * as fs from 'fs';

const buffer = await fs.promises.readFile('report.pdf');
const formData = new FormData();
formData.append('file', new Blob([buffer], { type: 'application/pdf' }), 'report.pdf');

const response = await fetch('https://deepfellow-server-host/custom/doc_chunker/convert?chunk=true', {
    method: 'POST',
    headers: {
        Authorization: 'Bearer DEEPFELLOW-PROJECT-API-KEY'
    },
    body: formData
});

const archive = Buffer.from(await response.arrayBuffer());
await fs.promises.writeFile('report.zip', archive);

document.json is the source of truth for everything downstream, so Doc Chunker produces it once and never modifies it. Image descriptions are written while the document is being produced, so adding them later means converting the file again.

Chunk a Document

POST /custom/doc_chunker/chunk accepts multipart/form-data with the document.json from a POST /convert archive in the file field, and returns JSON. It converts nothing and contacts no inference gateway, so it needs no model and leaves the document untouched. The assets aren't needed, because chunk content comes from the document's own text and metadata.

curl -X 'POST' \
  'https://deepfellow-server-host/custom/doc_chunker/chunk' \
  -H 'Authorization: Bearer DEEPFELLOW-PROJECT-API-KEY' \
  -F 'file=@document.json;type=application/json'

The response holds the chunks and a total count.

{
    "chunks": [
        {
            "text": "Quarterly revenue grew by 12 percent compared to the previous period.",
            "meta": {
                "headings": ["Financial Summary"],
                "pages": [3],
                "bboxes": [{ "page": 3, "l": 72.0, "t": 120.5, "r": 540.0, "b": 200.3 }],
                "self_refs": ["#/texts/12"],
                "labels": ["text"]
            },
            "start_index": 0,
            "end_index": 69
        }
    ],
    "count": 1
}

Every key in meta is conditional, and a chunk carries only the ones that apply to it.

KeyDescription
headingsThe headings the chunk sits under.
pagesThe pages the chunk's text comes from.
bboxesThe bounding boxes of the chunk's text, as page, l, t, r, and b.
self_refsThe references to the chunk's source items in document.json, for example #/texts/12.
labelsThe layout labels of the chunk's source items, for example text.
startFor audio and video only, the start of the transcript window in seconds.
endFor audio and video only, the end of the transcript window in seconds.

start_index and end_index are character offsets into the concatenation of the chunk texts, in the order Doc Chunker emitted them. They are not positions in the original file. Because the overlap extends the earlier chunk, one chunk's end_index reaches past the next chunk's start_index, and the difference is the length of the duplicated text, which is what you drop when you join chunks back together. To locate a chunk within the original document, use self_refs, bboxes, or pages.

Errors

StatusMeaning
422Doc Chunker rejects the request: a missing file field, an unreadable file, a failed conversion, a missing or unknown model, or a malformed document.json.
500An unhandled error inside Doc Chunker.
502The inference gateway refused the request or was unreachable.
504The conversion, one of its subprocesses such as LibreOffice or ffmpeg, or the inference gateway didn't finish in time.

Doc Chunker enforces no upload size limit of its own, so it never answers 413. The limit on the files you add to DeepFellow comes from DeepFellow Server.

Doc Chunker also exposes GET /custom/doc_chunker/health, which returns {"status": "ok"} when the service is ready. It returns 503 when one of the conversion backends has exited or a conversion has been running past its soft timeout. GET /custom/doc_chunker/version returns the version of the running container.

We use cookies on our website. We use them to ensure proper functioning of the site and, if you agree, for purposes such as analytics, marketing, and targeting ads.