Merge pull request #37751 from BerriAI/litellm_fal_gpt_image_2_keyed_pricing

fix(fal_ai): price gpt-image-2 per size and quality from request params
This commit is contained in:
Mateo Wang 2026-08-20 19:51:26 -07:00 committed by GitHub
commit 354f497faf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 1314 additions and 23 deletions

View file

@ -1371,6 +1371,7 @@ class CostCalculatorUtils:
return fal_ai_image_cost_calculator(
model=model,
image_response=completion_response,
optional_params=optional_params,
)
elif custom_llm_provider == litellm.LlmProviders.RUNWAYML.value:
from litellm.llms.runwayml.cost_calculator import (

View file

@ -1,25 +1,75 @@
from typing import Any, Final
from collections.abc import Mapping
from types import MappingProxyType
from typing import Final
import litellm
from litellm.types.utils import ImageResponse
FAL_KEYED_PRICING_DEFAULT_QUALITY: Final[str] = "high"
FAL_TEXT_TO_IMAGE_DEFAULT_SIZE: Final[str] = "1024-x-768"
FAL_NAMED_IMAGE_SIZES: Final[Mapping[str, str]] = MappingProxyType(
{
"square_hd": "1024-x-1024",
"square": "512-x-512",
"portrait_4_3": "768-x-1024",
"portrait_16_9": "576-x-1024",
"landscape_4_3": "1024-x-768",
"landscape_16_9": "1024-x-576",
}
)
def _keyed_size(model: str, optional_params: Mapping[str, object]) -> str | None:
image_size: Final = optional_params.get("image_size")
if image_size is None:
return None if model.endswith("/edit") else FAL_TEXT_TO_IMAGE_DEFAULT_SIZE
if isinstance(image_size, Mapping):
width: Final = image_size.get("width")
height: Final = image_size.get("height")
if isinstance(width, int) and isinstance(height, int):
return f"{width}-x-{height}"
return None
if isinstance(image_size, str):
return FAL_NAMED_IMAGE_SIZES.get(image_size)
return None
def _keyed_cost_per_image(model: str, optional_params: Mapping[str, object] | None) -> float | None:
if optional_params is None:
return None
size: Final = _keyed_size(model=model, optional_params=optional_params)
if size is None:
return None
raw_quality: Final = optional_params.get("quality")
quality: Final = (
raw_quality if isinstance(raw_quality, str) and raw_quality != "auto" else FAL_KEYED_PRICING_DEFAULT_QUALITY
)
keyed_entry: Final = litellm.model_cost.get(f"fal_ai/{quality}/{size}/{model}")
if keyed_entry is None:
return None
keyed_cost: Final = keyed_entry.get("output_cost_per_image")
return float(keyed_cost) if isinstance(keyed_cost, (int, float)) else None
def cost_calculator(
model: str,
image_response: Any,
image_response: object,
optional_params: Mapping[str, object] | None = None,
) -> float:
"""
fal.ai image generation cost calculator
"""
if not isinstance(image_response, ImageResponse):
raise ValueError(f"image_response must be of type ImageResponse got type={type(image_response)}")
# the proxy cost path passes the provider-prefixed model name
model = model.removeprefix(f"{litellm.LlmProviders.FAL_AI.value}/")
num_images: Final[int] = len(image_response.data) if image_response.data else 0
keyed_cost_per_image: Final = _keyed_cost_per_image(model=model, optional_params=optional_params)
if keyed_cost_per_image is not None:
return keyed_cost_per_image * num_images
_model_info: Final = litellm.get_model_info(
model=model,
custom_llm_provider=litellm.LlmProviders.FAL_AI.value,
)
output_cost_per_image: Final[float] = _model_info.get("output_cost_per_image") or 0.0
num_images: int = 0
if isinstance(image_response, ImageResponse):
if image_response.data:
num_images = len(image_response.data)
return output_cost_per_image * num_images
else:
raise ValueError(f"image_response must be of type ImageResponse got type={type(image_response)}")
return output_cost_per_image * num_images

View file

@ -17419,7 +17419,7 @@
"fal_ai/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"metadata": {
"notes": "OpenAI gpt-image-2 served through fal.ai. fal bills by token, so the flat output_cost_per_image here is fal's published per-image rate for a default request (quality=high, image_size=landscape_4_3 at 1024x768). Other canonical sizes at high quality: 1024x1024 $0.211, 1024x1536 $0.165, 1920x1080 $0.158, 2560x1440 $0.222, 3840x2160 $0.401"
"notes": "OpenAI gpt-image-2 served through fal.ai. fal bills by token but publishes deterministic per-image prices per size and quality, mirrored here as keyed entries fal_ai/{quality}/{width}-x-{height}/openai/gpt-image-2 that litellm's fal_ai cost calculator picks from the request params. This flat entry is the fallback when no keyed entry matches and carries the default request rate (quality=high, image_size=landscape_4_3 at 1024x768). quality=auto is priced as high"
},
"mode": "image_generation",
"output_cost_per_image": 0.145,
@ -17429,10 +17429,190 @@
],
"supports_vision": true
},
"fal_ai/low/1024-x-768/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1024/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.006,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1536/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1920-x-1080/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/2560-x-1440/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.007,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/3840-x-2160/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.012,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-768/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.037,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1024/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.053,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1536/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.042,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1920-x-1080/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.04,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/2560-x-1440/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.056,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/3840-x-2160/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.101,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-768/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.145,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1024/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.211,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1536/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.165,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1920-x-1080/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.158,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/2560-x-1440/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.222,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/3840-x-2160/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.401,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/gpt-image-2": {
"litellm_provider": "fal_ai",
"metadata": {
"notes": "Alias of fal_ai/openai/gpt-image-2, which litellm also accepts without the openai/ prefix. Same rate, see that entry for the size and quality caveat"
"notes": "Alias of fal_ai/openai/gpt-image-2, which litellm also accepts without the openai/ prefix. Same rates, including the keyed fal_ai/{quality}/{width}-x-{height}/gpt-image-2 entries; see that entry for details"
},
"mode": "image_generation",
"output_cost_per_image": 0.145,
@ -17442,13 +17622,373 @@
],
"supports_vision": true
},
"fal_ai/low/1024-x-768/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1024/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.006,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1536/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1920-x-1080/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/2560-x-1440/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.007,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/3840-x-2160/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.012,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-768/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.037,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1024/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.053,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1536/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.042,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1920-x-1080/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.04,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/2560-x-1440/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.056,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/3840-x-2160/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.101,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-768/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.145,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1024/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.211,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1536/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.165,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1920-x-1080/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.158,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/2560-x-1440/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.222,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/3840-x-2160/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.401,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"metadata": {
"notes": "Editing endpoint of gpt-image-2 on fal.ai, reached through the image generation path with fal's image_urls param since /v1/images/edits is not wired for fal_ai. Same rate as fal_ai/openai/gpt-image-2, see that entry for the size and quality caveat"
"notes": "Editing endpoint of gpt-image-2 on fal.ai, reached through the image generation path with fal's image_urls param since /v1/images/edits is not wired for fal_ai. Prices include one input image and live in keyed entries fal_ai/{quality}/{width}-x-{height}/openai/gpt-image-2/edit. This flat entry is the fallback for the default edit request (quality=high, image_size=auto, inferred from the input image, priced as 1024x768 high)"
},
"mode": "image_generation",
"output_cost_per_image": 0.145,
"output_cost_per_image": 0.151,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-768/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.011,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1024/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.015,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1536/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.018,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1920-x-1080/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.017,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/2560-x-1440/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.019,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/3840-x-2160/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.024,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-768/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.043,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1024/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.061,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1536/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.054,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1920-x-1080/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.053,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/2560-x-1440/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.068,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/3840-x-2160/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.113,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-768/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.151,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1024/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.219,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1536/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.178,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1920-x-1080/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.158,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/2560-x-1440/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.234,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/3840-x-2160/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.413,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"

View file

@ -17419,7 +17419,7 @@
"fal_ai/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"metadata": {
"notes": "OpenAI gpt-image-2 served through fal.ai. fal bills by token, so the flat output_cost_per_image here is fal's published per-image rate for a default request (quality=high, image_size=landscape_4_3 at 1024x768). Other canonical sizes at high quality: 1024x1024 $0.211, 1024x1536 $0.165, 1920x1080 $0.158, 2560x1440 $0.222, 3840x2160 $0.401"
"notes": "OpenAI gpt-image-2 served through fal.ai. fal bills by token but publishes deterministic per-image prices per size and quality, mirrored here as keyed entries fal_ai/{quality}/{width}-x-{height}/openai/gpt-image-2 that litellm's fal_ai cost calculator picks from the request params. This flat entry is the fallback when no keyed entry matches and carries the default request rate (quality=high, image_size=landscape_4_3 at 1024x768). quality=auto is priced as high"
},
"mode": "image_generation",
"output_cost_per_image": 0.145,
@ -17429,10 +17429,190 @@
],
"supports_vision": true
},
"fal_ai/low/1024-x-768/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1024/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.006,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1536/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1920-x-1080/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/2560-x-1440/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.007,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/3840-x-2160/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.012,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-768/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.037,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1024/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.053,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1536/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.042,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1920-x-1080/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.04,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/2560-x-1440/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.056,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/3840-x-2160/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.101,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-768/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.145,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1024/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.211,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1536/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.165,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1920-x-1080/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.158,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/2560-x-1440/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.222,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/3840-x-2160/openai/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.401,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/gpt-image-2": {
"litellm_provider": "fal_ai",
"metadata": {
"notes": "Alias of fal_ai/openai/gpt-image-2, which litellm also accepts without the openai/ prefix. Same rate, see that entry for the size and quality caveat"
"notes": "Alias of fal_ai/openai/gpt-image-2, which litellm also accepts without the openai/ prefix. Same rates, including the keyed fal_ai/{quality}/{width}-x-{height}/gpt-image-2 entries; see that entry for details"
},
"mode": "image_generation",
"output_cost_per_image": 0.145,
@ -17442,13 +17622,373 @@
],
"supports_vision": true
},
"fal_ai/low/1024-x-768/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1024/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.006,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1536/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1920-x-1080/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.005,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/2560-x-1440/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.007,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/3840-x-2160/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.012,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-768/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.037,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1024/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.053,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1536/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.042,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1920-x-1080/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.04,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/2560-x-1440/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.056,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/3840-x-2160/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.101,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-768/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.145,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1024/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.211,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1536/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.165,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1920-x-1080/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.158,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/2560-x-1440/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.222,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/3840-x-2160/gpt-image-2": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.401,
"source": "https://fal.ai/models/openai/gpt-image-2",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"metadata": {
"notes": "Editing endpoint of gpt-image-2 on fal.ai, reached through the image generation path with fal's image_urls param since /v1/images/edits is not wired for fal_ai. Same rate as fal_ai/openai/gpt-image-2, see that entry for the size and quality caveat"
"notes": "Editing endpoint of gpt-image-2 on fal.ai, reached through the image generation path with fal's image_urls param since /v1/images/edits is not wired for fal_ai. Prices include one input image and live in keyed entries fal_ai/{quality}/{width}-x-{height}/openai/gpt-image-2/edit. This flat entry is the fallback for the default edit request (quality=high, image_size=auto, inferred from the input image, priced as 1024x768 high)"
},
"mode": "image_generation",
"output_cost_per_image": 0.145,
"output_cost_per_image": 0.151,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-768/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.011,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1024/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.015,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1024-x-1536/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.018,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/1920-x-1080/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.017,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/2560-x-1440/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.019,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/low/3840-x-2160/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.024,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-768/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.043,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1024/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.061,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1024-x-1536/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.054,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/1920-x-1080/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.053,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/2560-x-1440/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.068,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/medium/3840-x-2160/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.113,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-768/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.151,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1024/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.219,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1024-x-1536/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.178,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/1920-x-1080/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.158,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/2560-x-1440/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.234,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"
],
"supports_vision": true
},
"fal_ai/high/3840-x-2160/openai/gpt-image-2/edit": {
"litellm_provider": "fal_ai",
"mode": "image_generation",
"output_cost_per_image": 0.413,
"source": "https://fal.ai/models/openai/gpt-image-2/edit",
"supported_endpoints": [
"/v1/images/generations"

View file

@ -128,19 +128,23 @@ def test_transform_image_generation_request():
@pytest.mark.parametrize(
"model",
("model", "expected_cost_for_two_images"),
[
"openai/gpt-image-2",
"gpt-image-2",
"openai/gpt-image-2/edit",
("openai/gpt-image-2", 0.29),
("gpt-image-2", 0.29),
("openai/gpt-image-2/edit", 0.302),
],
)
def test_cost_calculator_uses_registry_price(model, monkeypatch: pytest.MonkeyPatch):
def test_cost_calculator_uses_registry_price(
model, expected_cost_for_two_images, monkeypatch: pytest.MonkeyPatch
):
monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True")
monkeypatch.setattr(litellm, "model_cost", litellm.get_model_cost_map(url=""))
litellm.get_model_info.cache_clear()
response = ImageResponse(
data=[
ImageObject(url="https://v3b.fal.media/files/b/one.png"),
ImageObject(url="https://v3b.fal.media/files/b/two.png"),
]
)
assert cost_calculator(model=model, image_response=response) == pytest.approx(0.29)
assert cost_calculator(model=model, image_response=response) == pytest.approx(expected_cost_for_two_images)

View file

@ -0,0 +1,156 @@
import pytest
import litellm
from litellm.litellm_core_utils.llm_cost_calc.utils import CostCalculatorUtils
from litellm.llms.fal_ai.cost_calculator import cost_calculator
from litellm.types.utils import ImageObject, ImageResponse
@pytest.fixture(autouse=True)
def _use_local_model_cost_map(monkeypatch):
monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True")
monkeypatch.setattr(litellm, "model_cost", litellm.get_model_cost_map(url=""))
litellm.get_model_info.cache_clear()
yield
litellm.get_model_info.cache_clear()
def _image_response(num_images: int = 1) -> ImageResponse:
return ImageResponse(data=[ImageObject(url="https://example.com/img.png") for _ in range(num_images)])
def test_high_quality_1024x1024_uses_keyed_price():
cost = cost_calculator(
model="openai/gpt-image-2",
image_response=_image_response(),
optional_params={"quality": "high", "image_size": {"width": 1024, "height": 1024}},
)
assert cost == pytest.approx(0.211)
def test_alias_model_uses_keyed_price():
cost = cost_calculator(
model="gpt-image-2",
image_response=_image_response(),
optional_params={"quality": "high", "image_size": {"width": 1024, "height": 1024}},
)
assert cost == pytest.approx(0.211)
def test_provider_prefixed_model_uses_keyed_price():
cost = cost_calculator(
model="fal_ai/openai/gpt-image-2",
image_response=_image_response(),
optional_params={"quality": "high", "image_size": {"width": 1024, "height": 1024}},
)
assert cost == pytest.approx(0.211)
def test_provider_prefixed_edit_model_uses_keyed_edit_price():
cost = cost_calculator(
model="fal_ai/openai/gpt-image-2/edit",
image_response=_image_response(),
optional_params={"quality": "high", "image_size": {"width": 1024, "height": 1024}},
)
assert cost == pytest.approx(0.219)
def test_default_request_priced_at_default_size_and_quality():
cost = cost_calculator(
model="openai/gpt-image-2",
image_response=_image_response(),
optional_params={},
)
assert cost == pytest.approx(0.145)
def test_auto_quality_priced_as_high():
cost = cost_calculator(
model="openai/gpt-image-2",
image_response=_image_response(),
optional_params={"quality": "auto", "image_size": {"width": 1024, "height": 1024}},
)
assert cost == pytest.approx(0.211)
def test_low_quality_4k_uses_keyed_price():
cost = cost_calculator(
model="openai/gpt-image-2",
image_response=_image_response(),
optional_params={"quality": "low", "image_size": {"width": 3840, "height": 2160}},
)
assert cost == pytest.approx(0.012)
def test_named_fal_size_uses_keyed_price():
cost = cost_calculator(
model="openai/gpt-image-2",
image_response=_image_response(),
optional_params={"quality": "high", "image_size": "square_hd"},
)
assert cost == pytest.approx(0.211)
def test_edit_model_uses_keyed_edit_price():
cost = cost_calculator(
model="openai/gpt-image-2/edit",
image_response=_image_response(),
optional_params={"quality": "high", "image_size": {"width": 1024, "height": 1024}},
)
assert cost == pytest.approx(0.219)
def test_edit_model_without_size_falls_back_to_flat_price():
cost = cost_calculator(
model="openai/gpt-image-2/edit",
image_response=_image_response(),
optional_params={"quality": "high"},
)
assert cost == pytest.approx(0.151)
def test_missing_optional_params_falls_back_to_flat_price():
cost = cost_calculator(
model="openai/gpt-image-2",
image_response=_image_response(),
optional_params=None,
)
assert cost == pytest.approx(0.145)
def test_unlisted_size_falls_back_to_flat_price():
cost = cost_calculator(
model="openai/gpt-image-2",
image_response=_image_response(),
optional_params={"quality": "high", "image_size": {"width": 999, "height": 999}},
)
assert cost == pytest.approx(0.145)
def test_keyed_price_multiplies_per_image():
cost = cost_calculator(
model="openai/gpt-image-2",
image_response=_image_response(num_images=2),
optional_params={"quality": "high", "image_size": {"width": 1024, "height": 1024}},
)
assert cost == pytest.approx(0.422)
def test_route_image_generation_passes_optional_params_to_fal():
cost = CostCalculatorUtils.route_image_generation_cost_calculator(
model="openai/gpt-image-2",
completion_response=_image_response(),
custom_llm_provider="fal_ai",
optional_params={"quality": "high", "image_size": {"width": 1024, "height": 1024}},
)
assert cost == pytest.approx(0.211)
def test_route_image_generation_with_provider_prefixed_model_uses_keyed_price():
cost = CostCalculatorUtils.route_image_generation_cost_calculator(
model="fal_ai/openai/gpt-image-2",
completion_response=_image_response(),
custom_llm_provider="fal_ai",
optional_params={"quality": "high", "image_size": {"width": 1024, "height": 1024}},
)
assert cost == pytest.approx(0.211)