diff --git a/deepdoc/parser/mistral_parser.py b/deepdoc/parser/mistral_parser.py index a7d5c014a7..f60d112141 100644 --- a/deepdoc/parser/mistral_parser.py +++ b/deepdoc/parser/mistral_parser.py @@ -387,6 +387,17 @@ class MistralParser(RAGFlowPdfParser): def check_installation(self) -> tuple[bool, str]: if not self.api_key: return False, "Mistral API key is not configured." + + try: + r = requests.get(f"{self.base_url}/models", headers=self._headers(), timeout=10) + self.logger.info(f"[Mistral] API models endpoint reachable, status={r.status_code}") + if r.status_code != 200: + return False, f"Mistral API check failed: HTTP {r.status_code} {r.text[:200]}" + except Exception as exc: + reason = f"Mistral API check failed: {exc}" + self.logger.warning(reason) + return False, reason + return True, "" def _raise_for_status(self, resp, action: str) -> None: diff --git a/test/unit_test/deepdoc/parser/test_mistral_parser.py b/test/unit_test/deepdoc/parser/test_mistral_parser.py index 78840f58e6..d3c49e38c2 100644 --- a/test/unit_test/deepdoc/parser/test_mistral_parser.py +++ b/test/unit_test/deepdoc/parser/test_mistral_parser.py @@ -297,6 +297,7 @@ def test_call_ocr_inline_posts_pages_selector(monkeypatch): return _Resp(200, {"pages": [{"index": 5, "markdown": "x", "blocks": []}], "usage_info": {"pages_processed": 1}}) monkeypatch.setattr(m.requests, "post", fake_post) + monkeypatch.setattr(m.requests, "get", lambda *a, **k: _Resp(200, {})) out = p._call_ocr(b"%PDF-1.4 fake", "f.pdf", pages=[5]) assert captured["url"].endswith("/ocr") assert captured["json"]["pages"] == [5] @@ -309,6 +310,7 @@ def test_call_ocr_omits_pages_when_none(monkeypatch): p = _make_parser(m, api_key="sk-test") captured = {} monkeypatch.setattr(m.requests, "post", lambda url, headers=None, json=None, timeout=None, **kw: captured.update(json=json) or _Resp(200, {"pages": []})) + monkeypatch.setattr(m.requests, "get", lambda *a, **k: _Resp(200, {})) p._call_ocr(b"%PDF fake", "f.pdf", pages=None) assert "pages" not in captured["json"] @@ -316,6 +318,7 @@ def test_call_ocr_omits_pages_when_none(monkeypatch): def test_call_ocr_raises_on_http_error(monkeypatch): m = _load_mistral_parser(monkeypatch) p = _make_parser(m, api_key="sk-bad") + monkeypatch.setattr(m.requests, "get", lambda *a, **k: _Resp(200, {})) monkeypatch.setattr(m.requests, "post", lambda *a, **k: _Resp(401, text="Unauthorized")) with pytest.raises(RuntimeError, match="401"): p._call_ocr(b"%PDF fake", "f.pdf", pages=None) @@ -346,6 +349,7 @@ def test_call_ocr_upload_files_error_no_delete(monkeypatch): m = _load_mistral_parser(monkeypatch) p = _make_parser(m, api_key="sk-test", inline_max_bytes=4) calls = {"delete": []} + monkeypatch.setattr(m.requests, "get", lambda *a, **k: _Resp(200, {})) monkeypatch.setattr(m.requests, "post", lambda url, headers=None, json=None, data=None, files=None, timeout=None, **kw: _Resp(500, text="boom")) monkeypatch.setattr(m.requests, "delete", lambda url, headers=None, timeout=None, **kw: calls["delete"].append(url) or _Resp(200, {})) with pytest.raises(RuntimeError, match="500"): @@ -358,7 +362,7 @@ def test_call_ocr_signed_url_error_triggers_cleanup(monkeypatch): p = _make_parser(m, api_key="sk-test", inline_max_bytes=4) calls = {"delete": []} monkeypatch.setattr(m.requests, "post", lambda url, headers=None, json=None, data=None, files=None, timeout=None, **kw: _Resp(200, {"id": "file-1"})) - monkeypatch.setattr(m.requests, "get", lambda url, headers=None, params=None, timeout=None, **kw: _Resp(403, text="nope")) + monkeypatch.setattr(m.requests, "get", lambda url, headers=None, params=None, timeout=None, **kw: _Resp(200, {}) if "/models" in url else _Resp(403, text="nope")) monkeypatch.setattr(m.requests, "delete", lambda url, headers=None, timeout=None, **kw: calls["delete"].append(url) or _Resp(200, {})) with pytest.raises(RuntimeError, match="403"): p._call_ocr(b"%PDF-too-big", "big.pdf", pages=None)