mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix(passthrough): charge remote high-detail images at the high-detail upper bound
This commit is contained in:
parent
6ed72693dc
commit
4706acef95
7 changed files with 41 additions and 14 deletions
|
|
@ -172,6 +172,13 @@ def calculate_tiles_needed(
|
|||
return total_tiles
|
||||
|
||||
|
||||
def high_detail_image_token_upper_bound(base_tokens: int = 85) -> int:
|
||||
largest_tile_count: Final = calculate_tiles_needed(
|
||||
MAX_LONG_SIDE_FOR_IMAGE_HIGH_RES, MAX_SHORT_SIDE_FOR_IMAGE_HIGH_RES
|
||||
)
|
||||
return base_tokens + (base_tokens * 2) * largest_tile_count
|
||||
|
||||
|
||||
def _unpack_ints(fmt: str, buffer: bytes) -> tuple[int, ...]:
|
||||
return struct.unpack(fmt, buffer)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ import httpx
|
|||
|
||||
import litellm
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
from litellm.constants import DEFAULT_IMAGE_TOKEN_COUNT
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
|
||||
from litellm.litellm_core_utils.litellm_logging import (
|
||||
get_standard_logging_object_payload,
|
||||
)
|
||||
from litellm.litellm_core_utils.token_counter import high_detail_image_token_upper_bound
|
||||
from litellm.llms.openai.openai import OpenAIConfig
|
||||
from litellm.llms.openai.openai import OpenAIConfig as OpenAIConfigType
|
||||
from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig
|
||||
|
|
@ -133,7 +133,7 @@ def count_relayed_prompt_tokens(model: str, messages: Sequence[Mapping[str, obje
|
|||
]
|
||||
return (
|
||||
litellm.token_counter(model=model, messages=local_messages)
|
||||
+ DEFAULT_IMAGE_TOKEN_COUNT * remote_high_detail_images
|
||||
+ high_detail_image_token_upper_bound() * remote_high_detail_images
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
"limit": 3
|
||||
},
|
||||
"BLE001": {
|
||||
"limit": 2904
|
||||
"limit": 2900
|
||||
},
|
||||
"C401": {
|
||||
"limit": 8
|
||||
|
|
@ -201,7 +201,7 @@
|
|||
"limit": 310
|
||||
},
|
||||
"SIM103": {
|
||||
"limit": 110
|
||||
"limit": 108
|
||||
},
|
||||
"SIM113": {
|
||||
"limit": 3
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#### What this tests ####
|
||||
# This tests litellm.token_counter.token_counter() function
|
||||
import base64
|
||||
import importlib
|
||||
import time
|
||||
import traceback
|
||||
|
|
@ -14,7 +15,11 @@ import litellm
|
|||
from litellm import create_pretrained_tokenizer, decode, encode, get_modified_max_tokens
|
||||
from litellm import token_counter as token_counter_old
|
||||
import litellm.constants
|
||||
from litellm.litellm_core_utils.token_counter import _get_tiktoken_count_function
|
||||
from litellm.litellm_core_utils.token_counter import (
|
||||
_get_tiktoken_count_function,
|
||||
calculate_img_tokens,
|
||||
high_detail_image_token_upper_bound,
|
||||
)
|
||||
from litellm.litellm_core_utils.token_counter import token_counter as token_counter_new
|
||||
from tests.large_text import text
|
||||
from tests.test_litellm.litellm_core_utils.messages_with_counts import (
|
||||
|
|
@ -1412,3 +1417,18 @@ def test_openai_file_block_without_inline_bytes_counts_what_it_carries():
|
|||
assert _count_user_content([prompt, named]) == _count_user_content(
|
||||
[prompt, {"type": "text", "text": "report.pdf"}]
|
||||
)
|
||||
|
||||
|
||||
def _png_data_url(width: int, height: int) -> str:
|
||||
ihdr = b"\x89PNG\r\n\x1a\n" + (13).to_bytes(4, "big") + b"IHDR" + width.to_bytes(4, "big") + height.to_bytes(4, "big")
|
||||
return "data:image/png;base64," + base64.b64encode(ihdr + b"\x08\x06\x00\x00\x00").decode()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("width", "height"), [(1, 1), (768, 768), (2000, 768), (768, 2000), (4096, 4096), (8000, 3072)])
|
||||
def test_high_detail_image_token_upper_bound_covers_every_image_size(width: int, height: int) -> None:
|
||||
assert calculate_img_tokens(_png_data_url(width, height), mode="high") <= high_detail_image_token_upper_bound()
|
||||
|
||||
|
||||
def test_high_detail_image_token_upper_bound_is_reached_by_the_largest_high_res_image() -> None:
|
||||
assert calculate_img_tokens(_png_data_url(2000, 768), mode="high") == high_detail_image_token_upper_bound()
|
||||
assert calculate_img_tokens(_png_data_url(1, 1), mode="high") < high_detail_image_token_upper_bound()
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import httpx
|
|||
import pytest
|
||||
|
||||
import litellm
|
||||
from litellm.constants import DEFAULT_IMAGE_TOKEN_COUNT
|
||||
|
||||
|
||||
from litellm.litellm_core_utils.token_counter import high_detail_image_token_upper_bound
|
||||
from litellm.llms.azure.passthrough.transformation import AzurePassthroughConfig
|
||||
from litellm.types.utils import ModelResponse
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ def test_azure_passthrough_streaming_chunks_count_remote_image_prompt_tokens_wit
|
|||
text_only_messages = [{"role": "user", "content": [{"type": "text", "text": "Describe this"}]}]
|
||||
assert isinstance(response, ModelResponse)
|
||||
assert response.usage.prompt_tokens == (
|
||||
litellm.token_counter(model="gpt-4.1-mini", messages=text_only_messages) + DEFAULT_IMAGE_TOKEN_COUNT
|
||||
litellm.token_counter(model="gpt-4.1-mini", messages=text_only_messages) + high_detail_image_token_upper_bound()
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import pytest
|
|||
|
||||
|
||||
import litellm
|
||||
from litellm.constants import DEFAULT_IMAGE_TOKEN_COUNT
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
|
||||
from litellm.litellm_core_utils.token_counter import high_detail_image_token_upper_bound
|
||||
from litellm.proxy.pass_through_endpoints.llm_provider_handlers.openai_passthrough_logging_handler import (
|
||||
OpenAIPassthroughLoggingHandler,
|
||||
count_relayed_prompt_tokens,
|
||||
|
|
@ -2074,12 +2074,12 @@ def test_count_relayed_prompt_tokens_keeps_a_low_detail_remote_image_at_the_base
|
|||
assert count_relayed_prompt_tokens("gpt-4.1-mini", messages) == litellm.token_counter(
|
||||
model="gpt-4.1-mini", messages=messages
|
||||
)
|
||||
assert count_relayed_prompt_tokens("gpt-4.1-mini", messages) < DEFAULT_IMAGE_TOKEN_COUNT
|
||||
assert count_relayed_prompt_tokens("gpt-4.1-mini", messages) < high_detail_image_token_upper_bound()
|
||||
|
||||
|
||||
def test_count_relayed_prompt_tokens_estimates_only_the_remote_high_detail_image():
|
||||
def test_count_relayed_prompt_tokens_charges_only_the_remote_high_detail_image_at_the_upper_bound():
|
||||
messages = _image_messages(UNREACHABLE_IMAGE_URL, "high")
|
||||
|
||||
assert count_relayed_prompt_tokens("gpt-4.1-mini", messages) == (
|
||||
litellm.token_counter(model="gpt-4.1-mini", messages=TEXT_ONLY_MESSAGES) + DEFAULT_IMAGE_TOKEN_COUNT
|
||||
litellm.token_counter(model="gpt-4.1-mini", messages=TEXT_ONLY_MESSAGES) + high_detail_image_token_upper_bound()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"LIT001": {
|
||||
"limit": 22156
|
||||
"limit": 22146
|
||||
},
|
||||
"LIT002": {
|
||||
"limit": 26745
|
||||
|
|
@ -27,10 +27,10 @@
|
|||
"limit": 0
|
||||
},
|
||||
"LIT010": {
|
||||
"limit": 16434
|
||||
"limit": 16422
|
||||
},
|
||||
"LIT011": {
|
||||
"limit": 5504
|
||||
"limit": 5502
|
||||
},
|
||||
"LIT012": {
|
||||
"limit": 4486
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue