Xavierando
### Self Checks - [x] I have searched for existing issues, including closed ones. - [x] I confirm that I am using English to submit this report. - [x] Non-english title submissions will be closed directly. - [x] Please do not modify this template :) and fill in all the required fields. _Updated after the review on #20531: no separate "Mistral OCR" provider; legacy data handled as agreed there._ ### Is your feature request related to a problem? Mistral exposes a dedicated document OCR endpoint, `POST /v1/ocr`, that returns per-page Markdown (plus optional layout blocks and extracted tables) for PDFs and images. The Go ingestion path cannot use it as a PDF layout recognizer. On `main` @ 98b48a08: - A tenant model row left by the Python "Mistral OCR" factory, such as `mistral-ocr-latest@<instance>@Mistral OCR`, selected as the PDF `layout_recognizer` is not caught by any OCR branch of `maybeDispatchPDFVision` (`internal/ingestion/component/pdf_vision_dispatch.go:64-202`). It falls through to the VLM path (`:190`), and the model lookup fails with `provider "Mistral OCR" driver not found` (`internal/ingestion/component/dispatch_model.go:242-244`). `factory.go:96` maps only `"mistral"`. - The UUID or composite of a `mistral-ocr-*` model under the multi-type "Mistral" provider also falls to the VLM path, which renders pages to images and calls chat completions instead of `/v1/ocr`. - The existing client `MistralModel.OCRFile` (`internal/entity/models/mistral.go:584-669`) is not usable as a document parser: - it sends `*apiConfig.ApiKey` verbatim (`:630`), so a key stored as a JSON payload (`{"api_key": ..., "mistral_ocr_*": ...}`) is sent as the bearer token; - a base URL ending in `/v1` (the documented `https://api.mistral.ai/v1`) produces `/v1/v1/ocr` (`:597`); - it labels the data URL with `http.DetectContentType` (`:603`); a PDF with bytes before `%PDF-` is labelled `text/plain` and `/v1/ocr` rejects it with HTTP 422; - it has no Files API upload, so documents over the 20 MB data-URL limit fail; - it ignores the parser setup's `pages`; - it uses a fixed 120 s timeout (`:621`), too short for long PDFs; - it requests neither `include_blocks` nor `table_format`, so page headers/footers and image placeholders (``) end up in the chunks, and table placeholders are not replaced by the extracted table. ### Describe the feature you'd like 1. List `mistral-ocr-latest` as an `ocr` model of the existing Mistral provider (`conf/models/mistral.json`, next to `mistral-ocr-2512`). OCR backends are resolved by `ModelTypeOCR` plus `driver.Name()`, so no separate provider is needed. 2. Make `MistralModel.OCRFile` the single `/v1/ocr` client: base URL normalization, leading-bytes PDF detection, Files API upload above 20 MB, page selection, layout blocks with header/footer removal, inlined tables, long-operation timeout. 3. Keep data left by the Python "Mistral OCR" factory working: resolve models stored under that provider name (including `@Mistral OCR` references) as the Mistral provider's, and read its JSON-encoded key. A versioned migration that folds those rows into "Mistral" can follow separately. 4. Route a PDF parser setup to Mistral OCR when its layout recognizer names an `ocr` model on the Mistral driver (tenant model UUID or `model@instance@provider` composite). The output is Markdown without bounding boxes, the same contract as the Go MinerU and PaddleOCR dispatchers (`buildMarkdownOCRDispatchResult`). ### Describe implementation you've considered (a) #20531: catalog entry, client, and resolution of the legacy "Mistral OCR" data (points 1–3); (b) PDF dispatch (point 4), opened after (a); (c) optionally, the migration of the legacy rows, as a separate PR after (a). ### Documentation, adoption, use case Mistral OCR returns good Markdown, including tables, for scanned PDFs, without running a local OCR stack. ### Additional information Earlier Python-backend work: #17056 / #17057 (history only).