Gradio-API Integration#
Overview#
mineru-gradio does not call parsing libraries directly. Every conversion is dispatched over HTTP to a mineru-api FastAPI backend. By default the Gradio process owns that backend (a ReusableLocalAPIServer singleton launched in-process); passing --api-url hands control to an externally-managed server instead .
--api-url: Local vs. Remote Backend#
| Mode | How to start | Local process? |
|---|---|---|
| Local (default) | mineru-gradio | Gradio spawns mineru-api automatically; the singleton is _gradio_local_api_server |
| Remote | mineru-gradio --api-url http://<host>:<port> | No local process; Gradio calls the supplied URL directly |
When --api-url is not supplied, _gradio_local_api_server.ensure_started() is called at each conversion to guarantee the server is alive . The server process is launched via python -m mineru.cli.fast_api (subprocess) or multiprocessing.spawn (Ascend/Linux), with atexit cleanup . VLM warm-up on Gradio startup is gated by --enable-vlm-preload and only runs when no --api-url is provided .
CLI Parameter Forwarding#
Unknown CLI flags on mineru-gradio are forwarded to the internally-managed mineru-api via resolve_gradio_local_api_cli_args() . That function delegates to build_local_api_cli_args() in vlm_preload.py, which appends --enable-vlm-preload when appropriate but does not filter any other flags.
On the API side, fast_api.main() uses arg_parse(ctx) to normalize any unrecognised CLI flags (dashes → underscores, value coercion) into a dict, then split_service_and_model_config() separates service keys (e.g. enable_vlm_preload) from model kwargs. The model kwargs are stored as app.state.config and spread as **config into every run_parse_job() call .
Note: --host and --port are stripped from the forwarded args by strip_local_api_network_args() before the subprocess is launched, so Gradio's auto-allocated loopback port is not overridden .
Backend / Effort Flow: Gradio UI → FastAPI#
User selects backend + effort in Gradio UI
│
▼
_run_to_markdown_job() [gradio_app.py L1038-1057]
build_parse_request_form_data(backend=..., effort=..., ...)
│
▼ HTTP POST /tasks (multipart form)
mineru-api parse_request_form → ParseRequestOptions
│
▼
run_parse_job(... backend=request_options.backend,
effort=request_options.effort, ...,
**config) [fast_api.py L832-866]
│
▼
do_parse / aio_do_parse → backend-specific execution
- The user's backend/effort choice is captured by Gradio UI components and passed as keyword arguments into
_run_to_markdown_job(). - That function calls
build_parse_request_form_data()to assemble the multipart form, explicitly includingbackendandeffort. - The form is POSTed to
POST /tasks(or/file_parse). Theparse_request_formFastAPI dependency validates it into aParseRequestOptionsdataclass. run_parse_job()buildsparse_kwargswith explicit keys forbackend,effort,formula_enable,table_enable,image_analysis, etc., then spreads**config(the server's startup model kwargs) at the end.
The is_effort_option_visible() helper controls whether the effort radio button appears in the UI — it is only shown for hybrid-* backends . The is_image_analysis_option_visible() helper additionally hides the image analysis toggle when backend is hybrid with medium effort, because medium effort unconditionally disables image analysis inside the backend .
The Duplicate Keyword Argument Bug#
Symptom: TypeError: dict() got multiple values for keyword argument 'backend' (or 'effort').
Root cause: Any CLI flag passed to mineru-api at startup (e.g. --backend hybrid-engine, --effort high) is parsed into app.state.config as an arbitrary model kwarg. run_parse_job() then builds parse_kwargs with those same keys set explicitly from the request options, and finally does **config — causing Python to see duplicate keyword arguments when a key appears in both places .
Affected parameters: Any key that do_parse / aio_do_parse accepts and that is also a named parameter in run_parse_job()'s parse_kwargs dict — most commonly backend and effort.
Workarounds (until a fix lands):
- Don't pass conflicting keys to
mineru-apiat startup. Use--backendand--effortonly in the API request payload (via the Gradio UI or curl), not on the server command line. - If using
--api-url, start the server without--backend/--effortso itsapp.state.configstays clean; Gradio sends those per-request. - Don't run
mineru-apiandmineru-gradiosimultaneously without--api-url. Without--api-url, Gradio spawns its own internal API. If you also startmineru-apimanually, only the Gradio-managed one is used; the manual one is wasted, and any CLI flags you gave the manual instance don't apply.
Key Source Files#
| File | Role |
|---|---|
mineru/cli/gradio_app.py | UI, _run_to_markdown_job(), stream_to_markdown(), --api-url handling |
mineru/cli/api_client.py | LocalAPIServer, ReusableLocalAPIServer, build_parse_request_form_data(), strip_local_api_network_args() |
mineru/cli/fast_api.py | FastAPI app, run_parse_job(), AsyncParseTask, main() |
mineru/cli/vlm_preload.py | resolve_gradio_local_api_cli_args(), split_service_and_model_config() |
mineru/utils/cli_parser.py | parse_unknown_args(), arg_parse() — unknown-flag normalization |
mineru/cli/backend_options.py | DEFAULT_BACKEND, DEFAULT_HYBRID_EFFORT, backend constants |
mineru/cli/api_request.py | ParseRequestOptions, parse_request_form dependency |