fix: use seconds for Replicate runtime pricing

This commit is contained in:
nightcityblade 2026-07-15 11:24:06 +08:00 • committed by nightcityblade
parent 69a491e168
commit 0af09747ea
2 changed files with 31 additions and 5 deletions

View file

@ -699,12 +699,12 @@ def get_replicate_completion_pricing(completion_response: dict, total_time=0.0):
a100_80gb_price_per_second_public = (
DEFAULT_REPLICATE_GPU_PRICE_PER_SECOND # assume all calls sent to A100 80GB for now
)
if total_time == 0.0: # total time is in ms
if total_time == 0.0: # total time is in seconds
start_time = completion_response.get("created", time.time())
end_time = getattr(completion_response, "ended", time.time())
end_time = completion_response.get("ended", time.time())
total_time = end_time - start_time
return a100_80gb_price_per_second_public * total_time / 1000
return a100_80gb_price_per_second_public * total_time
def has_hidden_params(obj: Any) -> bool:
@ -1164,6 +1164,7 @@ def completion_cost(
- For un-mapped Replicate models, the cost is calculated based on the total time used for the request.
"""
try:
replicate_total_time_seconds = total_time or 0.0
call_type = _infer_call_type(call_type, completion_response) or "completion"
if (
@ -1283,7 +1284,10 @@ def completion_cost(
prompt_tokens_details = _usage.get("prompt_tokens_details") or {}
cache_read_input_tokens = prompt_tokens_details.get("cached_tokens", 0)
total_time = getattr(completion_response, "_response_ms", 0)
response_time_ms: float = getattr(completion_response, "_response_ms", 0) or 0
total_time = response_time_ms
if replicate_total_time_seconds == 0.0:
replicate_total_time_seconds = response_time_ms / 1000
hidden_params = getattr(completion_response, "_hidden_params", None)
if hidden_params is not None:
@ -1521,7 +1525,7 @@ def completion_cost(
# see https://replicate.com/pricing
elif (model in litellm.replicate_models or "replicate" in model) and model not in litellm.model_cost:
# for unmapped replicate model, default to replicate's time tracking logic
return get_replicate_completion_pricing(completion_response, total_time) # type: ignore
return get_replicate_completion_pricing(completion_response, replicate_total_time_seconds) # type: ignore
if model is None:
raise ValueError(

View file

@ -11,10 +11,12 @@ sys.path.insert(
from pydantic import BaseModel
import litellm
from litellm.constants import DEFAULT_REPLICATE_GPU_PRICE_PER_SECOND
from litellm.cost_calculator import (
RealtimeAPITokenUsageProcessor,
completion_cost,
cost_per_token,
get_replicate_completion_pricing,
handle_realtime_stream_cost_calculation,
response_cost_calculator,
)
@ -23,6 +25,26 @@ from litellm.types.utils import ModelResponse, PromptTokensDetailsWrapper, Usage
from litellm.utils import TranscriptionResponse
def test_unmapped_replicate_cost_with_explicit_seconds():
cost = completion_cost(model="replicate/unmapped-runtime", total_time=2.0)
assert cost == pytest.approx(DEFAULT_REPLICATE_GPU_PRICE_PER_SECOND * 2.0)
def test_unmapped_replicate_cost_with_timestamp_fallback():
response = {"created": 10.0, "ended": 12.0}
cost = get_replicate_completion_pricing(response)
assert cost == pytest.approx(DEFAULT_REPLICATE_GPU_PRICE_PER_SECOND * 2.0)
def test_unmapped_replicate_cost_converts_response_ms_to_seconds():
model = "replicate/unmapped-runtime"
response = ModelResponse(model=model)
response._response_ms = 2000.0
cost = completion_cost(model=model, completion_response=response)
assert cost == pytest.approx(DEFAULT_REPLICATE_GPU_PRICE_PER_SECOND * 2.0)
def test_cost_per_token_duplicate_openai_prefix_matches_model_cost(monkeypatch):
"""
Router/proxy configs may use deployment ids like openai/openai/<model>. Cost lookup must