From 8cfac2a24b3629d396a5316d3c50334e4ff88402 Mon Sep 17 00:00:00 2001 From: Yujong Lee Date: Wed, 2 Sep 2026 09:19:48 -0700 Subject: [PATCH] test(ocr): migrate parity fixtures to VCR cassettes --- tests/route_parity/README.md | 21 +++ tests/route_parity/fixtures/cassette.py | 147 ++++++++++++++++++ tests/route_parity/fixtures/pipeline.py | 18 ++- tests/route_parity/fixtures/recording.py | 62 ++++++-- tests/route_parity/fixtures/store.py | 65 +++++--- tests/route_parity/fixtures/test_cassette.py | 95 +++++++++++ tests/route_parity/fixtures/test_pipeline.py | 4 +- tests/route_parity/fixtures/test_recording.py | 46 +++++- tests/test_litellm/ocr/fixtures/README.md | 14 ++ ...64eff8b03523dfa908ea59ff1bb7bd185ede8.json | 138 ---------------- ...2f2996578fff02d93ec3011031ce2b4c511fc.yaml | 68 ++++++++ ...6a6cea47e1f67c0f48c9804cb09d1c4695f42.json | 91 ----------- ...c7ded7fea981215a478a12d8636eff8eb1157.yaml | 60 +++++++ ...b119bced6537f45cf08b27cbec08bb8f45951.yaml | 69 ++++++++ ...2e0a8f4a8bde179faaaa28f39b049e7886f07.json | 91 ----------- ...678b8acd5c2dc460cd06f5302a0bf05f3089c.json | 91 ----------- ...8bf3940c6eddbe486e66ad40e18974464eda7.json | 78 ---------- ...f46da887570de720a142e9df297bdd280608d.yaml | 85 ++++++++++ ...625aa688e6cbd69e01f94d1f3205ef41ab830.yaml | 68 ++++++++ ...c19740883cf42bb87221eafd16df3e597ceda.json | 110 ------------- ...f54fc03ab0db9076004caf5262ce3fed4f06b.json | 90 ----------- ...01606b7039583f55a0f85bfe38c7c15712adf.yaml | 67 ++++++++ ...69eb5c13a7327ed36f77a40c0b192c3a1bf4f.json | 122 --------------- ...da532390140ade4e10b5bb07570ca7b372499.yaml | 82 ++++++++++ ...598ef9e6df1813bee21137e88bcc14ce7a473.yaml | 92 +++++++++++ ...358dc7c9b0eafc64e7e2516d46e290fc93092.yaml | 83 ++++++++++ ...acf8c80e20574f6ef9782997eaef9adc10e0b.json | 91 ----------- ...57cd562048fc6a993cba093fe86a8937d104b.yaml | 68 ++++++++ ...e4f1a486bbe3165f5be777e67376075fd89a8.json | 111 ------------- ...e88e27651580bac1e145ad352728b1a0acd31.yaml | 68 ++++++++ ...8047b28006b5cbd4486d54c6fe89070e7a671.yaml | 68 ++++++++ ...d77447359bba8c29d6b31e650255298271d47.yaml | 67 ++++++++ ...3bba41a29b707d0cfafd74986e6ad8c2ed900.yaml | 68 ++++++++ ...b3b7dc37c5bf5dfd47e873c4cc695d6d7461f.yaml | 68 ++++++++ ...689c3583b09694a7ac086e4707be49b35eb06.yaml | 83 ++++++++++ ...ee17598a3a1265a630f9a6e42a2df352906bf.json | 91 ----------- ...c79a7f6895b1d6ef5c8f544bae77854bfd951.json | 93 ----------- ...ae74dd363ddda0d6677155afbd145d0dc3c36.yaml | 68 ++++++++ ...6d73ea777503f904a6bff9960a25046085d0d.json | 91 ----------- ...6ab165f1866eb074a8c079273eef5df512985.yaml | 105 +++++++++++++ ...77eebedf342e1844f9114d8db8b9de8a8b08b.json | 110 ------------- ...d176db3731e07107f45318fb681740ee49a74.json | 91 ----------- ...49d5a62e67fa9e6c51ba30de4eaf4bba5a73f.json | 91 ----------- ...33086cb79e87d2bdb99bdbb3b7e11751c43d7.json | 110 ------------- ...33573014c6353f8d2486cc34753ceab6c7c1a.json | 91 ----------- ...030105ad107ae3400532b20ad70ebbd021954.yaml | 70 +++++++++ ...a8cf08e7dc5bbe1f7286d7c04a0454baf5c66.json | 46 ------ ...7e201dfb9ac31de66094734ef38c288293625.json | 30 ---- ...7e201dfb9ac31de66094734ef38c288293625.yaml | 39 +++++ ...37e51b7e915b96a85e4ce8dfc41ba5f7f11df.yaml | 70 +++++++++ ...7e3b8fdbfe1fb5a9818a2fe47f02c2aad0fac.yaml | 69 ++++++++ ...a4b0c7ae2e28ce957493e996a006ef2fcc6be.json | 46 ------ ...921e3e782e4e9f10be9a4ba000a8caf1e9ab5.json | 45 ------ ...45a56b19b4775393c22bf9fa6ead2c3cc323c.json | 46 ------ ...2f06ce970d117de9828d72ed76b71b6f5adc1.json | 56 ------- ...7398c1c26cf1fb8f134b1326e79bd3d487c41.yaml | 72 +++++++++ ...52520370e0c873939813c2167799cffacba06.json | 48 ------ ...0c95f731a0913d223fbe1780bbaaef1ecd835.yaml | 83 ++++++++++ ...04be5c772291d89dd5a67480c21e4e2ac3834.json | 45 ------ ...ccb9e95c3aae1d774f03869cf7cacfaa9aa07.json | 82 ---------- ...e4239015b9b44376ce49c921f8fc057fb9c6a.yaml | 70 +++++++++ ...653fe30bde512da747d2fd8e78759ccdc9b90.yaml | 70 +++++++++ ...b98a3a0d251a27c3bb80178580a711c111e94.yaml | 100 ++++++++++++ ...a3a43364ea319d905b5030014f4d85e7c94e9.json | 50 ------ ...409b1ca17c23b9e491b4f8b6ac705acd05637.json | 48 ------ ...ee0396ea754023bd5ab34065efcc852914f15.json | 46 ------ ...3999653d141626ca1eadfdb47fc20d645b9d5.yaml | 72 +++++++++ ...84da6aa7892f8cdd4f22158ba4c700dbe8a81.json | 30 ---- ...84da6aa7892f8cdd4f22158ba4c700dbe8a81.yaml | 39 +++++ ...e92b04e51b1ea8b74eaa4a4382a01154b5f5a.yaml | 71 +++++++++ ...97f703d67d234593ac188f948142190fdf06d.yaml | 69 ++++++++ tests/test_litellm/ocr/fixtures/migrate.py | 63 ++++++++ tests/test_litellm/ocr/test_fixture_store.py | 28 ++++ 73 files changed, 2752 insertions(+), 2441 deletions(-) create mode 100644 tests/route_parity/fixtures/cassette.py create mode 100644 tests/route_parity/fixtures/test_cassette.py delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/0ab748e6b7315f0c7a36195cc4564eff8b03523dfa908ea59ff1bb7bd185ede8.json create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/0b234402bdfd3be223e731051202f2996578fff02d93ec3011031ce2b4c511fc.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/0c9204f5ed668c628835b9d60806a6cea47e1f67c0f48c9804cb09d1c4695f42.json create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/1f3001924ef2c46d3eccdedd808c7ded7fea981215a478a12d8636eff8eb1157.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/1f38e1eab857c22107df833aa63b119bced6537f45cf08b27cbec08bb8f45951.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/216aacc1aa47a6060445f2ea49a2e0a8f4a8bde179faaaa28f39b049e7886f07.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/2c893c555fe38cdfa0f03b43b5e678b8acd5c2dc460cd06f5302a0bf05f3089c.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/3832acde595e59e0b3f663c560c8bf3940c6eddbe486e66ad40e18974464eda7.json create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/38dbc05d8508355879de894ecc0f46da887570de720a142e9df297bdd280608d.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/3d5f42192461789f547b42c8f1b625aa688e6cbd69e01f94d1f3205ef41ab830.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/3e4f8a006942b85eb954833d42cc19740883cf42bb87221eafd16df3e597ceda.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/49328aed7d9a4833427d80c7ac4f54fc03ab0db9076004caf5262ce3fed4f06b.json create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/54ce0991a21ea668e2373d2b05801606b7039583f55a0f85bfe38c7c15712adf.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/67a074c43483176b6a8da74f21869eb5c13a7327ed36f77a40c0b192c3a1bf4f.json create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/7f7dc004625cb90e3f4bd2f473fda532390140ade4e10b5bb07570ca7b372499.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/99d9d5ac0449213a562a36163ee598ef9e6df1813bee21137e88bcc14ce7a473.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/9b9fb2f3a7eb8ca1e2d128ea96b358dc7c9b0eafc64e7e2516d46e290fc93092.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/9f220bfe8a2042fa74e1dada33facf8c80e20574f6ef9782997eaef9adc10e0b.json create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/a8693352d9ce0d7d120b2351d2257cd562048fc6a993cba093fe86a8937d104b.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/afc42ea89caa932d7ea33666d91e4f1a486bbe3165f5be777e67376075fd89a8.json create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/b19fdc140375a4eadfd6eb4e4cbe88e27651580bac1e145ad352728b1a0acd31.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/bdb616d21dece89481debccb9358047b28006b5cbd4486d54c6fe89070e7a671.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/c3066e2f2f964725b71ae891821d77447359bba8c29d6b31e650255298271d47.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/c57601c90e9b289e506cdc818523bba41a29b707d0cfafd74986e6ad8c2ed900.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/c5d33cb2b20fb76c9543ff57dc9b3b7dc37c5bf5dfd47e873c4cc695d6d7461f.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/c6f0f158205be7fc00bd962e341689c3583b09694a7ac086e4707be49b35eb06.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/c74f9b5ad64bd97d8b4c48772c9ee17598a3a1265a630f9a6e42a2df352906bf.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/cd2461bbef1fc222e80b3397231c79a7f6895b1d6ef5c8f544bae77854bfd951.json create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/cea250810b49cd17251ee8c036eae74dd363ddda0d6677155afbd145d0dc3c36.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/d1aa25a0353a8ff15c49088247a6d73ea777503f904a6bff9960a25046085d0d.json create mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/d80a6ccca02922ba9094426235a6ab165f1866eb074a8c079273eef5df512985.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/e362d4eb7aa5f50706b54d0bbb777eebedf342e1844f9114d8db8b9de8a8b08b.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/e9217f2a27a061f2ed26a567677d176db3731e07107f45318fb681740ee49a74.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/ea3c537a691b95003afc21b351549d5a62e67fa9e6c51ba30de4eaf4bba5a73f.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/effe3c112538d2aa6ac98e8f47033086cb79e87d2bdb99bdbb3b7e11751c43d7.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/mistral-ocr/f430ede1f4069abab794731b9c233573014c6353f8d2486cc34753ceab6c7c1a.json create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-legacy/09cc2f0155ffdc3d25abff96797030105ad107ae3400532b20ad70ebbd021954.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-legacy/5671d085483943d56d3e16d95a0a8cf08e7dc5bbe1f7286d7c04a0454baf5c66.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-legacy/7c4bbc65dfbc17bac7f0d179c5d7e201dfb9ac31de66094734ef38c288293625.json create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-legacy/7c4bbc65dfbc17bac7f0d179c5d7e201dfb9ac31de66094734ef38c288293625.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-legacy/953d2a3bfea5594f9df19fc3f6c37e51b7e915b96a85e4ce8dfc41ba5f7f11df.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-legacy/a41d4c9547448df927b308d619d7e3b8fdbfe1fb5a9818a2fe47f02c2aad0fac.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-legacy/ea3262579a0882bcb61972e2a2aa4b0c7ae2e28ce957493e996a006ef2fcc6be.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-legacy/fbf21ae169e9ddbca638f445bad921e3e782e4e9f10be9a4ba000a8caf1e9ab5.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/00312c58e0dccd4699086d6c37b45a56b19b4775393c22bf9fa6ead2c3cc323c.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/0b4ca483494e37fce75cc861ba62f06ce970d117de9828d72ed76b71b6f5adc1.json create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/2148dfafc823aea933d7c9aa8877398c1c26cf1fb8f134b1326e79bd3d487c41.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/3a512e502dc6310e671e8967a7652520370e0c873939813c2167799cffacba06.json create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/50890748074024915ef138fcb8e0c95f731a0913d223fbe1780bbaaef1ecd835.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/5227441615ac16de68a18458e9704be5c772291d89dd5a67480c21e4e2ac3834.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/75876320a008dc29db48c33e4d4ccb9e95c3aae1d774f03869cf7cacfaa9aa07.json create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/7cefa9e08179db20d45e255d269e4239015b9b44376ce49c921f8fc057fb9c6a.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/8270ee13cdfb2ceefd8302a1880653fe30bde512da747d2fd8e78759ccdc9b90.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/997cd381eb3019b71086e4fdab1b98a3a0d251a27c3bb80178580a711c111e94.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/aee30a1d7a51a3fd8837b56d6baa3a43364ea319d905b5030014f4d85e7c94e9.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/cfb4093138a106055f36402de37409b1ca17c23b9e491b4f8b6ac705acd05637.json delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/d5a49e5897e920719ca28697413ee0396ea754023bd5ab34065efcc852914f15.json create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/f2b260eca76347d5982b96c79563999653d141626ca1eadfdb47fc20d645b9d5.yaml delete mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/f317c1c7b57a6ac742de1b97f2f84da6aa7892f8cdd4f22158ba4c700dbe8a81.json create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/f317c1c7b57a6ac742de1b97f2f84da6aa7892f8cdd4f22158ba4c700dbe8a81.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/f55e3b684697b9f478393e35202e92b04e51b1ea8b74eaa4a4382a01154b5f5a.yaml create mode 100644 tests/test_litellm/ocr/fixtures/data/reducto-v3/f847dae1a1f6c3777ce3b65421a97f703d67d234593ac188f948142190fdf06d.yaml create mode 100644 tests/test_litellm/ocr/fixtures/migrate.py diff --git a/tests/route_parity/README.md b/tests/route_parity/README.md index c072b5ae575..e8d5c62ff9b 100644 --- a/tests/route_parity/README.md +++ b/tests/route_parity/README.md @@ -40,6 +40,27 @@ The shared package owns recording, replay, persistence, execution, comparison, a Each API package owns its input models, explicit strategies, provider targets, route-specific assets, fixture directory, and regeneration command. See the API package documentation for its configured contracts and recording command +## VCR cassettes + +Fixtures use VCR's YAML `version: 1` format with ordered request/response `interactions`. VCR handles text and binary +body serialization. Each cassette also contains `recorded_at`, `ttl_seconds: 0` (committed fixtures never expire), and +`x-litellm` metadata holding the SDK input and request provenance. Streaming responses carry +`x-litellm-chunk-lengths` so local replay preserves the original byte boundaries + +The recording server captures requests before forwarding their responses. Saved requests use the stable +`http://parity-provider.invalid` origin and strip authentication headers and credential query parameters. The upstream +request keeps its credentials. Provider response bytes and non-success statuses are preserved + +Standard VCR can load these files and replay their interactions. Parity tests keep using the local HTTP server because +Rust HTTP calls do not pass through VCR's Python patches. The harness still compares the two implementations' requests +against each other; the saved request is available for inspection and VCR playback, not a new parity assertion + +Refresh parity cassettes through the API's recording command. Generic VCR writers do not preserve the SDK metadata + +Legacy JSON fixtures remain readable. Migrated cassettes mark reconstructed requests as `python_replay`; fresh +recordings use `recorded`. The metadata extensions follow the filesystem cassette layout proposed in +[PR #39338](https://github.com/BerriAI/litellm/pull/39338), without depending on its unmerged persistence backend + ## References - [Hypothesis documentation](https://hypothesis.readthedocs.io/en/latest/) diff --git a/tests/route_parity/fixtures/cassette.py b/tests/route_parity/fixtures/cassette.py new file mode 100644 index 00000000000..6ab4210e031 --- /dev/null +++ b/tests/route_parity/fixtures/cassette.py @@ -0,0 +1,147 @@ +from __future__ import annotations + +from collections.abc import Mapping +from datetime import datetime +from itertools import accumulate +from typing import Final, Literal + +from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, TypeAdapter +from vcr.serialize import serialize +from vcr.serializers import yamlserializer + +from tests.route_parity.fixtures.recording import RecordedInteraction +from tests.route_parity.recorded_http import ( + HttpHeader, + RecordedHttpResponse, + RecordedHttpStreamResponse, + RecordedResponse, + RecordedStreamChunk, +) + +_OBJECT: Final = TypeAdapter(dict[str, object]) + + +class _CassetteModel(BaseModel): + model_config = ConfigDict(frozen=True, extra="forbid", populate_by_name=True) + + +class _Body(_CassetteModel): + string: str | bytes + + def as_bytes(self) -> bytes: + return self.string.encode("utf-8") if isinstance(self.string, str) else self.string + + +class _Status(_CassetteModel): + code: int + message: str + + +class _Request(_CassetteModel): + method: str + uri: str + body: str | bytes | None + headers: dict[str, tuple[str, ...]] + + +class _Response(_CassetteModel): + status: _Status + headers: dict[str, tuple[str, ...]] + body: _Body + chunk_lengths: tuple[int, ...] | None = Field(default=None, alias="x-litellm-chunk-lengths") + + def recorded_response(self) -> RecordedResponse: + headers: Final = tuple( + HttpHeader(name=name, value=value) for name, values in self.headers.items() for value in values + ) + body: Final = self.body.as_bytes() + if self.chunk_lengths is None: + return RecordedHttpResponse.from_bytes(self.status.code, headers, body) + if any(length < 0 for length in self.chunk_lengths) or sum(self.chunk_lengths) != len(body): + raise ValueError("cassette stream chunk lengths do not match the response body") + offsets: Final = tuple(accumulate(self.chunk_lengths, initial=0)) + return RecordedHttpStreamResponse( + kind="http_stream", + status_code=self.status.code, + headers=headers, + chunks=tuple(RecordedStreamChunk.from_bytes(body[start:end]) for start, end in zip(offsets, offsets[1:])), + ) + + +class _Interaction(_CassetteModel): + request: _Request + response: _Response + + +class _ParityMetadata(_CassetteModel): + schema_version: Literal[1] + request_source: Literal["recorded", "python_replay"] + case: dict[str, object] + + +class ParityCassette(_CassetteModel): + version: Literal[1] + recorded_at: AwareDatetime + ttl_seconds: Literal[0] + interactions: tuple[_Interaction, ...] + parity: _ParityMetadata = Field(alias="x-litellm") + + def case_data(self) -> dict[str, object]: + return { + **self.parity.case, + "provider_responses": tuple(item.response.recorded_response() for item in self.interactions), + } + + +def _response_dict(response: RecordedResponse) -> dict[str, object]: + headers: Final = { + name: [header.value for header in response.headers if header.name == name] + for name in dict.fromkeys(header.name for header in response.headers) + } + chunks: Final = ( + tuple(chunk.data_bytes() for chunk in response.chunks) + if isinstance(response, RecordedHttpStreamResponse) + else None + ) + body: Final = response.body_bytes() if isinstance(response, RecordedHttpResponse) else b"".join(chunks or ()) + return { + "status": {"code": response.status_code, "message": ""}, + "headers": headers, + "body": {"string": body}, + **({"x-litellm-chunk-lengths": list(map(len, chunks))} if chunks is not None else {}), + } + + +def serialize_cassette( + case: Mapping[str, object], + interactions: tuple[RecordedInteraction, ...], + recorded_at: datetime, + request_source: Literal["recorded", "python_replay"], +) -> str: + normalized: Final = _OBJECT.validate_python( + yamlserializer.deserialize( + serialize( + { + "requests": [item.request for item in interactions], + "responses": [_response_dict(item.response) for item in interactions], + }, + yamlserializer, + ) + ) + ) + payload: Final = { + **normalized, + "recorded_at": recorded_at.isoformat(), + "ttl_seconds": 0, + "x-litellm": { + "schema_version": 1, + "request_source": request_source, + "case": {key: value for key, value in case.items() if key != "provider_responses"}, + }, + } + ParityCassette.model_validate(payload).case_data() + return str(yamlserializer.serialize(payload)) + + +def deserialize_cassette(contents: str) -> ParityCassette: + return ParityCassette.model_validate(yamlserializer.deserialize(contents)) diff --git a/tests/route_parity/fixtures/pipeline.py b/tests/route_parity/fixtures/pipeline.py index 39e4ee76eb9..288fbeba7fa 100644 --- a/tests/route_parity/fixtures/pipeline.py +++ b/tests/route_parity/fixtures/pipeline.py @@ -11,7 +11,7 @@ from hypothesis.strategies import SearchStrategy from pydantic import BaseModel from tests.route_parity.fixtures.inputs import generate_case_inputs -from tests.route_parity.fixtures.recording import UpstreamEndpoint, record_upstream_responses +from tests.route_parity.fixtures.recording import UpstreamEndpoint, record_upstream_interactions from tests.route_parity.fixtures.store import ( FixtureInput, canonical_json, @@ -121,19 +121,25 @@ def build_recording_jobs( def _record_job(job: RecordingJob[InputT], case_type: type[CaseT]) -> RecordedFixture | CachedFixture: cached: Final = load_fixture(job.directory, job.case_input, case_type) if cached is not None: + path: Final = fixture_path(job.directory, job.case_input) return CachedFixture( target_name=job.target_name, case_id=job.case_id, - path=fixture_path(job.directory, job.case_input), + path=path if path.is_file() else path.with_suffix(".json"), ) - provider_responses: Final = record_upstream_responses( + interactions: Final = record_upstream_interactions( job.upstream, job.case_input, job.invocation.execute, ) - case: Final = case_type.model_validate({"litellm_input": job.case_input, "provider_responses": provider_responses}) - path: Final = save_fixture(job.directory, job.case_input, case) - return RecordedFixture(target_name=job.target_name, case_id=job.case_id, path=path) + case: Final = case_type.model_validate( + { + "litellm_input": job.case_input, + "provider_responses": tuple(item.response for item in interactions), + } + ) + saved_path: Final = save_fixture(job.directory, job.case_input, case, interactions) + return RecordedFixture(target_name=job.target_name, case_id=job.case_id, path=saved_path) def _completed_outcome( diff --git a/tests/route_parity/fixtures/recording.py b/tests/route_parity/fixtures/recording.py index d85f53324cb..9908a89ae91 100644 --- a/tests/route_parity/fixtures/recording.py +++ b/tests/route_parity/fixtures/recording.py @@ -10,6 +10,8 @@ from typing import Final, TypeVar, cast from urllib.parse import urlsplit, urlunsplit import httpx +from vcr.filters import remove_query_parameters +from vcr.request import Request from tests.provider_record_replay.http import ( dropped_request_headers, @@ -25,6 +27,21 @@ from tests.route_parity.recorded_http import ( ) _PARITY_PROVIDER_HOST: Final = "parity-provider.invalid" +_SECRET_HEADERS: Final = frozenset( + { + "authorization", + "proxy-authorization", + "cookie", + "x-api-key", + "api-key", + "anthropic-api-key", + "openai-api-key", + "azure-api-key", + "x-goog-api-key", + "ocp-apim-subscription-key", + "x-amz-security-token", + } +) InputT = TypeVar("InputT") @@ -34,6 +51,12 @@ class UpstreamEndpoint: base_url: str +@dataclass(frozen=True, slots=True) +class RecordedInteraction: + request: Request + response: RecordedResponse + + def _end_to_end_headers(headers: httpx.Headers) -> tuple[HttpHeader, ...]: decoded: Final = tuple((name.decode("ascii"), value.decode("latin-1")) for name, value in headers.raw) excluded: Final = dropped_response_headers(decoded) @@ -68,18 +91,18 @@ class _RecordingProvider(ThreadingHTTPServer): def __init__(self, spec: UpstreamEndpoint) -> None: super().__init__(("127.0.0.1", 0), _RecordingHandler) self.spec: Final = spec - self.responses: queue.Queue[RecordedResponse] = queue.Queue() + self.interactions: queue.Queue[RecordedInteraction] = queue.Queue() @property def url(self) -> str: return f"http://127.0.0.1:{self.server_address[1]}" - def take_responses(self) -> tuple[RecordedResponse, ...]: + def take_interactions(self) -> tuple[RecordedInteraction, ...]: try: - first: Final = self.responses.get(timeout=5) + first: Final = self.interactions.get(timeout=5) except queue.Empty as error: raise RuntimeError("successful SDK call did not produce a recorded response") from error - remaining: Final = tuple(self.responses.get_nowait() for _ in range(self.responses.qsize())) + remaining: Final = tuple(self.interactions.get_nowait() for _ in range(self.interactions.qsize())) return (first, *remaining) @@ -125,7 +148,16 @@ class _RecordingHandler(BaseHTTPRequestHandler): self._send_response(502, (), str(error).encode("utf-8")) return - provider.responses.put(recorded_response) + recorded_request: Final = remove_query_parameters( + Request( + self.command, + f"http://{_PARITY_PROVIDER_HOST}{self.path}", + request_body, + {name: value for name, value in forwarded_headers if name.lower() not in _SECRET_HEADERS}, + ), + ("api_key", "api-key", "key", "access_token", "subscription-key"), + ) + provider.interactions.put(RecordedInteraction(recorded_request, recorded_response)) if isinstance(recorded_response, RecordedHttpResponse): self._send_response( recorded_response.status_code, recorded_response.headers, recorded_response.body_bytes() @@ -203,19 +235,28 @@ def _recording_provider(spec: UpstreamEndpoint) -> Generator[_RecordingProvider] thread.join(timeout=5) -def _invoke_and_take_responses( +def _invoke_and_take_interactions( recorder: _RecordingProvider, case_input: InputT, sdk_call: Callable[[str, InputT], object], -) -> tuple[RecordedResponse, ...]: +) -> tuple[RecordedInteraction, ...]: try: sdk_call(recorder.url, case_input) except Exception as invocation_error: try: - return recorder.take_responses() + return recorder.take_interactions() except RuntimeError: raise invocation_error - return recorder.take_responses() + return recorder.take_interactions() + + +def record_upstream_interactions( + spec: UpstreamEndpoint, + case_input: InputT, + sdk_call: Callable[[str, InputT], object], +) -> tuple[RecordedInteraction, ...]: + with _recording_provider(spec) as recorder: + return _invoke_and_take_interactions(recorder, case_input, sdk_call) def record_upstream_responses( @@ -223,5 +264,4 @@ def record_upstream_responses( case_input: InputT, sdk_call: Callable[[str, InputT], object], ) -> tuple[RecordedResponse, ...]: - with _recording_provider(spec) as recorder: - return _invoke_and_take_responses(recorder, case_input, sdk_call) + return tuple(item.response for item in record_upstream_interactions(spec, case_input, sdk_call)) diff --git a/tests/route_parity/fixtures/store.py b/tests/route_parity/fixtures/store.py index a169d96c835..ca1ba58643d 100644 --- a/tests/route_parity/fixtures/store.py +++ b/tests/route_parity/fixtures/store.py @@ -2,13 +2,17 @@ from __future__ import annotations import hashlib import json +import tempfile from collections.abc import Mapping from datetime import datetime, timezone from pathlib import Path -from typing import Final, Protocol, TypeVar, cast +from typing import Final, Literal, Protocol, TypeVar, cast from pydantic import AwareDatetime, BaseModel, ConfigDict, TypeAdapter, ValidationError +from tests.route_parity.fixtures.cassette import deserialize_cassette, serialize_cassette +from tests.route_parity.fixtures.recording import RecordedInteraction + FIXTURE_SCHEMA_VERSION: Final = 1 JSON_OBJECT: Final = TypeAdapter(dict[str, object]) @@ -39,33 +43,58 @@ def fixture_cache_key(case_input: FixtureInput) -> dict[str, object]: def fixture_path(directory: Path, case_input: FixtureInput) -> Path: input_json: Final = canonical_json(fixture_cache_key(case_input)) digest: Final = hashlib.sha256(input_json.encode("utf-8")).hexdigest() - return directory / f"{digest}.json" + return directory / f"{digest}.yaml" def load_fixture(directory: Path, case_input: FixtureInput, case_type: type[CaseT]) -> CaseT | None: path: Final = fixture_path(directory, case_input) - if not path.is_file(): + if path.is_file(): + return read_fixture(path, case_type) + legacy_path: Final = path.with_suffix(".json") + if not legacy_path.is_file(): return None - return _load_fixture(JSON_OBJECT.validate_json(path.read_text(encoding="utf-8")), path, case_type) + return read_fixture(legacy_path, case_type) -def save_fixture(directory: Path, case_input: FixtureInput, case: BaseModel) -> Path: +def save_fixture( + directory: Path, + case_input: FixtureInput, + case: BaseModel, + interactions: tuple[RecordedInteraction, ...], + *, + recorded_at: datetime | None = None, + request_source: Literal["recorded", "python_replay"] = "recorded", +) -> Path: directory.mkdir(parents=True, exist_ok=True) path: Final = fixture_path(directory, case_input) - temporary_path: Final = path.with_suffix(".tmp") - envelope: Final = FixtureEnvelope( - schema_version=FIXTURE_SCHEMA_VERSION, - recorded_at=datetime.now(timezone.utc), - case=cast(dict[str, object], case.model_dump(mode="json", exclude_unset=True)), + serialized: Final = serialize_cassette( + cast(dict[str, object], case.model_dump(mode="json", exclude_unset=True)), + interactions, + recorded_at or datetime.now(timezone.utc), + request_source, ) - serialized: Final = ( - json.dumps(envelope.model_dump(mode="json", exclude_unset=True), indent=2, sort_keys=True) + "\n" - ) - temporary_path.write_text(serialized, encoding="utf-8") - temporary_path.replace(path) + with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", dir=directory, delete=False) as temporary: + temporary_path: Final = Path(temporary.name) + try: + temporary.write(serialized) + temporary.close() + temporary_path.replace(path) + finally: + temporary_path.unlink(missing_ok=True) return path +def read_fixture(path: Path, case_type: type[CaseT]) -> CaseT: + contents: Final = path.read_text(encoding="utf-8") + if path.suffix == ".json": + return _load_fixture(JSON_OBJECT.validate_json(contents), path, case_type) + try: + cassette: Final = deserialize_cassette(contents) + return case_type.model_validate(cassette.case_data()) + except ValueError as error: + raise ValueError(f"invalid parity cassette {path}") from error + + def _load_fixture(raw_fixture: dict[str, object], path: Path, case_type: type[CaseT]) -> CaseT: schema_version: Final = raw_fixture.get("schema_version") if schema_version != FIXTURE_SCHEMA_VERSION: @@ -83,10 +112,8 @@ def _load_fixture(raw_fixture: dict[str, object], path: Path, case_type: type[Ca def recorded_fixtures(directory: Path, case_type: type[CaseT]) -> tuple[CaseT, ...]: if not directory.is_dir(): return () - paths: Final = tuple(sorted(directory.rglob("*.json"))) - return tuple( - _load_fixture(JSON_OBJECT.validate_json(path.read_text(encoding="utf-8")), path, case_type) for path in paths - ) + paths: Final = tuple(sorted((*directory.rglob("*.yaml"), *directory.rglob("*.json")))) + return tuple(read_fixture(path, case_type) for path in paths) def fixture_directory(configured: Path | None, env_value: str | None, default: Path) -> Path: diff --git a/tests/route_parity/fixtures/test_cassette.py b/tests/route_parity/fixtures/test_cassette.py new file mode 100644 index 00000000000..d455a9a4d91 --- /dev/null +++ b/tests/route_parity/fixtures/test_cassette.py @@ -0,0 +1,95 @@ +from __future__ import annotations + +from datetime import datetime, timezone +from pathlib import Path +from typing import Final + +import httpx +import pytest +from vcr import VCR +from vcr.request import Request + +from tests.route_parity.fixture_models import ParityCase, SdkInputBase +from tests.route_parity.fixtures.cassette import deserialize_cassette +from tests.route_parity.fixtures.recording import RecordedInteraction +from tests.route_parity.fixtures.store import load_fixture, save_fixture +from tests.route_parity.recorded_http import ( + HttpHeader, + RecordedHttpResponse, + RecordedHttpStreamResponse, + RecordedResponse, + RecordedStreamChunk, +) +from tests.route_parity.replay import replay_server + +_URI: Final = "http://parity-provider.invalid/operation?api-version=1" + + +class _Input(SdkInputBase): + model: str = "fixture-model" + + +@pytest.mark.parametrize("body", (b'{"text":"caf\xc3\xa9"}', b"\x00\xff\x80", b"")) +def test_cassette_replays_repeated_requests_with_vcr_and_preserves_bytes(tmp_path: Path, body: bytes) -> None: + sdk_input: Final = _Input() + responses: Final = tuple( + RecordedHttpResponse.from_bytes( + status, + (HttpHeader(name="content-type", value="application/octet-stream"),), + body, + ) + for status in (200, 429) + ) + case: Final = ParityCase[_Input](litellm_input=sdk_input, provider_responses=responses) + interactions: Final = tuple( + RecordedInteraction(Request("POST", _URI, b"\xffrequest", {}), response) for response in responses + ) + timestamp: Final = datetime(2020, 1, 1, tzinfo=timezone.utc) + path: Final = save_fixture(tmp_path, sdk_input, case, interactions, recorded_at=timestamp) + + assert load_fixture(tmp_path, sdk_input, ParityCase[_Input]) == case + assert deserialize_cassette(path.read_text()).recorded_at == timestamp + with VCR().use_cassette(str(path), record_mode="none", match_on=("method", "uri", "body")) as cassette: + for status in (200, 429): + replayed: Final = httpx.post(_URI, content=b"\xffrequest") + assert replayed.status_code == status + assert replayed.content == body + assert cassette.all_played + + +def test_stream_cassette_preserves_chunk_boundaries_through_local_replay(tmp_path: Path) -> None: + sdk_input: Final = _Input() + chunks: Final = (b"data: caf\xc3", b"\xa9\n\n", b"data: [DONE]\n\n") + response: Final = RecordedHttpStreamResponse( + kind="http_stream", + status_code=200, + headers=(HttpHeader(name="content-type", value="text/event-stream"),), + chunks=tuple(RecordedStreamChunk.from_bytes(chunk) for chunk in chunks), + ) + case: Final = ParityCase[_Input](litellm_input=sdk_input, provider_responses=(response,)) + path: Final = save_fixture( + tmp_path, sdk_input, case, (RecordedInteraction(Request("POST", _URI, b"{}", {}), response),) + ) + loaded: Final = load_fixture(tmp_path, sdk_input, ParityCase[_Input]) + assert loaded == case + with replay_server() as server: + server.enqueue_response(loaded.provider_responses[0]) + with httpx.stream("POST", f"{server.url}/operation", content=b"{}") as replayed: + assert tuple(replayed.iter_raw()) == chunks + server.take_requests(1) + path.write_text(path.read_text().replace("- 10\n", "- 999\n")) + with pytest.raises(ValueError, match="invalid parity cassette"): + load_fixture(tmp_path, sdk_input, ParityCase[_Input]) + + +def test_cassette_preserves_duplicate_response_headers(tmp_path: Path) -> None: + sdk_input: Final = _Input() + response: Final[RecordedResponse] = RecordedHttpResponse.from_bytes( + 200, + (HttpHeader(name="x-test", value="first"), HttpHeader(name="x-test", value="second")), + b"{}", + ) + case: Final = ParityCase[_Input](litellm_input=sdk_input, provider_responses=(response,)) + save_fixture(tmp_path, sdk_input, case, (RecordedInteraction(Request("POST", _URI, b"", {}), response),)) + + assert load_fixture(tmp_path, sdk_input, ParityCase[_Input]) == case diff --git a/tests/route_parity/fixtures/test_pipeline.py b/tests/route_parity/fixtures/test_pipeline.py index 59366c9adb6..59de7ffbba7 100644 --- a/tests/route_parity/fixtures/test_pipeline.py +++ b/tests/route_parity/fixtures/test_pipeline.py @@ -174,7 +174,9 @@ def test_failure_does_not_stop_independent_recordings(tmp_path: Path) -> None: stale_input: Final = _FixtureInput(identifier="stale") stale_directory: Final = tmp_path / "stale" stale_directory.mkdir() - fixture_path(stale_directory, stale_input).write_text('{"schema_version": 0}\n', encoding="utf-8") + fixture_path(stale_directory, stale_input).with_suffix(".json").write_text( + '{"schema_version": 0}\n', encoding="utf-8" + ) with _upstream() as upstream: targets: Final = ( _target("stale", upstream.url, stale_input, _Invocation()), diff --git a/tests/route_parity/fixtures/test_recording.py b/tests/route_parity/fixtures/test_recording.py index 6dc70b7d8a2..77e387e5fba 100644 --- a/tests/route_parity/fixtures/test_recording.py +++ b/tests/route_parity/fixtures/test_recording.py @@ -14,7 +14,11 @@ from hypothesis import strategies as st from pydantic import BaseModel, ConfigDict from tests.route_parity.fixtures.pipeline import RecordingTarget, record_fixtures -from tests.route_parity.fixtures.recording import UpstreamEndpoint, record_upstream_responses +from tests.route_parity.fixtures.recording import ( + UpstreamEndpoint, + record_upstream_interactions, + record_upstream_responses, +) from tests.route_parity.fixtures.store import ( FIXTURE_SCHEMA_VERSION, fixture_path, @@ -96,6 +100,10 @@ class _ControlledUpstreamHandler(BaseHTTPRequestHandler): assert isinstance(upstream, _ControlledUpstream) length: Final = int(self.headers.get("content-length") or "0") self.rfile.read(length) + if self.path == "/credentials?api_key=query-secret&api-version=1": + authorized: Final = self.headers.get("authorization") == "Bearer header-secret" + self._send_json(200 if authorized else 401, b"{}") + return if self.path == "/upload": self._send_json(200, b'{"file_id":"fixture://document.pdf"}') return @@ -247,17 +255,17 @@ def test_recording_deduplicates_per_target_and_caps_global_concurrency(tmp_path: assert upstream.request_count == 2 assert upstream.max_active_requests == 2 assert len(recorded_fixtures(tmp_path, _ParityCase)) == 2 - for path in tmp_path.rglob("*.json"): + for path in tmp_path.rglob("*.yaml"): contents = path.read_text(encoding="utf-8") - assert f'"schema_version": {FIXTURE_SCHEMA_VERSION}' in contents - assert '"recorded_at":' in contents + assert f"schema_version: {FIXTURE_SCHEMA_VERSION}" in contents + assert "recorded_at:" in contents def test_pipeline_rejects_stale_fixture_before_provider_call(tmp_path: Path) -> None: case_input: Final = _case("stale") directory: Final = tmp_path / "stale-target" directory.mkdir() - path: Final = fixture_path(directory, case_input) + path: Final = fixture_path(directory, case_input).with_suffix(".json") path.write_text('{"schema_version": 0}\n', encoding="utf-8") target: Final = RecordingTarget( name="stale-target", @@ -345,6 +353,34 @@ def test_sensitive_response_headers_are_not_recorded() -> None: assert all(header.name.lower() != "set-cookie" for header in responses[0].headers) +def test_recorded_requests_strip_credentials_without_changing_the_live_request() -> None: + def sdk_call(api_base: str, case_input: _FixtureInput) -> object: + return httpx.post( + f"{api_base}/credentials?api_key=query-secret&api-version=1", + headers={ + "Authorization": "Bearer header-secret", + "Ocp-Apim-Subscription-Key": "azure-secret", + "Cookie": "session=cookie-secret", + "X-Test": case_input.identifier, + }, + content=b"\xffdocument", + ) + + with _controlled_upstream() as upstream: + interactions: Final = record_upstream_interactions( + UpstreamEndpoint(upstream.url), _case("credentials"), sdk_call + ) + + interaction: Final = interactions[0] + assert interaction.response.status_code == 200 + assert interaction.request.uri == "http://parity-provider.invalid/credentials?api-version=1" + assert interaction.request.body == b"\xffdocument" + assert interaction.request.headers["x-test"] == "credentials" + assert all( + header not in interaction.request.headers for header in ("authorization", "ocp-apim-subscription-key", "cookie") + ) + + @pytest.mark.parametrize("method", ("PUT", "PATCH", "DELETE")) def test_recording_and_replay_support_mutating_http_methods(method: str) -> None: sdk_call: Final = _method_sdk_call(method) diff --git a/tests/test_litellm/ocr/fixtures/README.md b/tests/test_litellm/ocr/fixtures/README.md index 7071467218c..a1b9c8c3a99 100644 --- a/tests/test_litellm/ocr/fixtures/README.md +++ b/tests/test_litellm/ocr/fixtures/README.md @@ -16,6 +16,20 @@ uv run python -m tests.test_litellm.ocr.fixtures.record --examples 4 --concurren `--concurrency` caps provider calls across all targets. Independent jobs finish after a failure, then the command exits nonzero if any job failed +New recordings are VCR YAML cassettes. The committed corpus contains 31 migrated cassettes: 18 Mistral, 9 Reducto v3, +and 4 Reducto legacy. Their original response bytes, statuses, headers, and recording timestamps are preserved + +To migrate an existing JSON fixture directory locally: + +```shell +uv run python -m tests.test_litellm.ocr.fixtures.migrate --fixture-dir tests/test_litellm/ocr/fixtures/data +``` + +The migration replays each old response through the Python SDK to reconstruct missing requests, writes and validates +the YAML cassette, then removes its JSON predecessor. It calls only local recording/replay servers and needs no provider +credentials. Reconstructed requests are labeled `python_replay`; they are not historical wire captures. Filenames use +the current normalized SDK input hash, including the fixture contract + OCR strategies generate public `litellm.ocr()` and `litellm.aocr()` inputs. Every case contains the normalized model, document, optional provider override, and LiteLLM keyword arguments. The fixture-only `contract` literal selects the input schema and is removed before calling the SDK. Strategies never build provider wire payloads diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/0ab748e6b7315f0c7a36195cc4564eff8b03523dfa908ea59ff1bb7bd185ede8.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/0ab748e6b7315f0c7a36195cc4564eff8b03523dfa908ea59ff1bb7bd185ede8.json deleted file mode 100644 index c64c248ab9c..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/0ab748e6b7315f0c7a36195cc4564eff8b03523dfa908ea59ff1bb7bd185ede8.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "case": { - "litellm_input": { - "bbox_annotation_format": { - "json_schema": { - "description": "Extract the visible document fields", - "name": "bounding_boxes", - "schema": { - "additionalProperties": false, - "properties": { - "title": { - "type": "string" - } - }, - "required": [ - "title" - ], - "type": "object" - }, - "strict": true - }, - "type": "json_schema" - }, - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "document_annotation_format": { - "json_schema": { - "description": "Extract the visible document fields", - "name": "document_title", - "schema": { - "additionalProperties": false, - "properties": { - "title": { - "type": "string" - } - }, - "required": [ - "title" - ], - "type": "object" - }, - "strict": true - }, - "type": "json_schema" - }, - "extract_header": true, - "image_min_size": 300, - "include_blocks": true, - "include_image_base64": false, - "model": "mistral/mistral-ocr-latest", - "pages": [ - 0 - ], - "table_format": "markdown" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOiJ7XCJ0aXRsZVwiOiBcIkludm9pY2VfMTIzXCJ9IiwidXNhZ2VfaW5mbyI6eyJwYWdlc19wcm9jZXNzZWQiOjEsImRvY19zaXplX2J5dGVzIjo0MTI0fX0=", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:26 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-85bd-7075-af53-8e341b35a63e" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-85bd-7075-af53-8e341b35a63e" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "43" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "432" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "433" - }, - { - "name": "x-kong-proxy-latency", - "value": "13" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d3a89a85f953-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:26.965078Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/0b234402bdfd3be223e731051202f2996578fff02d93ec3011031ce2b4c511fc.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/0b234402bdfd3be223e731051202f2996578fff02d93ec3011031ce2b4c511fc.yaml new file mode 100644 index 00000000000..f7aa8598016 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/0b234402bdfd3be223e731051202f2996578fff02d93ec3011031ce2b4c511fc.yaml @@ -0,0 +1,68 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"image_limit":1}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d3637dc2c090-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:15 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-5a87-7148-8ae4-4e14967bebf3 + x-envoy-upstream-service-time: + - '226' + x-kong-proxy-latency: + - '19' + x-kong-request-id: + - 01a05e89-5a87-7148-8ae4-4e14967bebf3 + x-kong-upstream-latency: + - '227' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '56' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:15.394028+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + image_limit: 1 + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/0c9204f5ed668c628835b9d60806a6cea47e1f67c0f48c9804cb09d1c4695f42.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/0c9204f5ed668c628835b9d60806a6cea47e1f67c0f48c9804cb09d1c4695f42.json deleted file mode 100644 index d267cfa4515..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/0c9204f5ed668c628835b9d60806a6cea47e1f67c0f48c9804cb09d1c4695f42.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "extract_footer": true, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:20 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-6c42-7ea1-b08b-07cae50734e0" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-6c42-7ea1-b08b-07cae50734e0" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "50" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "523" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "525" - }, - { - "name": "x-kong-proxy-latency", - "value": "13" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "CF-RAY", - "value": "a346d37fde0f1703-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:20.425444Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/1f3001924ef2c46d3eccdedd808c7ded7fea981215a478a12d8636eff8eb1157.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/1f3001924ef2c46d3eccdedd808c7ded7fea981215a478a12d8636eff8eb1157.yaml new file mode 100644 index 00000000000..f06a1033691 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/1f3001924ef2c46d3eccdedd808c7ded7fea981215a478a12d8636eff8eb1157.yaml @@ -0,0 +1,60 @@ +interactions: +- request: + body: '{"model":"invalid-ocr-model-for-parity","document":{"type":"document_url","document_url":"data:application/pdf;base64,JVBERi0xLjQKJZOMi54gUmVwb3J0TGFiIEdlbmVyYXRlZCBQREYgZG9jdW1lbnQgKG9wZW5zb3VyY2UpCjEgMCBvYmoKPDwKL0YxIDIgMCBSIC9GMiAzIDAgUgo+PgplbmRvYmoKMiAwIG9iago8PAovQmFzZUZvbnQgL0hlbHZldGljYSAvRW5jb2RpbmcgL1dpbkFuc2lFbmNvZGluZyAvTmFtZSAvRjEgL1N1YnR5cGUgL1R5cGUxIC9UeXBlIC9Gb250Cj4+CmVuZG9iagozIDAgb2JqCjw8Ci9CYXNlRm9udCAvSGVsdmV0aWNhLUJvbGQgL0VuY29kaW5nIC9XaW5BbnNpRW5jb2RpbmcgL05hbWUgL0YyIC9TdWJ0eXBlIC9UeXBlMSAvVHlwZSAvRm9udAo+PgplbmRvYmoKNCAwIG9iago8PAovQ29udGVudHMgMTggMCBSIC9NZWRpYUJveCBbIDAgMCA2MTIgNzkyIF0gL1BhcmVudCAxNyAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXQo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKNSAwIG9iago8PAovQml0c1BlckNvbXBvbmVudCA4IC9Db2xvclNwYWNlIC9EZXZpY2VSR0IgL0ZpbHRlciBbIC9BU0NJSTg1RGVjb2RlIC9GbGF0ZURlY29kZSBdIC9IZWlnaHQgMzIwIC9MZW5ndGggNTYxNSAvU3VidHlwZSAvSW1hZ2UgCiAgL1R5cGUgL1hPYmplY3QgL1dpZHRoIDMyMAo+PgpzdHJlYW0KR2IiL2w2I3BIcSVSZE1bNDNaKzdadVpbLUFpNUtMMzIvY0tJbkxtaixYPmxxXEVxWFItTGs6PWw+I1lObGclcFhybTBwMGRhSFMvXHBpPC5cPyFyU1Y1PGpoNFMhcj5xc1hSVXAtN18zVjItWWksZChNMkNrWk5yLz9aTUFIV0FwJUthNz8nWS4zRzs6WW4zZlZ0TVtFXERkPkY3b2FlZjgrbkw6XERhWFhyMjpMN25AWUAzJ2ZWWktaMTh0aDtXMiVJTV5yWylmQk08RyhULVx0VCNERidTRWktKCM4YTApUiVEODMyazdNQGksOjU1aT5GZTouckk9amVcNE9rW19gLG0oMEI6MW1ZNXE4RURtVWRdazs/KCVIbS1zcFAsMDhuQzlbWy5yST1qZ1U2ZTIsX2JeUz1eNXNhXEwzXGtqQ1RmZkMhWWRyKXBVVj1iSk9janByOG9FJ2ZWWTBETy1KKlg3MTZwTV5yWykyb0kuMDJjL0pGSDU5VDtFLExuNzlBRVk1J2c3SSpERSdUUVhqSSpvI0pUSHNtb2BuOF9tcFlHVS5ddF1sQ2toOGNmMGckYzsiLWBHa0ZpUSppIjUyaWVlXSMlQD5baXJCMzg6bzpFbzkyazY/XFk5IUNiRWhwdURNXnJbKTJiQD07bzY6KD5EMG0lImdpLi8mXVFXWjFoWFBwYy8/Wk1BZ2YvUE5fVl4+PzJYRlJPRVBvPz9ubGgtaVglMlIuWmFmIkxFcmtpOFNBLl0lRFVsKSdpZURNL25saSEscmFZXWU9XjVzYVxNLzpcZzBhJSVTK0o4N1xEXlxnXVUlS1otVU5UW2A+KD4lJF5UQ2JyJih0I0QiZklKP25QYmw5Q3BiXyRDQ0I5WS4zSEcmcFooWD9cOlFOMzVcWT1RKzI/TTM5U3Q/PjpJY1M9NWo6KW09WVQ0cC8uMmxZL0NNMW8lRiJvL0ViJlY+JDteb1dpO2omWCM1PjxjOC9tPlhjXVs9LGExPkRpOkRnZk8nRFYtcWA/UXI9O1pQXT5fcmpIW1pdNWxyJTBJLm42Q2VYaS0oPTlNWiFFJnJRQWdFayI4a1lmQ1Iyb2M+LlMlUTcrazlZL0NLX1NLQ3NibzMvLS5HX1A+KlErLWdzO2RNZT80bHU9Tj9aPzxsNG5IZV5ZSHN0M3BGR1o+WSZjQT9yVWd1V209KiJwYms5O1hyKj8+J2FvLilZUihHMjdub3BrOWdBO1YvMFIlWExqbVJBOC0yL3FYQC4pIztiMjopPE9uVUJvQC4pbjxha3IwdSFWXCw0QC4qYTxha3NsaG9Cbk9wWUlNIXFQQmlBLGlLXms6PWtyL3BfYiQnLDhdPFVQPWtxPFhvLDNiLFdWKVNPLzhlWzBhRTVPMjVmbl5DTXFhR0JxY3FmI3JeS245Yj9UbDNpIiNPbWNMMTNdViFvbnM4bURAP2BvZWdwUSt1TGlwUmBzVSFTZ2UmJGhOKGhyWjdCX0knMUJrRTVVY2hiXEoka0haQjpcaz1TdFoyYWNIPV1RVTNmZ0RBN1xZL0NLX1BOND0+Q1kvRXBHOSZqMDhtRD9UOllydCRHLWVxJlFkVGlVYCEoKllqWG5cbFFpIkNAMjtSQ2U+UT9dZWhTUXBLXlY8RFhlN3UvKSJgT001KD9XIjpycWBndGNXbDs3aSp0YiFiXEwvVEZeQSs0XElvXm9LdW1QZGYqOyc6XFp1XWQscWFfK1BkYD9NYzE5SnRJU1ddNjRCJDc5bmVVQXFFVzAuYm10cClzVy5eKHFba1AhW29baXFmOkZpLC8tLz5NSVFiVkxrUSw3PllRI0krTD5sSkAlNHBrNTY8NVBjTmxaLktRMCdDOFg+JCFCNW8mMDMyRWpdUUtsMmZCcT8wKjwsPyskXycmJSY/Y0JTUjJDIz4jbEwjTER1UEY5cloqL0taP1dqO3BQM1lOUVRJU20rQlhnNmJTaWNVUidjUV8mbTsyVT1MVHItZDpfbmRhXiZoYV1McD9OOW9rUihTV21ITjNwTzlwMF9ia048Xy5hKUxfQ28sQk1YaEJkWFIncVhKYCQhNUhmbidORCs9OGUrVkdgNS09Z3NtcGU0bXJURCxrJEsmK1VaUWJXLl9kJj9XWkZINl4tU1pvW2k3KUljL3RrU3BRVTc0Ri10dGY3czlScmk8VFQpai5sdEgvSkM0Jz5HWFA/RVg7XGo9YTxjcFxybVZuIypkXl02IkdPUVJENWxJcjNkMl9xckk/bTlma2BqUnI6YEs+KnVWM3BvSy9uczpgLWRwSiM2cGM9SS5cOWpkaT9fNG9aSWs9WFldMCVTJURSVjNJSDFFVGBDTjBcZ2pBPzZYVWhCTUhQQllQYSRXP2E4TyVRcDslRWkrTV1HcGlSS1lnZjg8NUxmZTxyVltOaD1LNllhL20kRy0vPVRTRDwqP0doSkljMEN0UDInPDVLKixwW05CUGsiUzouaj88JWIlUyFWLTdqWnE9R29wQ25AR1lmVzhfdWdhRDBQTCdIO3FgalBrWF51XSZhKmc4Yi9KTUNLb2lOZSJbT25YTHNUSWZJQU5ZOXAuSFI/WCJWaEwpdVYhX3JaO29icyREXUJUZyMqcm4/P1tHNFZZY1JqJTdcYjtSSiM3JEhbQG9bZCtKWkJbcCtnYSUuZT9iJk8xMFVhOCpYTTxtPWI8P3U0RTpgLj1JLj9kP0dWaSJLRS4/K2tTNHUqcWlNT2NwcSJkKjlTLEE5QG9vXkNlWyJDanBnaF82WGJOSi1DakRXQ2BHXWtSXGRrYUpNYTYlWW4yWWU8ZCxtdGNKUjxzXD1jSTksQWhwQ2dQSmRsU2dTcmwxVz9fNHBgcmBWKzM5NnBlJCtGZVwtIXJUSCQkS0hLUUI6JEE0bGdfT2UnRUdMZlEpI2JrPHBQK0tZKyYvRVdrQEFNZVR0TkJsZk0nUzBeN0xyckpUYF5pPSM1U3FtdT1ES0Q7JFIxSHRaKTkhJT1SJUBTT3FoSHFjUkRhO1hWbmllK0ZCOl9pczY5WWpdKVkzNmRiTjQuNyI0Jyohci5XQUksOFk8WGU9SmxPX1ZEP21qaUxgakRpKT5WNGFaN1ReRyVLOWhIR0YhJDdHTjVQWlJrJGNtM25bckFFcHRAbitlOW8/MUpwUk51ZVZJZ3I+cUdnRlshYj9scmwsXT0/RyVBZSNbY2ksYEQ/U0lvb0RdYUg8VTJYTWQ5O2UmaT9vMUkzPHJROjpfR05KIlNsPlc/ZDNPIkxxLm4oWkxcLzYhNk1WIVlQTjZURVlAVDIyaFhmVVdqPV8/RVAuLkAoUURYLltjZUdAXF5ML2xpaFI8RGVObCEvLFQ6QUZOSyRiaWg0OFdlIiQ/LFpkR1M5Zls3WyluTW1dVCYwXVt1Y04pPDxGZjlwMyEjXkQ8aj03YUU2InEkVFpVakxyRTtNYzlCZG1gQ2QwNEYobDhmLixWXkNaImxxXCw+QDBIXWMndEkxP15OKE9YIWdRUkQ2LXJZaydDaSlrOUBwRkNgPW5tOkxfam85UFdFLV06by50O2o4aFdWLlNyXVIxZ0gsOTUqSXNMVGtsRUI9STRsZGw2Xz1vSTBIMUtoWFk9OEpANV5EcFBtb1RNWmpMczhTTXUzTm47cm4yP1lQZE0oSGI3JC5uVHVzcWpUWFBGcjhsJF5eZ0IyIzRdREUsXz1vSTBIMUs4TWY2MldTLFh1LDByUThLPV1PVWxJcCMhWHFQOEFWXW5zOmBtLF8nW21IT3U7MEsndWU/byZMaFJZUEFrOmI2dSRrcTkrdEdUImpEYShiQD84SWNXNFloTkBma0pcbWM5SUBtJ0NTa10zRW5DUClfXixrX1BpJnBVSW5vb3UrW10mXEddUlFkP1JISVguYWExVmYxITsiYW9lQF1DbHVaRHFmKGVSLlA0c21tNkZDLk9tLUU3Im4kJG9aN0luK1xWPDsyS3MnRDtrJlBcRjRZZU5qJUFkPVs7P28xSTNXVyRlVlMhbVheSyRiaWg4LEJoTERkSWhlJFYkP0BTYGZIMzRXYm5dMl4hVWRCVGckR3I6Uy8uXXRhdXU/U0lvb21qKkJHOSJvPi4kSGxkMVJPJT49SiI4QG9pNS0xb15ML2xpaEFRPWgyPmtfPC1uS2thQlRnIjFyKjlzKU9VRnVmcmRyTkNII05HJDxQPy9XZmE+bzAwVWE5VWVjJ0dXcFAsMDtZbCJbIjhiMWEobiIrRmNcVG5QKj9TSW9vbiJwIyRNdFc6JlVwMGIjVUlrJTVrak9AOypjP19MbmVbNjNhYTlTbkxONURjaTxtYjgwVWE5VT8yZ0YyamxhVzUvOllLTFAuVlYsKV48Y0UyYypyWSRWJD9AXXVBa1dRIz5RUEQjKTg8cEJsQ2NoWnJdP3FoSkRUbyZUMyxEaG1OJm8vIkhwMFVhOCpGKzddXTRtRGUzLGs7YjEtSFkjcWhmKmlPSFRqSE5xdXJpZW8hXDNNNmYuRitbbmU8Il8uXSJFNG9KKjwybCxXTVpjUVEuUk51Zj1KK01gXGw/VkVDbmVbNjNha1AodDwtXFJtPzlQNGEiZiJaW1tkbEBdaFVuRWQ6K0xoMUJUZyNWcXV0LlxoUiE3K25lWzYzYWtPYUBONF4jazQmN0pZXy5dIkUqVzFXNVMoK2UtcjoxWV8tSFRLWzAyZ1o+U2owKjZeTC9saWhIR0VGbnR1LUk8I0V1YXI4bCUpa1YkOSFtJS0/SSIxamM0NEYrIiovV2dqckYmZkM7QkFmMWpQSj9vTDxdSy9qVCQlazdeSD9mM3JtbSlnVldaWmxucz0pUz84bWZINlxBSEtkX1cmI3JFY19vaylvQ2I8VFA2LlhPY15TPlc4LmJobEEiWzhbbi4pYW4qQGNqUz86WUgqRl9pSS5nJ1tAPG5vInJkY0U8JGgxV2RdTiUrSSlqJWZzSCpkSGQtI1s1PGE8J0NxOllvJyM0XHBSTzRpOyR0bC5QLTljbGRWcFY8U3FxWWwqVilTKWdiTz9FMFQqJEhsZUpdR15dcDdeVXNHNj5qNktuczpfQlxBLT5KbSwxX2EyY1g7XmJFRm05P2lPNGRuWWhQPVZtLSpcYVcnSTRkUW1OclcwIUxFWWwqVikpcy1QUi4oOF1GT0lNckpyOGwkPmlwWGt1RzRWWW8pbTZGQ2ppTWw7bikhZ3NvVmRpalgwRE5gYWE8Nz9wPkdXOVcvcXNzWWwqVilIZkZNOWFMMV0+TztrJSNyOGwmNG1JMCM8Rm5WYnEpa3NTN2ppUC10bitpPi5wU2ExI2hRP187YWgtTU1hRXA9KU5zYEZRJUVpK01dVzskJDRlbDxBOydHXDBCREtgN0dLSl9qSCMqJC5fVksqNnJwby5DcVxwciVEO0wyXEhfJj5lVCJJZ0pBKidpO0hQXm4kSDI1WElmQWdlWl1YPCRnajAmKS9Jc0xVNm9KXS5vZzpUQGJRWW8rZ28mUDVmRGolY0BHcVw6VW1tQCRFakYtJyxUIk1JVm4pWlRLNy9sYzxyUUYodEgjKiJYYzFUa01yOGwmdGtcbW9CWzxaXVJEVldqb0gyI1oyR3JQWjc0bXJCUnI7REV1YWgtaixKQG1cSm8oUDs5LGskbzIxXC1SYmIyNS1rUC5aNm5hNWlmMFErcWdCOGIrcUBTV249OD04a0NYOGIrTTRyMmI+MmsqXWosbz0nK1NablwlXFNyTGtMbnRGSyRtZF1vSE1Dc0goXGBNa0lOU2ZCT3EpPFdoLk5dcidXYS5jNj4sU0VLS1g+Tj1vYC9hbzAzcDNKZE9lUSFkJTNsKkdjZW1TMTM3NyJcdUtENHF0WDU2R3FqVGAvXEgqISluVD1yJGNqamRwVEQpT3EmP2gsOklDPzpNWWtPSjstPGZlRDxGRCxBK0dOU1J1Oj9NcmU+N2hrRSVMak1ZZTIrWEtfVWNoanU+S1QuPW5pPmJvNy1wTWAySVgyQTIhJGZmKTxRRzRnJUluYFoiOG1FMkxVVGpbUGhGZVs3QjxLMSxFPC1FaWhuP15MMjZIIjU+U29EKEBKUk8/Ml9Mcl0+X3JqS1ZDRi1IPTgxUW8xbjYoOUBHRXUham1VWFNeNS9BJSxxYi5HVXAwZGltdW84ODQnMUZZXC8+WHM/ZnNVKF5ba11lJGZjc2wvOlRoW11fOksvLHFiLHFYMEROQCddKz5CYC5gMTUncGNWJVdpcWQ/RUZJWVdrSzddM0dKTHNAYEdOZjNxV0JuVG4qYzR1J1FIM1VuLDZNMUhNXWVkRiRhbDlFdDlXbXJlPU0uV2I2PktGJjFwbXJXXFxBWVwuc1ppLDI+XXIhZlZbcWdRTCljZVknUnEwUTNkbSFjbm9jZVhzUnE3Qm9RcmRNZyxjWCEpL3E3QkwtaVZlV3FUIj9oPW5lV0VlQEYqcmlhUyFrKVxcQXUsJFtXWmA7UWInclJKaGldPk0tOWxwTXJGZzhhQSQtaFNQbCddcGVoPDhpY2hSYkY8XmppZjwxXydhRWovM2UtXGpnO0xONyhXUStyJSppV1dyZyhXQDZnJSdIKHE0NnQ1PVMqVCRWUWpKPTVxKixoJVUoZj5UODFePl9yaktbU2xsLlxHVnVaQmtfXXJLVGYoSD1fbU4kUlYvWSk9c1UvcDwwS0V0QC5LMnVfXyVNSm0oREVcSXRxVSYucmYiMF9haCFXVVx0cG5BP05rKW1EOm0wYk5qRjchO0ZccT01cSosPD0xLDhGWyJPPkhQVF08LF04SVUpMHUxUWI+SSohXER0LEVLdTxNLiwqX2dRWS4uJi5ZZW1ZalNWUVtcWmFmIUFFS0xTNWs0S2guOF5IQ1JTJkMiMCowa2E0XmpVTUU9NTUmUjdjQkhBWCUuJFdaYWYhQUU8LUU9a004Ky5cIjpQUjJpNCQrbjZ0MWVqIy0xKz5dR3Q7Vz0jOVloKityZVQjREYnTTQ6RjRHMkFFLVtJJSslRUtkbigkTGQoPjRBPXEwYD4oPWdTIl09QGhYYjU2bW9gbjhQSVRRWVlOPzlTNWxbRnAnZlVzZ1g3MCRELi5lNjtNXnJaWDJjL0lySXJGLGpaYWYhQUVGW2w1QENZV0woMEI5OkRXJTk8IS1FLyppZWo1RE5WWSVfJ2V1QG9FUShaMypyPlEkUmolNnM0YzpoLicpMD5NMnIjWyhuKk83X0VLZG9lWTVRPmFQUD1ANmA+KD1nXTRdbkQyY1xfaEhQVF08LGpwRDJeVWAlZyVkNyYjRUtkbzVwQU5uTmpJT10pXERlaVRRUTFEN0BjU1FZWmFmIUFFVyU2YF9oSDJvV0ZwNGk6I1wzXnI4bzNiKlMuUixpWy9ZLjxvVzUzZjxgIUgtPzI4XU0zaUVzY2YwaE9gOWVvP2U9T1ZvMnNMIT5hWkkiRkVRKForSUg2c1RaYWYhQW0zX0NhbW9gbjhQUC9vcHJ0Iy1rPW0jfj5lbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwKL0JpdHNQZXJDb21wb25lbnQgOCAvQ29sb3JTcGFjZSAvRGV2aWNlUkdCIC9GaWx0ZXIgWyAvQVNDSUk4NURlY29kZSAvRmxhdGVEZWNvZGUgXSAvSGVpZ2h0IDMyMCAvTGVuZ3RoIDYzMTEgL1N1YnR5cGUgL0ltYWdlIAogIC9UeXBlIC9YT2JqZWN0IC9XaWR0aCAzNjAKPj4Kc3RyZWFtCkdiIi9sOTYpO2cmT2BoPmVYVDgrZFFNWkZQbm1RMU04ai8kJDM7ODVOYzljbTkjSVk2JWc2MnBGJS5ybT9YTmoycWQyU1I5MXFvTmxnT01pJyNVYStVUiUyXWQnPzQmOkhlYVJEZDdfWi1eNWdYXERlUXFoJiRJbEJcWzY/YEdOTktQPUQnJ10oVDkzRVNHRy5VXzBEX1FAME5NZ2JyRVwvJ3JaZG9dcmluaWpSZkxEIixdbzwoRjhZTV5yWmFZMGQ+OVxTOj9tZTdXZD9EOFdiI2kibj1CKkd0WChZLi8+WTk2XkUkUyJQY19JMjVvPipvKWA2UzNxMmRTJ3AnZy8/WkwiXDlqU0AqQi1xPD04LGomRVNHSEFZUEFFQFMzJCoqWmFmIydpTFg8RGNlS1hjPmhXaDFgR05MVV1bbXElXS9qaXJaYWYjJ2lMXHE/LE0tITtmQ2A5T0VTR0c8bV1yRExXL2VMZC8/WkwiXDZjWGhNPGJQX1U8aGhWZ09uaGhZMHUtLXA0am1eNSlVcS8pbTkocWk3USt0XidGUiJNXnJaYVkuSE5eL1Q3MEoiTUUoP01WRWspK2NVLWQpaSs7Vm1eJ0ZfW2MnW21qIVQwTWoqTV90bUJhPV5bYyw0dGojUWhRaFkmWiMvP1pMIlw9cT5xNE03cig4XGROSi5ySDtEWm5yZ09EbGRna1hqPyFhZ09nSTsoQSZYJGpmQGBwYHAnaD5palJnQzhgT2dgTDQvNS1JMjVvPjJWXnU/NFBucEttTjguS2llbEtGUmswT0heYDFVVzNuVl9aPl1KVDFhaT0rNE5xZDRFM19LNiJZLi8+WS0uNyNeXiUoMV9cIillbldUSGguYG5cSC4ncUguNSpHZmRDRElbU09idD8nOFVDTzw3JyI5QU1zIjNISGE6KFdeUl5qJz8wYzArKU9sVSlALnJjTUwmTURKV2E+cD9tZUV1RWtnckEuP2xnbCNUJTlLJTRwS1dSMFIjPkk1P11kLnJaakElamRhSCE7XGhEcjZYakdNJS9EWk90OStCOnNxUmpXNDhDYlVUbmwmYjw/PypxQVFLOmhLPFNmLCVeJCc3KDFaK0Y/Uk9gQHNGLGNOPGZjMFc7IU02TClpanMzdWY3RF1yOT4vMiY/WkYmLWs6VSRDSCI0NmxqbFwuc1xGLy8mcTNPJUs+Pz5qWmllbSdJaDNgUzhqMDQqJms6PF5GbWJHTERRVCYxJ1F1S2UhTVgvUkRTcCNDc1onZlVwKWsnaTU2TE5lbzRhQTlIWCNQTUM9NTtDZyspY0VMWS4iW2IoMEI5dWpZR0taN1dhRSRxXmVuWzVLZGk8amMvLEYoMEI7W0NATSxsRiw7aWcpTGZZMU07K0VQaipmYSlQckkiQ05eJFYpMldqai5VRzIuWFJsOmhIJW1GKFMyV2hTRFVHMi5YVGY1YCwhLXRgY21FMFIhWW4qI2xcXk1NUEI3VydFaVxvcj04WVwhLkYwLkNwOic+Tz1gLDNeLVB0IzM9a0BTWEtTLiIlVU07K0M6L1dJV1tjZk8iYzRXVUszJyI5U1NnKS41Q1REUT0sRkErWjgtI1I0MU5caCs3NSRiZzA0PWxUKSciOVNTOWNBXzJUMTdcQSojWlV1TTsrRGUuPzIzVzpHNldLQXAoSyYua1YpZGlAUUhRaFBabydUJ0g+dEZhZFk6YklMVXQtWkFicVJRQipoJkpfY29mXTNNOUpsMmooNGVncmVOZ1tObDspbWshXE9UV1NvJyk7cmlpO29xUE9qWzRcT281VTVrWDtsXDxoNlotYFhXJCV1Myo4bEBXdShPL1RRMmRPPUpSNmZYMChvWEs4Kiw5QUpfKW1lNl41PjlwWXEjM0loXDtsN2lOUFtrREFEWykqcXJkZ29vZFwvO0ZOU0FlUE47WkVidVtFTUhVUGgxOHUjKmU0LjdHYDJgRmtbamEiaSQwJEJjLGIuRU5YPmZKdXJadFBkUTZ1MDpgXk5jXFZfbD1iYVhpYVgtSV09P2ZIPkZgP2FgSCxzRFlYakRtT0leTzouKDYrclAxISw3RmB1NGBCPD1WOGIuPm1RNEtidV5Ga3U8Ij5pXiwuQ1hbVTxRSz09NEBjLzxucDVTVjlqVmk+UGU9OFYtSFlUS3FhUVhaaV1cRT1JVEtpRzFlRCJERF8uamkyUXNXOjosdFYoalJyMiM+b2cucGFnbGA0RUpQc2BsZz40VzNhaFItRV00SjNoS1ZKUWpQQj1GbjorXU4jQWReQVk0NGQ9TkBDO0FuIilJbXM4LnM/QC5QIk9tNy9VRDlbUCwyXCVPTm85OkRwSVw0X1VVbzo7VUludCgpOXBmRUhNImUxajldNlxZa2BZOy4xcFdzbEpJVi9FZ2ZYcz8lTkRsJCJWSikuKjAmQEhFZl1RJkhqc0IhU3JLXGpNOVtQLDJddD8pdGFVXUpIYy0qb1lQSyoqRT02LlVvUE42bFlgcGVjQEkyNF9aRHNtN0o8bU1SRURhJ1U4WUhLbT41PG8mTWZZITNTTFhJI2ciKjM2MjFlRCJ0RFtcbCQ+LU46YUVtTFI6NEJePUxha1REQ3BxJkddQ1xYbFFsOU5QSVAzWDxPaU5aa1NQckhqckhOUTIoaSh0Ry1IMkRTZU46SD0wIVY9R1EjaShVdSloLl9HZ0RdZkhXLW5JcURiU1AoSCkmJi1yLltPXF8iS2RfZ2NJMC05W1AsMic+LSd0T3QoVWlwPVssJ0g3aiwwZDNPIVldSjk+VSZwOyJgZnMuRVZHISYwR11FbTpfaFk9XSYwNmw4NzJzQFNMS2YzKWpSJWQxQ0FwUnReRDk7J25tQl1HU1tvX0ZSVS5PbyZIWGxpKVJIZj1pbzZEVz08bzA0PDhiMiJqQSwpVS9sQEE4Q0ZBJTY3Q2pobkw4Yi8wbGo3My0zT1cqbGZVbydeVGlsVzM9MWVIT2pEajcxJlthM10+T2JVTjJMKmsjSGxdJDo3XyJOJldONyplSGRhMDdiYklvVnVgMk5qSWNgOHA/Zy01VzxeJmlSaU1DLUgnaS9KbStMUHNYRVY2W1InaEZMLCJqOT4obiYvOVxNbUJhS2wpQzk7SVVJayU5R1tuZzhWby81XT1LPSQ6MmoyUTZIKGhsKmA7KzlOW2ExOG5rYCEwOk80Ty5HclZfYGhCYDkoIiguKGY9JjZkKFIyKEFtYCJEPDotS0RaRmptJlApKTVWPl8qX1dfMGkmX0lvQUY0bGZEcWcpWy5uJj8lPlYxJTNZNU9FdT4/OUErZzUhLEsxbnEpM3VcOktocV89Zmw7XEBkcl8tSFYyN05TdHFlRzZRYWFUWkhbbjE3QktXKCNCZEYiNXQ6KWpiPEInXUoyaj1qTHJNT19rISVsaEIlZzJuWSsvaVlJbFNZUE45RXUpdDNMLFpwISYqXTsxQTEuclMsLyxeSFRiYGMrVEUqUSVPRzBOViJVSCIyXllhYTlkQUw6YiRGU2cxJmlUIXEiWFVYOj80MEQzPihBIVZORXAzQFM7ViElOzwxN0JLV14ic1VvRDdXclk1KTJiSjRnMkxRNz9jZkdnKUlyc0lHUVlXVDsvN0FTbGFkOVUuT3E0bVokMDg1Tzk4Y2NPJiQ9Y1JXcC1kM051VkdbbjgqR008PmRGK1EsZXFPR0kqYi5FM09ha09dUG4kYCkoRitjYFQ4XSpdcF1KMmo9alIpI2ZpR08tRkgoUW1oaVNKM21AdTtWVGdXVVZTJTFndWRkY1kuVFxHJy5fUiVkMUNwQEg6Q2NgY1YpbWRrTm4mXmtYZVpiLyJdUE42VEZOVCU8ZW1PP2slakdkXCw4YCRXLCkiLCUpKk9YWGAyajJRNkdvTSo/XEc5WlhQXSZoRDg0SmcobUhvbmxybVBhO19KX08sN1BeRFhEZ1FFODkrY1QrJloiQ0JCNmUhRS1IU3A/TkZAcFlNW1VkPXBISGI+O2AlJ1AqY0RJbjZxInFUTDNvUVNOQEM7QTA5bkpORT8qRyVeSD5YO21YOkJbVkopLipDdTRxQnInUXMjKShmMidHZVNxTiFSRmooNWlEQS03WUVnXWRKdURlX2pIaFMuclVZbj5DKzFnKkhsLHNUJ29TISljSlJiPzxWN1VVTVlaQUlLTXBubzkpJjBCVGckUGhLVGpgVCVFc0VTQGczcURiU1AoSDAoI283U0RnPTpJNCp1L3BVcmEtSFJjVl1TbFNHcCQwa3Vqa1ZHNEB1O1ZULnJUZiszWGU0TlohaU9qbzU5ZiowaCU7ZVByQ21eaDVIOCZZKlFeVDc/Y2V0Mmw6bEhWMUcuXFdTJGNaVExuXnMpalxSI2RLJVUvMDZxJmItSFJjVihmUD5saiwxTGhPdUZxKlhmcCw6PSc8NTNdT2Q8c29ldUNXRio9W143NlcyYWBtNydwP2QkME43bigxMnIqJT10TkpsbC5Dcyg8KiVEQ1pvZCRFTzYycGBncWpVRmxERipmJW1bP25OXDc/Y2V0Mmw6aytlLGMlX1dTJGNaVExuXnMpa1kjb1c8NHNGQzw3RG4xZUQjIWokVjcnbjMobW9rMXFHMkB1O1ZULnJXKFlxKVMtNWNfS1VYLnNZV14tSFJjViRvOycyMDc9MFdtcmxlbDtgJSdQSCIwVmdYLlJBUUhXJ0ZTJ01YYVdmYyw5Vi5dMy5eSUtNcG5vOSkmMEJUZyQ4aEplVXNdLCYoXEghWmhVUDtmQFBQLls9QUUwU0FTMCJrMGdnQSlmMGAmcUNQVVJeKWIpdCkuIWY7UEIoZCpEQT4sTi9DPylbUDUyaE08az9yUURtYz00THIvQHU7VlQ5QkQvJzkrQF4tR3A9MiRQKmEzLlJGYDxIKlYpWlRSTnNQQzJ0QVVXTGNYVVZBMkhtN3A+LjNGa0NCMzhHcD0yJFAuLm5aJERkZC8hSTVuLTlwMnVqMnAxUz9fRF5KN0EySG03WTIwL0A3ZXBaV05GWGs7aE5tI2M/SUphOD0vZVJEODRKZyhtSDRxOjFvZ0RCWTc+aCYpLDY6J1I1XilRLi11I1wzb2w5MjFlSFAhaFFVNlZLS2ElSzZmKEAnUE47LGklSyJsXk8/VFNBNmYoQCdQTjZUPSVEK0hpcVJqMVBLS11xQFNBVkpPXTdEPE5IYjI0O0RdX3JOJ0BcMUQsYm1zJT9MPGAzSFxeMjhCUV9COGFfNmpNcE5nPzxcY01MYjwjdE8hMTdCS1dWO0JrPUJHXj9wVj0haEMxN0JLV05TWlkqQF4oOEViYSJBbmhPKCQvbm06TD1fb2k1PEI6IV9mSDAoIzdSTyU+amhKZGBOIThELjViaWg1RG1IcmFvI0dGYFtoVm50XEJkIS4xLC02LHRIIjJeWWFhOF8jQC4tcmg/SDouWDdQXkRYMD45QGJWMUlGYlRdI0IxMTdCSUFcMlBDZSFUKiJRcHNUX28pdTQwTFlMM0M9XStBOFVQTTFgPiNNTEVMPiRZLidKb2InKyguXkMqOkkzMTw4aychRlJRckhYVCcuO29Ncl9FYmF1dDZOWWYmXFNVOysoXVFKMVBdRGROPEQ+aSJRVjFlRCIlRGFbNSNcXi85IUQzO0puTiRjWilqLEYxVStTWFBxOTkjKW5QMGtQIzYraT0pJUhLXStRK15KbzdQXkRYMDdsLSdNdWhldWVNPS1saEZMLCJqPVUqcVZET0QzXU48U01hVyY/OFAuXDNaODxzSSNUPTwiQk5aXSo1VDhkTkldUzU0YFFOaEsmOldmRGwrOnFQRi9TTDxbLS9MPT5Sb0F1P1x0cVwsW1FbTDcsXkshcDsoKW43NStibkNBKiZcIVJOdWdXMmVvMT9naDJ0MkRRZ10tNz9jZldvTD9BSk9TZUJFVGhVaDNWSikuKkMjMTZzIydjYVwubyUsVWBZOy4xMm9jaltkUW02LEhVW1IzaE8oJC9uZzhTYDdpS0hzTltYWUliOFhBOjhgIi0hNVkyJ2djVSRbSUlzR09dLUhSNGklRWhbLkAsPz87N3MybGw7YCUpJitFJipuIUxVPkJmNV9qWGEsNjlkaEMuUSklJSg8PUo5ZWJJPy46JDk5W1AsMmg3WzZlOlk8PT5cYGA3PjJsOjhPXVk8NyxPIVNXIWhWOkpAYTtcJjc4Uj1vKi8uRWtAPzNdaSszb2w4TFJPIyknMmNgRVwyRDVBXDpFQiNHJ01YYkJgPl1hYCNiLjA5XTVfVFZgWTsuMXBXc2w2Y2NgUDxXT1QhQS1aO10rLF5FMXVZcTZGR11QUUIiNmUocCxkM08iSF1sPjUqakxnLk5xYmJLVDtgJSkmNGA7PDQiJCYiXmY2RXRaYFk7LjFHSmJBVGBXND1YYk0+LWtIL2ZXNlAxU00vXCojKCNhcj8rTFAuXE5jQlRROyNIL2YkJVAxUykjNG49TC1HVD9RY0dvYjlYSCtnbDwtRWpxLzkmQTJmUE42bGFJNyRHKmY/SkBuUk8lPzdEWVtEN25FWmZvOi1iJChyUDEhLDhDXTs3YEI8PVY4YjBVVVFCLmQqWG9iNlk5SmwsZCslIk07PEJbY29RKWY8MTw7MEdkbjdwSyklPk5Ic1YkWnQxOD1uIz1cWCNIUzNvcSojXS5BJE8uSVJuPCxdQU1yYjRDTDs9Uz9CbipkUi1kUC5XKmhXNkhpcTksWjotLUVlIlVQLipndEttQ1hbWEsoNFttLjgtVU5QXCYkSCZpNkFCXjFbPFU5IiF0XUE9Yy0vcmkhUk5SMC4+a2hjJmlPQlhuR1s9KkswXVJiJT9tSShXMVFbLGEqZiYiMmYpSi1FS0tcWi5fT3VNLyg3aUZDNWBAXiciTmdbUT0+PldhPWE9RC1PW3JDIVwlRUNmITdXX3NWYklMVXQtWj03W29fPW06J2MyTy1VKDJJZFYyV2k5UD8yIUdEUik9YU5Vc0ZxPW51PFpnUmFuNiVYSSo9Ti8qKkA9NXBbT1ZQdXI+ZldNKDY4cyRScltsbFo/KlYuM1ZYaEtiMlI0RTozRXRkRHBhcjs7LUVAdCgvLSNTJ0lab1s5LWVfMyhzWygtZ1k0Wj89XG8jPVJFKnNDTSxNOytVQFZbZSFpPzcvNm4zRVAycUUkTmpVRF0lZkVxOGRWJ0RMOE91M29nYENTW1RWZVkvRzInb2k2ZFtFUywsPF9zdW5eaCJGdUNGaVlMTElDP1ddTVJhQS80bm5ZNyM5UzIvcHFEWyNBWmlzZ2NaTCtBR3BCSyQjXm1JaWd0K1MvRGc+aWZYKGdhZFA/MiFVbVwpXSZOUmBKKVQ1U2dYRUxGQWxkazVSS1puX0UpYD4oPWZdL1Q/UGBhSnR1YzwiN2pLPURrYTA1anRoRnNyP2U1KVVxb1YsbGJkaEZOX3RAQHRMUmYydFpeSl9WMilkTz1JZ1xEbDVjSU49ZmhPWD8oKTUpVXJaO0FoK2tYWitbZSZUa2JITUFzTEFXMiYsZS0tUC1cL001OEU0N1swZCteLyc4VjQ3JWhlLVtjWnFndUw3Qm9iXU5EYUFIOTZjQmQhSlFtQTc1IipcKWVPbms5NF1nWE9rRV1KSWY+bjdAS1tkXXU5JjAsRktNMXFuMS5nP3JGIVleTjAlPG4kOXB1WGJCQHUnXi0jUyZeSmldWHRRM1ZkSGdPPzxEQWArY0YuVnAhaT8hKjkjJyI6JDVuOiZAPFNWSCxhP1pGJG9pYDwkJywtVSwoTXNZbzInZlVxUVUoNnExRyVuMU9ZSU5RckVWJihQcVc5WydeViVuUE1WRilaWDpFOmBwNzNIIz1eNXM5RUFRLyhRJDZyWytGUCMsZ2gsPXVGaCRMPGgndTBsYD4saigyYUpKSUdySVg8ZW45IUFEOHFROWEnbWk8bS9jb2A+XUg2UTZlL0g0cForbVFaZDdXZ2dQZClMTmtOKVxZP3RdNy8/Wk0tXDNZJSoydEVSLyJNKWs8TVZGKC9Ub1JbOS9wZFRlWmFmIVFqMTs6JC5CYU8rXlgobnNnUGtJISVTKEVDNSlVcS81SGFHc3JGcmUtcUNKZVpjKyNCTWZ0bjJFV0goWShgPixqImZCWDE1cEBpSnJqMk85QC5ySTAyaVAjNislP2VgLUkyNW8+QiYmUlhyZi5wRk5JMU9SWS4yYGRnWGdobyVAK3JgSTI1bz5CJigpQ3JsUFstN1k8bV8uckkwMkwsc2QnJztYJEtjZjBpOk8xVE4uSXJdVitkQUc3TE1WRikqMm8lQDI5Y0JUIS8/Wk0tXDQuIVZlYnIuakhoOkhHRUxVciIyVFY0U15IUlErRERTRmEkZCRoMWZrNTxERDhvIy43YjloXi5ySS1xTlxQa1M9XjVzOUVMM0trVjU6I2JwJkZdYk0jUkpsM1NKSH4+ZW5kc3RyZWFtCmVuZG9iago3IDAgb2JqCjw8Ci9CaXRzUGVyQ29tcG9uZW50IDggL0NvbG9yU3BhY2UgL0RldmljZVJHQiAvRmlsdGVyIFsgL0FTQ0lJODVEZWNvZGUgL0ZsYXRlRGVjb2RlIF0gL0hlaWdodCAxMjAgL0xlbmd0aCAxMTI3IC9TdWJ0eXBlIC9JbWFnZSAKICAvVHlwZSAvWE9iamVjdCAvV2lkdGggMTIwCj4+CnN0cmVhbQpHYiIwUzk5LE4tJi1VQFxFIXAkZ3BWMjVzMGFrMXRuNyYxL2xDZkBjJmMmSVdZbGw5QUpWaz88RT8nSVdzI003Qj9BUzlPSD9qJUZDcWg3OmhvRkArSiVYZ2xMUk9Cay5uPTJNJXNITUo7bFFaVWdRNl4xLEZvb0BIMUJEVVM6dUdyIkIsaFBRS1ojJixIMyVOJGYwKz1ARlNlV2peTi89MSI4Ikw8RTs+KiIvbEdhQ1IkTW5nIW5pSyU2Z0QpV1JTJkBEKSsmXDRSMForQXM8KnMmcDcsY08yYlpeSz1baGFkbTktKVZmKFxhKEQsXzxXSSRXbUFzX1peVz5kam1WSDJlZjZnSGhPP2BpOExnVlRBYDxON1o7STIiLm1QPFNzIVguMiYpNDJbMypjSFwyMVNKZktpQjI+QTBjNlFxdVphajE0Qi0rQTlmaUc7TDFETGVlQ2FgSDJSPm0vR2VsRkJhKi5TSD5RNSZiMz9scSxnRFdyXTBPbD1UTFcuPzkoazhEY08mPF8qWUM6RkpvXE0jZ20sMkpZRDw1RDJrbXJLcj1fOU9kYmwiKEBZO1hLQFMpUHJsVlFNKEQ7XSo8MWYjQHUlXFR1Mi9wQ2wrPScxMy0xaTwwRl5UTEgxLGUkV0A2ayM+aVY0NU1LPkhGN1BGPW84XCNBOyttIVBGLCFVJE9WYCwqaTFRMUhZKCFpYGB1LjJxXVlpYVM6MjlVNGdZIzkmXG5YPV1XM3RmLEIqNF5gclNQbihDPjEpQVNbSHJPalIlbyZJTjNNbXFsKG1aREooPylFN2pSRVRwPzUkU14jWmFAQ05RUEgsJVtQSXI9NUg2QyckOkIqZSZRZTk0OyloY2pyMSdzZD4hbTxtcUYjO2Y3cUIsZEU4cjlcO2MxTC4+WUQ5MUZIKE8sUXFYNyEzdFpRRT1GXXJYIXM9XC02JzFEWCteXW9GbE49XGNZZDFDbVc4czF1dXNBNiRjT2s4N19pRmcqWjM0Y1hmdUYzYSplPzo+Jkw7TTJJRDlOUyxgYmwvVGQtXlFFS21NcGFeVGhoaDQoaWpyIW9fNW9NZEU9UEBXdTxrNTM/PitCMjtDM19XJFhDUTM/PiJLMjorQFNWKHNwTj1dTGpjczNdbDIjTkJ0JCdQRDo1O1UuI0hyY25yIVgjVURdNDZPJCUvKlAzU3A8NzspPG4hSS9ENF0/WFdON246Zyw/LkA5UCVpTFs6KkJrTlQvNGxDQC9acSFxaSxDZT5kZGtkNExsbmUxJl9RTV9mPjtQbDdWRTFNWldKbXInamxMcW1MUSo0X2lOaHItYmNKX1xjLldIIitwNkxPMSsxJjcnVzZaMjotUUZZNTksJ1M3PnE+QUhKLDdlYE8uKSJeSCtPPiNYPitLX0VPTjA+XWAqVHVfYUhOLlVEVnIhZWFNWE8lZUZDV09TMGNcVGE8UjdIZS9kXkhiVW5OMmZcJk9HSUdWb3QsMDhmODA8K3NSSzJtXkZ+PmVuZHN0cmVhbQplbmRvYmoKOCAwIG9iago8PAovQ29udGVudHMgMTkgMCBSIC9NZWRpYUJveCBbIDAgMCA2MTIgNzkyIF0gL1BhcmVudCAxNyAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXSAvWE9iamVjdCA8PAovRm9ybVhvYi4yYTg4YWM2NzEyYzljYTcyN2U0YWQ4ZjI1YmNiZGFlMiA3IDAgUiAvRm9ybVhvYi42YmU0MGVlYWFmMGQ4MWQxODc1MGRjMGE3ZjlkYzIxMyA1IDAgUiAvRm9ybVhvYi5lNWMzMTQ3ZDE4Zjk4NjdhNGYxMDhkM2E1NWEyNDhiNCA2IDAgUgo+Pgo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKOSAwIG9iago8PAovQSA8PAovUyAvVVJJIC9UeXBlIC9BY3Rpb24gL1VSSSAoaHR0cHM6Ly9leGFtcGxlLmNvbS9pbnZvaWNlcy9JTlYtMjA0OCkKPj4gL0JvcmRlciBbIDAgMCAwIF0gL1JlY3QgWyA0NSA1NzUgMzAwIDU5MCBdIC9TdWJ0eXBlIC9MaW5rIC9UeXBlIC9Bbm5vdAo+PgplbmRvYmoKMTAgMCBvYmoKPDwKL0MgWyAuODMgLjg5IC45NSBdIC9Db250ZW50cyAoVG90YWwgaGlnaGxpZ2h0ZWQgZm9yIHJldmlldykgL1F1YWRQb2ludHMgWyA0MCA1NzkgNTQwIDU3OSA0MCA1NTUgNTQwIDU1NSBdIC9SZWN0IFsgNDAgNTU1IDU0MCA1NzkgXSAvU3VidHlwZSAvSGlnaGxpZ2h0IC9UeXBlIC9Bbm5vdAo+PgplbmRvYmoKMTEgMCBvYmoKPDwKL0MgWyAwIDAgMCBdIC9Db250ZW50cyAoVmVyaWZ5IHRoZSBoaWdobGlnaHRlZCB0b3RhbCkgL1F1YWRQb2ludHMgWyA1MjAgNTI1IDU0MCA1MjUgNTIwIDU0NSA1NDAgNTQ1IF0gL1JlY3QgWyA1MjAgNTI1IDU0MCA1NDUgXSAvU3VidHlwZSAvVGV4dCAvVHlwZSAvQW5ub3QKPj4KZW5kb2JqCjEyIDAgb2JqCjw8Ci9Bbm5vdHMgWyA5IDAgUiAxMCAwIFIgMTEgMCBSIF0gL0NvbnRlbnRzIDIwIDAgUiAvTWVkaWFCb3ggWyAwIDAgNjEyIDc5MiBdIC9QYXJlbnQgMTcgMCBSIC9SZXNvdXJjZXMgPDwKL0ZvbnQgMSAwIFIgL1Byb2NTZXQgWyAvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJIF0KPj4gL1JvdGF0ZSAwIAogIC9UcmFucyA8PAoKPj4gL1R5cGUgL1BhZ2UKPj4KZW5kb2JqCjEzIDAgb2JqCjw8Ci9Db250ZW50cyAyMSAwIFIgL01lZGlhQm94IFsgMCAwIDYxMiA3OTIgXSAvUGFyZW50IDE3IDAgUiAvUmVzb3VyY2VzIDw8Ci9Gb250IDEgMCBSIC9Qcm9jU2V0IFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdCj4+IC9Sb3RhdGUgMCAvVHJhbnMgPDwKCj4+IAogIC9UeXBlIC9QYWdlCj4+CmVuZG9iagoxNCAwIG9iago8PAovQ29udGVudHMgMjIgMCBSIC9NZWRpYUJveCBbIDAgMCA2MTIgNzkyIF0gL1BhcmVudCAxNyAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXQo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKMTUgMCBvYmoKPDwKL1BhZ2VNb2RlIC9Vc2VOb25lIC9QYWdlcyAxNyAwIFIgL1R5cGUgL0NhdGFsb2cKPj4KZW5kb2JqCjE2IDAgb2JqCjw8Ci9BdXRob3IgKExpdGVMTE0gT0NSIGZpeHR1cmUgZ2VuZXJhdG9yKSAvQ3JlYXRpb25EYXRlIChEOjIwMDAwMTAxMDAwMDAwKzAwJzAwJykgL0NyZWF0b3IgKGFub255bW91cykgL0tleXdvcmRzIChPQ1IsIGludm9pY2UsIHRhYmxlLCBmaWd1cmUsIGFubm90YXRpb24pIC9Nb2REYXRlIChEOjIwMDAwMTAxMDAwMDAwKzAwJzAwJykgL1Byb2R1Y2VyIChSZXBvcnRMYWIgUERGIExpYnJhcnkgLSBcKG9wZW5zb3VyY2VcKSkgCiAgL1N1YmplY3QgKFNlbWFudGljIE9DUiBjb3ZlcmFnZSBmb3IgdGFibGVzLCBmaWd1cmVzLCBhbm5vdGF0aW9ucywgYW5kIG1ldGFkYXRhKSAvVGl0bGUgKFF1YXJ0ZXJseSBPcGVyYXRpb25zIFJlcG9ydCkgL1RyYXBwZWQgL0ZhbHNlCj4+CmVuZG9iagoxNyAwIG9iago8PAovQ291bnQgNSAvS2lkcyBbIDQgMCBSIDggMCBSIDEyIDAgUiAxMyAwIFIgMTQgMCBSIF0gL1R5cGUgL1BhZ2VzCj4+CmVuZG9iagoxOCAwIG9iago8PAovTGVuZ3RoIDIyODAKPj4Kc3RyZWFtCjEgMCAwIDEgMCAwIGNtICBCVCAvRjEgMTIgVGYgMTQuNCBUTCBFVAowIDAgMCByZwpCVCAvRjEgMTEgVGYgMTMuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc3MCBUbSAoUXVhcnRlcmx5IE9wZXJhdGlvbnMgUmVwb3J0KSBUaiBUKiBFVApCVCAvRjIgMTYgVGYgMTkuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc0NSBUbSAoSW52b2ljZSBTdW1tYXJ5IGFuZCBMaW5lIEl0ZW1zKSBUaiBUKiBFVApCVCAvRjEgOSBUZiAxMC44IFRMIEVUCkJUIDEgMCAwIDEgNDUgMzAgVG0gKENvbmZpZGVudGlhbCB8IFBhZ2UgMSBvZiA1KSBUaiBUKiBFVApuIDQ1IDYyNSBtIDQ1IDczMCBsIFMKbiAyNDUgNjI1IG0gMjQ1IDczMCBsIFMKbiA0MDUgNjI1IG0gNDA1IDczMCBsIFMKbiA1NjUgNjI1IG0gNTY1IDczMCBsIFMKbiA0NSA3MzAgbSA1NjUgNzMwIGwgUwpuIDQ1IDY5NSBtIDU2NSA2OTUgbCBTCm4gNDUgNjYwIG0gNTY1IDY2MCBsIFMKbiA0NSA2MjUgbSA1NjUgNjI1IGwgUwpCVCAxIDAgMCAxIDU1IDcwNyBUbSAoSXRlbSkgVGogVCogRVQKQlQgMSAwIDAgMSAyNTUgNzA3IFRtIChRdWFudGl0eSkgVGogVCogRVQKQlQgMSAwIDAgMSA0MTUgNzA3IFRtIChBbW91bnQpIFRqIFQqIEVUCkJUIDEgMCAwIDEgNTUgNjcyIFRtIChEb2N1bWVudCBhbmFseXNpcykgVGogVCogRVQKQlQgMSAwIDAgMSAyNTUgNjcyIFRtICgyKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQxNSA2NzIgVG0gKDEyMC4wMCkgVGogVCogRVQKQlQgMSAwIDAgMSA1NSA2MzcgVG0gKE9DUiB2ZXJpZmljYXRpb24pIFRqIFQqIEVUCkJUIDEgMCAwIDEgMjU1IDYzNyBUbSAoMSkgVGogVCogRVQKQlQgMSAwIDAgMSA0MTUgNjM3IFRtICg4MC4wMCkgVGogVCogRVQKbiA0NSA0OTUgbSA0NSA2MDAgbCBTCm4gMjQ1IDQ5NSBtIDI0NSA2MDAgbCBTCm4gNDA1IDQ5NSBtIDQwNSA2MDAgbCBTCm4gNTY1IDQ5NSBtIDU2NSA2MDAgbCBTCm4gNDUgNjAwIG0gNTY1IDYwMCBsIFMKbiA0NSA1NjUgbSA1NjUgNTY1IGwgUwpuIDQ1IDUzMCBtIDU2NSA1MzAgbCBTCm4gNDUgNDk1IG0gNTY1IDQ5NSBsIFMKQlQgMSAwIDAgMSA1NSA1NzcgVG0gKEl0ZW0gY29udGludWVkKSBUaiBUKiBFVApCVCAxIDAgMCAxIDI1NSA1NzcgVG0gKFF1YW50aXR5KSBUaiBUKiBFVApCVCAxIDAgMCAxIDQxNSA1NzcgVG0gKEFtb3VudCkgVGogVCogRVQKQlQgMSAwIDAgMSA1NSA1NDIgVG0gKEZpeHR1cmUgdmFsaWRhdGlvbikgVGogVCogRVQKQlQgMSAwIDAgMSAyNTUgNTQyIFRtICgzKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQxNSA1NDIgVG0gKDQ1LjAwKSBUaiBUKiBFVApCVCAxIDAgMCAxIDU1IDUwNyBUbSAoUHJvdmlkZXIgcmV2aWV3KSBUaiBUKiBFVApCVCAxIDAgMCAxIDI1NSA1MDcgVG0gKDEpIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDE1IDUwNyBUbSAoMjUuMDApIFRqIFQqIEVUCkJUIC9GMSAxMCBUZiAxMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDQ3MiBUbSAoU2VjdGlvbiAxLjE6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQ0NCBUbSAoU2VjdGlvbiAxLjI6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQxNiBUbSAoU2VjdGlvbiAxLjM6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM4OCBUbSAoU2VjdGlvbiAxLjQ6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM2MCBUbSAoU2VjdGlvbiAxLjU6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMzMiBUbSAoU2VjdGlvbiAxLjY6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMwNCBUbSAoU2VjdGlvbiAxLjc6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDI3NiBUbSAoU2VjdGlvbiAxLjg6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVAogCmVuZHN0cmVhbQplbmRvYmoKMTkgMCBvYmoKPDwKL0xlbmd0aCAxNzIzCj4+CnN0cmVhbQoxIDAgMCAxIDAgMCBjbSAgQlQgL0YxIDEyIFRmIDE0LjQgVEwgRVQKMCAwIDAgcmcKQlQgL0YxIDExIFRmIDEzLjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NzAgVG0gKFF1YXJ0ZXJseSBPcGVyYXRpb25zIFJlcG9ydCkgVGogVCogRVQKQlQgL0YyIDE2IFRmIDE5LjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NDUgVG0gKFJldmVudWUgQ2hhcnQgYW5kIEZvcm11bGEgUmV2aWV3KSBUaiBUKiBFVApCVCAvRjEgOSBUZiAxMC44IFRMIEVUCkJUIDEgMCAwIDEgNDUgMzAgVG0gKENvbmZpZGVudGlhbCB8IFBhZ2UgMiBvZiA1KSBUaiBUKiBFVAouMiAuNDUwOTggLjg1MDk4IHJnCm4gNzAgNjEwIDY1IDcwIHJlIGYqCm4gMTcwIDYxMCA2NSAxMTUgcmUgZioKbiAyNzAgNjEwIDY1IDkwIHJlIGYqCm4gMzcwIDYxMCA2NSAxMzAgcmUgZioKMCAwIDAgcmcKQlQgMSAwIDAgMSA5MCA1OTAgVG0gKFExKSBUaiBUKiBFVApCVCAxIDAgMCAxIDE5MCA1OTAgVG0gKFEyKSBUaiBUKiBFVApCVCAxIDAgMCAxIDI5MCA1OTAgVG0gKFEzKSBUaiBUKiBFVApCVCAxIDAgMCAxIDM5MCA1OTAgVG0gKFE0KSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDU1MCBUbSAoRm9ybXVsYTogZ3Jvc3MgbWFyZ2luID0gXChyZXZlbnVlIC0gY29zdFwpIC8gcmV2ZW51ZSkgVGogVCogRVQKcQo3MCAwIDAgNzAgNDU1IDY1NSBjbQovRm9ybVhvYi42YmU0MGVlYWFmMGQ4MWQxODc1MGRjMGE3ZjlkYzIxMyBEbwpRCnEKNzAgMCAwIDYyIDQ1NSA1NjUgY20KL0Zvcm1Yb2IuZTVjMzE0N2QxOGY5ODY3YTRmMTA4ZDNhNTVhMjQ4YjQgRG8KUQpxCjQ1IDAgMCA0NSA0NTUgNTAwIGNtCi9Gb3JtWG9iLjJhODhhYzY3MTJjOWNhNzI3ZTRhZDhmMjViY2JkYWUyIERvClEKQlQgL0YxIDEwIFRmIDEyIFRMIEVUCkJUIDEgMCAwIDEgNDUgNDcyIFRtIChTZWN0aW9uIDIuMTogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgNDQ0IFRtIChTZWN0aW9uIDIuMjogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgNDE2IFRtIChTZWN0aW9uIDIuMzogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzg4IFRtIChTZWN0aW9uIDIuNDogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzYwIFRtIChTZWN0aW9uIDIuNTogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzMyIFRtIChTZWN0aW9uIDIuNjogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzA0IFRtIChTZWN0aW9uIDIuNzogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMjc2IFRtIChTZWN0aW9uIDIuODogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCiAKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago8PAovTGVuZ3RoIDI0NjYKPj4Kc3RyZWFtCjEgMCAwIDEgMCAwIGNtICBCVCAvRjEgMTIgVGYgMTQuNCBUTCBFVAowIDAgMCByZwpCVCAvRjEgMTEgVGYgMTMuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc3MCBUbSAoUXVhcnRlcmx5IE9wZXJhdGlvbnMgUmVwb3J0KSBUaiBUKiBFVApCVCAvRjIgMTYgVGYgMTkuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc0NSBUbSAoS2V5IFZhbHVlcywgTGluaywgSGlnaGxpZ2h0LCBhbmQgQ29tbWVudCkgVGogVCogRVQKQlQgL0YxIDkgVGYgMTAuOCBUTCBFVApCVCAxIDAgMCAxIDQ1IDMwIFRtIChDb25maWRlbnRpYWwgfCBQYWdlIDMgb2YgNSkgVGogVCogRVQKQlQgL0YxIDEyIFRmIDE0LjQgVEwgRVQKQlQgMSAwIDAgMSA0NSA3MDAgVG0gKEludm9pY2UgTnVtYmVyOiBJTlYtMjA0OCkgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA2NzUgVG0gKFB1cmNoYXNlIE9yZGVyOiBQTy00MDk2KSBUaiBUKiBFVAouOTQ5MDIgLjkwMTk2MSAuMzUyOTQxIHJnCm4gNDAgNTU1IDUwMCAyNCByZSBmKgowIDAgMCByZwpCVCAxIDAgMCAxIDQ1IDU2MCBUbSAoSGlnaGxpZ2h0ZWQgdG90YWwgcmVxdWlyaW5nIHJldmlldykgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA1MzAgVG0gKFJldmlld2VyIGNvbW1lbnQ6IHZlcmlmeSB0aGUgaGlnaGxpZ2h0ZWQgdG90YWwgYmVmb3JlIGFwcHJvdmFsKSBUaiBUKiBFVAoxIDAgMCByZwpCVCAxIDAgMCAxIDQ1IDQ5NSBUbSAoUmV2aXNlZCB0b3RhbDogMjQ1LjAwKSBUaiBUKiBFVApuIDQ1IDUwMSBtIDE1MCA1MDEgbCBTCjAgMCAwIHJnCkJUIDEgMCAwIDEgNDUgNTc1IFRtIChodHRwczovL2V4YW1wbGUuY29tL2ludm9pY2VzL0lOVi0yMDQ4KSBUaiBUKiBFVApxCjEgMCAwIDEgOTAgMTMwIGNtCm4gMTggMCAyLjQgNzAgcmUgZioKbiAyMS42IDAgMS4yIDcwIHJlIGYqCm4gMjUuMiAwIDMuNiA3MCByZSBmKgpuIDMxLjIgMCAzLjYgNzAgcmUgZioKbiAzOC40IDAgMi40IDcwIHJlIGYqCm4gNDIgMCAxLjIgNzAgcmUgZioKbiA0NC40IDAgMi40IDcwIHJlIGYqCm4gNDkuMiAwIDIuNCA3MCByZSBmKgpuIDUyLjggMCAyLjQgNzAgcmUgZioKbiA1Ny42IDAgMy42IDcwIHJlIGYqCm4gNjIuNCAwIDIuNCA3MCByZSBmKgpuIDY2IDAgMy42IDcwIHJlIGYqCm4gNzAuOCAwIDIuNCA3MCByZSBmKgpuIDc2LjggMCAxLjIgNzAgcmUgZioKbiA4MS42IDAgMS4yIDcwIHJlIGYqCm4gODQgMCAzLjYgNzAgcmUgZioKbiA4OC44IDAgMi40IDcwIHJlIGYqCm4gOTIuNCAwIDMuNiA3MCByZSBmKgpuIDk3LjIgMCAxLjIgNzAgcmUgZioKbiA5OS42IDAgMy42IDcwIHJlIGYqCm4gMTA0LjQgMCAyLjQgNzAgcmUgZioKbiAxMTAuNCAwIDEuMiA3MCByZSBmKgpuIDExMi44IDAgNC44IDcwIHJlIGYqCm4gMTE4LjggMCAzLjYgNzAgcmUgZioKbiAxMjMuNiAwIDMuNiA3MCByZSBmKgpuIDEyOC40IDAgMi40IDcwIHJlIGYqCm4gMTMyIDAgMy42IDcwIHJlIGYqCm4gMTM2LjggMCAyLjQgNzAgcmUgZioKbiAxNDEuNiAwIDEuMiA3MCByZSBmKgpuIDE0NS4yIDAgMy42IDcwIHJlIGYqCm4gMTUwIDAgMi40IDcwIHJlIGYqCm4gMTU2IDAgMy42IDcwIHJlIGYqCm4gMTYwLjggMCAxLjIgNzAgcmUgZioKbiAxNjMuMiAwIDIuNCA3MCByZSBmKgpRCkJUIC9GMSAxMCBUZiAxMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDQ3MiBUbSAoU2VjdGlvbiAzLjE6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQ0NCBUbSAoU2VjdGlvbiAzLjI6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQxNiBUbSAoU2VjdGlvbiAzLjM6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM4OCBUbSAoU2VjdGlvbiAzLjQ6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM2MCBUbSAoU2VjdGlvbiAzLjU6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMzMiBUbSAoU2VjdGlvbiAzLjY6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMwNCBUbSAoU2VjdGlvbiAzLjc6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDI3NiBUbSAoU2VjdGlvbiAzLjg6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVAogCmVuZHN0cmVhbQplbmRvYmoKMjEgMCBvYmoKPDwKL0xlbmd0aCAxNDk0Cj4+CnN0cmVhbQoxIDAgMCAxIDAgMCBjbSAgQlQgL0YxIDEyIFRmIDE0LjQgVEwgRVQKMCAwIDAgcmcKQlQgL0YxIDExIFRmIDEzLjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NzAgVG0gKFF1YXJ0ZXJseSBPcGVyYXRpb25zIFJlcG9ydCkgVGogVCogRVQKQlQgL0YyIDE2IFRmIDE5LjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NDUgVG0gKEFwcHJvdmFsIFNpZ25hdHVyZSBhbmQgV2F0ZXJtYXJrKSBUaiBUKiBFVApCVCAvRjEgOSBUZiAxMC44IFRMIEVUCkJUIDEgMCAwIDEgNDUgMzAgVG0gKENvbmZpZGVudGlhbCB8IFBhZ2UgNCBvZiA1KSBUaiBUKiBFVApxCi44Mjc0NTEgLjgyNzQ1MSAuODI3NDUxIHJnCkJUIC9GMiA1NCBUZiA2NC44IFRMIEVUCi45MDYzMDggLjQyMjYxOCAtMC40MjI2MTggLjkwNjMwOCAxMTAgMzkwIGNtCkJUIDEgMCAwIDEgMCAwIFRtIChEUkFGVCkgVGogVCogRVQKUQowIDAgMCByZwpCVCAvRjEgMTIgVGYgMTQuNCBUTCBFVApCVCAxIDAgMCAxIDQ1IDYzNSBUbSAoQXBwcm92ZWQgYnk6IEpvcmRhbiBMZWUpIFRqIFQqIEVUCm4gNDUgNjEwIG0gMzEwIDYxMCBsIFMKbiA1NSA1OTUgbSA3NSA2MjUgMTEyIDYwMiAxNTUgNjAwIGMgUwpCVCAxIDAgMCAxIDQ1IDU4MCBUbSAoU2lnbmF0dXJlKSBUaiBUKiBFVApCVCAvRjEgMTAgVGYgMTIgVEwgRVQKQlQgMSAwIDAgMSA0NSA0NzIgVG0gKFNlY3Rpb24gNC4xOiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA0NDQgVG0gKFNlY3Rpb24gNC4yOiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA0MTYgVG0gKFNlY3Rpb24gNC4zOiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzODggVG0gKFNlY3Rpb24gNC40OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzNjAgVG0gKFNlY3Rpb24gNC41OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzMzIgVG0gKFNlY3Rpb24gNC42OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzMDQgVG0gKFNlY3Rpb24gNC43OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAyNzYgVG0gKFNlY3Rpb24gNC44OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKIAplbmRzdHJlYW0KZW5kb2JqCjIyIDAgb2JqCjw8Ci9MZW5ndGggMTMyNwo+PgpzdHJlYW0KMSAwIDAgMSAwIDAgY20gIEJUIC9GMSAxMiBUZiAxNC40IFRMIEVUCjAgMCAwIHJnCkJUIC9GMSAxMSBUZiAxMy4yIFRMIEVUCkJUIDEgMCAwIDEgNDUgNzcwIFRtIChRdWFydGVybHkgT3BlcmF0aW9ucyBSZXBvcnQpIFRqIFQqIEVUCkJUIC9GMiAxNiBUZiAxOS4yIFRMIEVUCkJUIDEgMCAwIDEgNDUgNzQ1IFRtIChBcHBlbmRpeCB3aXRoIFNlY3Rpb24gQm91bmRhcmllcykgVGogVCogRVQKQlQgL0YxIDkgVGYgMTAuOCBUTCBFVApCVCAxIDAgMCAxIDQ1IDMwIFRtIChDb25maWRlbnRpYWwgfCBQYWdlIDUgb2YgNSkgVGogVCogRVQKQlQgL0YyIDE0IFRmIDE2LjggVEwgRVQKQlQgMSAwIDAgMSA0NSA3MDAgVG0gKDEuIFNjb3BlKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDY1MCBUbSAoMi4gRmluZGluZ3MpIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgNjAwIFRtICgzLiBSZWNvbW1lbmRhdGlvbnMpIFRqIFQqIEVUCkJUIC9GMSAxMCBUZiAxMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDQ3MiBUbSAoU2VjdGlvbiA1LjE6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQ0NCBUbSAoU2VjdGlvbiA1LjI6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQxNiBUbSAoU2VjdGlvbiA1LjM6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM4OCBUbSAoU2VjdGlvbiA1LjQ6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM2MCBUbSAoU2VjdGlvbiA1LjU6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMzMiBUbSAoU2VjdGlvbiA1LjY6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMwNCBUbSAoU2VjdGlvbiA1Ljc6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDI3NiBUbSAoU2VjdGlvbiA1Ljg6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVAogCmVuZHN0cmVhbQplbmRvYmoKeHJlZgowIDIzCjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDA2MSAwMDAwMCBuIAowMDAwMDAwMTAyIDAwMDAwIG4gCjAwMDAwMDAyMDkgMDAwMDAgbiAKMDAwMDAwMDMyMSAwMDAwMCBuIAowMDAwMDAwNTE2IDAwMDAwIG4gCjAwMDAwMDYzMjIgMDAwMDAgbiAKMDAwMDAxMjgyNCAwMDAwMCBuIAowMDAwMDE0MTQyIDAwMDAwIG4gCjAwMDAwMTQ0OTYgMDAwMDAgbiAKMDAwMDAxNDY2NCAwMDAwMCBuIAowMDAwMDE0ODUwIDAwMDAwIG4gCjAwMDAwMTUwMjggMDAwMDAgbiAKMDAwMDAxNTI1NiAwMDAwMCBuIAowMDAwMDE1NDUyIDAwMDAwIG4gCjAwMDAwMTU2NDggMDAwMDAgbiAKMDAwMDAxNTcxOCAwMDAwMCBuIAowMDAwMDE2MTE1IDAwMDAwIG4gCjAwMDAwMTYyMDIgMDAwMDAgbiAKMDAwMDAxODUzNCAwMDAwMCBuIAowMDAwMDIwMzA5IDAwMDAwIG4gCjAwMDAwMjI4MjcgMDAwMDAgbiAKMDAwMDAyNDM3MyAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9JRCAKWzwyZjUwODkzYTFlYWZmMTExOWMwNDcwZmM0YzU3ZTI0Nz48MmY1MDg5M2ExZWFmZjExMTljMDQ3MGZjNGM1N2UyNDc+XQolIFJlcG9ydExhYiBnZW5lcmF0ZWQgUERGIGRvY3VtZW50IC0tIGRpZ2VzdCAob3BlbnNvdXJjZSkKCi9JbmZvIDE2IDAgUgovUm9vdCAxNSAwIFIKL1NpemUgMjMKPj4Kc3RhcnR4cmVmCjI1NzUyCiUlRU9GCg=="}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"object":"error","message":"Invalid model: invalid-ocr-model-for-parity","type":"invalid_model","param":null,"code":"1500","raw_status_code":400}' + headers: + CF-RAY: + - a34832c9ae37ad44-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 23:54:08 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05f64-fa6f-76c9-8b39-fd7d42840ba2 + x-envoy-upstream-service-time: + - '2' + x-kong-proxy-latency: + - '16' + x-kong-request-id: + - 01a05f64-fa6f-76c9-8b39-fd7d42840ba2 + x-kong-upstream-latency: + - '10' + status: + code: 400 + message: '' +recorded_at: '2026-09-01T23:54:08.641470+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKJZOMi54gUmVwb3J0TGFiIEdlbmVyYXRlZCBQREYgZG9jdW1lbnQgKG9wZW5zb3VyY2UpCjEgMCBvYmoKPDwKL0YxIDIgMCBSIC9GMiAzIDAgUgo+PgplbmRvYmoKMiAwIG9iago8PAovQmFzZUZvbnQgL0hlbHZldGljYSAvRW5jb2RpbmcgL1dpbkFuc2lFbmNvZGluZyAvTmFtZSAvRjEgL1N1YnR5cGUgL1R5cGUxIC9UeXBlIC9Gb250Cj4+CmVuZG9iagozIDAgb2JqCjw8Ci9CYXNlRm9udCAvSGVsdmV0aWNhLUJvbGQgL0VuY29kaW5nIC9XaW5BbnNpRW5jb2RpbmcgL05hbWUgL0YyIC9TdWJ0eXBlIC9UeXBlMSAvVHlwZSAvRm9udAo+PgplbmRvYmoKNCAwIG9iago8PAovQ29udGVudHMgMTggMCBSIC9NZWRpYUJveCBbIDAgMCA2MTIgNzkyIF0gL1BhcmVudCAxNyAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXQo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKNSAwIG9iago8PAovQml0c1BlckNvbXBvbmVudCA4IC9Db2xvclNwYWNlIC9EZXZpY2VSR0IgL0ZpbHRlciBbIC9BU0NJSTg1RGVjb2RlIC9GbGF0ZURlY29kZSBdIC9IZWlnaHQgMzIwIC9MZW5ndGggNTYxNSAvU3VidHlwZSAvSW1hZ2UgCiAgL1R5cGUgL1hPYmplY3QgL1dpZHRoIDMyMAo+PgpzdHJlYW0KR2IiL2w2I3BIcSVSZE1bNDNaKzdadVpbLUFpNUtMMzIvY0tJbkxtaixYPmxxXEVxWFItTGs6PWw+I1lObGclcFhybTBwMGRhSFMvXHBpPC5cPyFyU1Y1PGpoNFMhcj5xc1hSVXAtN18zVjItWWksZChNMkNrWk5yLz9aTUFIV0FwJUthNz8nWS4zRzs6WW4zZlZ0TVtFXERkPkY3b2FlZjgrbkw6XERhWFhyMjpMN25AWUAzJ2ZWWktaMTh0aDtXMiVJTV5yWylmQk08RyhULVx0VCNERidTRWktKCM4YTApUiVEODMyazdNQGksOjU1aT5GZTouckk9amVcNE9rW19gLG0oMEI6MW1ZNXE4RURtVWRdazs/KCVIbS1zcFAsMDhuQzlbWy5yST1qZ1U2ZTIsX2JeUz1eNXNhXEwzXGtqQ1RmZkMhWWRyKXBVVj1iSk9janByOG9FJ2ZWWTBETy1KKlg3MTZwTV5yWykyb0kuMDJjL0pGSDU5VDtFLExuNzlBRVk1J2c3SSpERSdUUVhqSSpvI0pUSHNtb2BuOF9tcFlHVS5ddF1sQ2toOGNmMGckYzsiLWBHa0ZpUSppIjUyaWVlXSMlQD5baXJCMzg6bzpFbzkyazY/XFk5IUNiRWhwdURNXnJbKTJiQD07bzY6KD5EMG0lImdpLi8mXVFXWjFoWFBwYy8/Wk1BZ2YvUE5fVl4+PzJYRlJPRVBvPz9ubGgtaVglMlIuWmFmIkxFcmtpOFNBLl0lRFVsKSdpZURNL25saSEscmFZXWU9XjVzYVxNLzpcZzBhJSVTK0o4N1xEXlxnXVUlS1otVU5UW2A+KD4lJF5UQ2JyJih0I0QiZklKP25QYmw5Q3BiXyRDQ0I5WS4zSEcmcFooWD9cOlFOMzVcWT1RKzI/TTM5U3Q/PjpJY1M9NWo6KW09WVQ0cC8uMmxZL0NNMW8lRiJvL0ViJlY+JDteb1dpO2omWCM1PjxjOC9tPlhjXVs9LGExPkRpOkRnZk8nRFYtcWA/UXI9O1pQXT5fcmpIW1pdNWxyJTBJLm42Q2VYaS0oPTlNWiFFJnJRQWdFayI4a1lmQ1Iyb2M+LlMlUTcrazlZL0NLX1NLQ3NibzMvLS5HX1A+KlErLWdzO2RNZT80bHU9Tj9aPzxsNG5IZV5ZSHN0M3BGR1o+WSZjQT9yVWd1V209KiJwYms5O1hyKj8+J2FvLilZUihHMjdub3BrOWdBO1YvMFIlWExqbVJBOC0yL3FYQC4pIztiMjopPE9uVUJvQC4pbjxha3IwdSFWXCw0QC4qYTxha3NsaG9Cbk9wWUlNIXFQQmlBLGlLXms6PWtyL3BfYiQnLDhdPFVQPWtxPFhvLDNiLFdWKVNPLzhlWzBhRTVPMjVmbl5DTXFhR0JxY3FmI3JeS245Yj9UbDNpIiNPbWNMMTNdViFvbnM4bURAP2BvZWdwUSt1TGlwUmBzVSFTZ2UmJGhOKGhyWjdCX0knMUJrRTVVY2hiXEoka0haQjpcaz1TdFoyYWNIPV1RVTNmZ0RBN1xZL0NLX1BOND0+Q1kvRXBHOSZqMDhtRD9UOllydCRHLWVxJlFkVGlVYCEoKllqWG5cbFFpIkNAMjtSQ2U+UT9dZWhTUXBLXlY8RFhlN3UvKSJgT001KD9XIjpycWBndGNXbDs3aSp0YiFiXEwvVEZeQSs0XElvXm9LdW1QZGYqOyc6XFp1XWQscWFfK1BkYD9NYzE5SnRJU1ddNjRCJDc5bmVVQXFFVzAuYm10cClzVy5eKHFba1AhW29baXFmOkZpLC8tLz5NSVFiVkxrUSw3PllRI0krTD5sSkAlNHBrNTY8NVBjTmxaLktRMCdDOFg+JCFCNW8mMDMyRWpdUUtsMmZCcT8wKjwsPyskXycmJSY/Y0JTUjJDIz4jbEwjTER1UEY5cloqL0taP1dqO3BQM1lOUVRJU20rQlhnNmJTaWNVUidjUV8mbTsyVT1MVHItZDpfbmRhXiZoYV1McD9OOW9rUihTV21ITjNwTzlwMF9ia048Xy5hKUxfQ28sQk1YaEJkWFIncVhKYCQhNUhmbidORCs9OGUrVkdgNS09Z3NtcGU0bXJURCxrJEsmK1VaUWJXLl9kJj9XWkZINl4tU1pvW2k3KUljL3RrU3BRVTc0Ri10dGY3czlScmk8VFQpai5sdEgvSkM0Jz5HWFA/RVg7XGo9YTxjcFxybVZuIypkXl02IkdPUVJENWxJcjNkMl9xckk/bTlma2BqUnI6YEs+KnVWM3BvSy9uczpgLWRwSiM2cGM9SS5cOWpkaT9fNG9aSWs9WFldMCVTJURSVjNJSDFFVGBDTjBcZ2pBPzZYVWhCTUhQQllQYSRXP2E4TyVRcDslRWkrTV1HcGlSS1lnZjg8NUxmZTxyVltOaD1LNllhL20kRy0vPVRTRDwqP0doSkljMEN0UDInPDVLKixwW05CUGsiUzouaj88JWIlUyFWLTdqWnE9R29wQ25AR1lmVzhfdWdhRDBQTCdIO3FgalBrWF51XSZhKmc4Yi9KTUNLb2lOZSJbT25YTHNUSWZJQU5ZOXAuSFI/WCJWaEwpdVYhX3JaO29icyREXUJUZyMqcm4/P1tHNFZZY1JqJTdcYjtSSiM3JEhbQG9bZCtKWkJbcCtnYSUuZT9iJk8xMFVhOCpYTTxtPWI8P3U0RTpgLj1JLj9kP0dWaSJLRS4/K2tTNHUqcWlNT2NwcSJkKjlTLEE5QG9vXkNlWyJDanBnaF82WGJOSi1DakRXQ2BHXWtSXGRrYUpNYTYlWW4yWWU8ZCxtdGNKUjxzXD1jSTksQWhwQ2dQSmRsU2dTcmwxVz9fNHBgcmBWKzM5NnBlJCtGZVwtIXJUSCQkS0hLUUI6JEE0bGdfT2UnRUdMZlEpI2JrPHBQK0tZKyYvRVdrQEFNZVR0TkJsZk0nUzBeN0xyckpUYF5pPSM1U3FtdT1ES0Q7JFIxSHRaKTkhJT1SJUBTT3FoSHFjUkRhO1hWbmllK0ZCOl9pczY5WWpdKVkzNmRiTjQuNyI0Jyohci5XQUksOFk8WGU9SmxPX1ZEP21qaUxgakRpKT5WNGFaN1ReRyVLOWhIR0YhJDdHTjVQWlJrJGNtM25bckFFcHRAbitlOW8/MUpwUk51ZVZJZ3I+cUdnRlshYj9scmwsXT0/RyVBZSNbY2ksYEQ/U0lvb0RdYUg8VTJYTWQ5O2UmaT9vMUkzPHJROjpfR05KIlNsPlc/ZDNPIkxxLm4oWkxcLzYhNk1WIVlQTjZURVlAVDIyaFhmVVdqPV8/RVAuLkAoUURYLltjZUdAXF5ML2xpaFI8RGVObCEvLFQ6QUZOSyRiaWg0OFdlIiQ/LFpkR1M5Zls3WyluTW1dVCYwXVt1Y04pPDxGZjlwMyEjXkQ8aj03YUU2InEkVFpVakxyRTtNYzlCZG1gQ2QwNEYobDhmLixWXkNaImxxXCw+QDBIXWMndEkxP15OKE9YIWdRUkQ2LXJZaydDaSlrOUBwRkNgPW5tOkxfam85UFdFLV06by50O2o4aFdWLlNyXVIxZ0gsOTUqSXNMVGtsRUI9STRsZGw2Xz1vSTBIMUtoWFk9OEpANV5EcFBtb1RNWmpMczhTTXUzTm47cm4yP1lQZE0oSGI3JC5uVHVzcWpUWFBGcjhsJF5eZ0IyIzRdREUsXz1vSTBIMUs4TWY2MldTLFh1LDByUThLPV1PVWxJcCMhWHFQOEFWXW5zOmBtLF8nW21IT3U7MEsndWU/byZMaFJZUEFrOmI2dSRrcTkrdEdUImpEYShiQD84SWNXNFloTkBma0pcbWM5SUBtJ0NTa10zRW5DUClfXixrX1BpJnBVSW5vb3UrW10mXEddUlFkP1JISVguYWExVmYxITsiYW9lQF1DbHVaRHFmKGVSLlA0c21tNkZDLk9tLUU3Im4kJG9aN0luK1xWPDsyS3MnRDtrJlBcRjRZZU5qJUFkPVs7P28xSTNXVyRlVlMhbVheSyRiaWg4LEJoTERkSWhlJFYkP0BTYGZIMzRXYm5dMl4hVWRCVGckR3I6Uy8uXXRhdXU/U0lvb21qKkJHOSJvPi4kSGxkMVJPJT49SiI4QG9pNS0xb15ML2xpaEFRPWgyPmtfPC1uS2thQlRnIjFyKjlzKU9VRnVmcmRyTkNII05HJDxQPy9XZmE+bzAwVWE5VWVjJ0dXcFAsMDtZbCJbIjhiMWEobiIrRmNcVG5QKj9TSW9vbiJwIyRNdFc6JlVwMGIjVUlrJTVrak9AOypjP19MbmVbNjNhYTlTbkxONURjaTxtYjgwVWE5VT8yZ0YyamxhVzUvOllLTFAuVlYsKV48Y0UyYypyWSRWJD9AXXVBa1dRIz5RUEQjKTg8cEJsQ2NoWnJdP3FoSkRUbyZUMyxEaG1OJm8vIkhwMFVhOCpGKzddXTRtRGUzLGs7YjEtSFkjcWhmKmlPSFRqSE5xdXJpZW8hXDNNNmYuRitbbmU8Il8uXSJFNG9KKjwybCxXTVpjUVEuUk51Zj1KK01gXGw/VkVDbmVbNjNha1AodDwtXFJtPzlQNGEiZiJaW1tkbEBdaFVuRWQ6K0xoMUJUZyNWcXV0LlxoUiE3K25lWzYzYWtPYUBONF4jazQmN0pZXy5dIkUqVzFXNVMoK2UtcjoxWV8tSFRLWzAyZ1o+U2owKjZeTC9saWhIR0VGbnR1LUk8I0V1YXI4bCUpa1YkOSFtJS0/SSIxamM0NEYrIiovV2dqckYmZkM7QkFmMWpQSj9vTDxdSy9qVCQlazdeSD9mM3JtbSlnVldaWmxucz0pUz84bWZINlxBSEtkX1cmI3JFY19vaylvQ2I8VFA2LlhPY15TPlc4LmJobEEiWzhbbi4pYW4qQGNqUz86WUgqRl9pSS5nJ1tAPG5vInJkY0U8JGgxV2RdTiUrSSlqJWZzSCpkSGQtI1s1PGE8J0NxOllvJyM0XHBSTzRpOyR0bC5QLTljbGRWcFY8U3FxWWwqVilTKWdiTz9FMFQqJEhsZUpdR15dcDdeVXNHNj5qNktuczpfQlxBLT5KbSwxX2EyY1g7XmJFRm05P2lPNGRuWWhQPVZtLSpcYVcnSTRkUW1OclcwIUxFWWwqVikpcy1QUi4oOF1GT0lNckpyOGwkPmlwWGt1RzRWWW8pbTZGQ2ppTWw7bikhZ3NvVmRpalgwRE5gYWE8Nz9wPkdXOVcvcXNzWWwqVilIZkZNOWFMMV0+TztrJSNyOGwmNG1JMCM8Rm5WYnEpa3NTN2ppUC10bitpPi5wU2ExI2hRP187YWgtTU1hRXA9KU5zYEZRJUVpK01dVzskJDRlbDxBOydHXDBCREtgN0dLSl9qSCMqJC5fVksqNnJwby5DcVxwciVEO0wyXEhfJj5lVCJJZ0pBKidpO0hQXm4kSDI1WElmQWdlWl1YPCRnajAmKS9Jc0xVNm9KXS5vZzpUQGJRWW8rZ28mUDVmRGolY0BHcVw6VW1tQCRFakYtJyxUIk1JVm4pWlRLNy9sYzxyUUYodEgjKiJYYzFUa01yOGwmdGtcbW9CWzxaXVJEVldqb0gyI1oyR3JQWjc0bXJCUnI7REV1YWgtaixKQG1cSm8oUDs5LGskbzIxXC1SYmIyNS1rUC5aNm5hNWlmMFErcWdCOGIrcUBTV249OD04a0NYOGIrTTRyMmI+MmsqXWosbz0nK1NablwlXFNyTGtMbnRGSyRtZF1vSE1Dc0goXGBNa0lOU2ZCT3EpPFdoLk5dcidXYS5jNj4sU0VLS1g+Tj1vYC9hbzAzcDNKZE9lUSFkJTNsKkdjZW1TMTM3NyJcdUtENHF0WDU2R3FqVGAvXEgqISluVD1yJGNqamRwVEQpT3EmP2gsOklDPzpNWWtPSjstPGZlRDxGRCxBK0dOU1J1Oj9NcmU+N2hrRSVMak1ZZTIrWEtfVWNoanU+S1QuPW5pPmJvNy1wTWAySVgyQTIhJGZmKTxRRzRnJUluYFoiOG1FMkxVVGpbUGhGZVs3QjxLMSxFPC1FaWhuP15MMjZIIjU+U29EKEBKUk8/Ml9Mcl0+X3JqS1ZDRi1IPTgxUW8xbjYoOUBHRXUham1VWFNeNS9BJSxxYi5HVXAwZGltdW84ODQnMUZZXC8+WHM/ZnNVKF5ba11lJGZjc2wvOlRoW11fOksvLHFiLHFYMEROQCddKz5CYC5gMTUncGNWJVdpcWQ/RUZJWVdrSzddM0dKTHNAYEdOZjNxV0JuVG4qYzR1J1FIM1VuLDZNMUhNXWVkRiRhbDlFdDlXbXJlPU0uV2I2PktGJjFwbXJXXFxBWVwuc1ppLDI+XXIhZlZbcWdRTCljZVknUnEwUTNkbSFjbm9jZVhzUnE3Qm9RcmRNZyxjWCEpL3E3QkwtaVZlV3FUIj9oPW5lV0VlQEYqcmlhUyFrKVxcQXUsJFtXWmA7UWInclJKaGldPk0tOWxwTXJGZzhhQSQtaFNQbCddcGVoPDhpY2hSYkY8XmppZjwxXydhRWovM2UtXGpnO0xONyhXUStyJSppV1dyZyhXQDZnJSdIKHE0NnQ1PVMqVCRWUWpKPTVxKixoJVUoZj5UODFePl9yaktbU2xsLlxHVnVaQmtfXXJLVGYoSD1fbU4kUlYvWSk9c1UvcDwwS0V0QC5LMnVfXyVNSm0oREVcSXRxVSYucmYiMF9haCFXVVx0cG5BP05rKW1EOm0wYk5qRjchO0ZccT01cSosPD0xLDhGWyJPPkhQVF08LF04SVUpMHUxUWI+SSohXER0LEVLdTxNLiwqX2dRWS4uJi5ZZW1ZalNWUVtcWmFmIUFFS0xTNWs0S2guOF5IQ1JTJkMiMCowa2E0XmpVTUU9NTUmUjdjQkhBWCUuJFdaYWYhQUU8LUU9a004Ky5cIjpQUjJpNCQrbjZ0MWVqIy0xKz5dR3Q7Vz0jOVloKityZVQjREYnTTQ6RjRHMkFFLVtJJSslRUtkbigkTGQoPjRBPXEwYD4oPWdTIl09QGhYYjU2bW9gbjhQSVRRWVlOPzlTNWxbRnAnZlVzZ1g3MCRELi5lNjtNXnJaWDJjL0lySXJGLGpaYWYhQUVGW2w1QENZV0woMEI5OkRXJTk8IS1FLyppZWo1RE5WWSVfJ2V1QG9FUShaMypyPlEkUmolNnM0YzpoLicpMD5NMnIjWyhuKk83X0VLZG9lWTVRPmFQUD1ANmA+KD1nXTRdbkQyY1xfaEhQVF08LGpwRDJeVWAlZyVkNyYjRUtkbzVwQU5uTmpJT10pXERlaVRRUTFEN0BjU1FZWmFmIUFFVyU2YF9oSDJvV0ZwNGk6I1wzXnI4bzNiKlMuUixpWy9ZLjxvVzUzZjxgIUgtPzI4XU0zaUVzY2YwaE9gOWVvP2U9T1ZvMnNMIT5hWkkiRkVRKForSUg2c1RaYWYhQW0zX0NhbW9gbjhQUC9vcHJ0Iy1rPW0jfj5lbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwKL0JpdHNQZXJDb21wb25lbnQgOCAvQ29sb3JTcGFjZSAvRGV2aWNlUkdCIC9GaWx0ZXIgWyAvQVNDSUk4NURlY29kZSAvRmxhdGVEZWNvZGUgXSAvSGVpZ2h0IDMyMCAvTGVuZ3RoIDYzMTEgL1N1YnR5cGUgL0ltYWdlIAogIC9UeXBlIC9YT2JqZWN0IC9XaWR0aCAzNjAKPj4Kc3RyZWFtCkdiIi9sOTYpO2cmT2BoPmVYVDgrZFFNWkZQbm1RMU04ai8kJDM7ODVOYzljbTkjSVk2JWc2MnBGJS5ybT9YTmoycWQyU1I5MXFvTmxnT01pJyNVYStVUiUyXWQnPzQmOkhlYVJEZDdfWi1eNWdYXERlUXFoJiRJbEJcWzY/YEdOTktQPUQnJ10oVDkzRVNHRy5VXzBEX1FAME5NZ2JyRVwvJ3JaZG9dcmluaWpSZkxEIixdbzwoRjhZTV5yWmFZMGQ+OVxTOj9tZTdXZD9EOFdiI2kibj1CKkd0WChZLi8+WTk2XkUkUyJQY19JMjVvPipvKWA2UzNxMmRTJ3AnZy8/WkwiXDlqU0AqQi1xPD04LGomRVNHSEFZUEFFQFMzJCoqWmFmIydpTFg8RGNlS1hjPmhXaDFgR05MVV1bbXElXS9qaXJaYWYjJ2lMXHE/LE0tITtmQ2A5T0VTR0c8bV1yRExXL2VMZC8/WkwiXDZjWGhNPGJQX1U8aGhWZ09uaGhZMHUtLXA0am1eNSlVcS8pbTkocWk3USt0XidGUiJNXnJaYVkuSE5eL1Q3MEoiTUUoP01WRWspK2NVLWQpaSs7Vm1eJ0ZfW2MnW21qIVQwTWoqTV90bUJhPV5bYyw0dGojUWhRaFkmWiMvP1pMIlw9cT5xNE03cig4XGROSi5ySDtEWm5yZ09EbGRna1hqPyFhZ09nSTsoQSZYJGpmQGBwYHAnaD5palJnQzhgT2dgTDQvNS1JMjVvPjJWXnU/NFBucEttTjguS2llbEtGUmswT0heYDFVVzNuVl9aPl1KVDFhaT0rNE5xZDRFM19LNiJZLi8+WS0uNyNeXiUoMV9cIillbldUSGguYG5cSC4ncUguNSpHZmRDRElbU09idD8nOFVDTzw3JyI5QU1zIjNISGE6KFdeUl5qJz8wYzArKU9sVSlALnJjTUwmTURKV2E+cD9tZUV1RWtnckEuP2xnbCNUJTlLJTRwS1dSMFIjPkk1P11kLnJaakElamRhSCE7XGhEcjZYakdNJS9EWk90OStCOnNxUmpXNDhDYlVUbmwmYjw/PypxQVFLOmhLPFNmLCVeJCc3KDFaK0Y/Uk9gQHNGLGNOPGZjMFc7IU02TClpanMzdWY3RF1yOT4vMiY/WkYmLWs6VSRDSCI0NmxqbFwuc1xGLy8mcTNPJUs+Pz5qWmllbSdJaDNgUzhqMDQqJms6PF5GbWJHTERRVCYxJ1F1S2UhTVgvUkRTcCNDc1onZlVwKWsnaTU2TE5lbzRhQTlIWCNQTUM9NTtDZyspY0VMWS4iW2IoMEI5dWpZR0taN1dhRSRxXmVuWzVLZGk8amMvLEYoMEI7W0NATSxsRiw7aWcpTGZZMU07K0VQaipmYSlQckkiQ05eJFYpMldqai5VRzIuWFJsOmhIJW1GKFMyV2hTRFVHMi5YVGY1YCwhLXRgY21FMFIhWW4qI2xcXk1NUEI3VydFaVxvcj04WVwhLkYwLkNwOic+Tz1gLDNeLVB0IzM9a0BTWEtTLiIlVU07K0M6L1dJV1tjZk8iYzRXVUszJyI5U1NnKS41Q1REUT0sRkErWjgtI1I0MU5caCs3NSRiZzA0PWxUKSciOVNTOWNBXzJUMTdcQSojWlV1TTsrRGUuPzIzVzpHNldLQXAoSyYua1YpZGlAUUhRaFBabydUJ0g+dEZhZFk6YklMVXQtWkFicVJRQipoJkpfY29mXTNNOUpsMmooNGVncmVOZ1tObDspbWshXE9UV1NvJyk7cmlpO29xUE9qWzRcT281VTVrWDtsXDxoNlotYFhXJCV1Myo4bEBXdShPL1RRMmRPPUpSNmZYMChvWEs4Kiw5QUpfKW1lNl41PjlwWXEjM0loXDtsN2lOUFtrREFEWykqcXJkZ29vZFwvO0ZOU0FlUE47WkVidVtFTUhVUGgxOHUjKmU0LjdHYDJgRmtbamEiaSQwJEJjLGIuRU5YPmZKdXJadFBkUTZ1MDpgXk5jXFZfbD1iYVhpYVgtSV09P2ZIPkZgP2FgSCxzRFlYakRtT0leTzouKDYrclAxISw3RmB1NGBCPD1WOGIuPm1RNEtidV5Ga3U8Ij5pXiwuQ1hbVTxRSz09NEBjLzxucDVTVjlqVmk+UGU9OFYtSFlUS3FhUVhaaV1cRT1JVEtpRzFlRCJERF8uamkyUXNXOjosdFYoalJyMiM+b2cucGFnbGA0RUpQc2BsZz40VzNhaFItRV00SjNoS1ZKUWpQQj1GbjorXU4jQWReQVk0NGQ9TkBDO0FuIilJbXM4LnM/QC5QIk9tNy9VRDlbUCwyXCVPTm85OkRwSVw0X1VVbzo7VUludCgpOXBmRUhNImUxajldNlxZa2BZOy4xcFdzbEpJVi9FZ2ZYcz8lTkRsJCJWSikuKjAmQEhFZl1RJkhqc0IhU3JLXGpNOVtQLDJddD8pdGFVXUpIYy0qb1lQSyoqRT02LlVvUE42bFlgcGVjQEkyNF9aRHNtN0o8bU1SRURhJ1U4WUhLbT41PG8mTWZZITNTTFhJI2ciKjM2MjFlRCJ0RFtcbCQ+LU46YUVtTFI6NEJePUxha1REQ3BxJkddQ1xYbFFsOU5QSVAzWDxPaU5aa1NQckhqckhOUTIoaSh0Ry1IMkRTZU46SD0wIVY9R1EjaShVdSloLl9HZ0RdZkhXLW5JcURiU1AoSCkmJi1yLltPXF8iS2RfZ2NJMC05W1AsMic+LSd0T3QoVWlwPVssJ0g3aiwwZDNPIVldSjk+VSZwOyJgZnMuRVZHISYwR11FbTpfaFk9XSYwNmw4NzJzQFNMS2YzKWpSJWQxQ0FwUnReRDk7J25tQl1HU1tvX0ZSVS5PbyZIWGxpKVJIZj1pbzZEVz08bzA0PDhiMiJqQSwpVS9sQEE4Q0ZBJTY3Q2pobkw4Yi8wbGo3My0zT1cqbGZVbydeVGlsVzM9MWVIT2pEajcxJlthM10+T2JVTjJMKmsjSGxdJDo3XyJOJldONyplSGRhMDdiYklvVnVgMk5qSWNgOHA/Zy01VzxeJmlSaU1DLUgnaS9KbStMUHNYRVY2W1InaEZMLCJqOT4obiYvOVxNbUJhS2wpQzk7SVVJayU5R1tuZzhWby81XT1LPSQ6MmoyUTZIKGhsKmA7KzlOW2ExOG5rYCEwOk80Ty5HclZfYGhCYDkoIiguKGY9JjZkKFIyKEFtYCJEPDotS0RaRmptJlApKTVWPl8qX1dfMGkmX0lvQUY0bGZEcWcpWy5uJj8lPlYxJTNZNU9FdT4/OUErZzUhLEsxbnEpM3VcOktocV89Zmw7XEBkcl8tSFYyN05TdHFlRzZRYWFUWkhbbjE3QktXKCNCZEYiNXQ6KWpiPEInXUoyaj1qTHJNT19rISVsaEIlZzJuWSsvaVlJbFNZUE45RXUpdDNMLFpwISYqXTsxQTEuclMsLyxeSFRiYGMrVEUqUSVPRzBOViJVSCIyXllhYTlkQUw6YiRGU2cxJmlUIXEiWFVYOj80MEQzPihBIVZORXAzQFM7ViElOzwxN0JLV14ic1VvRDdXclk1KTJiSjRnMkxRNz9jZkdnKUlyc0lHUVlXVDsvN0FTbGFkOVUuT3E0bVokMDg1Tzk4Y2NPJiQ9Y1JXcC1kM051VkdbbjgqR008PmRGK1EsZXFPR0kqYi5FM09ha09dUG4kYCkoRitjYFQ4XSpdcF1KMmo9alIpI2ZpR08tRkgoUW1oaVNKM21AdTtWVGdXVVZTJTFndWRkY1kuVFxHJy5fUiVkMUNwQEg6Q2NgY1YpbWRrTm4mXmtYZVpiLyJdUE42VEZOVCU8ZW1PP2slakdkXCw4YCRXLCkiLCUpKk9YWGAyajJRNkdvTSo/XEc5WlhQXSZoRDg0SmcobUhvbmxybVBhO19KX08sN1BeRFhEZ1FFODkrY1QrJloiQ0JCNmUhRS1IU3A/TkZAcFlNW1VkPXBISGI+O2AlJ1AqY0RJbjZxInFUTDNvUVNOQEM7QTA5bkpORT8qRyVeSD5YO21YOkJbVkopLipDdTRxQnInUXMjKShmMidHZVNxTiFSRmooNWlEQS03WUVnXWRKdURlX2pIaFMuclVZbj5DKzFnKkhsLHNUJ29TISljSlJiPzxWN1VVTVlaQUlLTXBubzkpJjBCVGckUGhLVGpgVCVFc0VTQGczcURiU1AoSDAoI283U0RnPTpJNCp1L3BVcmEtSFJjVl1TbFNHcCQwa3Vqa1ZHNEB1O1ZULnJUZiszWGU0TlohaU9qbzU5ZiowaCU7ZVByQ21eaDVIOCZZKlFeVDc/Y2V0Mmw6bEhWMUcuXFdTJGNaVExuXnMpalxSI2RLJVUvMDZxJmItSFJjVihmUD5saiwxTGhPdUZxKlhmcCw6PSc8NTNdT2Q8c29ldUNXRio9W143NlcyYWBtNydwP2QkME43bigxMnIqJT10TkpsbC5Dcyg8KiVEQ1pvZCRFTzYycGBncWpVRmxERipmJW1bP25OXDc/Y2V0Mmw6aytlLGMlX1dTJGNaVExuXnMpa1kjb1c8NHNGQzw3RG4xZUQjIWokVjcnbjMobW9rMXFHMkB1O1ZULnJXKFlxKVMtNWNfS1VYLnNZV14tSFJjViRvOycyMDc9MFdtcmxlbDtgJSdQSCIwVmdYLlJBUUhXJ0ZTJ01YYVdmYyw5Vi5dMy5eSUtNcG5vOSkmMEJUZyQ4aEplVXNdLCYoXEghWmhVUDtmQFBQLls9QUUwU0FTMCJrMGdnQSlmMGAmcUNQVVJeKWIpdCkuIWY7UEIoZCpEQT4sTi9DPylbUDUyaE08az9yUURtYz00THIvQHU7VlQ5QkQvJzkrQF4tR3A9MiRQKmEzLlJGYDxIKlYpWlRSTnNQQzJ0QVVXTGNYVVZBMkhtN3A+LjNGa0NCMzhHcD0yJFAuLm5aJERkZC8hSTVuLTlwMnVqMnAxUz9fRF5KN0EySG03WTIwL0A3ZXBaV05GWGs7aE5tI2M/SUphOD0vZVJEODRKZyhtSDRxOjFvZ0RCWTc+aCYpLDY6J1I1XilRLi11I1wzb2w5MjFlSFAhaFFVNlZLS2ElSzZmKEAnUE47LGklSyJsXk8/VFNBNmYoQCdQTjZUPSVEK0hpcVJqMVBLS11xQFNBVkpPXTdEPE5IYjI0O0RdX3JOJ0BcMUQsYm1zJT9MPGAzSFxeMjhCUV9COGFfNmpNcE5nPzxcY01MYjwjdE8hMTdCS1dWO0JrPUJHXj9wVj0haEMxN0JLV05TWlkqQF4oOEViYSJBbmhPKCQvbm06TD1fb2k1PEI6IV9mSDAoIzdSTyU+amhKZGBOIThELjViaWg1RG1IcmFvI0dGYFtoVm50XEJkIS4xLC02LHRIIjJeWWFhOF8jQC4tcmg/SDouWDdQXkRYMD45QGJWMUlGYlRdI0IxMTdCSUFcMlBDZSFUKiJRcHNUX28pdTQwTFlMM0M9XStBOFVQTTFgPiNNTEVMPiRZLidKb2InKyguXkMqOkkzMTw4aychRlJRckhYVCcuO29Ncl9FYmF1dDZOWWYmXFNVOysoXVFKMVBdRGROPEQ+aSJRVjFlRCIlRGFbNSNcXi85IUQzO0puTiRjWilqLEYxVStTWFBxOTkjKW5QMGtQIzYraT0pJUhLXStRK15KbzdQXkRYMDdsLSdNdWhldWVNPS1saEZMLCJqPVUqcVZET0QzXU48U01hVyY/OFAuXDNaODxzSSNUPTwiQk5aXSo1VDhkTkldUzU0YFFOaEsmOldmRGwrOnFQRi9TTDxbLS9MPT5Sb0F1P1x0cVwsW1FbTDcsXkshcDsoKW43NStibkNBKiZcIVJOdWdXMmVvMT9naDJ0MkRRZ10tNz9jZldvTD9BSk9TZUJFVGhVaDNWSikuKkMjMTZzIydjYVwubyUsVWBZOy4xMm9jaltkUW02LEhVW1IzaE8oJC9uZzhTYDdpS0hzTltYWUliOFhBOjhgIi0hNVkyJ2djVSRbSUlzR09dLUhSNGklRWhbLkAsPz87N3MybGw7YCUpJitFJipuIUxVPkJmNV9qWGEsNjlkaEMuUSklJSg8PUo5ZWJJPy46JDk5W1AsMmg3WzZlOlk8PT5cYGA3PjJsOjhPXVk8NyxPIVNXIWhWOkpAYTtcJjc4Uj1vKi8uRWtAPzNdaSszb2w4TFJPIyknMmNgRVwyRDVBXDpFQiNHJ01YYkJgPl1hYCNiLjA5XTVfVFZgWTsuMXBXc2w2Y2NgUDxXT1QhQS1aO10rLF5FMXVZcTZGR11QUUIiNmUocCxkM08iSF1sPjUqakxnLk5xYmJLVDtgJSkmNGA7PDQiJCYiXmY2RXRaYFk7LjFHSmJBVGBXND1YYk0+LWtIL2ZXNlAxU00vXCojKCNhcj8rTFAuXE5jQlRROyNIL2YkJVAxUykjNG49TC1HVD9RY0dvYjlYSCtnbDwtRWpxLzkmQTJmUE42bGFJNyRHKmY/SkBuUk8lPzdEWVtEN25FWmZvOi1iJChyUDEhLDhDXTs3YEI8PVY4YjBVVVFCLmQqWG9iNlk5SmwsZCslIk07PEJbY29RKWY8MTw7MEdkbjdwSyklPk5Ic1YkWnQxOD1uIz1cWCNIUzNvcSojXS5BJE8uSVJuPCxdQU1yYjRDTDs9Uz9CbipkUi1kUC5XKmhXNkhpcTksWjotLUVlIlVQLipndEttQ1hbWEsoNFttLjgtVU5QXCYkSCZpNkFCXjFbPFU5IiF0XUE9Yy0vcmkhUk5SMC4+a2hjJmlPQlhuR1s9KkswXVJiJT9tSShXMVFbLGEqZiYiMmYpSi1FS0tcWi5fT3VNLyg3aUZDNWBAXiciTmdbUT0+PldhPWE9RC1PW3JDIVwlRUNmITdXX3NWYklMVXQtWj03W29fPW06J2MyTy1VKDJJZFYyV2k5UD8yIUdEUik9YU5Vc0ZxPW51PFpnUmFuNiVYSSo9Ti8qKkA9NXBbT1ZQdXI+ZldNKDY4cyRScltsbFo/KlYuM1ZYaEtiMlI0RTozRXRkRHBhcjs7LUVAdCgvLSNTJ0lab1s5LWVfMyhzWygtZ1k0Wj89XG8jPVJFKnNDTSxNOytVQFZbZSFpPzcvNm4zRVAycUUkTmpVRF0lZkVxOGRWJ0RMOE91M29nYENTW1RWZVkvRzInb2k2ZFtFUywsPF9zdW5eaCJGdUNGaVlMTElDP1ddTVJhQS80bm5ZNyM5UzIvcHFEWyNBWmlzZ2NaTCtBR3BCSyQjXm1JaWd0K1MvRGc+aWZYKGdhZFA/MiFVbVwpXSZOUmBKKVQ1U2dYRUxGQWxkazVSS1puX0UpYD4oPWZdL1Q/UGBhSnR1YzwiN2pLPURrYTA1anRoRnNyP2U1KVVxb1YsbGJkaEZOX3RAQHRMUmYydFpeSl9WMilkTz1JZ1xEbDVjSU49ZmhPWD8oKTUpVXJaO0FoK2tYWitbZSZUa2JITUFzTEFXMiYsZS0tUC1cL001OEU0N1swZCteLyc4VjQ3JWhlLVtjWnFndUw3Qm9iXU5EYUFIOTZjQmQhSlFtQTc1IipcKWVPbms5NF1nWE9rRV1KSWY+bjdAS1tkXXU5JjAsRktNMXFuMS5nP3JGIVleTjAlPG4kOXB1WGJCQHUnXi0jUyZeSmldWHRRM1ZkSGdPPzxEQWArY0YuVnAhaT8hKjkjJyI6JDVuOiZAPFNWSCxhP1pGJG9pYDwkJywtVSwoTXNZbzInZlVxUVUoNnExRyVuMU9ZSU5RckVWJihQcVc5WydeViVuUE1WRilaWDpFOmBwNzNIIz1eNXM5RUFRLyhRJDZyWytGUCMsZ2gsPXVGaCRMPGgndTBsYD4saigyYUpKSUdySVg8ZW45IUFEOHFROWEnbWk8bS9jb2A+XUg2UTZlL0g0cForbVFaZDdXZ2dQZClMTmtOKVxZP3RdNy8/Wk0tXDNZJSoydEVSLyJNKWs8TVZGKC9Ub1JbOS9wZFRlWmFmIVFqMTs6JC5CYU8rXlgobnNnUGtJISVTKEVDNSlVcS81SGFHc3JGcmUtcUNKZVpjKyNCTWZ0bjJFV0goWShgPixqImZCWDE1cEBpSnJqMk85QC5ySTAyaVAjNislP2VgLUkyNW8+QiYmUlhyZi5wRk5JMU9SWS4yYGRnWGdobyVAK3JgSTI1bz5CJigpQ3JsUFstN1k8bV8uckkwMkwsc2QnJztYJEtjZjBpOk8xVE4uSXJdVitkQUc3TE1WRikqMm8lQDI5Y0JUIS8/Wk0tXDQuIVZlYnIuakhoOkhHRUxVciIyVFY0U15IUlErRERTRmEkZCRoMWZrNTxERDhvIy43YjloXi5ySS1xTlxQa1M9XjVzOUVMM0trVjU6I2JwJkZdYk0jUkpsM1NKSH4+ZW5kc3RyZWFtCmVuZG9iago3IDAgb2JqCjw8Ci9CaXRzUGVyQ29tcG9uZW50IDggL0NvbG9yU3BhY2UgL0RldmljZVJHQiAvRmlsdGVyIFsgL0FTQ0lJODVEZWNvZGUgL0ZsYXRlRGVjb2RlIF0gL0hlaWdodCAxMjAgL0xlbmd0aCAxMTI3IC9TdWJ0eXBlIC9JbWFnZSAKICAvVHlwZSAvWE9iamVjdCAvV2lkdGggMTIwCj4+CnN0cmVhbQpHYiIwUzk5LE4tJi1VQFxFIXAkZ3BWMjVzMGFrMXRuNyYxL2xDZkBjJmMmSVdZbGw5QUpWaz88RT8nSVdzI003Qj9BUzlPSD9qJUZDcWg3OmhvRkArSiVYZ2xMUk9Cay5uPTJNJXNITUo7bFFaVWdRNl4xLEZvb0BIMUJEVVM6dUdyIkIsaFBRS1ojJixIMyVOJGYwKz1ARlNlV2peTi89MSI4Ikw8RTs+KiIvbEdhQ1IkTW5nIW5pSyU2Z0QpV1JTJkBEKSsmXDRSMForQXM8KnMmcDcsY08yYlpeSz1baGFkbTktKVZmKFxhKEQsXzxXSSRXbUFzX1peVz5kam1WSDJlZjZnSGhPP2BpOExnVlRBYDxON1o7STIiLm1QPFNzIVguMiYpNDJbMypjSFwyMVNKZktpQjI+QTBjNlFxdVphajE0Qi0rQTlmaUc7TDFETGVlQ2FgSDJSPm0vR2VsRkJhKi5TSD5RNSZiMz9scSxnRFdyXTBPbD1UTFcuPzkoazhEY08mPF8qWUM6RkpvXE0jZ20sMkpZRDw1RDJrbXJLcj1fOU9kYmwiKEBZO1hLQFMpUHJsVlFNKEQ7XSo8MWYjQHUlXFR1Mi9wQ2wrPScxMy0xaTwwRl5UTEgxLGUkV0A2ayM+aVY0NU1LPkhGN1BGPW84XCNBOyttIVBGLCFVJE9WYCwqaTFRMUhZKCFpYGB1LjJxXVlpYVM6MjlVNGdZIzkmXG5YPV1XM3RmLEIqNF5gclNQbihDPjEpQVNbSHJPalIlbyZJTjNNbXFsKG1aREooPylFN2pSRVRwPzUkU14jWmFAQ05RUEgsJVtQSXI9NUg2QyckOkIqZSZRZTk0OyloY2pyMSdzZD4hbTxtcUYjO2Y3cUIsZEU4cjlcO2MxTC4+WUQ5MUZIKE8sUXFYNyEzdFpRRT1GXXJYIXM9XC02JzFEWCteXW9GbE49XGNZZDFDbVc4czF1dXNBNiRjT2s4N19pRmcqWjM0Y1hmdUYzYSplPzo+Jkw7TTJJRDlOUyxgYmwvVGQtXlFFS21NcGFeVGhoaDQoaWpyIW9fNW9NZEU9UEBXdTxrNTM/PitCMjtDM19XJFhDUTM/PiJLMjorQFNWKHNwTj1dTGpjczNdbDIjTkJ0JCdQRDo1O1UuI0hyY25yIVgjVURdNDZPJCUvKlAzU3A8NzspPG4hSS9ENF0/WFdON246Zyw/LkA5UCVpTFs6KkJrTlQvNGxDQC9acSFxaSxDZT5kZGtkNExsbmUxJl9RTV9mPjtQbDdWRTFNWldKbXInamxMcW1MUSo0X2lOaHItYmNKX1xjLldIIitwNkxPMSsxJjcnVzZaMjotUUZZNTksJ1M3PnE+QUhKLDdlYE8uKSJeSCtPPiNYPitLX0VPTjA+XWAqVHVfYUhOLlVEVnIhZWFNWE8lZUZDV09TMGNcVGE8UjdIZS9kXkhiVW5OMmZcJk9HSUdWb3QsMDhmODA8K3NSSzJtXkZ+PmVuZHN0cmVhbQplbmRvYmoKOCAwIG9iago8PAovQ29udGVudHMgMTkgMCBSIC9NZWRpYUJveCBbIDAgMCA2MTIgNzkyIF0gL1BhcmVudCAxNyAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXSAvWE9iamVjdCA8PAovRm9ybVhvYi4yYTg4YWM2NzEyYzljYTcyN2U0YWQ4ZjI1YmNiZGFlMiA3IDAgUiAvRm9ybVhvYi42YmU0MGVlYWFmMGQ4MWQxODc1MGRjMGE3ZjlkYzIxMyA1IDAgUiAvRm9ybVhvYi5lNWMzMTQ3ZDE4Zjk4NjdhNGYxMDhkM2E1NWEyNDhiNCA2IDAgUgo+Pgo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKOSAwIG9iago8PAovQSA8PAovUyAvVVJJIC9UeXBlIC9BY3Rpb24gL1VSSSAoaHR0cHM6Ly9leGFtcGxlLmNvbS9pbnZvaWNlcy9JTlYtMjA0OCkKPj4gL0JvcmRlciBbIDAgMCAwIF0gL1JlY3QgWyA0NSA1NzUgMzAwIDU5MCBdIC9TdWJ0eXBlIC9MaW5rIC9UeXBlIC9Bbm5vdAo+PgplbmRvYmoKMTAgMCBvYmoKPDwKL0MgWyAuODMgLjg5IC45NSBdIC9Db250ZW50cyAoVG90YWwgaGlnaGxpZ2h0ZWQgZm9yIHJldmlldykgL1F1YWRQb2ludHMgWyA0MCA1NzkgNTQwIDU3OSA0MCA1NTUgNTQwIDU1NSBdIC9SZWN0IFsgNDAgNTU1IDU0MCA1NzkgXSAvU3VidHlwZSAvSGlnaGxpZ2h0IC9UeXBlIC9Bbm5vdAo+PgplbmRvYmoKMTEgMCBvYmoKPDwKL0MgWyAwIDAgMCBdIC9Db250ZW50cyAoVmVyaWZ5IHRoZSBoaWdobGlnaHRlZCB0b3RhbCkgL1F1YWRQb2ludHMgWyA1MjAgNTI1IDU0MCA1MjUgNTIwIDU0NSA1NDAgNTQ1IF0gL1JlY3QgWyA1MjAgNTI1IDU0MCA1NDUgXSAvU3VidHlwZSAvVGV4dCAvVHlwZSAvQW5ub3QKPj4KZW5kb2JqCjEyIDAgb2JqCjw8Ci9Bbm5vdHMgWyA5IDAgUiAxMCAwIFIgMTEgMCBSIF0gL0NvbnRlbnRzIDIwIDAgUiAvTWVkaWFCb3ggWyAwIDAgNjEyIDc5MiBdIC9QYXJlbnQgMTcgMCBSIC9SZXNvdXJjZXMgPDwKL0ZvbnQgMSAwIFIgL1Byb2NTZXQgWyAvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJIF0KPj4gL1JvdGF0ZSAwIAogIC9UcmFucyA8PAoKPj4gL1R5cGUgL1BhZ2UKPj4KZW5kb2JqCjEzIDAgb2JqCjw8Ci9Db250ZW50cyAyMSAwIFIgL01lZGlhQm94IFsgMCAwIDYxMiA3OTIgXSAvUGFyZW50IDE3IDAgUiAvUmVzb3VyY2VzIDw8Ci9Gb250IDEgMCBSIC9Qcm9jU2V0IFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdCj4+IC9Sb3RhdGUgMCAvVHJhbnMgPDwKCj4+IAogIC9UeXBlIC9QYWdlCj4+CmVuZG9iagoxNCAwIG9iago8PAovQ29udGVudHMgMjIgMCBSIC9NZWRpYUJveCBbIDAgMCA2MTIgNzkyIF0gL1BhcmVudCAxNyAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXQo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKMTUgMCBvYmoKPDwKL1BhZ2VNb2RlIC9Vc2VOb25lIC9QYWdlcyAxNyAwIFIgL1R5cGUgL0NhdGFsb2cKPj4KZW5kb2JqCjE2IDAgb2JqCjw8Ci9BdXRob3IgKExpdGVMTE0gT0NSIGZpeHR1cmUgZ2VuZXJhdG9yKSAvQ3JlYXRpb25EYXRlIChEOjIwMDAwMTAxMDAwMDAwKzAwJzAwJykgL0NyZWF0b3IgKGFub255bW91cykgL0tleXdvcmRzIChPQ1IsIGludm9pY2UsIHRhYmxlLCBmaWd1cmUsIGFubm90YXRpb24pIC9Nb2REYXRlIChEOjIwMDAwMTAxMDAwMDAwKzAwJzAwJykgL1Byb2R1Y2VyIChSZXBvcnRMYWIgUERGIExpYnJhcnkgLSBcKG9wZW5zb3VyY2VcKSkgCiAgL1N1YmplY3QgKFNlbWFudGljIE9DUiBjb3ZlcmFnZSBmb3IgdGFibGVzLCBmaWd1cmVzLCBhbm5vdGF0aW9ucywgYW5kIG1ldGFkYXRhKSAvVGl0bGUgKFF1YXJ0ZXJseSBPcGVyYXRpb25zIFJlcG9ydCkgL1RyYXBwZWQgL0ZhbHNlCj4+CmVuZG9iagoxNyAwIG9iago8PAovQ291bnQgNSAvS2lkcyBbIDQgMCBSIDggMCBSIDEyIDAgUiAxMyAwIFIgMTQgMCBSIF0gL1R5cGUgL1BhZ2VzCj4+CmVuZG9iagoxOCAwIG9iago8PAovTGVuZ3RoIDIyODAKPj4Kc3RyZWFtCjEgMCAwIDEgMCAwIGNtICBCVCAvRjEgMTIgVGYgMTQuNCBUTCBFVAowIDAgMCByZwpCVCAvRjEgMTEgVGYgMTMuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc3MCBUbSAoUXVhcnRlcmx5IE9wZXJhdGlvbnMgUmVwb3J0KSBUaiBUKiBFVApCVCAvRjIgMTYgVGYgMTkuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc0NSBUbSAoSW52b2ljZSBTdW1tYXJ5IGFuZCBMaW5lIEl0ZW1zKSBUaiBUKiBFVApCVCAvRjEgOSBUZiAxMC44IFRMIEVUCkJUIDEgMCAwIDEgNDUgMzAgVG0gKENvbmZpZGVudGlhbCB8IFBhZ2UgMSBvZiA1KSBUaiBUKiBFVApuIDQ1IDYyNSBtIDQ1IDczMCBsIFMKbiAyNDUgNjI1IG0gMjQ1IDczMCBsIFMKbiA0MDUgNjI1IG0gNDA1IDczMCBsIFMKbiA1NjUgNjI1IG0gNTY1IDczMCBsIFMKbiA0NSA3MzAgbSA1NjUgNzMwIGwgUwpuIDQ1IDY5NSBtIDU2NSA2OTUgbCBTCm4gNDUgNjYwIG0gNTY1IDY2MCBsIFMKbiA0NSA2MjUgbSA1NjUgNjI1IGwgUwpCVCAxIDAgMCAxIDU1IDcwNyBUbSAoSXRlbSkgVGogVCogRVQKQlQgMSAwIDAgMSAyNTUgNzA3IFRtIChRdWFudGl0eSkgVGogVCogRVQKQlQgMSAwIDAgMSA0MTUgNzA3IFRtIChBbW91bnQpIFRqIFQqIEVUCkJUIDEgMCAwIDEgNTUgNjcyIFRtIChEb2N1bWVudCBhbmFseXNpcykgVGogVCogRVQKQlQgMSAwIDAgMSAyNTUgNjcyIFRtICgyKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQxNSA2NzIgVG0gKDEyMC4wMCkgVGogVCogRVQKQlQgMSAwIDAgMSA1NSA2MzcgVG0gKE9DUiB2ZXJpZmljYXRpb24pIFRqIFQqIEVUCkJUIDEgMCAwIDEgMjU1IDYzNyBUbSAoMSkgVGogVCogRVQKQlQgMSAwIDAgMSA0MTUgNjM3IFRtICg4MC4wMCkgVGogVCogRVQKbiA0NSA0OTUgbSA0NSA2MDAgbCBTCm4gMjQ1IDQ5NSBtIDI0NSA2MDAgbCBTCm4gNDA1IDQ5NSBtIDQwNSA2MDAgbCBTCm4gNTY1IDQ5NSBtIDU2NSA2MDAgbCBTCm4gNDUgNjAwIG0gNTY1IDYwMCBsIFMKbiA0NSA1NjUgbSA1NjUgNTY1IGwgUwpuIDQ1IDUzMCBtIDU2NSA1MzAgbCBTCm4gNDUgNDk1IG0gNTY1IDQ5NSBsIFMKQlQgMSAwIDAgMSA1NSA1NzcgVG0gKEl0ZW0gY29udGludWVkKSBUaiBUKiBFVApCVCAxIDAgMCAxIDI1NSA1NzcgVG0gKFF1YW50aXR5KSBUaiBUKiBFVApCVCAxIDAgMCAxIDQxNSA1NzcgVG0gKEFtb3VudCkgVGogVCogRVQKQlQgMSAwIDAgMSA1NSA1NDIgVG0gKEZpeHR1cmUgdmFsaWRhdGlvbikgVGogVCogRVQKQlQgMSAwIDAgMSAyNTUgNTQyIFRtICgzKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQxNSA1NDIgVG0gKDQ1LjAwKSBUaiBUKiBFVApCVCAxIDAgMCAxIDU1IDUwNyBUbSAoUHJvdmlkZXIgcmV2aWV3KSBUaiBUKiBFVApCVCAxIDAgMCAxIDI1NSA1MDcgVG0gKDEpIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDE1IDUwNyBUbSAoMjUuMDApIFRqIFQqIEVUCkJUIC9GMSAxMCBUZiAxMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDQ3MiBUbSAoU2VjdGlvbiAxLjE6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQ0NCBUbSAoU2VjdGlvbiAxLjI6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQxNiBUbSAoU2VjdGlvbiAxLjM6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM4OCBUbSAoU2VjdGlvbiAxLjQ6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM2MCBUbSAoU2VjdGlvbiAxLjU6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMzMiBUbSAoU2VjdGlvbiAxLjY6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMwNCBUbSAoU2VjdGlvbiAxLjc6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDI3NiBUbSAoU2VjdGlvbiAxLjg6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVAogCmVuZHN0cmVhbQplbmRvYmoKMTkgMCBvYmoKPDwKL0xlbmd0aCAxNzIzCj4+CnN0cmVhbQoxIDAgMCAxIDAgMCBjbSAgQlQgL0YxIDEyIFRmIDE0LjQgVEwgRVQKMCAwIDAgcmcKQlQgL0YxIDExIFRmIDEzLjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NzAgVG0gKFF1YXJ0ZXJseSBPcGVyYXRpb25zIFJlcG9ydCkgVGogVCogRVQKQlQgL0YyIDE2IFRmIDE5LjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NDUgVG0gKFJldmVudWUgQ2hhcnQgYW5kIEZvcm11bGEgUmV2aWV3KSBUaiBUKiBFVApCVCAvRjEgOSBUZiAxMC44IFRMIEVUCkJUIDEgMCAwIDEgNDUgMzAgVG0gKENvbmZpZGVudGlhbCB8IFBhZ2UgMiBvZiA1KSBUaiBUKiBFVAouMiAuNDUwOTggLjg1MDk4IHJnCm4gNzAgNjEwIDY1IDcwIHJlIGYqCm4gMTcwIDYxMCA2NSAxMTUgcmUgZioKbiAyNzAgNjEwIDY1IDkwIHJlIGYqCm4gMzcwIDYxMCA2NSAxMzAgcmUgZioKMCAwIDAgcmcKQlQgMSAwIDAgMSA5MCA1OTAgVG0gKFExKSBUaiBUKiBFVApCVCAxIDAgMCAxIDE5MCA1OTAgVG0gKFEyKSBUaiBUKiBFVApCVCAxIDAgMCAxIDI5MCA1OTAgVG0gKFEzKSBUaiBUKiBFVApCVCAxIDAgMCAxIDM5MCA1OTAgVG0gKFE0KSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDU1MCBUbSAoRm9ybXVsYTogZ3Jvc3MgbWFyZ2luID0gXChyZXZlbnVlIC0gY29zdFwpIC8gcmV2ZW51ZSkgVGogVCogRVQKcQo3MCAwIDAgNzAgNDU1IDY1NSBjbQovRm9ybVhvYi42YmU0MGVlYWFmMGQ4MWQxODc1MGRjMGE3ZjlkYzIxMyBEbwpRCnEKNzAgMCAwIDYyIDQ1NSA1NjUgY20KL0Zvcm1Yb2IuZTVjMzE0N2QxOGY5ODY3YTRmMTA4ZDNhNTVhMjQ4YjQgRG8KUQpxCjQ1IDAgMCA0NSA0NTUgNTAwIGNtCi9Gb3JtWG9iLjJhODhhYzY3MTJjOWNhNzI3ZTRhZDhmMjViY2JkYWUyIERvClEKQlQgL0YxIDEwIFRmIDEyIFRMIEVUCkJUIDEgMCAwIDEgNDUgNDcyIFRtIChTZWN0aW9uIDIuMTogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgNDQ0IFRtIChTZWN0aW9uIDIuMjogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgNDE2IFRtIChTZWN0aW9uIDIuMzogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzg4IFRtIChTZWN0aW9uIDIuNDogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzYwIFRtIChTZWN0aW9uIDIuNTogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzMyIFRtIChTZWN0aW9uIDIuNjogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzA0IFRtIChTZWN0aW9uIDIuNzogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMjc2IFRtIChTZWN0aW9uIDIuODogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCiAKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago8PAovTGVuZ3RoIDI0NjYKPj4Kc3RyZWFtCjEgMCAwIDEgMCAwIGNtICBCVCAvRjEgMTIgVGYgMTQuNCBUTCBFVAowIDAgMCByZwpCVCAvRjEgMTEgVGYgMTMuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc3MCBUbSAoUXVhcnRlcmx5IE9wZXJhdGlvbnMgUmVwb3J0KSBUaiBUKiBFVApCVCAvRjIgMTYgVGYgMTkuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc0NSBUbSAoS2V5IFZhbHVlcywgTGluaywgSGlnaGxpZ2h0LCBhbmQgQ29tbWVudCkgVGogVCogRVQKQlQgL0YxIDkgVGYgMTAuOCBUTCBFVApCVCAxIDAgMCAxIDQ1IDMwIFRtIChDb25maWRlbnRpYWwgfCBQYWdlIDMgb2YgNSkgVGogVCogRVQKQlQgL0YxIDEyIFRmIDE0LjQgVEwgRVQKQlQgMSAwIDAgMSA0NSA3MDAgVG0gKEludm9pY2UgTnVtYmVyOiBJTlYtMjA0OCkgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA2NzUgVG0gKFB1cmNoYXNlIE9yZGVyOiBQTy00MDk2KSBUaiBUKiBFVAouOTQ5MDIgLjkwMTk2MSAuMzUyOTQxIHJnCm4gNDAgNTU1IDUwMCAyNCByZSBmKgowIDAgMCByZwpCVCAxIDAgMCAxIDQ1IDU2MCBUbSAoSGlnaGxpZ2h0ZWQgdG90YWwgcmVxdWlyaW5nIHJldmlldykgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA1MzAgVG0gKFJldmlld2VyIGNvbW1lbnQ6IHZlcmlmeSB0aGUgaGlnaGxpZ2h0ZWQgdG90YWwgYmVmb3JlIGFwcHJvdmFsKSBUaiBUKiBFVAoxIDAgMCByZwpCVCAxIDAgMCAxIDQ1IDQ5NSBUbSAoUmV2aXNlZCB0b3RhbDogMjQ1LjAwKSBUaiBUKiBFVApuIDQ1IDUwMSBtIDE1MCA1MDEgbCBTCjAgMCAwIHJnCkJUIDEgMCAwIDEgNDUgNTc1IFRtIChodHRwczovL2V4YW1wbGUuY29tL2ludm9pY2VzL0lOVi0yMDQ4KSBUaiBUKiBFVApxCjEgMCAwIDEgOTAgMTMwIGNtCm4gMTggMCAyLjQgNzAgcmUgZioKbiAyMS42IDAgMS4yIDcwIHJlIGYqCm4gMjUuMiAwIDMuNiA3MCByZSBmKgpuIDMxLjIgMCAzLjYgNzAgcmUgZioKbiAzOC40IDAgMi40IDcwIHJlIGYqCm4gNDIgMCAxLjIgNzAgcmUgZioKbiA0NC40IDAgMi40IDcwIHJlIGYqCm4gNDkuMiAwIDIuNCA3MCByZSBmKgpuIDUyLjggMCAyLjQgNzAgcmUgZioKbiA1Ny42IDAgMy42IDcwIHJlIGYqCm4gNjIuNCAwIDIuNCA3MCByZSBmKgpuIDY2IDAgMy42IDcwIHJlIGYqCm4gNzAuOCAwIDIuNCA3MCByZSBmKgpuIDc2LjggMCAxLjIgNzAgcmUgZioKbiA4MS42IDAgMS4yIDcwIHJlIGYqCm4gODQgMCAzLjYgNzAgcmUgZioKbiA4OC44IDAgMi40IDcwIHJlIGYqCm4gOTIuNCAwIDMuNiA3MCByZSBmKgpuIDk3LjIgMCAxLjIgNzAgcmUgZioKbiA5OS42IDAgMy42IDcwIHJlIGYqCm4gMTA0LjQgMCAyLjQgNzAgcmUgZioKbiAxMTAuNCAwIDEuMiA3MCByZSBmKgpuIDExMi44IDAgNC44IDcwIHJlIGYqCm4gMTE4LjggMCAzLjYgNzAgcmUgZioKbiAxMjMuNiAwIDMuNiA3MCByZSBmKgpuIDEyOC40IDAgMi40IDcwIHJlIGYqCm4gMTMyIDAgMy42IDcwIHJlIGYqCm4gMTM2LjggMCAyLjQgNzAgcmUgZioKbiAxNDEuNiAwIDEuMiA3MCByZSBmKgpuIDE0NS4yIDAgMy42IDcwIHJlIGYqCm4gMTUwIDAgMi40IDcwIHJlIGYqCm4gMTU2IDAgMy42IDcwIHJlIGYqCm4gMTYwLjggMCAxLjIgNzAgcmUgZioKbiAxNjMuMiAwIDIuNCA3MCByZSBmKgpRCkJUIC9GMSAxMCBUZiAxMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDQ3MiBUbSAoU2VjdGlvbiAzLjE6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQ0NCBUbSAoU2VjdGlvbiAzLjI6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQxNiBUbSAoU2VjdGlvbiAzLjM6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM4OCBUbSAoU2VjdGlvbiAzLjQ6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM2MCBUbSAoU2VjdGlvbiAzLjU6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMzMiBUbSAoU2VjdGlvbiAzLjY6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMwNCBUbSAoU2VjdGlvbiAzLjc6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDI3NiBUbSAoU2VjdGlvbiAzLjg6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVAogCmVuZHN0cmVhbQplbmRvYmoKMjEgMCBvYmoKPDwKL0xlbmd0aCAxNDk0Cj4+CnN0cmVhbQoxIDAgMCAxIDAgMCBjbSAgQlQgL0YxIDEyIFRmIDE0LjQgVEwgRVQKMCAwIDAgcmcKQlQgL0YxIDExIFRmIDEzLjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NzAgVG0gKFF1YXJ0ZXJseSBPcGVyYXRpb25zIFJlcG9ydCkgVGogVCogRVQKQlQgL0YyIDE2IFRmIDE5LjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NDUgVG0gKEFwcHJvdmFsIFNpZ25hdHVyZSBhbmQgV2F0ZXJtYXJrKSBUaiBUKiBFVApCVCAvRjEgOSBUZiAxMC44IFRMIEVUCkJUIDEgMCAwIDEgNDUgMzAgVG0gKENvbmZpZGVudGlhbCB8IFBhZ2UgNCBvZiA1KSBUaiBUKiBFVApxCi44Mjc0NTEgLjgyNzQ1MSAuODI3NDUxIHJnCkJUIC9GMiA1NCBUZiA2NC44IFRMIEVUCi45MDYzMDggLjQyMjYxOCAtMC40MjI2MTggLjkwNjMwOCAxMTAgMzkwIGNtCkJUIDEgMCAwIDEgMCAwIFRtIChEUkFGVCkgVGogVCogRVQKUQowIDAgMCByZwpCVCAvRjEgMTIgVGYgMTQuNCBUTCBFVApCVCAxIDAgMCAxIDQ1IDYzNSBUbSAoQXBwcm92ZWQgYnk6IEpvcmRhbiBMZWUpIFRqIFQqIEVUCm4gNDUgNjEwIG0gMzEwIDYxMCBsIFMKbiA1NSA1OTUgbSA3NSA2MjUgMTEyIDYwMiAxNTUgNjAwIGMgUwpCVCAxIDAgMCAxIDQ1IDU4MCBUbSAoU2lnbmF0dXJlKSBUaiBUKiBFVApCVCAvRjEgMTAgVGYgMTIgVEwgRVQKQlQgMSAwIDAgMSA0NSA0NzIgVG0gKFNlY3Rpb24gNC4xOiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA0NDQgVG0gKFNlY3Rpb24gNC4yOiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA0MTYgVG0gKFNlY3Rpb24gNC4zOiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzODggVG0gKFNlY3Rpb24gNC40OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzNjAgVG0gKFNlY3Rpb24gNC41OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzMzIgVG0gKFNlY3Rpb24gNC42OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzMDQgVG0gKFNlY3Rpb24gNC43OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAyNzYgVG0gKFNlY3Rpb24gNC44OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKIAplbmRzdHJlYW0KZW5kb2JqCjIyIDAgb2JqCjw8Ci9MZW5ndGggMTMyNwo+PgpzdHJlYW0KMSAwIDAgMSAwIDAgY20gIEJUIC9GMSAxMiBUZiAxNC40IFRMIEVUCjAgMCAwIHJnCkJUIC9GMSAxMSBUZiAxMy4yIFRMIEVUCkJUIDEgMCAwIDEgNDUgNzcwIFRtIChRdWFydGVybHkgT3BlcmF0aW9ucyBSZXBvcnQpIFRqIFQqIEVUCkJUIC9GMiAxNiBUZiAxOS4yIFRMIEVUCkJUIDEgMCAwIDEgNDUgNzQ1IFRtIChBcHBlbmRpeCB3aXRoIFNlY3Rpb24gQm91bmRhcmllcykgVGogVCogRVQKQlQgL0YxIDkgVGYgMTAuOCBUTCBFVApCVCAxIDAgMCAxIDQ1IDMwIFRtIChDb25maWRlbnRpYWwgfCBQYWdlIDUgb2YgNSkgVGogVCogRVQKQlQgL0YyIDE0IFRmIDE2LjggVEwgRVQKQlQgMSAwIDAgMSA0NSA3MDAgVG0gKDEuIFNjb3BlKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDY1MCBUbSAoMi4gRmluZGluZ3MpIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgNjAwIFRtICgzLiBSZWNvbW1lbmRhdGlvbnMpIFRqIFQqIEVUCkJUIC9GMSAxMCBUZiAxMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDQ3MiBUbSAoU2VjdGlvbiA1LjE6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQ0NCBUbSAoU2VjdGlvbiA1LjI6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQxNiBUbSAoU2VjdGlvbiA1LjM6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM4OCBUbSAoU2VjdGlvbiA1LjQ6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM2MCBUbSAoU2VjdGlvbiA1LjU6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMzMiBUbSAoU2VjdGlvbiA1LjY6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMwNCBUbSAoU2VjdGlvbiA1Ljc6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDI3NiBUbSAoU2VjdGlvbiA1Ljg6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVAogCmVuZHN0cmVhbQplbmRvYmoKeHJlZgowIDIzCjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDA2MSAwMDAwMCBuIAowMDAwMDAwMTAyIDAwMDAwIG4gCjAwMDAwMDAyMDkgMDAwMDAgbiAKMDAwMDAwMDMyMSAwMDAwMCBuIAowMDAwMDAwNTE2IDAwMDAwIG4gCjAwMDAwMDYzMjIgMDAwMDAgbiAKMDAwMDAxMjgyNCAwMDAwMCBuIAowMDAwMDE0MTQyIDAwMDAwIG4gCjAwMDAwMTQ0OTYgMDAwMDAgbiAKMDAwMDAxNDY2NCAwMDAwMCBuIAowMDAwMDE0ODUwIDAwMDAwIG4gCjAwMDAwMTUwMjggMDAwMDAgbiAKMDAwMDAxNTI1NiAwMDAwMCBuIAowMDAwMDE1NDUyIDAwMDAwIG4gCjAwMDAwMTU2NDggMDAwMDAgbiAKMDAwMDAxNTcxOCAwMDAwMCBuIAowMDAwMDE2MTE1IDAwMDAwIG4gCjAwMDAwMTYyMDIgMDAwMDAgbiAKMDAwMDAxODUzNCAwMDAwMCBuIAowMDAwMDIwMzA5IDAwMDAwIG4gCjAwMDAwMjI4MjcgMDAwMDAgbiAKMDAwMDAyNDM3MyAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9JRCAKWzwyZjUwODkzYTFlYWZmMTExOWMwNDcwZmM0YzU3ZTI0Nz48MmY1MDg5M2ExZWFmZjExMTljMDQ3MGZjNGM1N2UyNDc+XQolIFJlcG9ydExhYiBnZW5lcmF0ZWQgUERGIGRvY3VtZW50IC0tIGRpZ2VzdCAob3BlbnNvdXJjZSkKCi9JbmZvIDE2IDAgUgovUm9vdCAxNSAwIFIKL1NpemUgMjMKPj4Kc3RhcnR4cmVmCjI1NzUyCiUlRU9GCg== + type: document_url + model: mistral/invalid-ocr-model-for-parity + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/1f38e1eab857c22107df833aa63b119bced6537f45cf08b27cbec08bb8f45951.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/1f38e1eab857c22107df833aa63b119bced6537f45cf08b27cbec08bb8f45951.yaml new file mode 100644 index 00000000000..8200c885e60 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/1f38e1eab857c22107df833aa63b119bced6537f45cf08b27cbec08bb8f45951.yaml @@ -0,0 +1,69 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"pages":[0]}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d35d1fbbebe5-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:14 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-5685-747f-b76d-dab242ea7512 + x-envoy-upstream-service-time: + - '179' + x-kong-proxy-latency: + - '12' + x-kong-request-id: + - 01a05e89-5685-747f-b76d-dab242ea7512 + x-kong-upstream-latency: + - '180' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '58' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:14.385374+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + model: mistral/mistral-ocr-latest + pages: + - 0 + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/216aacc1aa47a6060445f2ea49a2e0a8f4a8bde179faaaa28f39b049e7886f07.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/216aacc1aa47a6060445f2ea49a2e0a8f4a8bde179faaaa28f39b049e7886f07.json deleted file mode 100644 index 90c2a7e4793..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/216aacc1aa47a6060445f2ea49a2e0a8f4a8bde179faaaa28f39b049e7886f07.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "model": "mistral/mistral-ocr-latest", - "table_format": "markdown" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:21 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-7015-7a8d-a18c-37b9ceacbe77" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-7015-7a8d-a18c-37b9ceacbe77" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "49" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "337" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "338" - }, - { - "name": "x-kong-proxy-latency", - "value": "21" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d385ffbda0f2-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:21.430472Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/2c893c555fe38cdfa0f03b43b5e678b8acd5c2dc460cd06f5302a0bf05f3089c.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/2c893c555fe38cdfa0f03b43b5e678b8acd5c2dc460cd06f5302a0bf05f3089c.json deleted file mode 100644 index 825569a1936..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/2c893c555fe38cdfa0f03b43b5e678b8acd5c2dc460cd06f5302a0bf05f3089c.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "image_limit": 1, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:15 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-5a87-7148-8ae4-4e14967bebf3" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-5a87-7148-8ae4-4e14967bebf3" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "56" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "226" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "227" - }, - { - "name": "x-kong-proxy-latency", - "value": "19" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d3637dc2c090-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:15.394028Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/3832acde595e59e0b3f663c560c8bf3940c6eddbe486e66ad40e18974464eda7.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/3832acde595e59e0b3f663c560c8bf3940c6eddbe486e66ad40e18974464eda7.json deleted file mode 100644 index 3955a0e14c5..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/3832acde595e59e0b3f663c560c8bf3940c6eddbe486e66ad40e18974464eda7.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKJZOMi54gUmVwb3J0TGFiIEdlbmVyYXRlZCBQREYgZG9jdW1lbnQgKG9wZW5zb3VyY2UpCjEgMCBvYmoKPDwKL0YxIDIgMCBSIC9GMiAzIDAgUgo+PgplbmRvYmoKMiAwIG9iago8PAovQmFzZUZvbnQgL0hlbHZldGljYSAvRW5jb2RpbmcgL1dpbkFuc2lFbmNvZGluZyAvTmFtZSAvRjEgL1N1YnR5cGUgL1R5cGUxIC9UeXBlIC9Gb250Cj4+CmVuZG9iagozIDAgb2JqCjw8Ci9CYXNlRm9udCAvSGVsdmV0aWNhLUJvbGQgL0VuY29kaW5nIC9XaW5BbnNpRW5jb2RpbmcgL05hbWUgL0YyIC9TdWJ0eXBlIC9UeXBlMSAvVHlwZSAvRm9udAo+PgplbmRvYmoKNCAwIG9iago8PAovQ29udGVudHMgMTggMCBSIC9NZWRpYUJveCBbIDAgMCA2MTIgNzkyIF0gL1BhcmVudCAxNyAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXQo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKNSAwIG9iago8PAovQml0c1BlckNvbXBvbmVudCA4IC9Db2xvclNwYWNlIC9EZXZpY2VSR0IgL0ZpbHRlciBbIC9BU0NJSTg1RGVjb2RlIC9GbGF0ZURlY29kZSBdIC9IZWlnaHQgMzIwIC9MZW5ndGggNTYxNSAvU3VidHlwZSAvSW1hZ2UgCiAgL1R5cGUgL1hPYmplY3QgL1dpZHRoIDMyMAo+PgpzdHJlYW0KR2IiL2w2I3BIcSVSZE1bNDNaKzdadVpbLUFpNUtMMzIvY0tJbkxtaixYPmxxXEVxWFItTGs6PWw+I1lObGclcFhybTBwMGRhSFMvXHBpPC5cPyFyU1Y1PGpoNFMhcj5xc1hSVXAtN18zVjItWWksZChNMkNrWk5yLz9aTUFIV0FwJUthNz8nWS4zRzs6WW4zZlZ0TVtFXERkPkY3b2FlZjgrbkw6XERhWFhyMjpMN25AWUAzJ2ZWWktaMTh0aDtXMiVJTV5yWylmQk08RyhULVx0VCNERidTRWktKCM4YTApUiVEODMyazdNQGksOjU1aT5GZTouckk9amVcNE9rW19gLG0oMEI6MW1ZNXE4RURtVWRdazs/KCVIbS1zcFAsMDhuQzlbWy5yST1qZ1U2ZTIsX2JeUz1eNXNhXEwzXGtqQ1RmZkMhWWRyKXBVVj1iSk9janByOG9FJ2ZWWTBETy1KKlg3MTZwTV5yWykyb0kuMDJjL0pGSDU5VDtFLExuNzlBRVk1J2c3SSpERSdUUVhqSSpvI0pUSHNtb2BuOF9tcFlHVS5ddF1sQ2toOGNmMGckYzsiLWBHa0ZpUSppIjUyaWVlXSMlQD5baXJCMzg6bzpFbzkyazY/XFk5IUNiRWhwdURNXnJbKTJiQD07bzY6KD5EMG0lImdpLi8mXVFXWjFoWFBwYy8/Wk1BZ2YvUE5fVl4+PzJYRlJPRVBvPz9ubGgtaVglMlIuWmFmIkxFcmtpOFNBLl0lRFVsKSdpZURNL25saSEscmFZXWU9XjVzYVxNLzpcZzBhJSVTK0o4N1xEXlxnXVUlS1otVU5UW2A+KD4lJF5UQ2JyJih0I0QiZklKP25QYmw5Q3BiXyRDQ0I5WS4zSEcmcFooWD9cOlFOMzVcWT1RKzI/TTM5U3Q/PjpJY1M9NWo6KW09WVQ0cC8uMmxZL0NNMW8lRiJvL0ViJlY+JDteb1dpO2omWCM1PjxjOC9tPlhjXVs9LGExPkRpOkRnZk8nRFYtcWA/UXI9O1pQXT5fcmpIW1pdNWxyJTBJLm42Q2VYaS0oPTlNWiFFJnJRQWdFayI4a1lmQ1Iyb2M+LlMlUTcrazlZL0NLX1NLQ3NibzMvLS5HX1A+KlErLWdzO2RNZT80bHU9Tj9aPzxsNG5IZV5ZSHN0M3BGR1o+WSZjQT9yVWd1V209KiJwYms5O1hyKj8+J2FvLilZUihHMjdub3BrOWdBO1YvMFIlWExqbVJBOC0yL3FYQC4pIztiMjopPE9uVUJvQC4pbjxha3IwdSFWXCw0QC4qYTxha3NsaG9Cbk9wWUlNIXFQQmlBLGlLXms6PWtyL3BfYiQnLDhdPFVQPWtxPFhvLDNiLFdWKVNPLzhlWzBhRTVPMjVmbl5DTXFhR0JxY3FmI3JeS245Yj9UbDNpIiNPbWNMMTNdViFvbnM4bURAP2BvZWdwUSt1TGlwUmBzVSFTZ2UmJGhOKGhyWjdCX0knMUJrRTVVY2hiXEoka0haQjpcaz1TdFoyYWNIPV1RVTNmZ0RBN1xZL0NLX1BOND0+Q1kvRXBHOSZqMDhtRD9UOllydCRHLWVxJlFkVGlVYCEoKllqWG5cbFFpIkNAMjtSQ2U+UT9dZWhTUXBLXlY8RFhlN3UvKSJgT001KD9XIjpycWBndGNXbDs3aSp0YiFiXEwvVEZeQSs0XElvXm9LdW1QZGYqOyc6XFp1XWQscWFfK1BkYD9NYzE5SnRJU1ddNjRCJDc5bmVVQXFFVzAuYm10cClzVy5eKHFba1AhW29baXFmOkZpLC8tLz5NSVFiVkxrUSw3PllRI0krTD5sSkAlNHBrNTY8NVBjTmxaLktRMCdDOFg+JCFCNW8mMDMyRWpdUUtsMmZCcT8wKjwsPyskXycmJSY/Y0JTUjJDIz4jbEwjTER1UEY5cloqL0taP1dqO3BQM1lOUVRJU20rQlhnNmJTaWNVUidjUV8mbTsyVT1MVHItZDpfbmRhXiZoYV1McD9OOW9rUihTV21ITjNwTzlwMF9ia048Xy5hKUxfQ28sQk1YaEJkWFIncVhKYCQhNUhmbidORCs9OGUrVkdgNS09Z3NtcGU0bXJURCxrJEsmK1VaUWJXLl9kJj9XWkZINl4tU1pvW2k3KUljL3RrU3BRVTc0Ri10dGY3czlScmk8VFQpai5sdEgvSkM0Jz5HWFA/RVg7XGo9YTxjcFxybVZuIypkXl02IkdPUVJENWxJcjNkMl9xckk/bTlma2BqUnI6YEs+KnVWM3BvSy9uczpgLWRwSiM2cGM9SS5cOWpkaT9fNG9aSWs9WFldMCVTJURSVjNJSDFFVGBDTjBcZ2pBPzZYVWhCTUhQQllQYSRXP2E4TyVRcDslRWkrTV1HcGlSS1lnZjg8NUxmZTxyVltOaD1LNllhL20kRy0vPVRTRDwqP0doSkljMEN0UDInPDVLKixwW05CUGsiUzouaj88JWIlUyFWLTdqWnE9R29wQ25AR1lmVzhfdWdhRDBQTCdIO3FgalBrWF51XSZhKmc4Yi9KTUNLb2lOZSJbT25YTHNUSWZJQU5ZOXAuSFI/WCJWaEwpdVYhX3JaO29icyREXUJUZyMqcm4/P1tHNFZZY1JqJTdcYjtSSiM3JEhbQG9bZCtKWkJbcCtnYSUuZT9iJk8xMFVhOCpYTTxtPWI8P3U0RTpgLj1JLj9kP0dWaSJLRS4/K2tTNHUqcWlNT2NwcSJkKjlTLEE5QG9vXkNlWyJDanBnaF82WGJOSi1DakRXQ2BHXWtSXGRrYUpNYTYlWW4yWWU8ZCxtdGNKUjxzXD1jSTksQWhwQ2dQSmRsU2dTcmwxVz9fNHBgcmBWKzM5NnBlJCtGZVwtIXJUSCQkS0hLUUI6JEE0bGdfT2UnRUdMZlEpI2JrPHBQK0tZKyYvRVdrQEFNZVR0TkJsZk0nUzBeN0xyckpUYF5pPSM1U3FtdT1ES0Q7JFIxSHRaKTkhJT1SJUBTT3FoSHFjUkRhO1hWbmllK0ZCOl9pczY5WWpdKVkzNmRiTjQuNyI0Jyohci5XQUksOFk8WGU9SmxPX1ZEP21qaUxgakRpKT5WNGFaN1ReRyVLOWhIR0YhJDdHTjVQWlJrJGNtM25bckFFcHRAbitlOW8/MUpwUk51ZVZJZ3I+cUdnRlshYj9scmwsXT0/RyVBZSNbY2ksYEQ/U0lvb0RdYUg8VTJYTWQ5O2UmaT9vMUkzPHJROjpfR05KIlNsPlc/ZDNPIkxxLm4oWkxcLzYhNk1WIVlQTjZURVlAVDIyaFhmVVdqPV8/RVAuLkAoUURYLltjZUdAXF5ML2xpaFI8RGVObCEvLFQ6QUZOSyRiaWg0OFdlIiQ/LFpkR1M5Zls3WyluTW1dVCYwXVt1Y04pPDxGZjlwMyEjXkQ8aj03YUU2InEkVFpVakxyRTtNYzlCZG1gQ2QwNEYobDhmLixWXkNaImxxXCw+QDBIXWMndEkxP15OKE9YIWdRUkQ2LXJZaydDaSlrOUBwRkNgPW5tOkxfam85UFdFLV06by50O2o4aFdWLlNyXVIxZ0gsOTUqSXNMVGtsRUI9STRsZGw2Xz1vSTBIMUtoWFk9OEpANV5EcFBtb1RNWmpMczhTTXUzTm47cm4yP1lQZE0oSGI3JC5uVHVzcWpUWFBGcjhsJF5eZ0IyIzRdREUsXz1vSTBIMUs4TWY2MldTLFh1LDByUThLPV1PVWxJcCMhWHFQOEFWXW5zOmBtLF8nW21IT3U7MEsndWU/byZMaFJZUEFrOmI2dSRrcTkrdEdUImpEYShiQD84SWNXNFloTkBma0pcbWM5SUBtJ0NTa10zRW5DUClfXixrX1BpJnBVSW5vb3UrW10mXEddUlFkP1JISVguYWExVmYxITsiYW9lQF1DbHVaRHFmKGVSLlA0c21tNkZDLk9tLUU3Im4kJG9aN0luK1xWPDsyS3MnRDtrJlBcRjRZZU5qJUFkPVs7P28xSTNXVyRlVlMhbVheSyRiaWg4LEJoTERkSWhlJFYkP0BTYGZIMzRXYm5dMl4hVWRCVGckR3I6Uy8uXXRhdXU/U0lvb21qKkJHOSJvPi4kSGxkMVJPJT49SiI4QG9pNS0xb15ML2xpaEFRPWgyPmtfPC1uS2thQlRnIjFyKjlzKU9VRnVmcmRyTkNII05HJDxQPy9XZmE+bzAwVWE5VWVjJ0dXcFAsMDtZbCJbIjhiMWEobiIrRmNcVG5QKj9TSW9vbiJwIyRNdFc6JlVwMGIjVUlrJTVrak9AOypjP19MbmVbNjNhYTlTbkxONURjaTxtYjgwVWE5VT8yZ0YyamxhVzUvOllLTFAuVlYsKV48Y0UyYypyWSRWJD9AXXVBa1dRIz5RUEQjKTg8cEJsQ2NoWnJdP3FoSkRUbyZUMyxEaG1OJm8vIkhwMFVhOCpGKzddXTRtRGUzLGs7YjEtSFkjcWhmKmlPSFRqSE5xdXJpZW8hXDNNNmYuRitbbmU8Il8uXSJFNG9KKjwybCxXTVpjUVEuUk51Zj1KK01gXGw/VkVDbmVbNjNha1AodDwtXFJtPzlQNGEiZiJaW1tkbEBdaFVuRWQ6K0xoMUJUZyNWcXV0LlxoUiE3K25lWzYzYWtPYUBONF4jazQmN0pZXy5dIkUqVzFXNVMoK2UtcjoxWV8tSFRLWzAyZ1o+U2owKjZeTC9saWhIR0VGbnR1LUk8I0V1YXI4bCUpa1YkOSFtJS0/SSIxamM0NEYrIiovV2dqckYmZkM7QkFmMWpQSj9vTDxdSy9qVCQlazdeSD9mM3JtbSlnVldaWmxucz0pUz84bWZINlxBSEtkX1cmI3JFY19vaylvQ2I8VFA2LlhPY15TPlc4LmJobEEiWzhbbi4pYW4qQGNqUz86WUgqRl9pSS5nJ1tAPG5vInJkY0U8JGgxV2RdTiUrSSlqJWZzSCpkSGQtI1s1PGE8J0NxOllvJyM0XHBSTzRpOyR0bC5QLTljbGRWcFY8U3FxWWwqVilTKWdiTz9FMFQqJEhsZUpdR15dcDdeVXNHNj5qNktuczpfQlxBLT5KbSwxX2EyY1g7XmJFRm05P2lPNGRuWWhQPVZtLSpcYVcnSTRkUW1OclcwIUxFWWwqVikpcy1QUi4oOF1GT0lNckpyOGwkPmlwWGt1RzRWWW8pbTZGQ2ppTWw7bikhZ3NvVmRpalgwRE5gYWE8Nz9wPkdXOVcvcXNzWWwqVilIZkZNOWFMMV0+TztrJSNyOGwmNG1JMCM8Rm5WYnEpa3NTN2ppUC10bitpPi5wU2ExI2hRP187YWgtTU1hRXA9KU5zYEZRJUVpK01dVzskJDRlbDxBOydHXDBCREtgN0dLSl9qSCMqJC5fVksqNnJwby5DcVxwciVEO0wyXEhfJj5lVCJJZ0pBKidpO0hQXm4kSDI1WElmQWdlWl1YPCRnajAmKS9Jc0xVNm9KXS5vZzpUQGJRWW8rZ28mUDVmRGolY0BHcVw6VW1tQCRFakYtJyxUIk1JVm4pWlRLNy9sYzxyUUYodEgjKiJYYzFUa01yOGwmdGtcbW9CWzxaXVJEVldqb0gyI1oyR3JQWjc0bXJCUnI7REV1YWgtaixKQG1cSm8oUDs5LGskbzIxXC1SYmIyNS1rUC5aNm5hNWlmMFErcWdCOGIrcUBTV249OD04a0NYOGIrTTRyMmI+MmsqXWosbz0nK1NablwlXFNyTGtMbnRGSyRtZF1vSE1Dc0goXGBNa0lOU2ZCT3EpPFdoLk5dcidXYS5jNj4sU0VLS1g+Tj1vYC9hbzAzcDNKZE9lUSFkJTNsKkdjZW1TMTM3NyJcdUtENHF0WDU2R3FqVGAvXEgqISluVD1yJGNqamRwVEQpT3EmP2gsOklDPzpNWWtPSjstPGZlRDxGRCxBK0dOU1J1Oj9NcmU+N2hrRSVMak1ZZTIrWEtfVWNoanU+S1QuPW5pPmJvNy1wTWAySVgyQTIhJGZmKTxRRzRnJUluYFoiOG1FMkxVVGpbUGhGZVs3QjxLMSxFPC1FaWhuP15MMjZIIjU+U29EKEBKUk8/Ml9Mcl0+X3JqS1ZDRi1IPTgxUW8xbjYoOUBHRXUham1VWFNeNS9BJSxxYi5HVXAwZGltdW84ODQnMUZZXC8+WHM/ZnNVKF5ba11lJGZjc2wvOlRoW11fOksvLHFiLHFYMEROQCddKz5CYC5gMTUncGNWJVdpcWQ/RUZJWVdrSzddM0dKTHNAYEdOZjNxV0JuVG4qYzR1J1FIM1VuLDZNMUhNXWVkRiRhbDlFdDlXbXJlPU0uV2I2PktGJjFwbXJXXFxBWVwuc1ppLDI+XXIhZlZbcWdRTCljZVknUnEwUTNkbSFjbm9jZVhzUnE3Qm9RcmRNZyxjWCEpL3E3QkwtaVZlV3FUIj9oPW5lV0VlQEYqcmlhUyFrKVxcQXUsJFtXWmA7UWInclJKaGldPk0tOWxwTXJGZzhhQSQtaFNQbCddcGVoPDhpY2hSYkY8XmppZjwxXydhRWovM2UtXGpnO0xONyhXUStyJSppV1dyZyhXQDZnJSdIKHE0NnQ1PVMqVCRWUWpKPTVxKixoJVUoZj5UODFePl9yaktbU2xsLlxHVnVaQmtfXXJLVGYoSD1fbU4kUlYvWSk9c1UvcDwwS0V0QC5LMnVfXyVNSm0oREVcSXRxVSYucmYiMF9haCFXVVx0cG5BP05rKW1EOm0wYk5qRjchO0ZccT01cSosPD0xLDhGWyJPPkhQVF08LF04SVUpMHUxUWI+SSohXER0LEVLdTxNLiwqX2dRWS4uJi5ZZW1ZalNWUVtcWmFmIUFFS0xTNWs0S2guOF5IQ1JTJkMiMCowa2E0XmpVTUU9NTUmUjdjQkhBWCUuJFdaYWYhQUU8LUU9a004Ky5cIjpQUjJpNCQrbjZ0MWVqIy0xKz5dR3Q7Vz0jOVloKityZVQjREYnTTQ6RjRHMkFFLVtJJSslRUtkbigkTGQoPjRBPXEwYD4oPWdTIl09QGhYYjU2bW9gbjhQSVRRWVlOPzlTNWxbRnAnZlVzZ1g3MCRELi5lNjtNXnJaWDJjL0lySXJGLGpaYWYhQUVGW2w1QENZV0woMEI5OkRXJTk8IS1FLyppZWo1RE5WWSVfJ2V1QG9FUShaMypyPlEkUmolNnM0YzpoLicpMD5NMnIjWyhuKk83X0VLZG9lWTVRPmFQUD1ANmA+KD1nXTRdbkQyY1xfaEhQVF08LGpwRDJeVWAlZyVkNyYjRUtkbzVwQU5uTmpJT10pXERlaVRRUTFEN0BjU1FZWmFmIUFFVyU2YF9oSDJvV0ZwNGk6I1wzXnI4bzNiKlMuUixpWy9ZLjxvVzUzZjxgIUgtPzI4XU0zaUVzY2YwaE9gOWVvP2U9T1ZvMnNMIT5hWkkiRkVRKForSUg2c1RaYWYhQW0zX0NhbW9gbjhQUC9vcHJ0Iy1rPW0jfj5lbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwKL0JpdHNQZXJDb21wb25lbnQgOCAvQ29sb3JTcGFjZSAvRGV2aWNlUkdCIC9GaWx0ZXIgWyAvQVNDSUk4NURlY29kZSAvRmxhdGVEZWNvZGUgXSAvSGVpZ2h0IDMyMCAvTGVuZ3RoIDYzMTEgL1N1YnR5cGUgL0ltYWdlIAogIC9UeXBlIC9YT2JqZWN0IC9XaWR0aCAzNjAKPj4Kc3RyZWFtCkdiIi9sOTYpO2cmT2BoPmVYVDgrZFFNWkZQbm1RMU04ai8kJDM7ODVOYzljbTkjSVk2JWc2MnBGJS5ybT9YTmoycWQyU1I5MXFvTmxnT01pJyNVYStVUiUyXWQnPzQmOkhlYVJEZDdfWi1eNWdYXERlUXFoJiRJbEJcWzY/YEdOTktQPUQnJ10oVDkzRVNHRy5VXzBEX1FAME5NZ2JyRVwvJ3JaZG9dcmluaWpSZkxEIixdbzwoRjhZTV5yWmFZMGQ+OVxTOj9tZTdXZD9EOFdiI2kibj1CKkd0WChZLi8+WTk2XkUkUyJQY19JMjVvPipvKWA2UzNxMmRTJ3AnZy8/WkwiXDlqU0AqQi1xPD04LGomRVNHSEFZUEFFQFMzJCoqWmFmIydpTFg8RGNlS1hjPmhXaDFgR05MVV1bbXElXS9qaXJaYWYjJ2lMXHE/LE0tITtmQ2A5T0VTR0c8bV1yRExXL2VMZC8/WkwiXDZjWGhNPGJQX1U8aGhWZ09uaGhZMHUtLXA0am1eNSlVcS8pbTkocWk3USt0XidGUiJNXnJaYVkuSE5eL1Q3MEoiTUUoP01WRWspK2NVLWQpaSs7Vm1eJ0ZfW2MnW21qIVQwTWoqTV90bUJhPV5bYyw0dGojUWhRaFkmWiMvP1pMIlw9cT5xNE03cig4XGROSi5ySDtEWm5yZ09EbGRna1hqPyFhZ09nSTsoQSZYJGpmQGBwYHAnaD5palJnQzhgT2dgTDQvNS1JMjVvPjJWXnU/NFBucEttTjguS2llbEtGUmswT0heYDFVVzNuVl9aPl1KVDFhaT0rNE5xZDRFM19LNiJZLi8+WS0uNyNeXiUoMV9cIillbldUSGguYG5cSC4ncUguNSpHZmRDRElbU09idD8nOFVDTzw3JyI5QU1zIjNISGE6KFdeUl5qJz8wYzArKU9sVSlALnJjTUwmTURKV2E+cD9tZUV1RWtnckEuP2xnbCNUJTlLJTRwS1dSMFIjPkk1P11kLnJaakElamRhSCE7XGhEcjZYakdNJS9EWk90OStCOnNxUmpXNDhDYlVUbmwmYjw/PypxQVFLOmhLPFNmLCVeJCc3KDFaK0Y/Uk9gQHNGLGNOPGZjMFc7IU02TClpanMzdWY3RF1yOT4vMiY/WkYmLWs6VSRDSCI0NmxqbFwuc1xGLy8mcTNPJUs+Pz5qWmllbSdJaDNgUzhqMDQqJms6PF5GbWJHTERRVCYxJ1F1S2UhTVgvUkRTcCNDc1onZlVwKWsnaTU2TE5lbzRhQTlIWCNQTUM9NTtDZyspY0VMWS4iW2IoMEI5dWpZR0taN1dhRSRxXmVuWzVLZGk8amMvLEYoMEI7W0NATSxsRiw7aWcpTGZZMU07K0VQaipmYSlQckkiQ05eJFYpMldqai5VRzIuWFJsOmhIJW1GKFMyV2hTRFVHMi5YVGY1YCwhLXRgY21FMFIhWW4qI2xcXk1NUEI3VydFaVxvcj04WVwhLkYwLkNwOic+Tz1gLDNeLVB0IzM9a0BTWEtTLiIlVU07K0M6L1dJV1tjZk8iYzRXVUszJyI5U1NnKS41Q1REUT0sRkErWjgtI1I0MU5caCs3NSRiZzA0PWxUKSciOVNTOWNBXzJUMTdcQSojWlV1TTsrRGUuPzIzVzpHNldLQXAoSyYua1YpZGlAUUhRaFBabydUJ0g+dEZhZFk6YklMVXQtWkFicVJRQipoJkpfY29mXTNNOUpsMmooNGVncmVOZ1tObDspbWshXE9UV1NvJyk7cmlpO29xUE9qWzRcT281VTVrWDtsXDxoNlotYFhXJCV1Myo4bEBXdShPL1RRMmRPPUpSNmZYMChvWEs4Kiw5QUpfKW1lNl41PjlwWXEjM0loXDtsN2lOUFtrREFEWykqcXJkZ29vZFwvO0ZOU0FlUE47WkVidVtFTUhVUGgxOHUjKmU0LjdHYDJgRmtbamEiaSQwJEJjLGIuRU5YPmZKdXJadFBkUTZ1MDpgXk5jXFZfbD1iYVhpYVgtSV09P2ZIPkZgP2FgSCxzRFlYakRtT0leTzouKDYrclAxISw3RmB1NGBCPD1WOGIuPm1RNEtidV5Ga3U8Ij5pXiwuQ1hbVTxRSz09NEBjLzxucDVTVjlqVmk+UGU9OFYtSFlUS3FhUVhaaV1cRT1JVEtpRzFlRCJERF8uamkyUXNXOjosdFYoalJyMiM+b2cucGFnbGA0RUpQc2BsZz40VzNhaFItRV00SjNoS1ZKUWpQQj1GbjorXU4jQWReQVk0NGQ9TkBDO0FuIilJbXM4LnM/QC5QIk9tNy9VRDlbUCwyXCVPTm85OkRwSVw0X1VVbzo7VUludCgpOXBmRUhNImUxajldNlxZa2BZOy4xcFdzbEpJVi9FZ2ZYcz8lTkRsJCJWSikuKjAmQEhFZl1RJkhqc0IhU3JLXGpNOVtQLDJddD8pdGFVXUpIYy0qb1lQSyoqRT02LlVvUE42bFlgcGVjQEkyNF9aRHNtN0o8bU1SRURhJ1U4WUhLbT41PG8mTWZZITNTTFhJI2ciKjM2MjFlRCJ0RFtcbCQ+LU46YUVtTFI6NEJePUxha1REQ3BxJkddQ1xYbFFsOU5QSVAzWDxPaU5aa1NQckhqckhOUTIoaSh0Ry1IMkRTZU46SD0wIVY9R1EjaShVdSloLl9HZ0RdZkhXLW5JcURiU1AoSCkmJi1yLltPXF8iS2RfZ2NJMC05W1AsMic+LSd0T3QoVWlwPVssJ0g3aiwwZDNPIVldSjk+VSZwOyJgZnMuRVZHISYwR11FbTpfaFk9XSYwNmw4NzJzQFNMS2YzKWpSJWQxQ0FwUnReRDk7J25tQl1HU1tvX0ZSVS5PbyZIWGxpKVJIZj1pbzZEVz08bzA0PDhiMiJqQSwpVS9sQEE4Q0ZBJTY3Q2pobkw4Yi8wbGo3My0zT1cqbGZVbydeVGlsVzM9MWVIT2pEajcxJlthM10+T2JVTjJMKmsjSGxdJDo3XyJOJldONyplSGRhMDdiYklvVnVgMk5qSWNgOHA/Zy01VzxeJmlSaU1DLUgnaS9KbStMUHNYRVY2W1InaEZMLCJqOT4obiYvOVxNbUJhS2wpQzk7SVVJayU5R1tuZzhWby81XT1LPSQ6MmoyUTZIKGhsKmA7KzlOW2ExOG5rYCEwOk80Ty5HclZfYGhCYDkoIiguKGY9JjZkKFIyKEFtYCJEPDotS0RaRmptJlApKTVWPl8qX1dfMGkmX0lvQUY0bGZEcWcpWy5uJj8lPlYxJTNZNU9FdT4/OUErZzUhLEsxbnEpM3VcOktocV89Zmw7XEBkcl8tSFYyN05TdHFlRzZRYWFUWkhbbjE3QktXKCNCZEYiNXQ6KWpiPEInXUoyaj1qTHJNT19rISVsaEIlZzJuWSsvaVlJbFNZUE45RXUpdDNMLFpwISYqXTsxQTEuclMsLyxeSFRiYGMrVEUqUSVPRzBOViJVSCIyXllhYTlkQUw6YiRGU2cxJmlUIXEiWFVYOj80MEQzPihBIVZORXAzQFM7ViElOzwxN0JLV14ic1VvRDdXclk1KTJiSjRnMkxRNz9jZkdnKUlyc0lHUVlXVDsvN0FTbGFkOVUuT3E0bVokMDg1Tzk4Y2NPJiQ9Y1JXcC1kM051VkdbbjgqR008PmRGK1EsZXFPR0kqYi5FM09ha09dUG4kYCkoRitjYFQ4XSpdcF1KMmo9alIpI2ZpR08tRkgoUW1oaVNKM21AdTtWVGdXVVZTJTFndWRkY1kuVFxHJy5fUiVkMUNwQEg6Q2NgY1YpbWRrTm4mXmtYZVpiLyJdUE42VEZOVCU8ZW1PP2slakdkXCw4YCRXLCkiLCUpKk9YWGAyajJRNkdvTSo/XEc5WlhQXSZoRDg0SmcobUhvbmxybVBhO19KX08sN1BeRFhEZ1FFODkrY1QrJloiQ0JCNmUhRS1IU3A/TkZAcFlNW1VkPXBISGI+O2AlJ1AqY0RJbjZxInFUTDNvUVNOQEM7QTA5bkpORT8qRyVeSD5YO21YOkJbVkopLipDdTRxQnInUXMjKShmMidHZVNxTiFSRmooNWlEQS03WUVnXWRKdURlX2pIaFMuclVZbj5DKzFnKkhsLHNUJ29TISljSlJiPzxWN1VVTVlaQUlLTXBubzkpJjBCVGckUGhLVGpgVCVFc0VTQGczcURiU1AoSDAoI283U0RnPTpJNCp1L3BVcmEtSFJjVl1TbFNHcCQwa3Vqa1ZHNEB1O1ZULnJUZiszWGU0TlohaU9qbzU5ZiowaCU7ZVByQ21eaDVIOCZZKlFeVDc/Y2V0Mmw6bEhWMUcuXFdTJGNaVExuXnMpalxSI2RLJVUvMDZxJmItSFJjVihmUD5saiwxTGhPdUZxKlhmcCw6PSc8NTNdT2Q8c29ldUNXRio9W143NlcyYWBtNydwP2QkME43bigxMnIqJT10TkpsbC5Dcyg8KiVEQ1pvZCRFTzYycGBncWpVRmxERipmJW1bP25OXDc/Y2V0Mmw6aytlLGMlX1dTJGNaVExuXnMpa1kjb1c8NHNGQzw3RG4xZUQjIWokVjcnbjMobW9rMXFHMkB1O1ZULnJXKFlxKVMtNWNfS1VYLnNZV14tSFJjViRvOycyMDc9MFdtcmxlbDtgJSdQSCIwVmdYLlJBUUhXJ0ZTJ01YYVdmYyw5Vi5dMy5eSUtNcG5vOSkmMEJUZyQ4aEplVXNdLCYoXEghWmhVUDtmQFBQLls9QUUwU0FTMCJrMGdnQSlmMGAmcUNQVVJeKWIpdCkuIWY7UEIoZCpEQT4sTi9DPylbUDUyaE08az9yUURtYz00THIvQHU7VlQ5QkQvJzkrQF4tR3A9MiRQKmEzLlJGYDxIKlYpWlRSTnNQQzJ0QVVXTGNYVVZBMkhtN3A+LjNGa0NCMzhHcD0yJFAuLm5aJERkZC8hSTVuLTlwMnVqMnAxUz9fRF5KN0EySG03WTIwL0A3ZXBaV05GWGs7aE5tI2M/SUphOD0vZVJEODRKZyhtSDRxOjFvZ0RCWTc+aCYpLDY6J1I1XilRLi11I1wzb2w5MjFlSFAhaFFVNlZLS2ElSzZmKEAnUE47LGklSyJsXk8/VFNBNmYoQCdQTjZUPSVEK0hpcVJqMVBLS11xQFNBVkpPXTdEPE5IYjI0O0RdX3JOJ0BcMUQsYm1zJT9MPGAzSFxeMjhCUV9COGFfNmpNcE5nPzxcY01MYjwjdE8hMTdCS1dWO0JrPUJHXj9wVj0haEMxN0JLV05TWlkqQF4oOEViYSJBbmhPKCQvbm06TD1fb2k1PEI6IV9mSDAoIzdSTyU+amhKZGBOIThELjViaWg1RG1IcmFvI0dGYFtoVm50XEJkIS4xLC02LHRIIjJeWWFhOF8jQC4tcmg/SDouWDdQXkRYMD45QGJWMUlGYlRdI0IxMTdCSUFcMlBDZSFUKiJRcHNUX28pdTQwTFlMM0M9XStBOFVQTTFgPiNNTEVMPiRZLidKb2InKyguXkMqOkkzMTw4aychRlJRckhYVCcuO29Ncl9FYmF1dDZOWWYmXFNVOysoXVFKMVBdRGROPEQ+aSJRVjFlRCIlRGFbNSNcXi85IUQzO0puTiRjWilqLEYxVStTWFBxOTkjKW5QMGtQIzYraT0pJUhLXStRK15KbzdQXkRYMDdsLSdNdWhldWVNPS1saEZMLCJqPVUqcVZET0QzXU48U01hVyY/OFAuXDNaODxzSSNUPTwiQk5aXSo1VDhkTkldUzU0YFFOaEsmOldmRGwrOnFQRi9TTDxbLS9MPT5Sb0F1P1x0cVwsW1FbTDcsXkshcDsoKW43NStibkNBKiZcIVJOdWdXMmVvMT9naDJ0MkRRZ10tNz9jZldvTD9BSk9TZUJFVGhVaDNWSikuKkMjMTZzIydjYVwubyUsVWBZOy4xMm9jaltkUW02LEhVW1IzaE8oJC9uZzhTYDdpS0hzTltYWUliOFhBOjhgIi0hNVkyJ2djVSRbSUlzR09dLUhSNGklRWhbLkAsPz87N3MybGw7YCUpJitFJipuIUxVPkJmNV9qWGEsNjlkaEMuUSklJSg8PUo5ZWJJPy46JDk5W1AsMmg3WzZlOlk8PT5cYGA3PjJsOjhPXVk8NyxPIVNXIWhWOkpAYTtcJjc4Uj1vKi8uRWtAPzNdaSszb2w4TFJPIyknMmNgRVwyRDVBXDpFQiNHJ01YYkJgPl1hYCNiLjA5XTVfVFZgWTsuMXBXc2w2Y2NgUDxXT1QhQS1aO10rLF5FMXVZcTZGR11QUUIiNmUocCxkM08iSF1sPjUqakxnLk5xYmJLVDtgJSkmNGA7PDQiJCYiXmY2RXRaYFk7LjFHSmJBVGBXND1YYk0+LWtIL2ZXNlAxU00vXCojKCNhcj8rTFAuXE5jQlRROyNIL2YkJVAxUykjNG49TC1HVD9RY0dvYjlYSCtnbDwtRWpxLzkmQTJmUE42bGFJNyRHKmY/SkBuUk8lPzdEWVtEN25FWmZvOi1iJChyUDEhLDhDXTs3YEI8PVY4YjBVVVFCLmQqWG9iNlk5SmwsZCslIk07PEJbY29RKWY8MTw7MEdkbjdwSyklPk5Ic1YkWnQxOD1uIz1cWCNIUzNvcSojXS5BJE8uSVJuPCxdQU1yYjRDTDs9Uz9CbipkUi1kUC5XKmhXNkhpcTksWjotLUVlIlVQLipndEttQ1hbWEsoNFttLjgtVU5QXCYkSCZpNkFCXjFbPFU5IiF0XUE9Yy0vcmkhUk5SMC4+a2hjJmlPQlhuR1s9KkswXVJiJT9tSShXMVFbLGEqZiYiMmYpSi1FS0tcWi5fT3VNLyg3aUZDNWBAXiciTmdbUT0+PldhPWE9RC1PW3JDIVwlRUNmITdXX3NWYklMVXQtWj03W29fPW06J2MyTy1VKDJJZFYyV2k5UD8yIUdEUik9YU5Vc0ZxPW51PFpnUmFuNiVYSSo9Ti8qKkA9NXBbT1ZQdXI+ZldNKDY4cyRScltsbFo/KlYuM1ZYaEtiMlI0RTozRXRkRHBhcjs7LUVAdCgvLSNTJ0lab1s5LWVfMyhzWygtZ1k0Wj89XG8jPVJFKnNDTSxNOytVQFZbZSFpPzcvNm4zRVAycUUkTmpVRF0lZkVxOGRWJ0RMOE91M29nYENTW1RWZVkvRzInb2k2ZFtFUywsPF9zdW5eaCJGdUNGaVlMTElDP1ddTVJhQS80bm5ZNyM5UzIvcHFEWyNBWmlzZ2NaTCtBR3BCSyQjXm1JaWd0K1MvRGc+aWZYKGdhZFA/MiFVbVwpXSZOUmBKKVQ1U2dYRUxGQWxkazVSS1puX0UpYD4oPWZdL1Q/UGBhSnR1YzwiN2pLPURrYTA1anRoRnNyP2U1KVVxb1YsbGJkaEZOX3RAQHRMUmYydFpeSl9WMilkTz1JZ1xEbDVjSU49ZmhPWD8oKTUpVXJaO0FoK2tYWitbZSZUa2JITUFzTEFXMiYsZS0tUC1cL001OEU0N1swZCteLyc4VjQ3JWhlLVtjWnFndUw3Qm9iXU5EYUFIOTZjQmQhSlFtQTc1IipcKWVPbms5NF1nWE9rRV1KSWY+bjdAS1tkXXU5JjAsRktNMXFuMS5nP3JGIVleTjAlPG4kOXB1WGJCQHUnXi0jUyZeSmldWHRRM1ZkSGdPPzxEQWArY0YuVnAhaT8hKjkjJyI6JDVuOiZAPFNWSCxhP1pGJG9pYDwkJywtVSwoTXNZbzInZlVxUVUoNnExRyVuMU9ZSU5RckVWJihQcVc5WydeViVuUE1WRilaWDpFOmBwNzNIIz1eNXM5RUFRLyhRJDZyWytGUCMsZ2gsPXVGaCRMPGgndTBsYD4saigyYUpKSUdySVg8ZW45IUFEOHFROWEnbWk8bS9jb2A+XUg2UTZlL0g0cForbVFaZDdXZ2dQZClMTmtOKVxZP3RdNy8/Wk0tXDNZJSoydEVSLyJNKWs8TVZGKC9Ub1JbOS9wZFRlWmFmIVFqMTs6JC5CYU8rXlgobnNnUGtJISVTKEVDNSlVcS81SGFHc3JGcmUtcUNKZVpjKyNCTWZ0bjJFV0goWShgPixqImZCWDE1cEBpSnJqMk85QC5ySTAyaVAjNislP2VgLUkyNW8+QiYmUlhyZi5wRk5JMU9SWS4yYGRnWGdobyVAK3JgSTI1bz5CJigpQ3JsUFstN1k8bV8uckkwMkwsc2QnJztYJEtjZjBpOk8xVE4uSXJdVitkQUc3TE1WRikqMm8lQDI5Y0JUIS8/Wk0tXDQuIVZlYnIuakhoOkhHRUxVciIyVFY0U15IUlErRERTRmEkZCRoMWZrNTxERDhvIy43YjloXi5ySS1xTlxQa1M9XjVzOUVMM0trVjU6I2JwJkZdYk0jUkpsM1NKSH4+ZW5kc3RyZWFtCmVuZG9iago3IDAgb2JqCjw8Ci9CaXRzUGVyQ29tcG9uZW50IDggL0NvbG9yU3BhY2UgL0RldmljZVJHQiAvRmlsdGVyIFsgL0FTQ0lJODVEZWNvZGUgL0ZsYXRlRGVjb2RlIF0gL0hlaWdodCAxMjAgL0xlbmd0aCAxMTI3IC9TdWJ0eXBlIC9JbWFnZSAKICAvVHlwZSAvWE9iamVjdCAvV2lkdGggMTIwCj4+CnN0cmVhbQpHYiIwUzk5LE4tJi1VQFxFIXAkZ3BWMjVzMGFrMXRuNyYxL2xDZkBjJmMmSVdZbGw5QUpWaz88RT8nSVdzI003Qj9BUzlPSD9qJUZDcWg3OmhvRkArSiVYZ2xMUk9Cay5uPTJNJXNITUo7bFFaVWdRNl4xLEZvb0BIMUJEVVM6dUdyIkIsaFBRS1ojJixIMyVOJGYwKz1ARlNlV2peTi89MSI4Ikw8RTs+KiIvbEdhQ1IkTW5nIW5pSyU2Z0QpV1JTJkBEKSsmXDRSMForQXM8KnMmcDcsY08yYlpeSz1baGFkbTktKVZmKFxhKEQsXzxXSSRXbUFzX1peVz5kam1WSDJlZjZnSGhPP2BpOExnVlRBYDxON1o7STIiLm1QPFNzIVguMiYpNDJbMypjSFwyMVNKZktpQjI+QTBjNlFxdVphajE0Qi0rQTlmaUc7TDFETGVlQ2FgSDJSPm0vR2VsRkJhKi5TSD5RNSZiMz9scSxnRFdyXTBPbD1UTFcuPzkoazhEY08mPF8qWUM6RkpvXE0jZ20sMkpZRDw1RDJrbXJLcj1fOU9kYmwiKEBZO1hLQFMpUHJsVlFNKEQ7XSo8MWYjQHUlXFR1Mi9wQ2wrPScxMy0xaTwwRl5UTEgxLGUkV0A2ayM+aVY0NU1LPkhGN1BGPW84XCNBOyttIVBGLCFVJE9WYCwqaTFRMUhZKCFpYGB1LjJxXVlpYVM6MjlVNGdZIzkmXG5YPV1XM3RmLEIqNF5gclNQbihDPjEpQVNbSHJPalIlbyZJTjNNbXFsKG1aREooPylFN2pSRVRwPzUkU14jWmFAQ05RUEgsJVtQSXI9NUg2QyckOkIqZSZRZTk0OyloY2pyMSdzZD4hbTxtcUYjO2Y3cUIsZEU4cjlcO2MxTC4+WUQ5MUZIKE8sUXFYNyEzdFpRRT1GXXJYIXM9XC02JzFEWCteXW9GbE49XGNZZDFDbVc4czF1dXNBNiRjT2s4N19pRmcqWjM0Y1hmdUYzYSplPzo+Jkw7TTJJRDlOUyxgYmwvVGQtXlFFS21NcGFeVGhoaDQoaWpyIW9fNW9NZEU9UEBXdTxrNTM/PitCMjtDM19XJFhDUTM/PiJLMjorQFNWKHNwTj1dTGpjczNdbDIjTkJ0JCdQRDo1O1UuI0hyY25yIVgjVURdNDZPJCUvKlAzU3A8NzspPG4hSS9ENF0/WFdON246Zyw/LkA5UCVpTFs6KkJrTlQvNGxDQC9acSFxaSxDZT5kZGtkNExsbmUxJl9RTV9mPjtQbDdWRTFNWldKbXInamxMcW1MUSo0X2lOaHItYmNKX1xjLldIIitwNkxPMSsxJjcnVzZaMjotUUZZNTksJ1M3PnE+QUhKLDdlYE8uKSJeSCtPPiNYPitLX0VPTjA+XWAqVHVfYUhOLlVEVnIhZWFNWE8lZUZDV09TMGNcVGE8UjdIZS9kXkhiVW5OMmZcJk9HSUdWb3QsMDhmODA8K3NSSzJtXkZ+PmVuZHN0cmVhbQplbmRvYmoKOCAwIG9iago8PAovQ29udGVudHMgMTkgMCBSIC9NZWRpYUJveCBbIDAgMCA2MTIgNzkyIF0gL1BhcmVudCAxNyAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXSAvWE9iamVjdCA8PAovRm9ybVhvYi4yYTg4YWM2NzEyYzljYTcyN2U0YWQ4ZjI1YmNiZGFlMiA3IDAgUiAvRm9ybVhvYi42YmU0MGVlYWFmMGQ4MWQxODc1MGRjMGE3ZjlkYzIxMyA1IDAgUiAvRm9ybVhvYi5lNWMzMTQ3ZDE4Zjk4NjdhNGYxMDhkM2E1NWEyNDhiNCA2IDAgUgo+Pgo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKOSAwIG9iago8PAovQSA8PAovUyAvVVJJIC9UeXBlIC9BY3Rpb24gL1VSSSAoaHR0cHM6Ly9leGFtcGxlLmNvbS9pbnZvaWNlcy9JTlYtMjA0OCkKPj4gL0JvcmRlciBbIDAgMCAwIF0gL1JlY3QgWyA0NSA1NzUgMzAwIDU5MCBdIC9TdWJ0eXBlIC9MaW5rIC9UeXBlIC9Bbm5vdAo+PgplbmRvYmoKMTAgMCBvYmoKPDwKL0MgWyAuODMgLjg5IC45NSBdIC9Db250ZW50cyAoVG90YWwgaGlnaGxpZ2h0ZWQgZm9yIHJldmlldykgL1F1YWRQb2ludHMgWyA0MCA1NzkgNTQwIDU3OSA0MCA1NTUgNTQwIDU1NSBdIC9SZWN0IFsgNDAgNTU1IDU0MCA1NzkgXSAvU3VidHlwZSAvSGlnaGxpZ2h0IC9UeXBlIC9Bbm5vdAo+PgplbmRvYmoKMTEgMCBvYmoKPDwKL0MgWyAwIDAgMCBdIC9Db250ZW50cyAoVmVyaWZ5IHRoZSBoaWdobGlnaHRlZCB0b3RhbCkgL1F1YWRQb2ludHMgWyA1MjAgNTI1IDU0MCA1MjUgNTIwIDU0NSA1NDAgNTQ1IF0gL1JlY3QgWyA1MjAgNTI1IDU0MCA1NDUgXSAvU3VidHlwZSAvVGV4dCAvVHlwZSAvQW5ub3QKPj4KZW5kb2JqCjEyIDAgb2JqCjw8Ci9Bbm5vdHMgWyA5IDAgUiAxMCAwIFIgMTEgMCBSIF0gL0NvbnRlbnRzIDIwIDAgUiAvTWVkaWFCb3ggWyAwIDAgNjEyIDc5MiBdIC9QYXJlbnQgMTcgMCBSIC9SZXNvdXJjZXMgPDwKL0ZvbnQgMSAwIFIgL1Byb2NTZXQgWyAvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJIF0KPj4gL1JvdGF0ZSAwIAogIC9UcmFucyA8PAoKPj4gL1R5cGUgL1BhZ2UKPj4KZW5kb2JqCjEzIDAgb2JqCjw8Ci9Db250ZW50cyAyMSAwIFIgL01lZGlhQm94IFsgMCAwIDYxMiA3OTIgXSAvUGFyZW50IDE3IDAgUiAvUmVzb3VyY2VzIDw8Ci9Gb250IDEgMCBSIC9Qcm9jU2V0IFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdCj4+IC9Sb3RhdGUgMCAvVHJhbnMgPDwKCj4+IAogIC9UeXBlIC9QYWdlCj4+CmVuZG9iagoxNCAwIG9iago8PAovQ29udGVudHMgMjIgMCBSIC9NZWRpYUJveCBbIDAgMCA2MTIgNzkyIF0gL1BhcmVudCAxNyAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXQo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKMTUgMCBvYmoKPDwKL1BhZ2VNb2RlIC9Vc2VOb25lIC9QYWdlcyAxNyAwIFIgL1R5cGUgL0NhdGFsb2cKPj4KZW5kb2JqCjE2IDAgb2JqCjw8Ci9BdXRob3IgKExpdGVMTE0gT0NSIGZpeHR1cmUgZ2VuZXJhdG9yKSAvQ3JlYXRpb25EYXRlIChEOjIwMDAwMTAxMDAwMDAwKzAwJzAwJykgL0NyZWF0b3IgKGFub255bW91cykgL0tleXdvcmRzIChPQ1IsIGludm9pY2UsIHRhYmxlLCBmaWd1cmUsIGFubm90YXRpb24pIC9Nb2REYXRlIChEOjIwMDAwMTAxMDAwMDAwKzAwJzAwJykgL1Byb2R1Y2VyIChSZXBvcnRMYWIgUERGIExpYnJhcnkgLSBcKG9wZW5zb3VyY2VcKSkgCiAgL1N1YmplY3QgKFNlbWFudGljIE9DUiBjb3ZlcmFnZSBmb3IgdGFibGVzLCBmaWd1cmVzLCBhbm5vdGF0aW9ucywgYW5kIG1ldGFkYXRhKSAvVGl0bGUgKFF1YXJ0ZXJseSBPcGVyYXRpb25zIFJlcG9ydCkgL1RyYXBwZWQgL0ZhbHNlCj4+CmVuZG9iagoxNyAwIG9iago8PAovQ291bnQgNSAvS2lkcyBbIDQgMCBSIDggMCBSIDEyIDAgUiAxMyAwIFIgMTQgMCBSIF0gL1R5cGUgL1BhZ2VzCj4+CmVuZG9iagoxOCAwIG9iago8PAovTGVuZ3RoIDIyODAKPj4Kc3RyZWFtCjEgMCAwIDEgMCAwIGNtICBCVCAvRjEgMTIgVGYgMTQuNCBUTCBFVAowIDAgMCByZwpCVCAvRjEgMTEgVGYgMTMuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc3MCBUbSAoUXVhcnRlcmx5IE9wZXJhdGlvbnMgUmVwb3J0KSBUaiBUKiBFVApCVCAvRjIgMTYgVGYgMTkuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc0NSBUbSAoSW52b2ljZSBTdW1tYXJ5IGFuZCBMaW5lIEl0ZW1zKSBUaiBUKiBFVApCVCAvRjEgOSBUZiAxMC44IFRMIEVUCkJUIDEgMCAwIDEgNDUgMzAgVG0gKENvbmZpZGVudGlhbCB8IFBhZ2UgMSBvZiA1KSBUaiBUKiBFVApuIDQ1IDYyNSBtIDQ1IDczMCBsIFMKbiAyNDUgNjI1IG0gMjQ1IDczMCBsIFMKbiA0MDUgNjI1IG0gNDA1IDczMCBsIFMKbiA1NjUgNjI1IG0gNTY1IDczMCBsIFMKbiA0NSA3MzAgbSA1NjUgNzMwIGwgUwpuIDQ1IDY5NSBtIDU2NSA2OTUgbCBTCm4gNDUgNjYwIG0gNTY1IDY2MCBsIFMKbiA0NSA2MjUgbSA1NjUgNjI1IGwgUwpCVCAxIDAgMCAxIDU1IDcwNyBUbSAoSXRlbSkgVGogVCogRVQKQlQgMSAwIDAgMSAyNTUgNzA3IFRtIChRdWFudGl0eSkgVGogVCogRVQKQlQgMSAwIDAgMSA0MTUgNzA3IFRtIChBbW91bnQpIFRqIFQqIEVUCkJUIDEgMCAwIDEgNTUgNjcyIFRtIChEb2N1bWVudCBhbmFseXNpcykgVGogVCogRVQKQlQgMSAwIDAgMSAyNTUgNjcyIFRtICgyKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQxNSA2NzIgVG0gKDEyMC4wMCkgVGogVCogRVQKQlQgMSAwIDAgMSA1NSA2MzcgVG0gKE9DUiB2ZXJpZmljYXRpb24pIFRqIFQqIEVUCkJUIDEgMCAwIDEgMjU1IDYzNyBUbSAoMSkgVGogVCogRVQKQlQgMSAwIDAgMSA0MTUgNjM3IFRtICg4MC4wMCkgVGogVCogRVQKbiA0NSA0OTUgbSA0NSA2MDAgbCBTCm4gMjQ1IDQ5NSBtIDI0NSA2MDAgbCBTCm4gNDA1IDQ5NSBtIDQwNSA2MDAgbCBTCm4gNTY1IDQ5NSBtIDU2NSA2MDAgbCBTCm4gNDUgNjAwIG0gNTY1IDYwMCBsIFMKbiA0NSA1NjUgbSA1NjUgNTY1IGwgUwpuIDQ1IDUzMCBtIDU2NSA1MzAgbCBTCm4gNDUgNDk1IG0gNTY1IDQ5NSBsIFMKQlQgMSAwIDAgMSA1NSA1NzcgVG0gKEl0ZW0gY29udGludWVkKSBUaiBUKiBFVApCVCAxIDAgMCAxIDI1NSA1NzcgVG0gKFF1YW50aXR5KSBUaiBUKiBFVApCVCAxIDAgMCAxIDQxNSA1NzcgVG0gKEFtb3VudCkgVGogVCogRVQKQlQgMSAwIDAgMSA1NSA1NDIgVG0gKEZpeHR1cmUgdmFsaWRhdGlvbikgVGogVCogRVQKQlQgMSAwIDAgMSAyNTUgNTQyIFRtICgzKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQxNSA1NDIgVG0gKDQ1LjAwKSBUaiBUKiBFVApCVCAxIDAgMCAxIDU1IDUwNyBUbSAoUHJvdmlkZXIgcmV2aWV3KSBUaiBUKiBFVApCVCAxIDAgMCAxIDI1NSA1MDcgVG0gKDEpIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDE1IDUwNyBUbSAoMjUuMDApIFRqIFQqIEVUCkJUIC9GMSAxMCBUZiAxMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDQ3MiBUbSAoU2VjdGlvbiAxLjE6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQ0NCBUbSAoU2VjdGlvbiAxLjI6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQxNiBUbSAoU2VjdGlvbiAxLjM6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM4OCBUbSAoU2VjdGlvbiAxLjQ6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM2MCBUbSAoU2VjdGlvbiAxLjU6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMzMiBUbSAoU2VjdGlvbiAxLjY6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMwNCBUbSAoU2VjdGlvbiAxLjc6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDI3NiBUbSAoU2VjdGlvbiAxLjg6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVAogCmVuZHN0cmVhbQplbmRvYmoKMTkgMCBvYmoKPDwKL0xlbmd0aCAxNzIzCj4+CnN0cmVhbQoxIDAgMCAxIDAgMCBjbSAgQlQgL0YxIDEyIFRmIDE0LjQgVEwgRVQKMCAwIDAgcmcKQlQgL0YxIDExIFRmIDEzLjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NzAgVG0gKFF1YXJ0ZXJseSBPcGVyYXRpb25zIFJlcG9ydCkgVGogVCogRVQKQlQgL0YyIDE2IFRmIDE5LjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NDUgVG0gKFJldmVudWUgQ2hhcnQgYW5kIEZvcm11bGEgUmV2aWV3KSBUaiBUKiBFVApCVCAvRjEgOSBUZiAxMC44IFRMIEVUCkJUIDEgMCAwIDEgNDUgMzAgVG0gKENvbmZpZGVudGlhbCB8IFBhZ2UgMiBvZiA1KSBUaiBUKiBFVAouMiAuNDUwOTggLjg1MDk4IHJnCm4gNzAgNjEwIDY1IDcwIHJlIGYqCm4gMTcwIDYxMCA2NSAxMTUgcmUgZioKbiAyNzAgNjEwIDY1IDkwIHJlIGYqCm4gMzcwIDYxMCA2NSAxMzAgcmUgZioKMCAwIDAgcmcKQlQgMSAwIDAgMSA5MCA1OTAgVG0gKFExKSBUaiBUKiBFVApCVCAxIDAgMCAxIDE5MCA1OTAgVG0gKFEyKSBUaiBUKiBFVApCVCAxIDAgMCAxIDI5MCA1OTAgVG0gKFEzKSBUaiBUKiBFVApCVCAxIDAgMCAxIDM5MCA1OTAgVG0gKFE0KSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDU1MCBUbSAoRm9ybXVsYTogZ3Jvc3MgbWFyZ2luID0gXChyZXZlbnVlIC0gY29zdFwpIC8gcmV2ZW51ZSkgVGogVCogRVQKcQo3MCAwIDAgNzAgNDU1IDY1NSBjbQovRm9ybVhvYi42YmU0MGVlYWFmMGQ4MWQxODc1MGRjMGE3ZjlkYzIxMyBEbwpRCnEKNzAgMCAwIDYyIDQ1NSA1NjUgY20KL0Zvcm1Yb2IuZTVjMzE0N2QxOGY5ODY3YTRmMTA4ZDNhNTVhMjQ4YjQgRG8KUQpxCjQ1IDAgMCA0NSA0NTUgNTAwIGNtCi9Gb3JtWG9iLjJhODhhYzY3MTJjOWNhNzI3ZTRhZDhmMjViY2JkYWUyIERvClEKQlQgL0YxIDEwIFRmIDEyIFRMIEVUCkJUIDEgMCAwIDEgNDUgNDcyIFRtIChTZWN0aW9uIDIuMTogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgNDQ0IFRtIChTZWN0aW9uIDIuMjogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgNDE2IFRtIChTZWN0aW9uIDIuMzogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzg4IFRtIChTZWN0aW9uIDIuNDogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzYwIFRtIChTZWN0aW9uIDIuNTogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzMyIFRtIChTZWN0aW9uIDIuNjogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMzA0IFRtIChTZWN0aW9uIDIuNzogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgMjc2IFRtIChTZWN0aW9uIDIuODogSW52b2ljZSB0b3RhbHMsIHJlZ2lvbmFsIHJldmVudWUsIGFuZCByZWNvbmNpbGlhdGlvbiBub3Rlcy4pIFRqIFQqIEVUCiAKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago8PAovTGVuZ3RoIDI0NjYKPj4Kc3RyZWFtCjEgMCAwIDEgMCAwIGNtICBCVCAvRjEgMTIgVGYgMTQuNCBUTCBFVAowIDAgMCByZwpCVCAvRjEgMTEgVGYgMTMuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc3MCBUbSAoUXVhcnRlcmx5IE9wZXJhdGlvbnMgUmVwb3J0KSBUaiBUKiBFVApCVCAvRjIgMTYgVGYgMTkuMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDc0NSBUbSAoS2V5IFZhbHVlcywgTGluaywgSGlnaGxpZ2h0LCBhbmQgQ29tbWVudCkgVGogVCogRVQKQlQgL0YxIDkgVGYgMTAuOCBUTCBFVApCVCAxIDAgMCAxIDQ1IDMwIFRtIChDb25maWRlbnRpYWwgfCBQYWdlIDMgb2YgNSkgVGogVCogRVQKQlQgL0YxIDEyIFRmIDE0LjQgVEwgRVQKQlQgMSAwIDAgMSA0NSA3MDAgVG0gKEludm9pY2UgTnVtYmVyOiBJTlYtMjA0OCkgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA2NzUgVG0gKFB1cmNoYXNlIE9yZGVyOiBQTy00MDk2KSBUaiBUKiBFVAouOTQ5MDIgLjkwMTk2MSAuMzUyOTQxIHJnCm4gNDAgNTU1IDUwMCAyNCByZSBmKgowIDAgMCByZwpCVCAxIDAgMCAxIDQ1IDU2MCBUbSAoSGlnaGxpZ2h0ZWQgdG90YWwgcmVxdWlyaW5nIHJldmlldykgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA1MzAgVG0gKFJldmlld2VyIGNvbW1lbnQ6IHZlcmlmeSB0aGUgaGlnaGxpZ2h0ZWQgdG90YWwgYmVmb3JlIGFwcHJvdmFsKSBUaiBUKiBFVAoxIDAgMCByZwpCVCAxIDAgMCAxIDQ1IDQ5NSBUbSAoUmV2aXNlZCB0b3RhbDogMjQ1LjAwKSBUaiBUKiBFVApuIDQ1IDUwMSBtIDE1MCA1MDEgbCBTCjAgMCAwIHJnCkJUIDEgMCAwIDEgNDUgNTc1IFRtIChodHRwczovL2V4YW1wbGUuY29tL2ludm9pY2VzL0lOVi0yMDQ4KSBUaiBUKiBFVApxCjEgMCAwIDEgOTAgMTMwIGNtCm4gMTggMCAyLjQgNzAgcmUgZioKbiAyMS42IDAgMS4yIDcwIHJlIGYqCm4gMjUuMiAwIDMuNiA3MCByZSBmKgpuIDMxLjIgMCAzLjYgNzAgcmUgZioKbiAzOC40IDAgMi40IDcwIHJlIGYqCm4gNDIgMCAxLjIgNzAgcmUgZioKbiA0NC40IDAgMi40IDcwIHJlIGYqCm4gNDkuMiAwIDIuNCA3MCByZSBmKgpuIDUyLjggMCAyLjQgNzAgcmUgZioKbiA1Ny42IDAgMy42IDcwIHJlIGYqCm4gNjIuNCAwIDIuNCA3MCByZSBmKgpuIDY2IDAgMy42IDcwIHJlIGYqCm4gNzAuOCAwIDIuNCA3MCByZSBmKgpuIDc2LjggMCAxLjIgNzAgcmUgZioKbiA4MS42IDAgMS4yIDcwIHJlIGYqCm4gODQgMCAzLjYgNzAgcmUgZioKbiA4OC44IDAgMi40IDcwIHJlIGYqCm4gOTIuNCAwIDMuNiA3MCByZSBmKgpuIDk3LjIgMCAxLjIgNzAgcmUgZioKbiA5OS42IDAgMy42IDcwIHJlIGYqCm4gMTA0LjQgMCAyLjQgNzAgcmUgZioKbiAxMTAuNCAwIDEuMiA3MCByZSBmKgpuIDExMi44IDAgNC44IDcwIHJlIGYqCm4gMTE4LjggMCAzLjYgNzAgcmUgZioKbiAxMjMuNiAwIDMuNiA3MCByZSBmKgpuIDEyOC40IDAgMi40IDcwIHJlIGYqCm4gMTMyIDAgMy42IDcwIHJlIGYqCm4gMTM2LjggMCAyLjQgNzAgcmUgZioKbiAxNDEuNiAwIDEuMiA3MCByZSBmKgpuIDE0NS4yIDAgMy42IDcwIHJlIGYqCm4gMTUwIDAgMi40IDcwIHJlIGYqCm4gMTU2IDAgMy42IDcwIHJlIGYqCm4gMTYwLjggMCAxLjIgNzAgcmUgZioKbiAxNjMuMiAwIDIuNCA3MCByZSBmKgpRCkJUIC9GMSAxMCBUZiAxMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDQ3MiBUbSAoU2VjdGlvbiAzLjE6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQ0NCBUbSAoU2VjdGlvbiAzLjI6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQxNiBUbSAoU2VjdGlvbiAzLjM6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM4OCBUbSAoU2VjdGlvbiAzLjQ6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM2MCBUbSAoU2VjdGlvbiAzLjU6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMzMiBUbSAoU2VjdGlvbiAzLjY6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMwNCBUbSAoU2VjdGlvbiAzLjc6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDI3NiBUbSAoU2VjdGlvbiAzLjg6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVAogCmVuZHN0cmVhbQplbmRvYmoKMjEgMCBvYmoKPDwKL0xlbmd0aCAxNDk0Cj4+CnN0cmVhbQoxIDAgMCAxIDAgMCBjbSAgQlQgL0YxIDEyIFRmIDE0LjQgVEwgRVQKMCAwIDAgcmcKQlQgL0YxIDExIFRmIDEzLjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NzAgVG0gKFF1YXJ0ZXJseSBPcGVyYXRpb25zIFJlcG9ydCkgVGogVCogRVQKQlQgL0YyIDE2IFRmIDE5LjIgVEwgRVQKQlQgMSAwIDAgMSA0NSA3NDUgVG0gKEFwcHJvdmFsIFNpZ25hdHVyZSBhbmQgV2F0ZXJtYXJrKSBUaiBUKiBFVApCVCAvRjEgOSBUZiAxMC44IFRMIEVUCkJUIDEgMCAwIDEgNDUgMzAgVG0gKENvbmZpZGVudGlhbCB8IFBhZ2UgNCBvZiA1KSBUaiBUKiBFVApxCi44Mjc0NTEgLjgyNzQ1MSAuODI3NDUxIHJnCkJUIC9GMiA1NCBUZiA2NC44IFRMIEVUCi45MDYzMDggLjQyMjYxOCAtMC40MjI2MTggLjkwNjMwOCAxMTAgMzkwIGNtCkJUIDEgMCAwIDEgMCAwIFRtIChEUkFGVCkgVGogVCogRVQKUQowIDAgMCByZwpCVCAvRjEgMTIgVGYgMTQuNCBUTCBFVApCVCAxIDAgMCAxIDQ1IDYzNSBUbSAoQXBwcm92ZWQgYnk6IEpvcmRhbiBMZWUpIFRqIFQqIEVUCm4gNDUgNjEwIG0gMzEwIDYxMCBsIFMKbiA1NSA1OTUgbSA3NSA2MjUgMTEyIDYwMiAxNTUgNjAwIGMgUwpCVCAxIDAgMCAxIDQ1IDU4MCBUbSAoU2lnbmF0dXJlKSBUaiBUKiBFVApCVCAvRjEgMTAgVGYgMTIgVEwgRVQKQlQgMSAwIDAgMSA0NSA0NzIgVG0gKFNlY3Rpb24gNC4xOiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA0NDQgVG0gKFNlY3Rpb24gNC4yOiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSA0MTYgVG0gKFNlY3Rpb24gNC4zOiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzODggVG0gKFNlY3Rpb24gNC40OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzNjAgVG0gKFNlY3Rpb24gNC41OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzMzIgVG0gKFNlY3Rpb24gNC42OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAzMDQgVG0gKFNlY3Rpb24gNC43OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKQlQgMSAwIDAgMSA0NSAyNzYgVG0gKFNlY3Rpb24gNC44OiBJbnZvaWNlIHRvdGFscywgcmVnaW9uYWwgcmV2ZW51ZSwgYW5kIHJlY29uY2lsaWF0aW9uIG5vdGVzLikgVGogVCogRVQKIAplbmRzdHJlYW0KZW5kb2JqCjIyIDAgb2JqCjw8Ci9MZW5ndGggMTMyNwo+PgpzdHJlYW0KMSAwIDAgMSAwIDAgY20gIEJUIC9GMSAxMiBUZiAxNC40IFRMIEVUCjAgMCAwIHJnCkJUIC9GMSAxMSBUZiAxMy4yIFRMIEVUCkJUIDEgMCAwIDEgNDUgNzcwIFRtIChRdWFydGVybHkgT3BlcmF0aW9ucyBSZXBvcnQpIFRqIFQqIEVUCkJUIC9GMiAxNiBUZiAxOS4yIFRMIEVUCkJUIDEgMCAwIDEgNDUgNzQ1IFRtIChBcHBlbmRpeCB3aXRoIFNlY3Rpb24gQm91bmRhcmllcykgVGogVCogRVQKQlQgL0YxIDkgVGYgMTAuOCBUTCBFVApCVCAxIDAgMCAxIDQ1IDMwIFRtIChDb25maWRlbnRpYWwgfCBQYWdlIDUgb2YgNSkgVGogVCogRVQKQlQgL0YyIDE0IFRmIDE2LjggVEwgRVQKQlQgMSAwIDAgMSA0NSA3MDAgVG0gKDEuIFNjb3BlKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDY1MCBUbSAoMi4gRmluZGluZ3MpIFRqIFQqIEVUCkJUIDEgMCAwIDEgNDUgNjAwIFRtICgzLiBSZWNvbW1lbmRhdGlvbnMpIFRqIFQqIEVUCkJUIC9GMSAxMCBUZiAxMiBUTCBFVApCVCAxIDAgMCAxIDQ1IDQ3MiBUbSAoU2VjdGlvbiA1LjE6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQ0NCBUbSAoU2VjdGlvbiA1LjI6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDQxNiBUbSAoU2VjdGlvbiA1LjM6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM4OCBUbSAoU2VjdGlvbiA1LjQ6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDM2MCBUbSAoU2VjdGlvbiA1LjU6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMzMiBUbSAoU2VjdGlvbiA1LjY6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDMwNCBUbSAoU2VjdGlvbiA1Ljc6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVApCVCAxIDAgMCAxIDQ1IDI3NiBUbSAoU2VjdGlvbiA1Ljg6IEludm9pY2UgdG90YWxzLCByZWdpb25hbCByZXZlbnVlLCBhbmQgcmVjb25jaWxpYXRpb24gbm90ZXMuKSBUaiBUKiBFVAogCmVuZHN0cmVhbQplbmRvYmoKeHJlZgowIDIzCjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDA2MSAwMDAwMCBuIAowMDAwMDAwMTAyIDAwMDAwIG4gCjAwMDAwMDAyMDkgMDAwMDAgbiAKMDAwMDAwMDMyMSAwMDAwMCBuIAowMDAwMDAwNTE2IDAwMDAwIG4gCjAwMDAwMDYzMjIgMDAwMDAgbiAKMDAwMDAxMjgyNCAwMDAwMCBuIAowMDAwMDE0MTQyIDAwMDAwIG4gCjAwMDAwMTQ0OTYgMDAwMDAgbiAKMDAwMDAxNDY2NCAwMDAwMCBuIAowMDAwMDE0ODUwIDAwMDAwIG4gCjAwMDAwMTUwMjggMDAwMDAgbiAKMDAwMDAxNTI1NiAwMDAwMCBuIAowMDAwMDE1NDUyIDAwMDAwIG4gCjAwMDAwMTU2NDggMDAwMDAgbiAKMDAwMDAxNTcxOCAwMDAwMCBuIAowMDAwMDE2MTE1IDAwMDAwIG4gCjAwMDAwMTYyMDIgMDAwMDAgbiAKMDAwMDAxODUzNCAwMDAwMCBuIAowMDAwMDIwMzA5IDAwMDAwIG4gCjAwMDAwMjI4MjcgMDAwMDAgbiAKMDAwMDAyNDM3MyAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9JRCAKWzwyZjUwODkzYTFlYWZmMTExOWMwNDcwZmM0YzU3ZTI0Nz48MmY1MDg5M2ExZWFmZjExMTljMDQ3MGZjNGM1N2UyNDc+XQolIFJlcG9ydExhYiBnZW5lcmF0ZWQgUERGIGRvY3VtZW50IC0tIGRpZ2VzdCAob3BlbnNvdXJjZSkKCi9JbmZvIDE2IDAgUgovUm9vdCAxNSAwIFIKL1NpemUgMjMKPj4Kc3RhcnR4cmVmCjI1NzUyCiUlRU9GCg==", - "type": "document_url" - }, - "model": "mistral/invalid-ocr-model-for-parity" - }, - "provider_responses": [ - { - "body_b64": "eyJvYmplY3QiOiJlcnJvciIsIm1lc3NhZ2UiOiJJbnZhbGlkIG1vZGVsOiBpbnZhbGlkLW9jci1tb2RlbC1mb3ItcGFyaXR5IiwidHlwZSI6ImludmFsaWRfbW9kZWwiLCJwYXJhbSI6bnVsbCwiY29kZSI6IjE1MDAiLCJyYXdfc3RhdHVzX2NvZGUiOjQwMH0=", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 23:54:08 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05f64-fa6f-76c9-8b39-fd7d42840ba2" - }, - { - "name": "x-kong-request-id", - "value": "01a05f64-fa6f-76c9-8b39-fd7d42840ba2" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "2" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "10" - }, - { - "name": "x-kong-proxy-latency", - "value": "16" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "CF-RAY", - "value": "a34832c9ae37ad44-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 400 - } - ] - }, - "recorded_at": "2026-09-01T23:54:08.641470Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/38dbc05d8508355879de894ecc0f46da887570de720a142e9df297bdd280608d.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/38dbc05d8508355879de894ecc0f46da887570de720a142e9df297bdd280608d.yaml new file mode 100644 index 00000000000..a9fd2d0fbec --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/38dbc05d8508355879de894ecc0f46da887570de720a142e9df297bdd280608d.yaml @@ -0,0 +1,85 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"document_annotation_format":{"type":"json_schema","json_schema":{"name":"document_title","description":"Extract + the visible document fields","schema":{"additionalProperties":false,"properties":{"title":{"type":"string"}},"required":["title"],"type":"object"},"strict":true}},"document_annotation_prompt":"Extract + the visible title"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":"{\"title\": + \"invoice 123\"}","usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d376581f74f9-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:18 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-664a-740d-a112-0a1183c302b3 + x-envoy-upstream-service-time: + - '402' + x-kong-proxy-latency: + - '20' + x-kong-request-id: + - 01a05e89-664a-740d-a112-0a1183c302b3 + x-kong-upstream-latency: + - '403' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '52' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:18.915814+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + document_annotation_format: + json_schema: + description: Extract the visible document fields + name: document_title + schema: + additionalProperties: false + properties: + title: + type: string + required: + - title + type: object + strict: true + type: json_schema + document_annotation_prompt: Extract the visible title + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/3d5f42192461789f547b42c8f1b625aa688e6cbd69e01f94d1f3205ef41ab830.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/3d5f42192461789f547b42c8f1b625aa688e6cbd69e01f94d1f3205ef41ab830.yaml new file mode 100644 index 00000000000..a471b8f7bae --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/3d5f42192461789f547b42c8f1b625aa688e6cbd69e01f94d1f3205ef41ab830.yaml @@ -0,0 +1,68 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"extract_header":true}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d37c9944d8a7-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:19 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-6a3a-76c7-85b8-d40a7156155e + x-envoy-upstream-service-time: + - '230' + x-kong-proxy-latency: + - '16' + x-kong-request-id: + - 01a05e89-6a3a-76c7-85b8-d40a7156155e + x-kong-upstream-latency: + - '230' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '51' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:19.420285+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + extract_header: true + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/3e4f8a006942b85eb954833d42cc19740883cf42bb87221eafd16df3e597ceda.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/3e4f8a006942b85eb954833d42cc19740883cf42bb87221eafd16df3e597ceda.json deleted file mode 100644 index e850ffe1a9e..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/3e4f8a006942b85eb954833d42cc19740883cf42bb87221eafd16df3e597ceda.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "case": { - "litellm_input": { - "bbox_annotation_format": { - "json_schema": { - "description": "Extract the visible document fields", - "name": "bounding_boxes", - "schema": { - "additionalProperties": false, - "properties": { - "title": { - "type": "string" - } - }, - "required": [ - "title" - ], - "type": "object" - }, - "strict": true - }, - "type": "json_schema" - }, - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:16 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-5e6e-70ac-890d-c0110a5e81af" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-5e6e-70ac-890d-c0110a5e81af" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "54" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "210" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "212" - }, - { - "name": "x-kong-proxy-latency", - "value": "17" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d369be838fc5-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:16.402593Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/49328aed7d9a4833427d80c7ac4f54fc03ab0db9076004caf5262ce3fed4f06b.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/49328aed7d9a4833427d80c7ac4f54fc03ab0db9076004caf5262ce3fed4f06b.json deleted file mode 100644 index 5c5284f6908..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/49328aed7d9a4833427d80c7ac4f54fc03ab0db9076004caf5262ce3fed4f06b.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:13 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-52b4-7e7b-983e-5bc4e5469b39" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-52b4-7e7b-983e-5bc4e5469b39" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "59" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "554" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "557" - }, - { - "name": "x-kong-proxy-latency", - "value": "13" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d356fb3698ce-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:13.880852Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/54ce0991a21ea668e2373d2b05801606b7039583f55a0f85bfe38c7c15712adf.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/54ce0991a21ea668e2373d2b05801606b7039583f55a0f85bfe38c7c15712adf.yaml new file mode 100644 index 00000000000..90a4abd5574 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/54ce0991a21ea668e2373d2b05801606b7039583f55a0f85bfe38c7c15712adf.yaml @@ -0,0 +1,67 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d356fb3698ce-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:13 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-52b4-7e7b-983e-5bc4e5469b39 + x-envoy-upstream-service-time: + - '554' + x-kong-proxy-latency: + - '13' + x-kong-request-id: + - 01a05e89-52b4-7e7b-983e-5bc4e5469b39 + x-kong-upstream-latency: + - '557' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '59' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:13.880852+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/67a074c43483176b6a8da74f21869eb5c13a7327ed36f77a40c0b192c3a1bf4f.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/67a074c43483176b6a8da74f21869eb5c13a7327ed36f77a40c0b192c3a1bf4f.json deleted file mode 100644 index b41ca54e61d..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/67a074c43483176b6a8da74f21869eb5c13a7327ed36f77a40c0b192c3a1bf4f.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "case": { - "litellm_input": { - "bbox_annotation_format": { - "json_schema": { - "description": "Extract the visible document fields", - "name": "bounding_boxes", - "schema": { - "additionalProperties": false, - "properties": { - "title": { - "type": "string" - } - }, - "required": [ - "title" - ], - "type": "object" - }, - "strict": true - }, - "type": "json_schema" - }, - "confidence_scores_granularity": "page", - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "extract_footer": false, - "extract_header": true, - "id": "case-1", - "image_limit": 1, - "image_min_size": 300, - "include_blocks": false, - "include_image_base64": true, - "model": "mistral/mistral-ocr-latest", - "pages": [ - 0 - ], - "table_format": "markdown" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiVGVzdCBQREYgRmlsZSIsImltYWdlcyI6W10sInRhYmxlcyI6W10sImh5cGVybGlua3MiOltdLCJoZWFkZXIiOm51bGwsImZvb3RlciI6bnVsbCwiZGltZW5zaW9ucyI6eyJkcGkiOjkzLCJoZWlnaHQiOjEwMjMsIndpZHRoIjo3OTF9LCJjb25maWRlbmNlX3Njb3JlcyI6eyJ3b3JkX2NvbmZpZGVuY2Vfc2NvcmVzIjpbXSwiYXZlcmFnZV9wYWdlX2NvbmZpZGVuY2Vfc2NvcmUiOjAuOTM3NjIyOTc0NDMyMjkzNiwibWluaW11bV9wYWdlX2NvbmZpZGVuY2Vfc2NvcmUiOjAuMjI1OTA1NTA3OTYwMzY4MzV9LCJibG9ja3MiOm51bGx9XSwibW9kZWwiOiJtaXN0cmFsLW9jci1sYXRlc3QiLCJkb2N1bWVudF9hbm5vdGF0aW9uIjpudWxsLCJ1c2FnZV9pbmZvIjp7InBhZ2VzX3Byb2Nlc3NlZCI6MSwiZG9jX3NpemVfYnl0ZXMiOjU4OX19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:24 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-7deb-72b4-976d-4c244b056782" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-7deb-72b4-976d-4c244b056782" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "45" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "373" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "373" - }, - { - "name": "x-kong-proxy-latency", - "value": "17" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d39c1fe5cf12-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:24.951956Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/7f7dc004625cb90e3f4bd2f473fda532390140ade4e10b5bb07570ca7b372499.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/7f7dc004625cb90e3f4bd2f473fda532390140ade4e10b5bb07570ca7b372499.yaml new file mode 100644 index 00000000000..748948e5e8c --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/7f7dc004625cb90e3f4bd2f473fda532390140ade4e10b5bb07570ca7b372499.yaml @@ -0,0 +1,82 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"bbox_annotation_format":{"type":"json_schema","json_schema":{"name":"bounding_boxes","description":"Extract + the visible document fields","schema":{"additionalProperties":false,"properties":{"title":{"type":"string"}},"required":["title"],"type":"object"},"strict":true}}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d369be838fc5-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:16 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-5e6e-70ac-890d-c0110a5e81af + x-envoy-upstream-service-time: + - '210' + x-kong-proxy-latency: + - '17' + x-kong-request-id: + - 01a05e89-5e6e-70ac-890d-c0110a5e81af + x-kong-upstream-latency: + - '212' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '54' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:16.402593+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + bbox_annotation_format: + json_schema: + description: Extract the visible document fields + name: bounding_boxes + schema: + additionalProperties: false + properties: + title: + type: string + required: + - title + type: object + strict: true + type: json_schema + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/99d9d5ac0449213a562a36163ee598ef9e6df1813bee21137e88bcc14ce7a473.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/99d9d5ac0449213a562a36163ee598ef9e6df1813bee21137e88bcc14ce7a473.yaml new file mode 100644 index 00000000000..80c9a75578a --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/99d9d5ac0449213a562a36163ee598ef9e6df1813bee21137e88bcc14ce7a473.yaml @@ -0,0 +1,92 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"document_url","document_url":"data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg=="},"pages":[0],"include_image_base64":true,"image_limit":1,"image_min_size":300,"bbox_annotation_format":{"type":"json_schema","json_schema":{"name":"bounding_boxes","description":"Extract + the visible document fields","schema":{"additionalProperties":false,"properties":{"title":{"type":"string"}},"required":["title"],"type":"object"},"strict":true}},"extract_header":true,"extract_footer":false,"table_format":"markdown","confidence_scores_granularity":"page","include_blocks":false,"id":"case-1"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"Test PDF File","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":93,"height":1023,"width":791},"confidence_scores":{"word_confidence_scores":[],"average_page_confidence_score":0.9376229744322936,"minimum_page_confidence_score":0.22590550796036835},"blocks":null}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":589}}' + headers: + CF-RAY: + - a346d39c1fe5cf12-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:24 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-7deb-72b4-976d-4c244b056782 + x-envoy-upstream-service-time: + - '373' + x-kong-proxy-latency: + - '17' + x-kong-request-id: + - 01a05e89-7deb-72b4-976d-4c244b056782 + x-kong-upstream-latency: + - '373' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '45' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:24.951956+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + bbox_annotation_format: + json_schema: + description: Extract the visible document fields + name: bounding_boxes + schema: + additionalProperties: false + properties: + title: + type: string + required: + - title + type: object + strict: true + type: json_schema + confidence_scores_granularity: page + contract: mistral + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + extract_footer: false + extract_header: true + id: case-1 + image_limit: 1 + image_min_size: 300 + include_blocks: false + include_image_base64: true + model: mistral/mistral-ocr-latest + pages: + - 0 + table_format: markdown + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/9b9fb2f3a7eb8ca1e2d128ea96b358dc7c9b0eafc64e7e2516d46e290fc93092.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/9b9fb2f3a7eb8ca1e2d128ea96b358dc7c9b0eafc64e7e2516d46e290fc93092.yaml new file mode 100644 index 00000000000..847bac3f431 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/9b9fb2f3a7eb8ca1e2d128ea96b358dc7c9b0eafc64e7e2516d46e290fc93092.yaml @@ -0,0 +1,83 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"document_annotation_format":{"type":"json_schema","json_schema":{"name":"document_title","description":"Extract + the visible document fields","schema":{"additionalProperties":false,"properties":{"title":{"type":"string"}},"required":["title"],"type":"object"},"strict":true}}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":"{\"title\": + \"Invoice_123\"}","usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d36cd82f15ba-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:17 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-6060-71cb-9e35-66ab873b99f3 + x-envoy-upstream-service-time: + - '888' + x-kong-proxy-latency: + - '12' + x-kong-request-id: + - 01a05e89-6060-71cb-9e35-66ab873b99f3 + x-kong-upstream-latency: + - '889' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '53' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:17.908846+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + document_annotation_format: + json_schema: + description: Extract the visible document fields + name: document_title + schema: + additionalProperties: false + properties: + title: + type: string + required: + - title + type: object + strict: true + type: json_schema + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/9f220bfe8a2042fa74e1dada33facf8c80e20574f6ef9782997eaef9adc10e0b.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/9f220bfe8a2042fa74e1dada33facf8c80e20574f6ef9782997eaef9adc10e0b.json deleted file mode 100644 index 2df35ce95fb..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/9f220bfe8a2042fa74e1dada33facf8c80e20574f6ef9782997eaef9adc10e0b.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "image_min_size": 300, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:15 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-5c60-769b-abf3-44dcefdf5282" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-5c60-769b-abf3-44dcefdf5282" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "55" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "272" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "273" - }, - { - "name": "x-kong-proxy-latency", - "value": "17" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "CF-RAY", - "value": "a346d36688d203c2-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:15.898087Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/a8693352d9ce0d7d120b2351d2257cd562048fc6a993cba093fe86a8937d104b.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/a8693352d9ce0d7d120b2351d2257cd562048fc6a993cba093fe86a8937d104b.yaml new file mode 100644 index 00000000000..3b5f8bb85e1 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/a8693352d9ce0d7d120b2351d2257cd562048fc6a993cba093fe86a8937d104b.yaml @@ -0,0 +1,68 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"include_image_base64":true}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d360593c138a-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:14 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-588e-7e32-a54b-f816bc6c1dc4 + x-envoy-upstream-service-time: + - '242' + x-kong-proxy-latency: + - '16' + x-kong-request-id: + - 01a05e89-588e-7e32-a54b-f816bc6c1dc4 + x-kong-upstream-latency: + - '242' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '57' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:14.889667+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + include_image_base64: true + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/afc42ea89caa932d7ea33666d91e4f1a486bbe3165f5be777e67376075fd89a8.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/afc42ea89caa932d7ea33666d91e4f1a486bbe3165f5be777e67376075fd89a8.json deleted file mode 100644 index a863479da52..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/afc42ea89caa932d7ea33666d91e4f1a486bbe3165f5be777e67376075fd89a8.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "document_annotation_format": { - "json_schema": { - "description": "Extract the visible document fields", - "name": "document_title", - "schema": { - "additionalProperties": false, - "properties": { - "title": { - "type": "string" - } - }, - "required": [ - "title" - ], - "type": "object" - }, - "strict": true - }, - "type": "json_schema" - }, - "document_annotation_prompt": "Extract the visible title", - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOiJ7XCJ0aXRsZVwiOiBcImludm9pY2UgMTIzXCJ9IiwidXNhZ2VfaW5mbyI6eyJwYWdlc19wcm9jZXNzZWQiOjEsImRvY19zaXplX2J5dGVzIjo0MTI0fX0=", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:18 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-664a-740d-a112-0a1183c302b3" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-664a-740d-a112-0a1183c302b3" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "52" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "402" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "403" - }, - { - "name": "x-kong-proxy-latency", - "value": "20" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d376581f74f9-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:18.915814Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/b19fdc140375a4eadfd6eb4e4cbe88e27651580bac1e145ad352728b1a0acd31.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/b19fdc140375a4eadfd6eb4e4cbe88e27651580bac1e145ad352728b1a0acd31.yaml new file mode 100644 index 00000000000..acabdaf2b5e --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/b19fdc140375a4eadfd6eb4e4cbe88e27651580bac1e145ad352728b1a0acd31.yaml @@ -0,0 +1,68 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"image_min_size":300}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d36688d203c2-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:15 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-5c60-769b-abf3-44dcefdf5282 + x-envoy-upstream-service-time: + - '272' + x-kong-proxy-latency: + - '17' + x-kong-request-id: + - 01a05e89-5c60-769b-abf3-44dcefdf5282 + x-kong-upstream-latency: + - '273' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '55' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:15.898087+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + image_min_size: 300 + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/bdb616d21dece89481debccb9358047b28006b5cbd4486d54c6fe89070e7a671.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/bdb616d21dece89481debccb9358047b28006b5cbd4486d54c6fe89070e7a671.yaml new file mode 100644 index 00000000000..ed060cd05ca --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/bdb616d21dece89481debccb9358047b28006b5cbd4486d54c6fe89070e7a671.yaml @@ -0,0 +1,68 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"id":"case-1"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d398da783ad4-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:23 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-7bdc-74c5-b8eb-15fbd25b6cfd + x-envoy-upstream-service-time: + - '182' + x-kong-proxy-latency: + - '22' + x-kong-request-id: + - 01a05e89-7bdc-74c5-b8eb-15fbd25b6cfd + x-kong-upstream-latency: + - '183' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '46' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:23.946966+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + id: case-1 + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c3066e2f2f964725b71ae891821d77447359bba8c29d6b31e650255298271d47.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c3066e2f2f964725b71ae891821d77447359bba8c29d6b31e650255298271d47.yaml new file mode 100644 index 00000000000..22d01018046 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c3066e2f2f964725b71ae891821d77447359bba8c29d6b31e650255298271d47.yaml @@ -0,0 +1,67 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"include_blocks":false}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":null}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d392a8432af7-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:22 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-7802-768c-bf57-9021a209ab48 + x-envoy-upstream-service-time: + - '213' + x-kong-proxy-latency: + - '17' + x-kong-request-id: + - 01a05e89-7802-768c-bf57-9021a209ab48 + x-kong-upstream-latency: + - '214' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '47' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:23.442341+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + include_blocks: false + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c57601c90e9b289e506cdc818523bba41a29b707d0cfafd74986e6ad8c2ed900.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c57601c90e9b289e506cdc818523bba41a29b707d0cfafd74986e6ad8c2ed900.yaml new file mode 100644 index 00000000000..9d1a1e55835 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c57601c90e9b289e506cdc818523bba41a29b707d0cfafd74986e6ad8c2ed900.yaml @@ -0,0 +1,68 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"confidence_scores_granularity":"page"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":{"word_confidence_scores":[],"average_page_confidence_score":0.90845564554897,"minimum_page_confidence_score":0.16168208839823475},"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d38c59681749-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:22 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-7411-7d2c-9e43-01320e4cad1c + x-envoy-upstream-service-time: + - '329' + x-kong-proxy-latency: + - '14' + x-kong-request-id: + - 01a05e89-7411-7d2c-9e43-01320e4cad1c + x-kong-upstream-latency: + - '330' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '48' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:22.437385+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + confidence_scores_granularity: page + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c5d33cb2b20fb76c9543ff57dc9b3b7dc37c5bf5dfd47e873c4cc695d6d7461f.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c5d33cb2b20fb76c9543ff57dc9b3b7dc37c5bf5dfd47e873c4cc695d6d7461f.yaml new file mode 100644 index 00000000000..7afaa689756 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c5d33cb2b20fb76c9543ff57dc9b3b7dc37c5bf5dfd47e873c4cc695d6d7461f.yaml @@ -0,0 +1,68 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"extract_footer":true}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d37fde0f1703-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:20 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-6c42-7ea1-b08b-07cae50734e0 + x-envoy-upstream-service-time: + - '523' + x-kong-proxy-latency: + - '13' + x-kong-request-id: + - 01a05e89-6c42-7ea1-b08b-07cae50734e0 + x-kong-upstream-latency: + - '525' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '50' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:20.425444+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + extract_footer: true + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c6f0f158205be7fc00bd962e341689c3583b09694a7ac086e4707be49b35eb06.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c6f0f158205be7fc00bd962e341689c3583b09694a7ac086e4707be49b35eb06.yaml new file mode 100644 index 00000000000..09c39780583 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c6f0f158205be7fc00bd962e341689c3583b09694a7ac086e4707be49b35eb06.yaml @@ -0,0 +1,83 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"document_url","document_url":"data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg=="},"document_annotation_format":{"type":"json_schema","json_schema":{"name":"document_title","description":"Extract + the visible document fields","schema":{"additionalProperties":false,"properties":{"title":{"type":"string"}},"required":["title"],"type":"object"},"strict":true}}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"Test PDF File","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":93,"height":1023,"width":791},"confidence_scores":null,"blocks":[{"top_left_x":126,"top_left_y":104,"bottom_right_x":229,"bottom_right_y":127,"content":"Test + PDF File","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":"{\"title\": + \"Test_PDF_File\"}","usage_info":{"pages_processed":1,"doc_size_bytes":589}}' + headers: + CF-RAY: + - a346d3a25d0cccb8-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:25 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-81d5-79f8-914d-e3863af2d24b + x-envoy-upstream-service-time: + - '448' + x-kong-proxy-latency: + - '15' + x-kong-request-id: + - 01a05e89-81d5-79f8-914d-e3863af2d24b + x-kong-upstream-latency: + - '449' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '44' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:25.959391+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + document_annotation_format: + json_schema: + description: Extract the visible document fields + name: document_title + schema: + additionalProperties: false + properties: + title: + type: string + required: + - title + type: object + strict: true + type: json_schema + model: mistral/mistral-ocr-latest + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c74f9b5ad64bd97d8b4c48772c9ee17598a3a1265a630f9a6e42a2df352906bf.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c74f9b5ad64bd97d8b4c48772c9ee17598a3a1265a630f9a6e42a2df352906bf.json deleted file mode 100644 index 258236960e1..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/c74f9b5ad64bd97d8b4c48772c9ee17598a3a1265a630f9a6e42a2df352906bf.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "case": { - "litellm_input": { - "confidence_scores_granularity": "page", - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOnsid29yZF9jb25maWRlbmNlX3Njb3JlcyI6W10sImF2ZXJhZ2VfcGFnZV9jb25maWRlbmNlX3Njb3JlIjowLjkwODQ1NTY0NTU0ODk3LCJtaW5pbXVtX3BhZ2VfY29uZmlkZW5jZV9zY29yZSI6MC4xNjE2ODIwODgzOTgyMzQ3NX0sImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:22 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-7411-7d2c-9e43-01320e4cad1c" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-7411-7d2c-9e43-01320e4cad1c" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "48" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "329" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "330" - }, - { - "name": "x-kong-proxy-latency", - "value": "14" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "CF-RAY", - "value": "a346d38c59681749-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:22.437385Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/cd2461bbef1fc222e80b3397231c79a7f6895b1d6ef5c8f544bae77854bfd951.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/cd2461bbef1fc222e80b3397231c79a7f6895b1d6ef5c8f544bae77854bfd951.json deleted file mode 100644 index 8b0adfe8406..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/cd2461bbef1fc222e80b3397231c79a7f6895b1d6ef5c8f544bae77854bfd951.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "model": "mistral/mistral-ocr-latest", - "pages": [ - 0 - ] - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:14 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-5685-747f-b76d-dab242ea7512" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-5685-747f-b76d-dab242ea7512" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "58" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "179" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "180" - }, - { - "name": "x-kong-proxy-latency", - "value": "12" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d35d1fbbebe5-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:14.385374Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/cea250810b49cd17251ee8c036eae74dd363ddda0d6677155afbd145d0dc3c36.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/cea250810b49cd17251ee8c036eae74dd363ddda0d6677155afbd145d0dc3c36.yaml new file mode 100644 index 00000000000..85d37a96634 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/cea250810b49cd17251ee8c036eae74dd363ddda0d6677155afbd145d0dc3c36.yaml @@ -0,0 +1,68 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"table_format":"markdown"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":null,"usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d385ffbda0f2-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:21 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-7015-7a8d-a18c-37b9ceacbe77 + x-envoy-upstream-service-time: + - '337' + x-kong-proxy-latency: + - '21' + x-kong-request-id: + - 01a05e89-7015-7a8d-a18c-37b9ceacbe77 + x-kong-upstream-latency: + - '338' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '49' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:21.430472+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + model: mistral/mistral-ocr-latest + table_format: markdown + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/d1aa25a0353a8ff15c49088247a6d73ea777503f904a6bff9960a25046085d0d.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/d1aa25a0353a8ff15c49088247a6d73ea777503f904a6bff9960a25046085d0d.json deleted file mode 100644 index 56a42b8b1b3..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/d1aa25a0353a8ff15c49088247a6d73ea777503f904a6bff9960a25046085d0d.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "include_image_base64": true, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:14 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-588e-7e32-a54b-f816bc6c1dc4" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-588e-7e32-a54b-f816bc6c1dc4" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "57" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "242" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "242" - }, - { - "name": "x-kong-proxy-latency", - "value": "16" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d360593c138a-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:14.889667Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/d80a6ccca02922ba9094426235a6ab165f1866eb074a8c079273eef5df512985.yaml b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/d80a6ccca02922ba9094426235a6ab165f1866eb074a8c079273eef5df512985.yaml new file mode 100644 index 00000000000..5e8fe1a1cdc --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/d80a6ccca02922ba9094426235a6ab165f1866eb074a8c079273eef5df512985.yaml @@ -0,0 +1,105 @@ +interactions: +- request: + body: '{"model":"mistral-ocr-latest","document":{"type":"image_url","image_url":"https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24"},"pages":[0],"include_image_base64":false,"image_min_size":300,"bbox_annotation_format":{"type":"json_schema","json_schema":{"name":"bounding_boxes","description":"Extract + the visible document fields","schema":{"additionalProperties":false,"properties":{"title":{"type":"string"}},"required":["title"],"type":"object"},"strict":true}},"document_annotation_format":{"type":"json_schema","json_schema":{"name":"document_title","description":"Extract + the visible document fields","schema":{"additionalProperties":false,"properties":{"title":{"type":"string"}},"required":["title"],"type":"object"},"strict":true}},"extract_header":true,"table_format":"markdown","include_blocks":true}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/v1/ocr + response: + body: + string: '{"pages":[{"index":0,"markdown":"invoice 123","images":[],"tables":[],"hyperlinks":[],"header":null,"footer":null,"dimensions":{"dpi":200,"height":300,"width":800},"confidence_scores":null,"blocks":[{"top_left_x":335,"top_left_y":138,"bottom_right_x":464,"bottom_right_y":162,"content":"invoice + 123","confidence_scores":null,"type":"text"}]}],"model":"mistral-ocr-latest","document_annotation":"{\"title\": + \"Invoice_123\"}","usage_info":{"pages_processed":1,"doc_size_bytes":4124}}' + headers: + CF-RAY: + - a346d3a89a85f953-SJC + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:26 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=15552000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + mistral-correlation-id: + - 01a05e89-85bd-7075-af53-8e341b35a63e + x-envoy-upstream-service-time: + - '432' + x-kong-proxy-latency: + - '13' + x-kong-request-id: + - 01a05e89-85bd-7075-af53-8e341b35a63e + x-kong-upstream-latency: + - '433' + x-ratelimit-limit-ocr-pages-minute: + - '60' + x-ratelimit-ocr-pages-query-cost: + - '1' + x-ratelimit-remaining-ocr-pages-minute: + - '43' + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:26.965078+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + bbox_annotation_format: + json_schema: + description: Extract the visible document fields + name: bounding_boxes + schema: + additionalProperties: false + properties: + title: + type: string + required: + - title + type: object + strict: true + type: json_schema + contract: mistral + document: + image_url: https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24 + type: image_url + document_annotation_format: + json_schema: + description: Extract the visible document fields + name: document_title + schema: + additionalProperties: false + properties: + title: + type: string + required: + - title + type: object + strict: true + type: json_schema + extract_header: true + image_min_size: 300 + include_blocks: true + include_image_base64: false + model: mistral/mistral-ocr-latest + pages: + - 0 + table_format: markdown + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/e362d4eb7aa5f50706b54d0bbb777eebedf342e1844f9114d8db8b9de8a8b08b.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/e362d4eb7aa5f50706b54d0bbb777eebedf342e1844f9114d8db8b9de8a8b08b.json deleted file mode 100644 index 26ef9198a4a..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/e362d4eb7aa5f50706b54d0bbb777eebedf342e1844f9114d8db8b9de8a8b08b.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "document_annotation_format": { - "json_schema": { - "description": "Extract the visible document fields", - "name": "document_title", - "schema": { - "additionalProperties": false, - "properties": { - "title": { - "type": "string" - } - }, - "required": [ - "title" - ], - "type": "object" - }, - "strict": true - }, - "type": "json_schema" - }, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOiJ7XCJ0aXRsZVwiOiBcIkludm9pY2VfMTIzXCJ9IiwidXNhZ2VfaW5mbyI6eyJwYWdlc19wcm9jZXNzZWQiOjEsImRvY19zaXplX2J5dGVzIjo0MTI0fX0=", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:17 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-6060-71cb-9e35-66ab873b99f3" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-6060-71cb-9e35-66ab873b99f3" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "53" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "888" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "889" - }, - { - "name": "x-kong-proxy-latency", - "value": "12" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "CF-RAY", - "value": "a346d36cd82f15ba-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:17.908846Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/e9217f2a27a061f2ed26a567677d176db3731e07107f45318fb681740ee49a74.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/e9217f2a27a061f2ed26a567677d176db3731e07107f45318fb681740ee49a74.json deleted file mode 100644 index ac946e47da2..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/e9217f2a27a061f2ed26a567677d176db3731e07107f45318fb681740ee49a74.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "extract_header": true, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:19 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-6a3a-76c7-85b8-d40a7156155e" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-6a3a-76c7-85b8-d40a7156155e" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "51" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "230" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "230" - }, - { - "name": "x-kong-proxy-latency", - "value": "16" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "CF-RAY", - "value": "a346d37c9944d8a7-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:19.420285Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/ea3c537a691b95003afc21b351549d5a62e67fa9e6c51ba30de4eaf4bba5a73f.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/ea3c537a691b95003afc21b351549d5a62e67fa9e6c51ba30de4eaf4bba5a73f.json deleted file mode 100644 index e52dc13fe18..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/ea3c537a691b95003afc21b351549d5a62e67fa9e6c51ba30de4eaf4bba5a73f.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "id": "case-1", - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6W3sidG9wX2xlZnRfeCI6MzM1LCJ0b3BfbGVmdF95IjoxMzgsImJvdHRvbV9yaWdodF94Ijo0NjQsImJvdHRvbV9yaWdodF95IjoxNjIsImNvbnRlbnQiOiJpbnZvaWNlIDEyMyIsImNvbmZpZGVuY2Vfc2NvcmVzIjpudWxsLCJ0eXBlIjoidGV4dCJ9XX1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:23 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-7bdc-74c5-b8eb-15fbd25b6cfd" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-7bdc-74c5-b8eb-15fbd25b6cfd" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "46" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "182" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "183" - }, - { - "name": "x-kong-proxy-latency", - "value": "22" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "CF-RAY", - "value": "a346d398da783ad4-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:23.946966Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/effe3c112538d2aa6ac98e8f47033086cb79e87d2bdb99bdbb3b7e11751c43d7.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/effe3c112538d2aa6ac98e8f47033086cb79e87d2bdb99bdbb3b7e11751c43d7.json deleted file mode 100644 index 0282c98cc4e..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/effe3c112538d2aa6ac98e8f47033086cb79e87d2bdb99bdbb3b7e11751c43d7.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "document_annotation_format": { - "json_schema": { - "description": "Extract the visible document fields", - "name": "document_title", - "schema": { - "additionalProperties": false, - "properties": { - "title": { - "type": "string" - } - }, - "required": [ - "title" - ], - "type": "object" - }, - "strict": true - }, - "type": "json_schema" - }, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiVGVzdCBQREYgRmlsZSIsImltYWdlcyI6W10sInRhYmxlcyI6W10sImh5cGVybGlua3MiOltdLCJoZWFkZXIiOm51bGwsImZvb3RlciI6bnVsbCwiZGltZW5zaW9ucyI6eyJkcGkiOjkzLCJoZWlnaHQiOjEwMjMsIndpZHRoIjo3OTF9LCJjb25maWRlbmNlX3Njb3JlcyI6bnVsbCwiYmxvY2tzIjpbeyJ0b3BfbGVmdF94IjoxMjYsInRvcF9sZWZ0X3kiOjEwNCwiYm90dG9tX3JpZ2h0X3giOjIyOSwiYm90dG9tX3JpZ2h0X3kiOjEyNywiY29udGVudCI6IlRlc3QgUERGIEZpbGUiLCJjb25maWRlbmNlX3Njb3JlcyI6bnVsbCwidHlwZSI6InRleHQifV19XSwibW9kZWwiOiJtaXN0cmFsLW9jci1sYXRlc3QiLCJkb2N1bWVudF9hbm5vdGF0aW9uIjoie1widGl0bGVcIjogXCJUZXN0X1BERl9GaWxlXCJ9IiwidXNhZ2VfaW5mbyI6eyJwYWdlc19wcm9jZXNzZWQiOjEsImRvY19zaXplX2J5dGVzIjo1ODl9fQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:25 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-81d5-79f8-914d-e3863af2d24b" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-81d5-79f8-914d-e3863af2d24b" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "44" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "448" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "449" - }, - { - "name": "x-kong-proxy-latency", - "value": "15" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "CF-RAY", - "value": "a346d3a25d0cccb8-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:25.959391Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/f430ede1f4069abab794731b9c233573014c6353f8d2486cc34753ceab6c7c1a.json b/tests/test_litellm/ocr/fixtures/data/mistral-ocr/f430ede1f4069abab794731b9c233573014c6353f8d2486cc34753ceab6c7c1a.json deleted file mode 100644 index 5ac0eefa39b..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/mistral-ocr/f430ede1f4069abab794731b9c233573014c6353f8d2486cc34753ceab6c7c1a.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "image_url": "https://dummyjson.com/image/800x300/ffffff/000000?text=invoice%20123&fontSize=24", - "type": "image_url" - }, - "include_blocks": false, - "model": "mistral/mistral-ocr-latest" - }, - "provider_responses": [ - { - "body_b64": "eyJwYWdlcyI6W3siaW5kZXgiOjAsIm1hcmtkb3duIjoiaW52b2ljZSAxMjMiLCJpbWFnZXMiOltdLCJ0YWJsZXMiOltdLCJoeXBlcmxpbmtzIjpbXSwiaGVhZGVyIjpudWxsLCJmb290ZXIiOm51bGwsImRpbWVuc2lvbnMiOnsiZHBpIjoyMDAsImhlaWdodCI6MzAwLCJ3aWR0aCI6ODAwfSwiY29uZmlkZW5jZV9zY29yZXMiOm51bGwsImJsb2NrcyI6bnVsbH1dLCJtb2RlbCI6Im1pc3RyYWwtb2NyLWxhdGVzdCIsImRvY3VtZW50X2Fubm90YXRpb24iOm51bGwsInVzYWdlX2luZm8iOnsicGFnZXNfcHJvY2Vzc2VkIjoxLCJkb2Nfc2l6ZV9ieXRlcyI6NDEyNH19", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:22 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "mistral-correlation-id", - "value": "01a05e89-7802-768c-bf57-9021a209ab48" - }, - { - "name": "x-kong-request-id", - "value": "01a05e89-7802-768c-bf57-9021a209ab48" - }, - { - "name": "x-ratelimit-limit-ocr-pages-minute", - "value": "60" - }, - { - "name": "x-ratelimit-remaining-ocr-pages-minute", - "value": "47" - }, - { - "name": "x-ratelimit-ocr-pages-query-cost", - "value": "1" - }, - { - "name": "x-envoy-upstream-service-time", - "value": "213" - }, - { - "name": "Server", - "value": "cloudflare" - }, - { - "name": "access-control-allow-origin", - "value": "*" - }, - { - "name": "x-kong-upstream-latency", - "value": "214" - }, - { - "name": "x-kong-proxy-latency", - "value": "17" - }, - { - "name": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "name": "cf-cache-status", - "value": "DYNAMIC" - }, - { - "name": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains; preload" - }, - { - "name": "CF-RAY", - "value": "a346d392a8432af7-SJC" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=86400" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:23.442341Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/09cc2f0155ffdc3d25abff96797030105ad107ae3400532b20ad70ebbd021954.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/09cc2f0155ffdc3d25abff96797030105ad107ae3400532b20ad70ebbd021954.yaml new file mode 100644 index 00000000000..36cb1ff8ce1 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/09cc2f0155ffdc3d25abff96797030105ad107ae3400532b20ad70ebbd021954.yaml @@ -0,0 +1,70 @@ +interactions: +- request: + body: "--3d54cb2e388c04dbfc172c1497aaa396\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--3d54cb2e388c04dbfc172c1497aaa396--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=3d54cb2e388c04dbfc172c1497aaa396 + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://45d3cbbc-4d77-4967-8941-935b0c4a0493.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:58 GMT + status: + code: 200 + message: '' +- request: + body: '{"document_url":"reducto://45d3cbbc-4d77-4967-8941-935b0c4a0493.pdf"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"262ed683-ecd8-40b9-a568-f7b7014854c9","duration":2.4146597385406494,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/a91f568b-6e98-4962-9924-097202093779.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195456Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=aa77b33e20fc1426307688f55147d57e8d3b2286a787c096b2da016d7d7d0c93","studio_link":"https://studio.reducto.ai/job/cddd635e-5d16-4621-bf48-031e7637dc0b","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16352969387356803,"top":0.10490237663507056,"width":0.11855640077405508,"height":0.011359045881442221,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7126715332269669},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:59 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:59.198829+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_legacy + custom_llm_provider: reducto + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + model: parse-legacy + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/5671d085483943d56d3e16d95a0a8cf08e7dc5bbe1f7286d7c04a0454baf5c66.json b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/5671d085483943d56d3e16d95a0a8cf08e7dc5bbe1f7286d7c04a0454baf5c66.json deleted file mode 100644 index bee1e77d15a..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/5671d085483943d56d3e16d95a0a8cf08e7dc5bbe1f7286d7c04a0454baf5c66.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "case": { - "litellm_input": { - "custom_llm_provider": "reducto", - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "model": "parse-legacy" - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovLzQ1ZDNjYmJjLTRkNzctNDk2Ny04OTQxLTkzNWIwYzRhMDQ5My5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:58 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiIyNjJlZDY4My1lY2Q4LTQwYjktYTU2OC1mN2I3MDE0ODU0YzkiLCJkdXJhdGlvbiI6Mi40MTQ2NTk3Mzg1NDA2NDk0LCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvYTkxZjU2OGItNmU5OC00OTYyLTk5MjQtMDk3MjAyMDkzNzc5LnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQ1NlomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPWFhNzdiMzNlMjBmYzE0MjYzMDc2ODhmNTUxNDdkNTdlOGQzYjIyODZhNzg3YzA5NmIyZGEwMTZkN2Q3ZDBjOTMiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iL2NkZGQ2MzVlLTVkMTYtNDYyMS1iZjQ4LTAzMWU3NjM3ZGMwYiIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MzUyOTY5Mzg3MzU2ODAzLCJ0b3AiOjAuMTA0OTAyMzc2NjM1MDcwNTYsIndpZHRoIjowLjExODU1NjQwMDc3NDA1NTA4LCJoZWlnaHQiOjAuMDExMzU5MDQ1ODgxNDQyMjIxLCJwYWdlIjoxLCJvcmlnaW5hbF9wYWdlIjoxfSwiY29udGVudCI6IlRlc3QgUERGIEZpbGUiLCJpbWFnZV91cmwiOm51bGwsImNoYXJ0X2RhdGEiOm51bGwsImNvbmZpZGVuY2UiOiJoaWdoIiwiZ3JhbnVsYXJfY29uZmlkZW5jZSI6eyJleHRyYWN0X2NvbmZpZGVuY2UiOm51bGwsInBhcnNlX2NvbmZpZGVuY2UiOjAuNzEyNjcxNTMzMjI2OTY2OX0sImV4dHJhIjpudWxsfV19XSwib2NyIjpudWxsLCJjdXN0b20iOm51bGx9LCJwYXJzZV9tb2RlIjpudWxsLCJkb2N1bWVudF9wcm9wZXJ0aWVzIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:59 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:59.198829Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/7c4bbc65dfbc17bac7f0d179c5d7e201dfb9ac31de66094734ef38c288293625.json b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/7c4bbc65dfbc17bac7f0d179c5d7e201dfb9ac31de66094734ef38c288293625.json deleted file mode 100644 index 88998036863..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/7c4bbc65dfbc17bac7f0d179c5d7e201dfb9ac31de66094734ef38c288293625.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "reducto://invalid-document-for-parity", - "type": "document_url" - }, - "model": "reducto/parse-legacy" - }, - "provider_responses": [ - { - "body_b64": "eyJlcnJvciI6eyJjb2RlIjo0MDQsIm5hbWUiOiJOT1RfRk9VTkQiLCJtZXNzYWdlIjoiRG9jdW1lbnQgJ1RoZSBmaWxlIG1heSBoYXZlIGV4cGlyZWQgb3IgYmVlbiBkZWxldGVkLiBQbGVhc2UgcmUtdXBsb2FkIGFuZCB0cnkgYWdhaW4uJyBub3QgZm91bmQifSwiZGV0YWlsIjoiRG9jdW1lbnQgJ1RoZSBmaWxlIG1heSBoYXZlIGV4cGlyZWQgb3IgYmVlbiBkZWxldGVkLiBQbGVhc2UgcmUtdXBsb2FkIGFuZCB0cnkgYWdhaW4uJyBub3QgZm91bmQifQ==", - "headers": [ - { - "name": "Date", - "value": "Wed, 02 Sep 2026 01:14:06 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 404 - } - ] - }, - "recorded_at": "2026-09-02T01:14:06.814847Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/7c4bbc65dfbc17bac7f0d179c5d7e201dfb9ac31de66094734ef38c288293625.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/7c4bbc65dfbc17bac7f0d179c5d7e201dfb9ac31de66094734ef38c288293625.yaml new file mode 100644 index 00000000000..deb47484ec8 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/7c4bbc65dfbc17bac7f0d179c5d7e201dfb9ac31de66094734ef38c288293625.yaml @@ -0,0 +1,39 @@ +interactions: +- request: + body: '{"document_url":"reducto://invalid-document-for-parity"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"error":{"code":404,"name":"NOT_FOUND","message":"Document ''The file + may have expired or been deleted. Please re-upload and try again.'' not found"},"detail":"Document + ''The file may have expired or been deleted. Please re-upload and try again.'' + not found"}' + headers: + Content-Type: + - application/json + Date: + - Wed, 02 Sep 2026 01:14:06 GMT + status: + code: 404 + message: '' +recorded_at: '2026-09-02T01:14:06.814847+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_legacy + document: + document_url: reducto://invalid-document-for-parity + type: document_url + model: reducto/parse-legacy + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/953d2a3bfea5594f9df19fc3f6c37e51b7e915b96a85e4ce8dfc41ba5f7f11df.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/953d2a3bfea5594f9df19fc3f6c37e51b7e915b96a85e4ce8dfc41ba5f7f11df.yaml new file mode 100644 index 00000000000..1e1c7c44463 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/953d2a3bfea5594f9df19fc3f6c37e51b7e915b96a85e4ce8dfc41ba5f7f11df.yaml @@ -0,0 +1,70 @@ +interactions: +- request: + body: "--90e8e7e6a71b2a4b14695234a736d695\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--90e8e7e6a71b2a4b14695234a736d695--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=90e8e7e6a71b2a4b14695234a736d695 + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://b9f242fd-fdb4-4b0a-9535-f11f432c7678.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:57 GMT + status: + code: 200 + message: '' +- request: + body: '{"document_url":"reducto://b9f242fd-fdb4-4b0a-9535-f11f432c7678.pdf","options":{"enhance":{}}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"25b78189-66fe-46d9-8114-14372a9d442d","duration":2.4146597385406494,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/a91f568b-6e98-4962-9924-097202093779.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195456Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=aa77b33e20fc1426307688f55147d57e8d3b2286a787c096b2da016d7d7d0c93","studio_link":"https://studio.reducto.ai/job/cddd635e-5d16-4621-bf48-031e7637dc0b","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16352969387356803,"top":0.10490237663507056,"width":0.11855640077405508,"height":0.011359045881442221,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7126715332269669},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:57 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:58.471820+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_legacy + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + enhance: {} + model: reducto/parse-legacy + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/a41d4c9547448df927b308d619d7e3b8fdbfe1fb5a9818a2fe47f02c2aad0fac.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/a41d4c9547448df927b308d619d7e3b8fdbfe1fb5a9818a2fe47f02c2aad0fac.yaml new file mode 100644 index 00000000000..a7a927cf93c --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/a41d4c9547448df927b308d619d7e3b8fdbfe1fb5a9818a2fe47f02c2aad0fac.yaml @@ -0,0 +1,69 @@ +interactions: +- request: + body: "--87aea09e72c511f78d32f6eabd194f5c\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--87aea09e72c511f78d32f6eabd194f5c--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=87aea09e72c511f78d32f6eabd194f5c + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://a91f568b-6e98-4962-9924-097202093779.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:53 GMT + status: + code: 200 + message: '' +- request: + body: '{"document_url":"reducto://a91f568b-6e98-4962-9924-097202093779.pdf"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"cddd635e-5d16-4621-bf48-031e7637dc0b","duration":2.4146597385406494,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/a91f568b-6e98-4962-9924-097202093779.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195456Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=aa77b33e20fc1426307688f55147d57e8d3b2286a787c096b2da016d7d7d0c93","studio_link":"https://studio.reducto.ai/job/cddd635e-5d16-4621-bf48-031e7637dc0b","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16352969387356803,"top":0.10490237663507056,"width":0.11855640077405508,"height":0.011359045881442221,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7126715332269669},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:57 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:57.246119+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_legacy + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + model: reducto/parse-legacy + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/ea3262579a0882bcb61972e2a2aa4b0c7ae2e28ce957493e996a006ef2fcc6be.json b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/ea3262579a0882bcb61972e2a2aa4b0c7ae2e28ce957493e996a006ef2fcc6be.json deleted file mode 100644 index 34d76fe9abf..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/ea3262579a0882bcb61972e2a2aa4b0c7ae2e28ce957493e996a006ef2fcc6be.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "enhance": {}, - "model": "reducto/parse-legacy" - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovL2I5ZjI0MmZkLWZkYjQtNGIwYS05NTM1LWYxMWY0MzJjNzY3OC5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:57 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiIyNWI3ODE4OS02NmZlLTQ2ZDktODExNC0xNDM3MmE5ZDQ0MmQiLCJkdXJhdGlvbiI6Mi40MTQ2NTk3Mzg1NDA2NDk0LCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvYTkxZjU2OGItNmU5OC00OTYyLTk5MjQtMDk3MjAyMDkzNzc5LnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQ1NlomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPWFhNzdiMzNlMjBmYzE0MjYzMDc2ODhmNTUxNDdkNTdlOGQzYjIyODZhNzg3YzA5NmIyZGEwMTZkN2Q3ZDBjOTMiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iL2NkZGQ2MzVlLTVkMTYtNDYyMS1iZjQ4LTAzMWU3NjM3ZGMwYiIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MzUyOTY5Mzg3MzU2ODAzLCJ0b3AiOjAuMTA0OTAyMzc2NjM1MDcwNTYsIndpZHRoIjowLjExODU1NjQwMDc3NDA1NTA4LCJoZWlnaHQiOjAuMDExMzU5MDQ1ODgxNDQyMjIxLCJwYWdlIjoxLCJvcmlnaW5hbF9wYWdlIjoxfSwiY29udGVudCI6IlRlc3QgUERGIEZpbGUiLCJpbWFnZV91cmwiOm51bGwsImNoYXJ0X2RhdGEiOm51bGwsImNvbmZpZGVuY2UiOiJoaWdoIiwiZ3JhbnVsYXJfY29uZmlkZW5jZSI6eyJleHRyYWN0X2NvbmZpZGVuY2UiOm51bGwsInBhcnNlX2NvbmZpZGVuY2UiOjAuNzEyNjcxNTMzMjI2OTY2OX0sImV4dHJhIjpudWxsfV19XSwib2NyIjpudWxsLCJjdXN0b20iOm51bGx9LCJwYXJzZV9tb2RlIjpudWxsLCJkb2N1bWVudF9wcm9wZXJ0aWVzIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:57 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:58.471820Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/fbf21ae169e9ddbca638f445bad921e3e782e4e9f10be9a4ba000a8caf1e9ab5.json b/tests/test_litellm/ocr/fixtures/data/reducto-legacy/fbf21ae169e9ddbca638f445bad921e3e782e4e9f10be9a4ba000a8caf1e9ab5.json deleted file mode 100644 index 3761d4e1f45..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-legacy/fbf21ae169e9ddbca638f445bad921e3e782e4e9f10be9a4ba000a8caf1e9ab5.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "model": "reducto/parse-legacy" - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovL2E5MWY1NjhiLTZlOTgtNDk2Mi05OTI0LTA5NzIwMjA5Mzc3OS5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:53 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiJjZGRkNjM1ZS01ZDE2LTQ2MjEtYmY0OC0wMzFlNzYzN2RjMGIiLCJkdXJhdGlvbiI6Mi40MTQ2NTk3Mzg1NDA2NDk0LCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvYTkxZjU2OGItNmU5OC00OTYyLTk5MjQtMDk3MjAyMDkzNzc5LnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQ1NlomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPWFhNzdiMzNlMjBmYzE0MjYzMDc2ODhmNTUxNDdkNTdlOGQzYjIyODZhNzg3YzA5NmIyZGEwMTZkN2Q3ZDBjOTMiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iL2NkZGQ2MzVlLTVkMTYtNDYyMS1iZjQ4LTAzMWU3NjM3ZGMwYiIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MzUyOTY5Mzg3MzU2ODAzLCJ0b3AiOjAuMTA0OTAyMzc2NjM1MDcwNTYsIndpZHRoIjowLjExODU1NjQwMDc3NDA1NTA4LCJoZWlnaHQiOjAuMDExMzU5MDQ1ODgxNDQyMjIxLCJwYWdlIjoxLCJvcmlnaW5hbF9wYWdlIjoxfSwiY29udGVudCI6IlRlc3QgUERGIEZpbGUiLCJpbWFnZV91cmwiOm51bGwsImNoYXJ0X2RhdGEiOm51bGwsImNvbmZpZGVuY2UiOiJoaWdoIiwiZ3JhbnVsYXJfY29uZmlkZW5jZSI6eyJleHRyYWN0X2NvbmZpZGVuY2UiOm51bGwsInBhcnNlX2NvbmZpZGVuY2UiOjAuNzEyNjcxNTMzMjI2OTY2OX0sImV4dHJhIjpudWxsfV19XSwib2NyIjpudWxsLCJjdXN0b20iOm51bGx9LCJwYXJzZV9tb2RlIjpudWxsLCJkb2N1bWVudF9wcm9wZXJ0aWVzIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:57 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:57.246119Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/00312c58e0dccd4699086d6c37b45a56b19b4775393c22bf9fa6ead2c3cc323c.json b/tests/test_litellm/ocr/fixtures/data/reducto-v3/00312c58e0dccd4699086d6c37b45a56b19b4775393c22bf9fa6ead2c3cc323c.json deleted file mode 100644 index f4343921dd2..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-v3/00312c58e0dccd4699086d6c37b45a56b19b4775393c22bf9fa6ead2c3cc323c.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "case": { - "litellm_input": { - "custom_llm_provider": "reducto", - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "model": "parse-v3" - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovL2E2ZDNjM2JiLWE2ZjEtNDYzNi04YjNhLWVlOTIwYjI5ZDM4Ny5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:46 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiI0YTc4Yzk3NS0xODY1LTQ2ZmUtOGY4OS1iZWE5MmE0OWUyMTUiLCJkdXJhdGlvbiI6MS4xMTk0NDI3MDEzMzk3MjE3LCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvNmFiOWJjZjQtMTg5My00YjM3LWJkZGItYWNkYThjZTQ1ZGZiLnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQ0NVomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPTFkYjYxZDMzZjYwMmYxM2U4NDQ0ZTg1ODBiNzM3YjMxZjM0NmU0NzQ5M2NjN2VjYTdjNGZjZGRiZGUwZGZiNDMiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iL2QzNDU1NDlmLTVkOTgtNGM2Mi1iM2UzLTI0Yzk5MDE0NGRmNCIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MTg5NTc0NTI3MTgyNzQ4LCJ0b3AiOjAuMDk0NzkyOTU1NTM4MTQxMjEsIndpZHRoIjowLjExOTQ2MjkwNjUwODIwODc1LCJoZWlnaHQiOjAuMDIxNDY0MTQzMDE3MTA1MDcsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb250ZW50IjoiVGVzdCBQREYgRmlsZSIsImltYWdlX3VybCI6bnVsbCwiY2hhcnRfZGF0YSI6bnVsbCwiY29uZmlkZW5jZSI6ImhpZ2giLCJncmFudWxhcl9jb25maWRlbmNlIjp7ImV4dHJhY3RfY29uZmlkZW5jZSI6bnVsbCwicGFyc2VfY29uZmlkZW5jZSI6MC43MTg1MzU1NjkzMTAxODgyfSwiZXh0cmEiOm51bGx9XX1dLCJvY3IiOm51bGwsImN1c3RvbSI6bnVsbH0sInBhcnNlX21vZGUiOm51bGwsImRvY3VtZW50X3Byb3BlcnRpZXMiOm51bGx9", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:47 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:47.967951Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/0b4ca483494e37fce75cc861ba62f06ce970d117de9828d72ed76b71b6f5adc1.json b/tests/test_litellm/ocr/fixtures/data/reducto-v3/0b4ca483494e37fce75cc861ba62f06ce970d117de9828d72ed76b71b6f5adc1.json deleted file mode 100644 index 61080492535..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-v3/0b4ca483494e37fce75cc861ba62f06ce970d117de9828d72ed76b71b6f5adc1.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "case": { - "litellm_input": { - "custom_llm_provider": null, - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "formatting": { - "add_page_markers": true, - "include": [ - "change_tracking", - "highlight", - "comments" - ], - "merge_tables": true, - "table_output_format": "json" - }, - "model": "reducto/parse-v3" - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovL2Y4YmYxN2U4LWNhMGItNGFkZC1iNDg0LTk5ODJkMmU0YWMyYS5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:50 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiJlMzc5MjM4Ny04Mzg0LTQ1YWEtYjAyZS1hODQ1MjFkYjExNmEiLCJkdXJhdGlvbiI6MS4wNDk3MzYyNjEzNjc3OTc5LCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvZjhiZjE3ZTgtY2EwYi00YWRkLWI0ODQtOTk4MmQyZTRhYzJhLnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQ1MlomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPTczNjcyNzVhNjlkZmQ1M2Y5ZmNmOWYwMjc3N2YwZmU5NzNlN2U1NDFmYTE4NzFlMDM0N2Y3ODhiOGM1MDc4ZjQiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iL2UzNzkyMzg3LTgzODQtNDVhYS1iMDJlLWE4NDUyMWRiMTE2YSIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IltbU1RBUlQgT0YgUEFHRSAxXV1cblxuIyBUZXN0IFBERiBGaWxlXG5cbltbRU5EIE9GIFBBR0UgMV1dIiwiZW1iZWQiOiJbW1NUQVJUIE9GIFBBR0UgMV1dXG5cbiMgVGVzdCBQREYgRmlsZVxuXG5bW0VORCBPRiBQQUdFIDFdXSIsImVucmljaGVkIjpudWxsLCJlbnJpY2htZW50X3N1Y2Nlc3MiOmZhbHNlLCJibG9ja3MiOlt7InR5cGUiOiJQYWdlIE51bWJlciIsImJib3giOnsibGVmdCI6MC4wLCJ0b3AiOjAuMCwid2lkdGgiOjAuMCwiaGVpZ2h0IjowLjAsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb250ZW50IjoiW1tTVEFSVCBPRiBQQUdFIDFdXSIsImltYWdlX3VybCI6bnVsbCwiY2hhcnRfZGF0YSI6bnVsbCwiY29uZmlkZW5jZSI6ImhpZ2giLCJncmFudWxhcl9jb25maWRlbmNlIjp7ImV4dHJhY3RfY29uZmlkZW5jZSI6bnVsbCwicGFyc2VfY29uZmlkZW5jZSI6bnVsbH0sImV4dHJhIjpudWxsfSx7InR5cGUiOiJUaXRsZSIsImJib3giOnsibGVmdCI6MC4xNjE4OTU3NDUyNzE4Mjc0OCwidG9wIjowLjA5NDc5Mjk1NTUzODE0MTIxLCJ3aWR0aCI6MC4xMTk0NjI5MDY1MDgyMDg3NSwiaGVpZ2h0IjowLjAyMTQ2NDE0MzAxNzEwNTA3LCJwYWdlIjoxLCJvcmlnaW5hbF9wYWdlIjoxfSwiY29udGVudCI6IlRlc3QgUERGIEZpbGUiLCJpbWFnZV91cmwiOm51bGwsImNoYXJ0X2RhdGEiOm51bGwsImNvbmZpZGVuY2UiOiJoaWdoIiwiZ3JhbnVsYXJfY29uZmlkZW5jZSI6eyJleHRyYWN0X2NvbmZpZGVuY2UiOm51bGwsInBhcnNlX2NvbmZpZGVuY2UiOjAuNzE4NTM1NTY5MzEwMTg4Mn0sImV4dHJhIjpudWxsfSx7InR5cGUiOiJQYWdlIE51bWJlciIsImJib3giOnsibGVmdCI6MC4wLCJ0b3AiOjAuMCwid2lkdGgiOjAuMCwiaGVpZ2h0IjowLjAsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb250ZW50IjoiW1tFTkQgT0YgUEFHRSAxXV0iLCJpbWFnZV91cmwiOm51bGwsImNoYXJ0X2RhdGEiOm51bGwsImNvbmZpZGVuY2UiOiJoaWdoIiwiZ3JhbnVsYXJfY29uZmlkZW5jZSI6eyJleHRyYWN0X2NvbmZpZGVuY2UiOm51bGwsInBhcnNlX2NvbmZpZGVuY2UiOm51bGx9LCJleHRyYSI6bnVsbH1dfV0sIm9jciI6bnVsbCwiY3VzdG9tIjpudWxsfSwicGFyc2VfbW9kZSI6bnVsbCwiZG9jdW1lbnRfcHJvcGVydGllcyI6bnVsbH0=", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:52 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:53.454592Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/2148dfafc823aea933d7c9aa8877398c1c26cf1fb8f134b1326e79bd3d487c41.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-v3/2148dfafc823aea933d7c9aa8877398c1c26cf1fb8f134b1326e79bd3d487c41.yaml new file mode 100644 index 00000000000..474e6aba8c3 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-v3/2148dfafc823aea933d7c9aa8877398c1c26cf1fb8f134b1326e79bd3d487c41.yaml @@ -0,0 +1,72 @@ +interactions: +- request: + body: "--3c37fd2676c46ae1ff34a706baa70fad\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--3c37fd2676c46ae1ff34a706baa70fad--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=3c37fd2676c46ae1ff34a706baa70fad + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://671d6e00-6df5-493a-bd9e-8bbf3d77d3ab.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:36 GMT + status: + code: 200 + message: '' +- request: + body: '{"input":"reducto://671d6e00-6df5-493a-bd9e-8bbf3d77d3ab.pdf","retrieval":{"chunking":{"chunk_mode":"page"}}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"8f15b6dd-f2d2-48e2-a4c9-0230a9ace704","duration":3.7510643005371094,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/671d6e00-6df5-493a-bd9e-8bbf3d77d3ab.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195440Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=96a4f904e8d3ca58d399ab21ade69ec0ea62ff5dfee320c5eeaa6eaa0c4e0561","studio_link":"https://studio.reducto.ai/job/8f15b6dd-f2d2-48e2-a4c9-0230a9ace704","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16189574527182748,"top":0.09479295553814121,"width":0.11946290650820875,"height":0.02146414301710507,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7185355693101882},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:40 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:41.233002+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_v3 + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + model: reducto/parse-v3 + retrieval: + chunking: + chunk_mode: page + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/3a512e502dc6310e671e8967a7652520370e0c873939813c2167799cffacba06.json b/tests/test_litellm/ocr/fixtures/data/reducto-v3/3a512e502dc6310e671e8967a7652520370e0c873939813c2167799cffacba06.json deleted file mode 100644 index dbdce610f6d..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-v3/3a512e502dc6310e671e8967a7652520370e0c873939813c2167799cffacba06.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "model": "reducto/parse-v3", - "settings": { - "return_ocr_data": true - } - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovL2ZjNmViY2IxLTk1ZDQtNDZlYy05MGQwLWVmY2EzM2VmMTk3Zi5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:41 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiIzZjZlZjY0ZC1jOTQ5LTRiOGQtOTg5OC1hZmIzYjAxNjY5ZTYiLCJkdXJhdGlvbiI6MS40NDgwNzQzNDA4MjAzMTI1LCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvZmM2ZWJjYjEtOTVkNC00NmVjLTkwZDAtZWZjYTMzZWYxOTdmLnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQ0M1omWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPTA5NjVjYTEyOWNlZTQ5YTQxNjUwZGYxNTIwNTdhMTdhNGY5ZTI2NWY5MmYyMjYxYTRmNjU3NjU4NzI3MmViMDMiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iLzNmNmVmNjRkLWM5NDktNGI4ZC05ODk4LWFmYjNiMDE2NjllNiIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MTg5NTc0NTI3MTgyNzQ4LCJ0b3AiOjAuMDk0NzkyOTU1NTM4MTQxMjEsIndpZHRoIjowLjExOTQ2MjkwNjUwODIwODc1LCJoZWlnaHQiOjAuMDIxNDY0MTQzMDE3MTA1MDcsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb250ZW50IjoiVGVzdCBQREYgRmlsZSIsImltYWdlX3VybCI6bnVsbCwiY2hhcnRfZGF0YSI6bnVsbCwiY29uZmlkZW5jZSI6ImhpZ2giLCJncmFudWxhcl9jb25maWRlbmNlIjp7ImV4dHJhY3RfY29uZmlkZW5jZSI6bnVsbCwicGFyc2VfY29uZmlkZW5jZSI6MC43MTg1MzU1NjkzMTAxODgyfSwiZXh0cmEiOm51bGx9XX1dLCJvY3IiOnsid29yZHMiOlt7InRleHQiOiJUZXN0IiwiYmJveCI6eyJsZWZ0IjowLjE2MTg5NDc1NDY0NjY1MDMyLCJ0b3AiOjAuMDk0OTE5MjE0MzQ0OTg3OTcsIndpZHRoIjowLjAzODMyMDg5MDQzOTEwMjA3LCJoZWlnaHQiOjAuMDIxMDE5NTMxMDE4ODA2MjI1LCJwYWdlIjoxLCJvcmlnaW5hbF9wYWdlIjoxfSwiY29uZmlkZW5jZSI6MS4wLCJjaHVua19pbmRleCI6bnVsbCwicm90YXRpb24iOjM1OX0seyJ0ZXh0IjoiUERGIiwiYmJveCI6eyJsZWZ0IjowLjIwNTQ4MTk1OTMyNDI1NzA2LCJ0b3AiOjAuMDk1MTQ5OTA3MTk4ODE5MjQsIndpZHRoIjowLjAzOTM5OTI5MDM5NjQ5NzE0LCJoZWlnaHQiOjAuMDIxMDI1MjQzNDMxNjMwNzYsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb25maWRlbmNlIjoxLjAsImNodW5rX2luZGV4IjpudWxsLCJyb3RhdGlvbiI6MzU5fSx7InRleHQiOiJGaWxlIiwiYmJveCI6eyJsZWZ0IjowLjI1MDE0NzU3NjQyNTU4OTc3LCJ0b3AiOjAuMDk1Mzg2MzAyODMyNDAxMTUsIndpZHRoIjowLjAzMTc3MjAxNTE0MTUwNTgyLCJoZWlnaHQiOjAuMDIwOTg0ODcxMjE4OTAyODk1LCJwYWdlIjoxLCJvcmlnaW5hbF9wYWdlIjoxfSwiY29uZmlkZW5jZSI6MS4wLCJjaHVua19pbmRleCI6bnVsbCwicm90YXRpb24iOjM1OX1dLCJsaW5lcyI6W3sidGV4dCI6IlRlc3QgUERGIEZpbGUiLCJiYm94Ijp7ImxlZnQiOjAuMTYxODk0NzU0NjQ2NjUwMzIsInRvcCI6MC4wOTQ5MTkyMTQzNDQ5ODc5Nywid2lkdGgiOjAuMTIwMDI0ODM2OTIwNDQ1MjYsImhlaWdodCI6MC4wMjE0NTE5NTk3MDYzMTYwOTIsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb25maWRlbmNlIjoxLjAsImNodW5rX2luZGV4IjpudWxsLCJyb3RhdGlvbiI6MzU5fV19LCJjdXN0b20iOm51bGx9LCJwYXJzZV9tb2RlIjpudWxsLCJkb2N1bWVudF9wcm9wZXJ0aWVzIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:43 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:43.968997Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/50890748074024915ef138fcb8e0c95f731a0913d223fbe1780bbaaef1ecd835.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-v3/50890748074024915ef138fcb8e0c95f731a0913d223fbe1780bbaaef1ecd835.yaml new file mode 100644 index 00000000000..31f5ed2be1c --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-v3/50890748074024915ef138fcb8e0c95f731a0913d223fbe1780bbaaef1ecd835.yaml @@ -0,0 +1,83 @@ +interactions: +- request: + body: "--43159c32150fa5f506932c4b4a645ef6\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--43159c32150fa5f506932c4b4a645ef6--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=43159c32150fa5f506932c4b4a645ef6 + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://f8bf17e8-ca0b-4add-b484-9982d2e4ac2a.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:50 GMT + status: + code: 200 + message: '' +- request: + body: '{"input":"reducto://f8bf17e8-ca0b-4add-b484-9982d2e4ac2a.pdf","formatting":{"add_page_markers":true,"table_output_format":"json","merge_tables":true,"include":["change_tracking","highlight","comments"]}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"e3792387-8384-45aa-b02e-a84521db116a","duration":1.0497362613677979,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/f8bf17e8-ca0b-4add-b484-9982d2e4ac2a.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195452Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=7367275a69dfd53f9fcf9f02777f0fe973e7e541fa1871e0347f788b8c5078f4","studio_link":"https://studio.reducto.ai/job/e3792387-8384-45aa-b02e-a84521db116a","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"[[START + OF PAGE 1]]\n\n# Test PDF File\n\n[[END OF PAGE 1]]","embed":"[[START OF PAGE + 1]]\n\n# Test PDF File\n\n[[END OF PAGE 1]]","enriched":null,"enrichment_success":false,"blocks":[{"type":"Page + Number","bbox":{"left":0.0,"top":0.0,"width":0.0,"height":0.0,"page":1,"original_page":1},"content":"[[START + OF PAGE 1]]","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":null},"extra":null},{"type":"Title","bbox":{"left":0.16189574527182748,"top":0.09479295553814121,"width":0.11946290650820875,"height":0.02146414301710507,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7185355693101882},"extra":null},{"type":"Page + Number","bbox":{"left":0.0,"top":0.0,"width":0.0,"height":0.0,"page":1,"original_page":1},"content":"[[END + OF PAGE 1]]","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":null},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:52 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:53.454592+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_v3 + custom_llm_provider: null + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + formatting: + add_page_markers: true + include: + - change_tracking + - highlight + - comments + merge_tables: true + table_output_format: json + model: reducto/parse-v3 + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/5227441615ac16de68a18458e9704be5c772291d89dd5a67480c21e4e2ac3834.json b/tests/test_litellm/ocr/fixtures/data/reducto-v3/5227441615ac16de68a18458e9704be5c772291d89dd5a67480c21e4e2ac3834.json deleted file mode 100644 index ca28cecbe63..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-v3/5227441615ac16de68a18458e9704be5c772291d89dd5a67480c21e4e2ac3834.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "model": "reducto/parse-v3" - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovLzAxMGIwMWIyLTgzYmQtNDQ2ZC1hZjExLWQxMjBjNWFjMmMwMi5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:27 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiI4MTM4YTZjNi1iNzI2LTQzMDAtOTBiNC1lNmQ1ZDQzZjZmNzAiLCJkdXJhdGlvbiI6MS4yNjQ4MjcyNTE0MzQzMjYyLCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvMDEwYjAxYjItODNiZC00NDZkLWFmMTEtZDEyMGM1YWMyYzAyLnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQyOFomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPTNjZGE5MDIwZmVmZmY4NWQ5ZGQxM2YxMjQ5MDhkN2IwMGU1NWI2ZTgyYTcyMDM5NTQ2ZDI2MjA5OWNmY2YzYjQiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iLzgxMzhhNmM2LWI3MjYtNDMwMC05MGI0LWU2ZDVkNDNmNmY3MCIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MTg5NTc0NTI3MTgyNzQ4LCJ0b3AiOjAuMDk0NzkyOTU1NTM4MTQxMjEsIndpZHRoIjowLjExOTQ2MjkwNjUwODIwODc1LCJoZWlnaHQiOjAuMDIxNDY0MTQzMDE3MTA1MDcsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb250ZW50IjoiVGVzdCBQREYgRmlsZSIsImltYWdlX3VybCI6bnVsbCwiY2hhcnRfZGF0YSI6bnVsbCwiY29uZmlkZW5jZSI6ImhpZ2giLCJncmFudWxhcl9jb25maWRlbmNlIjp7ImV4dHJhY3RfY29uZmlkZW5jZSI6bnVsbCwicGFyc2VfY29uZmlkZW5jZSI6MC43MTg1MzU1NjkzMTAxODgyfSwiZXh0cmEiOm51bGx9XX1dLCJvY3IiOm51bGwsImN1c3RvbSI6bnVsbH0sInBhcnNlX21vZGUiOm51bGwsImRvY3VtZW50X3Byb3BlcnRpZXMiOm51bGx9", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:29 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:30.255600Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/75876320a008dc29db48c33e4d4ccb9e95c3aae1d774f03869cf7cacfaa9aa07.json b/tests/test_litellm/ocr/fixtures/data/reducto-v3/75876320a008dc29db48c33e4d4ccb9e95c3aae1d774f03869cf7cacfaa9aa07.json deleted file mode 100644 index b28e1a7efee..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-v3/75876320a008dc29db48c33e4d4ccb9e95c3aae1d774f03869cf7cacfaa9aa07.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "case": { - "litellm_input": { - "custom_llm_provider": null, - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "formatting": { - "add_page_markers": false, - "include": [ - "signatures", - "ignore_watermarks" - ], - "merge_tables": true, - "table_output_format": "json" - }, - "model": "reducto/parse-v3", - "retrieval": { - "chunking": { - "chunk_mode": "variable", - "chunk_overlap": 32, - "chunk_size": 1500 - }, - "embedding_optimized": false, - "filter_blocks": [ - "Figure", - "Table", - "Key Value" - ] - }, - "settings": { - "embed_pdf_metadata": false, - "embed_pdf_metadata_dpi": 100, - "extraction_mode": "hybrid", - "force_url_result": false, - "ocr_system": "legacy", - "page_range": [ - 1 - ], - "persist_results": false, - "return_images": [], - "return_ocr_data": false, - "timeout": 900.0 - } - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovLzVkZjc0NWY0LTI4NzctNGNmNi05YmRlLWEyZjgyOWM5M2VlYS5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:48 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiI3Y2E2NzI0Mi0xNjc3LTQ4NGUtYjJlZi1iMjU2ZGNkZDFlYTQiLCJkdXJhdGlvbiI6MS4zMzU5MzA4MjQyNzk3ODUyLCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvNWRmNzQ1ZjQtMjg3Ny00Y2Y2LTliZGUtYTJmODI5YzkzZWVhLnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQ0OVomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPTA3N2E2NTUxMjAxZDI1NjJmZDE1NDNmZDVjMzkxNTQxY2ZmZTYwNmQ2NDMwN2EzZjZkMTAzY2YxODIxOWY4MGEiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iLzdjYTY3MjQyLTE2NzctNDg0ZS1iMmVmLWIyNTZkY2RkMWVhNCIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MTg5NTc0NTI3MTgyNzQ4LCJ0b3AiOjAuMDk0NzkyOTU1NTM4MTQxMjEsIndpZHRoIjowLjExOTQ2MjkwNjUwODIwODc1LCJoZWlnaHQiOjAuMDIxNDY0MTQzMDE3MTA1MDcsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb250ZW50IjoiVGVzdCBQREYgRmlsZSIsImltYWdlX3VybCI6bnVsbCwiY2hhcnRfZGF0YSI6bnVsbCwiY29uZmlkZW5jZSI6ImhpZ2giLCJncmFudWxhcl9jb25maWRlbmNlIjp7ImV4dHJhY3RfY29uZmlkZW5jZSI6bnVsbCwicGFyc2VfY29uZmlkZW5jZSI6MC43MTg1MzU1NjkzMTAxODgyfSwiZXh0cmEiOm51bGx9XX1dLCJvY3IiOm51bGwsImN1c3RvbSI6bnVsbH0sInBhcnNlX21vZGUiOm51bGwsImRvY3VtZW50X3Byb3BlcnRpZXMiOm51bGx9", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:50 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:50.708637Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/7cefa9e08179db20d45e255d269e4239015b9b44376ce49c921f8fc057fb9c6a.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-v3/7cefa9e08179db20d45e255d269e4239015b9b44376ce49c921f8fc057fb9c6a.yaml new file mode 100644 index 00000000000..02bd747a4d3 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-v3/7cefa9e08179db20d45e255d269e4239015b9b44376ce49c921f8fc057fb9c6a.yaml @@ -0,0 +1,70 @@ +interactions: +- request: + body: "--ba392e7bb7694af286b0acfe46365a0f\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--ba392e7bb7694af286b0acfe46365a0f--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=ba392e7bb7694af286b0acfe46365a0f + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://a6d3c3bb-a6f1-4636-8b3a-ee920b29d387.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:46 GMT + status: + code: 200 + message: '' +- request: + body: '{"input":"reducto://a6d3c3bb-a6f1-4636-8b3a-ee920b29d387.pdf"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"4a78c975-1865-46fe-8f89-bea92a49e215","duration":1.1194427013397217,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/6ab9bcf4-1893-4b37-bddb-acda8ce45dfb.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195445Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=1db61d33f602f13e8444e8580b737b31f346e47493cc7eca7c4fcddbde0dfb43","studio_link":"https://studio.reducto.ai/job/d345549f-5d98-4c62-b3e3-24c990144df4","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16189574527182748,"top":0.09479295553814121,"width":0.11946290650820875,"height":0.02146414301710507,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7185355693101882},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:47 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:47.967951+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_v3 + custom_llm_provider: reducto + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + model: parse-v3 + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/8270ee13cdfb2ceefd8302a1880653fe30bde512da747d2fd8e78759ccdc9b90.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-v3/8270ee13cdfb2ceefd8302a1880653fe30bde512da747d2fd8e78759ccdc9b90.yaml new file mode 100644 index 00000000000..2bc911985eb --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-v3/8270ee13cdfb2ceefd8302a1880653fe30bde512da747d2fd8e78759ccdc9b90.yaml @@ -0,0 +1,70 @@ +interactions: +- request: + body: "--0f6127f8c781afd158616115a5ebdece\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--0f6127f8c781afd158616115a5ebdece--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=0f6127f8c781afd158616115a5ebdece + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://6ab9bcf4-1893-4b37-bddb-acda8ce45dfb.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:44 GMT + status: + code: 200 + message: '' +- request: + body: '{"input":"reducto://6ab9bcf4-1893-4b37-bddb-acda8ce45dfb.pdf"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"d345549f-5d98-4c62-b3e3-24c990144df4","duration":1.1194427013397217,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/6ab9bcf4-1893-4b37-bddb-acda8ce45dfb.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195445Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=1db61d33f602f13e8444e8580b737b31f346e47493cc7eca7c4fcddbde0dfb43","studio_link":"https://studio.reducto.ai/job/d345549f-5d98-4c62-b3e3-24c990144df4","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16189574527182748,"top":0.09479295553814121,"width":0.11946290650820875,"height":0.02146414301710507,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7185355693101882},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:46 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:46.694836+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_v3 + custom_llm_provider: null + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + model: reducto/parse-v3 + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/997cd381eb3019b71086e4fdab1b98a3a0d251a27c3bb80178580a711c111e94.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-v3/997cd381eb3019b71086e4fdab1b98a3a0d251a27c3bb80178580a711c111e94.yaml new file mode 100644 index 00000000000..622db8dee4a --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-v3/997cd381eb3019b71086e4fdab1b98a3a0d251a27c3bb80178580a711c111e94.yaml @@ -0,0 +1,100 @@ +interactions: +- request: + body: "--22b7cb49f85a1ae5113a6328b0381ffb\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--22b7cb49f85a1ae5113a6328b0381ffb--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=22b7cb49f85a1ae5113a6328b0381ffb + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://5df745f4-2877-4cf6-9bde-a2f829c93eea.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:48 GMT + status: + code: 200 + message: '' +- request: + body: '{"input":"reducto://5df745f4-2877-4cf6-9bde-a2f829c93eea.pdf","formatting":{"add_page_markers":false,"table_output_format":"json","merge_tables":true,"include":["signatures","ignore_watermarks"]},"retrieval":{"chunking":{"chunk_mode":"variable","chunk_size":1500,"chunk_overlap":32},"filter_blocks":["Figure","Table","Key + Value"],"embedding_optimized":false},"settings":{"ocr_system":"legacy","extraction_mode":"hybrid","force_url_result":false,"return_ocr_data":false,"return_images":[],"embed_pdf_metadata":false,"embed_pdf_metadata_dpi":100,"persist_results":false,"timeout":900.0,"page_range":[1]}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"7ca67242-1677-484e-b2ef-b256dcdd1ea4","duration":1.3359308242797852,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/5df745f4-2877-4cf6-9bde-a2f829c93eea.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195449Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=077a6551201d2562fd1543fd5c391541cffe606d64307a3f6d103cf18219f80a","studio_link":"https://studio.reducto.ai/job/7ca67242-1677-484e-b2ef-b256dcdd1ea4","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16189574527182748,"top":0.09479295553814121,"width":0.11946290650820875,"height":0.02146414301710507,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7185355693101882},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:50 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:50.708637+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_v3 + custom_llm_provider: null + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + formatting: + add_page_markers: false + include: + - signatures + - ignore_watermarks + merge_tables: true + table_output_format: json + model: reducto/parse-v3 + retrieval: + chunking: + chunk_mode: variable + chunk_overlap: 32 + chunk_size: 1500 + embedding_optimized: false + filter_blocks: + - Figure + - Table + - Key Value + settings: + embed_pdf_metadata: false + embed_pdf_metadata_dpi: 100 + extraction_mode: hybrid + force_url_result: false + ocr_system: legacy + page_range: + - 1 + persist_results: false + return_images: [] + return_ocr_data: false + timeout: 900.0 + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/aee30a1d7a51a3fd8837b56d6baa3a43364ea319d905b5030014f4d85e7c94e9.json b/tests/test_litellm/ocr/fixtures/data/reducto-v3/aee30a1d7a51a3fd8837b56d6baa3a43364ea319d905b5030014f4d85e7c94e9.json deleted file mode 100644 index ba07f5baa4f..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-v3/aee30a1d7a51a3fd8837b56d6baa3a43364ea319d905b5030014f4d85e7c94e9.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "model": "reducto/parse-v3", - "retrieval": { - "chunking": { - "chunk_mode": "page" - } - } - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovLzY3MWQ2ZTAwLTZkZjUtNDkzYS1iZDllLThiYmYzZDc3ZDNhYi5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:36 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiI4ZjE1YjZkZC1mMmQyLTQ4ZTItYTRjOS0wMjMwYTlhY2U3MDQiLCJkdXJhdGlvbiI6My43NTEwNjQzMDA1MzcxMDk0LCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvNjcxZDZlMDAtNmRmNS00OTNhLWJkOWUtOGJiZjNkNzdkM2FiLnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQ0MFomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPTk2YTRmOTA0ZThkM2NhNThkMzk5YWIyMWFkZTY5ZWMwZWE2MmZmNWRmZWUzMjBjNWVlYWE2ZWFhMGM0ZTA1NjEiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iLzhmMTViNmRkLWYyZDItNDhlMi1hNGM5LTAyMzBhOWFjZTcwNCIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MTg5NTc0NTI3MTgyNzQ4LCJ0b3AiOjAuMDk0NzkyOTU1NTM4MTQxMjEsIndpZHRoIjowLjExOTQ2MjkwNjUwODIwODc1LCJoZWlnaHQiOjAuMDIxNDY0MTQzMDE3MTA1MDcsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb250ZW50IjoiVGVzdCBQREYgRmlsZSIsImltYWdlX3VybCI6bnVsbCwiY2hhcnRfZGF0YSI6bnVsbCwiY29uZmlkZW5jZSI6ImhpZ2giLCJncmFudWxhcl9jb25maWRlbmNlIjp7ImV4dHJhY3RfY29uZmlkZW5jZSI6bnVsbCwicGFyc2VfY29uZmlkZW5jZSI6MC43MTg1MzU1NjkzMTAxODgyfSwiZXh0cmEiOm51bGx9XX1dLCJvY3IiOm51bGwsImN1c3RvbSI6bnVsbH0sInBhcnNlX21vZGUiOm51bGwsImRvY3VtZW50X3Byb3BlcnRpZXMiOm51bGx9", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:40 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:41.233002Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/cfb4093138a106055f36402de37409b1ca17c23b9e491b4f8b6ac705acd05637.json b/tests/test_litellm/ocr/fixtures/data/reducto-v3/cfb4093138a106055f36402de37409b1ca17c23b9e491b4f8b6ac705acd05637.json deleted file mode 100644 index 8b7dc56ebc5..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-v3/cfb4093138a106055f36402de37409b1ca17c23b9e491b4f8b6ac705acd05637.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "formatting": { - "table_output_format": "md" - }, - "model": "reducto/parse-v3" - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovL2YzY2MzYzcyLTYxNGEtNDEwNC1iYjcwLWE1MTZmMzcxNDhlMC5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:30 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiJhYmE5MjRkYy03NzczLTRkZmYtYTRhOC0zNTQ5MzY2ZWE5ZmEiLCJkdXJhdGlvbiI6NC41NzY0MTcyMDc3MTc4OTU1LCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvZjNjYzNjNzItNjE0YS00MTA0LWJiNzAtYTUxNmYzNzE0OGUwLnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQzNVomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPTdkNGM5NDY0YmIzYTFhOWQ1YzdhNWY5NTdiYzEwODEzZmIxNmZjYzZkZTNmZWEyMDU0YTQwYjQ2OWZmYTc5YjMiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iL2FiYTkyNGRjLTc3NzMtNGRmZi1hNGE4LTM1NDkzNjZlYTlmYSIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MTg5NTc0NTI3MTgyNzQ4LCJ0b3AiOjAuMDk0NzkyOTU1NTM4MTQxMjEsIndpZHRoIjowLjExOTQ2MjkwNjUwODIwODc1LCJoZWlnaHQiOjAuMDIxNDY0MTQzMDE3MTA1MDcsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb250ZW50IjoiVGVzdCBQREYgRmlsZSIsImltYWdlX3VybCI6bnVsbCwiY2hhcnRfZGF0YSI6bnVsbCwiY29uZmlkZW5jZSI6ImhpZ2giLCJncmFudWxhcl9jb25maWRlbmNlIjp7ImV4dHJhY3RfY29uZmlkZW5jZSI6bnVsbCwicGFyc2VfY29uZmlkZW5jZSI6MC43MTg1MzU1NjkzMTAxODgyfSwiZXh0cmEiOm51bGx9XX1dLCJvY3IiOm51bGwsImN1c3RvbSI6bnVsbH0sInBhcnNlX21vZGUiOm51bGwsImRvY3VtZW50X3Byb3BlcnRpZXMiOm51bGx9", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:35 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:35.993066Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/d5a49e5897e920719ca28697413ee0396ea754023bd5ab34065efcc852914f15.json b/tests/test_litellm/ocr/fixtures/data/reducto-v3/d5a49e5897e920719ca28697413ee0396ea754023bd5ab34065efcc852914f15.json deleted file mode 100644 index 2253db90a1f..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-v3/d5a49e5897e920719ca28697413ee0396ea754023bd5ab34065efcc852914f15.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "case": { - "litellm_input": { - "custom_llm_provider": null, - "document": { - "document_url": "data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg==", - "type": "document_url" - }, - "model": "reducto/parse-v3" - }, - "provider_responses": [ - { - "body_b64": "eyJmaWxlX2lkIjoicmVkdWN0bzovLzZhYjliY2Y0LTE4OTMtNGIzNy1iZGRiLWFjZGE4Y2U0NWRmYi5wZGYiLCJwcmVzaWduZWRfdXJsIjpudWxsfQ==", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:44 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - }, - { - "body_b64": "eyJyZXNwb25zZV90eXBlIjoicGFyc2UiLCJqb2JfaWQiOiJkMzQ1NTQ5Zi01ZDk4LTRjNjItYjNlMy0yNGM5OTAxNDRkZjQiLCJkdXJhdGlvbiI6MS4xMTk0NDI3MDEzMzk3MjE3LCJwZGZfdXJsIjoiaHR0cHM6Ly9wcm9kLXN0b3JhZ2UyMDI0MTAxMDE0NDc0NTE0MDkwMDAwMDAwMS5zMy5hbWF6b25hd3MuY29tL29yZy84YmQ5ODNkMS00N2RkLTQ0MGItOTNkOC00MzE0MTJkODE5YmYvNmFiOWJjZjQtMTg5My00YjM3LWJkZGItYWNkYThjZTQ1ZGZiLnBkZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUEyVU9LNk9WQk9VWUw3V1lBJTJGMjAyNjA5MDElMkZ1cy13ZXN0LTIlMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTAxVDE5NTQ0NVomWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmWC1BbXotU2lnbmF0dXJlPTFkYjYxZDMzZjYwMmYxM2U4NDQ0ZTg1ODBiNzM3YjMxZjM0NmU0NzQ5M2NjN2VjYTdjNGZjZGRiZGUwZGZiNDMiLCJzdHVkaW9fbGluayI6Imh0dHBzOi8vc3R1ZGlvLnJlZHVjdG8uYWkvam9iL2QzNDU1NDlmLTVkOTgtNGM2Mi1iM2UzLTI0Yzk5MDE0NGRmNCIsInVzYWdlIjp7Im51bV9wYWdlcyI6MSwiY3JlZGl0cyI6MS4wLCJjcmVkaXRfYnJlYWtkb3duIjp7InBhZ2UiOjEuMH0sInBhZ2VfYmlsbGluZ19icmVha2Rvd24iOnsiMSI6WyJwYWdlIl19LCJub25fZW1wdHlfY2VsbF9jb3VudCI6bnVsbH0sInJlc3VsdCI6eyJ0eXBlIjoiZnVsbCIsImNodW5rcyI6W3siY29udGVudCI6IiMgVGVzdCBQREYgRmlsZSIsImVtYmVkIjoiIyBUZXN0IFBERiBGaWxlIiwiZW5yaWNoZWQiOm51bGwsImVucmljaG1lbnRfc3VjY2VzcyI6ZmFsc2UsImJsb2NrcyI6W3sidHlwZSI6IlRpdGxlIiwiYmJveCI6eyJsZWZ0IjowLjE2MTg5NTc0NTI3MTgyNzQ4LCJ0b3AiOjAuMDk0NzkyOTU1NTM4MTQxMjEsIndpZHRoIjowLjExOTQ2MjkwNjUwODIwODc1LCJoZWlnaHQiOjAuMDIxNDY0MTQzMDE3MTA1MDcsInBhZ2UiOjEsIm9yaWdpbmFsX3BhZ2UiOjF9LCJjb250ZW50IjoiVGVzdCBQREYgRmlsZSIsImltYWdlX3VybCI6bnVsbCwiY2hhcnRfZGF0YSI6bnVsbCwiY29uZmlkZW5jZSI6ImhpZ2giLCJncmFudWxhcl9jb25maWRlbmNlIjp7ImV4dHJhY3RfY29uZmlkZW5jZSI6bnVsbCwicGFyc2VfY29uZmlkZW5jZSI6MC43MTg1MzU1NjkzMTAxODgyfSwiZXh0cmEiOm51bGx9XX1dLCJvY3IiOm51bGwsImN1c3RvbSI6bnVsbH0sInBhcnNlX21vZGUiOm51bGwsImRvY3VtZW50X3Byb3BlcnRpZXMiOm51bGx9", - "headers": [ - { - "name": "Date", - "value": "Tue, 01 Sep 2026 19:54:46 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 200 - } - ] - }, - "recorded_at": "2026-09-01T19:54:46.694836Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/f2b260eca76347d5982b96c79563999653d141626ca1eadfdb47fc20d645b9d5.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-v3/f2b260eca76347d5982b96c79563999653d141626ca1eadfdb47fc20d645b9d5.yaml new file mode 100644 index 00000000000..4515e0a0823 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-v3/f2b260eca76347d5982b96c79563999653d141626ca1eadfdb47fc20d645b9d5.yaml @@ -0,0 +1,72 @@ +interactions: +- request: + body: "--7108360c769817ee2464c4729615e289\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--7108360c769817ee2464c4729615e289--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=7108360c769817ee2464c4729615e289 + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://fc6ebcb1-95d4-46ec-90d0-efca33ef197f.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:41 GMT + status: + code: 200 + message: '' +- request: + body: '{"input":"reducto://fc6ebcb1-95d4-46ec-90d0-efca33ef197f.pdf","settings":{"return_ocr_data":true}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"3f6ef64d-c949-4b8d-9898-afb3b01669e6","duration":1.4480743408203125,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/fc6ebcb1-95d4-46ec-90d0-efca33ef197f.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195443Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=0965ca129cee49a41650df152057a17a4f9e265f92f2261a4f6576587272eb03","studio_link":"https://studio.reducto.ai/job/3f6ef64d-c949-4b8d-9898-afb3b01669e6","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16189574527182748,"top":0.09479295553814121,"width":0.11946290650820875,"height":0.02146414301710507,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7185355693101882},"extra":null}]}],"ocr":{"words":[{"text":"Test","bbox":{"left":0.16189475464665032,"top":0.09491921434498797,"width":0.03832089043910207,"height":0.021019531018806225,"page":1,"original_page":1},"confidence":1.0,"chunk_index":null,"rotation":359},{"text":"PDF","bbox":{"left":0.20548195932425706,"top":0.09514990719881924,"width":0.03939929039649714,"height":0.02102524343163076,"page":1,"original_page":1},"confidence":1.0,"chunk_index":null,"rotation":359},{"text":"File","bbox":{"left":0.25014757642558977,"top":0.09538630283240115,"width":0.03177201514150582,"height":0.020984871218902895,"page":1,"original_page":1},"confidence":1.0,"chunk_index":null,"rotation":359}],"lines":[{"text":"Test + PDF File","bbox":{"left":0.16189475464665032,"top":0.09491921434498797,"width":0.12002483692044526,"height":0.021451959706316092,"page":1,"original_page":1},"confidence":1.0,"chunk_index":null,"rotation":359}]},"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:43 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:43.968997+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_v3 + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + model: reducto/parse-v3 + settings: + return_ocr_data: true + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/f317c1c7b57a6ac742de1b97f2f84da6aa7892f8cdd4f22158ba4c700dbe8a81.json b/tests/test_litellm/ocr/fixtures/data/reducto-v3/f317c1c7b57a6ac742de1b97f2f84da6aa7892f8cdd4f22158ba4c700dbe8a81.json deleted file mode 100644 index 5ec2d6c684e..00000000000 --- a/tests/test_litellm/ocr/fixtures/data/reducto-v3/f317c1c7b57a6ac742de1b97f2f84da6aa7892f8cdd4f22158ba4c700dbe8a81.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "case": { - "litellm_input": { - "document": { - "document_url": "reducto://invalid-document-for-parity", - "type": "document_url" - }, - "model": "reducto/parse-v3" - }, - "provider_responses": [ - { - "body_b64": "eyJlcnJvciI6eyJjb2RlIjo0MDQsIm5hbWUiOiJOT1RfRk9VTkQiLCJtZXNzYWdlIjoiRG9jdW1lbnQgJ1RoZSBmaWxlIG1heSBoYXZlIGV4cGlyZWQgb3IgYmVlbiBkZWxldGVkLiBQbGVhc2UgcmUtdXBsb2FkIGFuZCB0cnkgYWdhaW4uJyBub3QgZm91bmQifSwiZGV0YWlsIjoiRG9jdW1lbnQgJ1RoZSBmaWxlIG1heSBoYXZlIGV4cGlyZWQgb3IgYmVlbiBkZWxldGVkLiBQbGVhc2UgcmUtdXBsb2FkIGFuZCB0cnkgYWdhaW4uJyBub3QgZm91bmQifQ==", - "headers": [ - { - "name": "Date", - "value": "Wed, 02 Sep 2026 01:14:02 GMT" - }, - { - "name": "Content-Type", - "value": "application/json" - } - ], - "kind": "http", - "status_code": 404 - } - ] - }, - "recorded_at": "2026-09-02T01:14:02.538070Z", - "schema_version": 1 -} diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/f317c1c7b57a6ac742de1b97f2f84da6aa7892f8cdd4f22158ba4c700dbe8a81.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-v3/f317c1c7b57a6ac742de1b97f2f84da6aa7892f8cdd4f22158ba4c700dbe8a81.yaml new file mode 100644 index 00000000000..3349f3f6b2d --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-v3/f317c1c7b57a6ac742de1b97f2f84da6aa7892f8cdd4f22158ba4c700dbe8a81.yaml @@ -0,0 +1,39 @@ +interactions: +- request: + body: '{"input":"reducto://invalid-document-for-parity"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"error":{"code":404,"name":"NOT_FOUND","message":"Document ''The file + may have expired or been deleted. Please re-upload and try again.'' not found"},"detail":"Document + ''The file may have expired or been deleted. Please re-upload and try again.'' + not found"}' + headers: + Content-Type: + - application/json + Date: + - Wed, 02 Sep 2026 01:14:02 GMT + status: + code: 404 + message: '' +recorded_at: '2026-09-02T01:14:02.538070+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_v3 + document: + document_url: reducto://invalid-document-for-parity + type: document_url + model: reducto/parse-v3 + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/f55e3b684697b9f478393e35202e92b04e51b1ea8b74eaa4a4382a01154b5f5a.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-v3/f55e3b684697b9f478393e35202e92b04e51b1ea8b74eaa4a4382a01154b5f5a.yaml new file mode 100644 index 00000000000..5731fa1c48d --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-v3/f55e3b684697b9f478393e35202e92b04e51b1ea8b74eaa4a4382a01154b5f5a.yaml @@ -0,0 +1,71 @@ +interactions: +- request: + body: "--04abc28545d4b46a8ee703e56d88cc0c\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--04abc28545d4b46a8ee703e56d88cc0c--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=04abc28545d4b46a8ee703e56d88cc0c + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://f3cc3c72-614a-4104-bb70-a516f37148e0.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:30 GMT + status: + code: 200 + message: '' +- request: + body: '{"input":"reducto://f3cc3c72-614a-4104-bb70-a516f37148e0.pdf","formatting":{"table_output_format":"md"}}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"aba924dc-7773-4dff-a4a8-3549366ea9fa","duration":4.5764172077178955,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/f3cc3c72-614a-4104-bb70-a516f37148e0.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195435Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=7d4c9464bb3a1a9d5c7a5f957bc10813fb16fcc6de3fea2054a40b469ffa79b3","studio_link":"https://studio.reducto.ai/job/aba924dc-7773-4dff-a4a8-3549366ea9fa","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16189574527182748,"top":0.09479295553814121,"width":0.11946290650820875,"height":0.02146414301710507,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7185355693101882},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:35 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:35.993066+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_v3 + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + formatting: + table_output_format: md + model: reducto/parse-v3 + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/data/reducto-v3/f847dae1a1f6c3777ce3b65421a97f703d67d234593ac188f948142190fdf06d.yaml b/tests/test_litellm/ocr/fixtures/data/reducto-v3/f847dae1a1f6c3777ce3b65421a97f703d67d234593ac188f948142190fdf06d.yaml new file mode 100644 index 00000000000..02298f5a2f0 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/data/reducto-v3/f847dae1a1f6c3777ce3b65421a97f703d67d234593ac188f948142190fdf06d.yaml @@ -0,0 +1,69 @@ +interactions: +- request: + body: "--b7daa0c5be8f80d33a4eb7a54318d93a\r\nContent-Disposition: form-data; name=\"file\"; + filename=\"document\"\r\nContent-Type: application/pdf\r\n\r\n%PDF-1.4\n1 0 + obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n2 0 obj\n<< /Type /Pages /Kids + [3 0 R] /Count 1 >>\nendobj\n3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources + 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj\n4 0 obj\n<< /Font + << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>\nendobj\n5 + 0 obj\n<< /Length 44 >>\nstream\nBT\n/F1 12 Tf\n100 700 Td\n(Test PDF File) + Tj\nET\nendstream\nendobj\nxref\n0 6\n0000000000 65535 f \n0000000009 00000 + n \n0000000058 00000 n \n0000000115 00000 n \n0000000214 00000 n \n0000000293 + 00000 n \ntrailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n385\n%%EOF\n\r\n--b7daa0c5be8f80d33a4eb7a54318d93a--\r\n" + headers: + Accept: + - '*/*' + Content-Type: + - multipart/form-data; boundary=b7daa0c5be8f80d33a4eb7a54318d93a + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/upload + response: + body: + string: '{"file_id":"reducto://010b01b2-83bd-446d-af11-d120c5ac2c02.pdf","presigned_url":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:27 GMT + status: + code: 200 + message: '' +- request: + body: '{"input":"reducto://010b01b2-83bd-446d-af11-d120c5ac2c02.pdf"}' + headers: + Accept: + - '*/*' + Content-Type: + - application/json + User-Agent: + - litellm/1.101.0 + method: POST + uri: http://parity-provider.invalid/parse + response: + body: + string: '{"response_type":"parse","job_id":"8138a6c6-b726-4300-90b4-e6d5d43f6f70","duration":1.2648272514343262,"pdf_url":"https://prod-storage20241010144745140900000001.s3.amazonaws.com/org/8bd983d1-47dd-440b-93d8-431412d819bf/010b01b2-83bd-446d-af11-d120c5ac2c02.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA2UOK6OVBOUYL7WYA%2F20260901%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260901T195428Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=host&X-Amz-Signature=3cda9020fefff85d9dd13f124908d7b00e55b6e82a72039546d262099cfcf3b4","studio_link":"https://studio.reducto.ai/job/8138a6c6-b726-4300-90b4-e6d5d43f6f70","usage":{"num_pages":1,"credits":1.0,"credit_breakdown":{"page":1.0},"page_billing_breakdown":{"1":["page"]},"non_empty_cell_count":null},"result":{"type":"full","chunks":[{"content":"# + Test PDF File","embed":"# Test PDF File","enriched":null,"enrichment_success":false,"blocks":[{"type":"Title","bbox":{"left":0.16189574527182748,"top":0.09479295553814121,"width":0.11946290650820875,"height":0.02146414301710507,"page":1,"original_page":1},"content":"Test + PDF File","image_url":null,"chart_data":null,"confidence":"high","granular_confidence":{"extract_confidence":null,"parse_confidence":0.7185355693101882},"extra":null}]}],"ocr":null,"custom":null},"parse_mode":null,"document_properties":null}' + headers: + Content-Type: + - application/json + Date: + - Tue, 01 Sep 2026 19:54:29 GMT + status: + code: 200 + message: '' +recorded_at: '2026-09-01T19:54:30.255600+00:00' +ttl_seconds: 0 +version: 1 +x-litellm: + case: + litellm_input: + contract: reducto_v3 + document: + document_url: data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db250ZW50cyA1IDAgUiA+PgplbmRvYmoKNCAwIG9iago8PCAvRm9udCA8PCAvRjEgPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhID4+ID4+ID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUCi9GMSAxMiBUZgoxMDAgNzAwIFRkCihUZXN0IFBERiBGaWxlKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDU4IDAwMDAwIG4gCjAwMDAwMDAxMTUgMDAwMDAgbiAKMDAwMDAwMDIxNCAwMDAwMCBuIAowMDAwMDAwMjkzIDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNiAvUm9vdCAxIDAgUiA+PgpzdGFydHhyZWYKMzg1CiUlRU9GCg== + type: document_url + model: reducto/parse-v3 + request_source: python_replay + schema_version: 1 diff --git a/tests/test_litellm/ocr/fixtures/migrate.py b/tests/test_litellm/ocr/fixtures/migrate.py new file mode 100644 index 00000000000..41265896888 --- /dev/null +++ b/tests/test_litellm/ocr/fixtures/migrate.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +import argparse +from pathlib import Path +from typing import Final, cast + +import litellm +from litellm.rust_bridge.ocr import use_litellm_rust +from tests.route_parity.fixtures.recording import ( + RecordedInteraction, + UpstreamEndpoint, + record_upstream_interactions, +) +from tests.route_parity.fixtures.store import FixtureEnvelope, read_fixture, save_fixture +from tests.route_parity.replay import replay_server +from tests.test_litellm.ocr.fixtures.common import OcrSdkCall +from tests.test_litellm.ocr.fixtures.config import configured_fixture_directory +from tests.test_litellm.ocr.fixtures.models import OcrParityCase, OcrSdkInput + + +def _invoke(provider_url: str, case_input: OcrSdkInput) -> object: + sdk_call: Final = cast(OcrSdkCall, litellm.ocr) + return sdk_call(api_base=provider_url, api_key="test-key", **case_input.as_sdk_kwargs()) + + +def migrate_fixture(path: Path) -> Path: + case: Final = read_fixture(path, OcrParityCase) + envelope: Final = FixtureEnvelope.model_validate_json(path.read_text(encoding="utf-8")) + with replay_server() as provider: + for response in case.provider_responses: + provider.enqueue_response(response) + captured: Final = record_upstream_interactions(UpstreamEndpoint(provider.url), case.litellm_input, _invoke) + provider.take_requests(len(case.provider_responses)) + interactions: Final = tuple( + RecordedInteraction(item.request, response) + for item, response in zip(captured, case.provider_responses, strict=True) + ) + destination: Final = save_fixture( + path.parent, + case.litellm_input, + case, + interactions, + recorded_at=envelope.recorded_at, + request_source="python_replay", + ) + read_fixture(destination, OcrParityCase) + path.unlink() + return destination + + +def main() -> None: + parser: Final = argparse.ArgumentParser() + parser.add_argument("--fixture-dir", type=Path, default=configured_fixture_directory()) + args: Final = parser.parse_args() + directory: Final = cast(Path, args.fixture_dir) + use_litellm_rust(False, ocr=None, aocr=None) + paths: Final = tuple(sorted(directory.rglob("*.json"))) + for path in paths: + print(f"Migrated {path.name} to {migrate_fixture(path).name}") + + +if __name__ == "__main__": + main() diff --git a/tests/test_litellm/ocr/test_fixture_store.py b/tests/test_litellm/ocr/test_fixture_store.py index f13606e208b..a01b6805e9a 100644 --- a/tests/test_litellm/ocr/test_fixture_store.py +++ b/tests/test_litellm/ocr/test_fixture_store.py @@ -1,14 +1,18 @@ from __future__ import annotations from dataclasses import dataclass +from datetime import datetime, timezone from pathlib import Path from queue import Queue from typing import Final, Protocol, cast import pytest +from tests.route_parity.fixtures.cassette import deserialize_cassette from tests.route_parity.fixtures.pytest_support import parametrize_recorded_fixtures +from tests.route_parity.fixtures.store import FixtureEnvelope, read_fixture, recorded_fixtures from tests.test_litellm.ocr.conftest import ocr_fixture_id, ocr_fixture_marks +from tests.test_litellm.ocr.fixtures.migrate import migrate_fixture from tests.test_litellm.ocr.fixtures.models import OcrParityCase @@ -55,3 +59,27 @@ def test_recorded_fixture_parametrization_applies_case_specific_marks() -> None: assert all(parameter.marks[0].name == "xfail" for parameter in reducto_parameters) assert all(parameter.marks[0].kwargs["strict"] is False for parameter in reducto_parameters) assert all(parameter.marks == () for parameter in supported_parameters) + + +def test_legacy_fixture_migration_preserves_responses_and_labels_reconstructed_requests(tmp_path: Path) -> None: + case: Final = recorded_fixtures(Path(__file__).with_name("fixtures") / "data" / "mistral-ocr", OcrParityCase)[0] + timestamp: Final = datetime(2020, 1, 1, tzinfo=timezone.utc) + envelope: Final = FixtureEnvelope( + schema_version=1, + recorded_at=timestamp, + case=case.model_dump(mode="json", exclude_unset=True), + ) + legacy_path: Final = tmp_path / "legacy.json" + legacy_path.write_text(envelope.model_dump_json()) + + destination: Final = migrate_fixture(legacy_path) + + assert not legacy_path.exists() + assert read_fixture(destination, OcrParityCase) == case + cassette: Final = deserialize_cassette(destination.read_text()) + assert cassette.recorded_at == timestamp + assert cassette.parity.request_source == "python_replay" + assert len(cassette.interactions) == len(case.provider_responses) + assert cassette.interactions[0].request.method == "POST" + assert cassette.interactions[0].request.uri == "http://parity-provider.invalid/v1/ocr" + assert "authorization" not in cassette.interactions[0].request.headers