mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-27 01:22:18 +00:00
* refactor(ocr): remove the Python OCR execution path and require the Rust route Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fmt * refactor(ocr): tidy the native OCR passthrough binding Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * style(ocr): ruff format the azure passthrough transformation Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * refactor(ocr): resolve passthrough OCR costing in one Rust call Replace passthrough_url/passthrough_transform with passthrough_response, which matches the relayed endpoint against each Azure config's path segments instead of building a fake request to call get_complete_url. The binding drops the unused headers, status and api_base arguments. Catch the ValueError/RuntimeError the binding raises so a relayed body that is not OCR-shaped falls back to the passthrough object instead of failing logging, and cover the relay against the real binding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ocr): drop the unused LlmProviders import from health check helpers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: drop the ocr_testing job now that tests/ocr_tests is gone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(ocr): restore the live OCR matrix and the ocr_testing job The public litellm.ocr / aocr / Router interface is unchanged by the Rust migration, so the live provider matrix still applies. Drops the stale VCR skip list for the deleted test_rust_bridge.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(ocr): import Final in the health check helper tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Yujong Lee <yujong@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
3.3 KiB
Python
86 lines
3.3 KiB
Python
import json
|
|
from datetime import datetime
|
|
from typing import Final
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
import litellm
|
|
from litellm.litellm_core_utils.litellm_logging import Logging
|
|
from litellm.llms.azure_ai.passthrough.transformation import AzureAIPassthroughConfig
|
|
from litellm.llms.base_llm.ocr.transformation import OCRResponse
|
|
|
|
pytestmark = pytest.mark.requires_rust_extension
|
|
FOUNDRY_BASE: Final = "https://my-resource.services.ai.azure.com"
|
|
MISTRAL_BODY: Final = {
|
|
"pages": [{"index": 0, "markdown": "page one"}, {"index": 1, "markdown": "page two"}],
|
|
"model": "mistral-document-ai-2512",
|
|
"usage_info": {"pages_processed": 2, "doc_size_bytes": 4321},
|
|
}
|
|
COHERE_BODY: Final = {"id": "parse-1", "pages": [], "meta": {"billed_units": {"pages": 3}}}
|
|
|
|
|
|
def _relay(model: str, native_path: str, body: object) -> tuple[object, Logging]:
|
|
logging_obj: Final = Logging(
|
|
model=model,
|
|
messages=[],
|
|
stream=False,
|
|
call_type="allm_passthrough_route",
|
|
start_time=datetime.now(),
|
|
litellm_call_id="call-1",
|
|
function_id="fn-1",
|
|
)
|
|
logging_obj.update_environment_variables(
|
|
model=model,
|
|
litellm_params={"api_base": FOUNDRY_BASE, "custom_llm_provider": "azure_ai"},
|
|
optional_params={},
|
|
custom_llm_provider="azure_ai",
|
|
)
|
|
response: Final = httpx.Response(
|
|
status_code=200,
|
|
headers={"content-type": "application/json"},
|
|
content=json.dumps(body).encode(),
|
|
request=httpx.Request("POST", f"{FOUNDRY_BASE}/{native_path}?api-version=2024-05-01-preview"),
|
|
)
|
|
result: Final = AzureAIPassthroughConfig().logging_non_streaming_response(
|
|
model=model,
|
|
custom_llm_provider="azure_ai",
|
|
httpx_response=response,
|
|
request_data={"model": model},
|
|
logging_obj=logging_obj,
|
|
endpoint=f"{model}/{native_path}",
|
|
)
|
|
return result, logging_obj
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("model", "native_path", "body", "pages"),
|
|
[
|
|
("mistral-document-ai-2512", "providers/mistral/azure/ocr", MISTRAL_BODY, 2),
|
|
("Cohere-parse-v5", "providers/cohere/v2/parse", COHERE_BODY, 3),
|
|
],
|
|
)
|
|
def test_ocr_relay_is_costed_per_page(model: str, native_path: str, body: object, pages: int) -> None:
|
|
result, logging_obj = _relay(model, native_path, body)
|
|
per_page: Final = litellm.get_model_info(f"azure_ai/{model}")["ocr_cost_per_page"]
|
|
|
|
assert isinstance(result, OCRResponse)
|
|
assert result.usage_info is not None
|
|
assert result.usage_info.pages_processed == pages
|
|
assert logging_obj.call_type == "aocr"
|
|
assert per_page is not None and per_page > 0
|
|
assert logging_obj._response_cost_calculator(result=result) == pytest.approx(pages * per_page) # pyright: ignore[reportPrivateUsage] # the per-page cost path is what the relay routes into
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("native_path", "body", "logged"),
|
|
[
|
|
("models/info", {"name": "mistral-document-ai-2512"}, {"name": "mistral-document-ai-2512"}),
|
|
("providers/mistral/azure/ocr", ["not", "an", "ocr", "body"], '["not", "an", "ocr", "body"]'),
|
|
],
|
|
)
|
|
def test_non_ocr_relay_keeps_the_passthrough_object(native_path: str, body: object, logged: object) -> None:
|
|
result, logging_obj = _relay("mistral-document-ai-2512", native_path, body)
|
|
|
|
assert result == {"response": logged}
|
|
assert logging_obj.call_type == "allm_passthrough_route"
|