diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index 701cefb771e..aeb3931076d 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -4338,6 +4338,7 @@ class BaseLLMHTTPHandler: headers=extra_headers or {}, model="", api_key=api_key, + litellm_params=litellm_params, ) if extra_headers: @@ -4413,6 +4414,7 @@ class BaseLLMHTTPHandler: headers=extra_headers or {}, model="", api_key=api_key, + litellm_params=litellm_params, ) if extra_headers: @@ -4727,6 +4729,7 @@ class BaseLLMHTTPHandler: api_key=api_key, headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: @@ -4899,6 +4902,7 @@ class BaseLLMHTTPHandler: api_key=api_key, headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: @@ -4985,6 +4989,7 @@ class BaseLLMHTTPHandler: api_key=api_key, headers=extra_headers or {}, model="", + litellm_params=litellm_params, ) if extra_headers: diff --git a/litellm/llms/vertex_ai/videos/transformation.py b/litellm/llms/vertex_ai/videos/transformation.py index 4cf3e036d3f..8a542ae4ef0 100644 --- a/litellm/llms/vertex_ai/videos/transformation.py +++ b/litellm/llms/vertex_ai/videos/transformation.py @@ -222,6 +222,8 @@ class VertexAIVideoConfig(BaseVideoConfig, VertexBase): # Construct the URL if api_base: base_url = api_base.rstrip("/") + elif vertex_location == "global": + base_url = "https://aiplatform.googleapis.com" else: base_url = f"https://{vertex_location}-aiplatform.googleapis.com" diff --git a/litellm/proxy/route_llm_request.py b/litellm/proxy/route_llm_request.py index 221aa16f912..68823828fa1 100644 --- a/litellm/proxy/route_llm_request.py +++ b/litellm/proxy/route_llm_request.py @@ -257,8 +257,19 @@ async def route_request( "aretrieve_container", "adelete_container", ]: - # moderation endpoint does not require `model` parameter + # These endpoints can work with or without model parameter return getattr(llm_router, f"{route_type}")(**data) + elif route_type in [ + "avideo_status", + "avideo_content", + "avideo_remix", + ]: + # Video endpoints: If model is provided (e.g., from decoded video_id), try router first + try: + return getattr(llm_router, f"{route_type}")(**data) + except Exception: + # If router fails (e.g., model not found in router), fall back to direct call + return getattr(litellm, f"{route_type}")(**data) elif user_model is not None: return getattr(litellm, f"{route_type}")(**data) diff --git a/litellm/proxy/video_endpoints/endpoints.py b/litellm/proxy/video_endpoints/endpoints.py index 25114921dbc..5e00eb58455 100644 --- a/litellm/proxy/video_endpoints/endpoints.py +++ b/litellm/proxy/video_endpoints/endpoints.py @@ -1,20 +1,21 @@ #### Video Endpoints ##### +from typing import Any, Dict, Optional + import orjson -from fastapi import APIRouter, Depends, Request, Response, UploadFile, File +from fastapi import APIRouter, Depends, File, Request, Response, UploadFile from fastapi.responses import ORJSONResponse -from typing import Optional, Dict, Any from litellm.proxy._types import * from litellm.proxy.auth.user_api_key_auth import UserAPIKeyAuth, user_api_key_auth from litellm.proxy.common_request_processing import ProxyBaseLLMRequestProcessing -from litellm.proxy.image_endpoints.endpoints import batch_to_bytesio from litellm.proxy.common_utils.http_parsing_utils import _read_request_body from litellm.proxy.common_utils.openai_endpoint_utils import ( get_custom_llm_provider_from_request_body, get_custom_llm_provider_from_request_headers, get_custom_llm_provider_from_request_query, ) +from litellm.proxy.image_endpoints.endpoints import batch_to_bytesio from litellm.types.videos.utils import decode_video_id_with_provider router = APIRouter() @@ -240,6 +241,7 @@ async def video_status( decoded = decode_video_id_with_provider(video_id) provider_from_id = decoded.get("custom_llm_provider") + model_id_from_decoded = decoded.get("model_id") custom_llm_provider = ( get_custom_llm_provider_from_request_headers(request=request) @@ -251,6 +253,13 @@ async def video_status( if custom_llm_provider: data["custom_llm_provider"] = custom_llm_provider + # Resolve model_name from model_id if available + # This allows the router to automatically inject litellm_params from the model config + if model_id_from_decoded and llm_router: + resolved_model = llm_router.resolve_model_name_from_model_id(model_id_from_decoded) + if resolved_model: + data["model"] = resolved_model + # Process request using ProxyBaseLLMRequestProcessing processor = ProxyBaseLLMRequestProcessing(data=data) try: @@ -331,6 +340,7 @@ async def video_content( decoded = decode_video_id_with_provider(video_id) provider_from_id = decoded.get("custom_llm_provider") + model_id_from_decoded = decoded.get("model_id") custom_llm_provider = ( get_custom_llm_provider_from_request_headers(request=request) @@ -341,6 +351,12 @@ async def video_content( if custom_llm_provider: data["custom_llm_provider"] = custom_llm_provider + # Resolve model_name from model_id if available + # This allows the router to automatically inject litellm_params from the model config + if model_id_from_decoded and llm_router: + resolved_model = llm_router.resolve_model_name_from_model_id(model_id_from_decoded) + if resolved_model: + data["model"] = resolved_model # Process request using ProxyBaseLLMRequestProcessing processor = ProxyBaseLLMRequestProcessing(data=data) try: @@ -436,6 +452,7 @@ async def video_remix( decoded = decode_video_id_with_provider(video_id) provider_from_id = decoded.get("custom_llm_provider") + model_id_from_decoded = decoded.get("model_id") custom_llm_provider = ( get_custom_llm_provider_from_request_headers(request=request) @@ -446,6 +463,13 @@ async def video_remix( if custom_llm_provider: data["custom_llm_provider"] = custom_llm_provider + # Resolve model_name from model_id if available + # This allows the router to automatically inject litellm_params from the model config + if model_id_from_decoded and llm_router: + resolved_model = llm_router.resolve_model_name_from_model_id(model_id_from_decoded) + if resolved_model: + data["model"] = resolved_model + # Process request using ProxyBaseLLMRequestProcessing processor = ProxyBaseLLMRequestProcessing(data=data) try: diff --git a/litellm/router.py b/litellm/router.py index efc622ed3c3..b39e719022f 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -43,10 +43,6 @@ import litellm import litellm.litellm_core_utils import litellm.litellm_core_utils.exception_mapping_utils from litellm import get_secret_str -from litellm.router_utils.common_utils import ( - filter_team_based_models, - filter_web_search_deployments, -) from litellm._logging import verbose_router_logger from litellm._uuid import uuid from litellm.caching.caching import ( @@ -89,6 +85,10 @@ from litellm.router_utils.clientside_credential_handler import ( get_dynamic_litellm_params, is_clientside_credential, ) +from litellm.router_utils.common_utils import ( + filter_team_based_models, + filter_web_search_deployments, +) from litellm.router_utils.cooldown_cache import CooldownCache from litellm.router_utils.cooldown_handlers import ( DEFAULT_COOLDOWN_TIME_SECONDS, @@ -157,7 +157,11 @@ from litellm.types.utils import ( ) from litellm.types.utils import ModelInfo from litellm.types.utils import ModelInfo as ModelMapInfo -from litellm.types.utils import ModelResponseStream, StandardLoggingPayload, Usage +from litellm.types.utils import ( + ModelResponseStream, + StandardLoggingPayload, + Usage, +) from litellm.utils import ( CustomStreamWrapper, EmbeddingResponse, @@ -6679,6 +6683,58 @@ class Router: """ return candidate_id in self.model_id_to_deployment_index_map + def resolve_model_name_from_model_id(self, model_id: Optional[str]) -> Optional[str]: + """ + Resolve model_name from model_id. + + This method attempts to find the correct model_name to use with the router + so that litellm_params can be automatically injected from the model config. + + Strategy: + 1. First, check if model_id directly matches a model_name or deployment ID + 2. If not, search through router's model_list to find a match by litellm_params.model + 3. Return the model_name if found, None otherwise + + Args: + model_id: The model_id extracted from decoded video_id + (could be model_name or litellm_params.model value) + + Returns: + model_name if found, None otherwise. If None, the request will fall through + to normal flow using environment variables. + """ + if not model_id: + return None + + # Strategy 1: Check if model_id directly matches a model_name or deployment ID + if model_id in self.model_names or self.has_model_id(model_id): + return model_id + + # Strategy 2: Search through router's model_list to find by litellm_params.model + all_models = self.get_model_list(model_name=None) + if not all_models: + return None + + for deployment in all_models: + litellm_params = deployment.get("litellm_params", {}) + actual_model = litellm_params.get("model") + + # Match by exact match or by checking if actual_model ends with /model_id or :model_id + # e.g., model_id="veo-2.0-generate-001" matches actual_model="vertex_ai/veo-2.0-generate-001" + matches = ( + actual_model == model_id + or (actual_model and actual_model.endswith(f"/{model_id}")) + or (actual_model and actual_model.endswith(f":{model_id}")) + ) + + if matches: + model_name = deployment.get("model_name") + if model_name: + return model_name + + # No match found + return None + def map_team_model(self, team_model_name: str, team_id: str) -> Optional[str]: """ Map a team model name to a team-specific model name. diff --git a/litellm/videos/main.py b/litellm/videos/main.py index be95b4ab9b2..74e41ed5be3 100644 --- a/litellm/videos/main.py +++ b/litellm/videos/main.py @@ -1,25 +1,26 @@ import asyncio import contextvars -from functools import partial -from typing import Any, Coroutine, Literal, Optional, Union, overload, Dict, List - import json +from functools import partial +from typing import Any, Coroutine, Dict, List, Literal, Optional, Union, overload + import litellm +from litellm.constants import DEFAULT_VIDEO_ENDPOINT_MODEL +from litellm.constants import request_timeout as DEFAULT_REQUEST_TIMEOUT from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider +from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj +from litellm.llms.base_llm.videos.transformation import BaseVideoConfig +from litellm.llms.custom_httpx.llm_http_handler import BaseLLMHTTPHandler +from litellm.main import base_llm_http_handler +from litellm.types.router import GenericLiteLLMParams +from litellm.types.utils import CallTypes, FileTypes from litellm.types.videos.main import ( VideoCreateOptionalRequestParams, VideoObject, ) -from litellm.videos.utils import VideoGenerationRequestUtils -from litellm.constants import DEFAULT_VIDEO_ENDPOINT_MODEL, request_timeout as DEFAULT_REQUEST_TIMEOUT -from litellm.main import base_llm_http_handler -from litellm.utils import client, ProviderConfigManager -from litellm.types.utils import FileTypes, CallTypes -from litellm.types.router import GenericLiteLLMParams -from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj -from litellm.llms.base_llm.videos.transformation import BaseVideoConfig -from litellm.llms.custom_httpx.llm_http_handler import BaseLLMHTTPHandler from litellm.types.videos.utils import decode_video_id_with_provider +from litellm.utils import ProviderConfigManager, client +from litellm.videos.utils import VideoGenerationRequestUtils #################### Initialize provider clients #################### llm_http_handler: BaseLLMHTTPHandler = BaseLLMHTTPHandler() @@ -416,10 +417,10 @@ async def avideo_content( loop = asyncio.get_event_loop() kwargs["async_call"] = True - # Ensure custom_llm_provider is not None - default to openai if not provided - # Video content endpoints don't require a model parameter + # Try to decode provider from video_id if not explicitly provided if custom_llm_provider is None: - custom_llm_provider = "openai" + decoded = decode_video_id_with_provider(video_id) + custom_llm_provider = decoded.get("custom_llm_provider") or "openai" func = partial( video_content,