---
title: "DocumentAnalysisService"
manual: "TYPO3 LLM Extension"
version: "0.35"
permalink: "https://docs.typo3.org/permalink/netresearch/nr-llm:api-document-analysis-service@0.35"
source: "Api/DocumentAnalysisService.rst"
modified: "2026-09-16T22:09:16+00:00"
---

# DocumentAnalysisService

-   **class DocumentAnalysisService**

    -   *Fully qualified name:* `\Netresearch\NrLlm\Specialized\Document\DocumentAnalysisService`

    Stateless "understand this document" primitive ([ADR-076](https://docs.typo3.org/permalink/netresearch/nr-llm:adr-076@0.35)).

    When the resolved provider implements
    `DocumentCapableInterface` (Gemini, Claude), the PDF is
    ingested natively as a Base64 document block in a single chat
    call — whole-document reasoning. Otherwise the document is
    rasterized page-by-page with poppler and each page is read by
    the vision model; the per-page answers are concatenated with
    `[Page N]` markers.

    -   **analyzeDocument(string $pdf, string $prompt, ?ChatOptions $options = null) : DocumentAnalysisResult**

        Analyze a PDF with a custom prompt.

        -   *param string $pdf:*

            Raw PDF bytes (must start with the
            `%PDF-` header)

        -   *param string $prompt:*

            Analysis prompt, applied to the whole
            document on the native path and to each page on the
            fallback

        -   *param ChatOptions|null $options:*

            Chat options; `provider`,
            `model`, `maxTokens`, `temperature` and the budget
            attribution fields (`beUserUid`, `plannedCost`) are
            passed through to whichever path runs

        -   *throws:*

            `UnsupportedFormatException` when the bytes are
            not a PDF

        -   *throws:*

            `ProviderException` when no provider is
            resolvable (no explicit provider and no active default
            configuration) — the same error a plain `chat()` call
            raises

        -   *throws:*

            `ServiceUnavailableException` when the provider
            lacks native PDF support and poppler is not installed

        -   *throws:*

            `PdfRasterizationException` when rasterization
            itself fails

        *Returns:* `DocumentAnalysisResult` with the answer text, the model/provider that produced it, whether the native document path was used, and the rasterized page count

## Usage

**Analyzing a PDF**

```php
use Netresearch\NrLlm\Service\Option\ChatOptions;
use Netresearch\NrLlm\Specialized\Document\DocumentAnalysisService;

public function __construct(
    private readonly DocumentAnalysisService $documentAnalysis,
) {}

$result = $this->documentAnalysis->analyzeDocument(
    $pdfBytes,
    'List the key obligations defined in this contract.',
    new ChatOptions(maxTokens: 1024),
);

$result->text;                    // the answer
$result->usedNativeDocumentPath;  // true: one whole-document call
$result->rasterizedPageCount;     // pages read on the fallback path
```

## Optional system dependency: poppler

The rasterization fallback shells out to the poppler binaries
`pdftoppm` and `pdfimages` (Debian/Ubuntu package
`poppler-utils`; declared in `composer.json` `suggest`). They
are only needed when the resolved provider has no native PDF
support. Without them, the fallback fails with the typed
`ServiceUnavailableException` (code `1784211009`) naming
both remedies: install `poppler-utils` or configure a
document-capable provider. The native path never touches poppler.

Degradation policy is the caller's: on the fallback path a failed
page fails the call — catch and retry (or degrade) in the consumer.

## PdfRasterizerInterface

-   **class PdfRasterizerInterface**

    -   *Fully qualified name:* `\Netresearch\NrLlm\Specialized\Document\PdfRasterizerInterface`

    Rasterizes PDF pages to PNG blobs. The default implementation is
    the poppler-backed `PopplerPdfRenderer`; substitute it by
    aliasing the interface to another class in your
    `Services.yaml`.

    -   **imagePages(string $absolutePath) : array**

        1-based page numbers carrying at least one embedded raster
        image.

    -   **renderPage(string $absolutePath, int $page) : string**

        PNG bytes of one rasterized page.

    -   **renderDocument(string $absolutePath) : array**

        PNG bytes per 1-based page number for the whole document.

    -   **isAvailable() : bool**

        Whether the system binaries are present.
