hirokamitai Claude Opus 4.7 (1M context) commited on
Commit
ccbf2d4
·
1 Parent(s): 9f4344b

Fix quality mode 500: pass ClaudeService instance to PdfConverter

Browse files

marker's PdfConverter.__init__ eagerly resolves `default_llm_service`
(GoogleGeminiService) when `use_llm=True` *before* it applies any
config-dict override. So naming "marker.services.claude.ClaudeService"
in config["llm_service"] never took effect — Gemini's
verify_config_keys check fired first and 500'd on missing
gemini_api_key.

Build the ClaudeService instance ourselves and pass it via the
PdfConverter `llm_service=` constructor arg; that takes precedence
over the default and skips the Gemini path entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files changed (2) hide show
  1. _project/CHANGELOG.md +1 -0
  2. app/parser.py +15 -5
_project/CHANGELOG.md CHANGED
@@ -8,6 +8,7 @@ Newest first. Format: `## YYYY-MM-DD — short title`, then bullets.
8
 
9
  ## Unreleased
10
 
 
11
  - **Fix:** Pre-create `<site-packages>/static/fonts/` and chown to the `app` user. marker-pdf's `PdfConverter.__init__` calls `download_font()`, which writes there on first parse — without the chown the non-root container user got `PermissionError`, surfaced as 500 from `/parse`. Affected both `fast` and `quality` modes.
12
  - **Fix:** Redirect `~/.cache` to the bucket via `XDG_CACHE_HOME=/data/cache` and add `DATALAB_CACHE_DIR=/data/datalab` for explicit coverage. marker uses Vik's `datalab` loader for text-detection and OCR-error-detection models, which writes to `~/.cache/datalab/` by default. Without the redirect those models re-downloaded into the container's ephemeral overlay on every cold start (despite the bucket being mounted), adding seconds of avoidable latency. Also pinned `HF_HUB_CACHE` and `TRANSFORMERS_CACHE` explicitly under `/data/hf/`.
13
 
 
8
 
9
  ## Unreleased
10
 
11
+ - **Fix:** Instantiate `ClaudeService` ourselves in `app/parser.py` and pass it to `PdfConverter(llm_service=…)` instead of naming the service via `config["llm_service"]`. Marker's `PdfConverter.__init__` eagerly resolves `default_llm_service` (Gemini) when `use_llm=True` *before* applying the config override, so the previous setup tripped Gemini's `gemini_api_key` check even though we never wanted Gemini. Surfaced as 500 from `/parse` in `quality` mode.
12
  - **Fix:** Pre-create `<site-packages>/static/fonts/` and chown to the `app` user. marker-pdf's `PdfConverter.__init__` calls `download_font()`, which writes there on first parse — without the chown the non-root container user got `PermissionError`, surfaced as 500 from `/parse`. Affected both `fast` and `quality` modes.
13
  - **Fix:** Redirect `~/.cache` to the bucket via `XDG_CACHE_HOME=/data/cache` and add `DATALAB_CACHE_DIR=/data/datalab` for explicit coverage. marker uses Vik's `datalab` loader for text-detection and OCR-error-detection models, which writes to `~/.cache/datalab/` by default. Without the redirect those models re-downloaded into the container's ephemeral overlay on every cold start (despite the bucket being mounted), adding seconds of avoidable latency. Also pinned `HF_HUB_CACHE` and `TRANSFORMERS_CACHE` explicitly under `/data/hf/`.
14
 
app/parser.py CHANGED
@@ -16,6 +16,7 @@ import torch
16
  from marker.converters.pdf import PdfConverter
17
  from marker.models import create_model_dict
18
  from marker.output import text_from_rendered
 
19
 
20
  log = logging.getLogger(__name__)
21
 
@@ -35,22 +36,31 @@ def device() -> str:
35
  def parse(pdf_path: str | Path, mode: Mode = "fast") -> tuple[str, int]:
36
  """Run marker on the PDF at `pdf_path`. Returns (markdown, page_count)."""
37
  config: dict[str, object] = {"output_format": "markdown"}
 
38
  if mode == "quality":
39
  api_key = os.getenv("ANTHROPIC_API_KEY")
40
  if not api_key:
41
  raise RuntimeError(
42
  "parse_mode=quality requires ANTHROPIC_API_KEY to be set."
43
  )
44
- config.update(
45
- {
46
- "use_llm": True,
47
- "llm_service": "marker.services.claude.ClaudeService",
 
 
 
 
48
  "claude_api_key": api_key,
49
  "claude_model_name": CLAUDE_MODEL,
50
  }
51
  )
52
 
53
- converter = PdfConverter(artifact_dict=_models, config=config)
 
 
 
 
54
  rendered = converter(str(pdf_path))
55
  text, _, _ = text_from_rendered(rendered)
56
  return text, _page_count(rendered, pdf_path)
 
16
  from marker.converters.pdf import PdfConverter
17
  from marker.models import create_model_dict
18
  from marker.output import text_from_rendered
19
+ from marker.services.claude import ClaudeService
20
 
21
  log = logging.getLogger(__name__)
22
 
 
36
  def parse(pdf_path: str | Path, mode: Mode = "fast") -> tuple[str, int]:
37
  """Run marker on the PDF at `pdf_path`. Returns (markdown, page_count)."""
38
  config: dict[str, object] = {"output_format": "markdown"}
39
+ llm_service: ClaudeService | None = None
40
  if mode == "quality":
41
  api_key = os.getenv("ANTHROPIC_API_KEY")
42
  if not api_key:
43
  raise RuntimeError(
44
  "parse_mode=quality requires ANTHROPIC_API_KEY to be set."
45
  )
46
+ config["use_llm"] = True
47
+ # Pass the service instance directly. Marker's PdfConverter eagerly
48
+ # instantiates `default_llm_service` (Gemini) when `use_llm=True`,
49
+ # *before* applying any config-dict override — so naming the service
50
+ # in `config["llm_service"]` is too late and trips Gemini's config
51
+ # check. Supplying the instance via the constructor arg skips that.
52
+ llm_service = ClaudeService(
53
+ config={
54
  "claude_api_key": api_key,
55
  "claude_model_name": CLAUDE_MODEL,
56
  }
57
  )
58
 
59
+ converter = PdfConverter(
60
+ artifact_dict=_models,
61
+ config=config,
62
+ llm_service=llm_service,
63
+ )
64
  rendered = converter(str(pdf_path))
65
  text, _, _ = text_from_rendered(rendered)
66
  return text, _page_count(rendered, pdf_path)