Spaces:
Paused
Paused
| #### CRUD ENDPOINTS for UI Settings ##### | |
| from typing import Any, Dict, List, Union | |
| from fastapi import APIRouter, Depends, HTTPException | |
| import litellm | |
| from litellm._logging import verbose_proxy_logger | |
| from litellm.proxy._types import * | |
| from litellm.proxy.auth.user_api_key_auth import user_api_key_auth | |
| from litellm.types.proxy.management_endpoints.ui_sso import DefaultTeamSSOParams, SSOConfig | |
| router = APIRouter() | |
| class IPAddress(BaseModel): | |
| ip: str | |
| class SettingsResponse(BaseModel): | |
| """Base response model for settings with values and schema information""" | |
| values: Dict[str, Any] | |
| """The current configuration values""" | |
| field_schema: Dict[str, Any] | |
| """Schema information including descriptions and property types for UI display""" | |
| class SSOSettingsResponse(SettingsResponse): | |
| """Response model for SSO settings""" | |
| pass | |
| class InternalUserSettingsResponse(SettingsResponse): | |
| """Response model for internal user settings""" | |
| pass | |
| class DefaultTeamSettingsResponse(SettingsResponse): | |
| """Response model for default team settings""" | |
| pass | |
| async def get_allowed_ips(): | |
| from litellm.proxy.proxy_server import general_settings | |
| _allowed_ip = general_settings.get("allowed_ips") | |
| return {"data": _allowed_ip} | |
| async def add_allowed_ip(ip_address: IPAddress): | |
| from litellm.proxy.proxy_server import ( | |
| general_settings, | |
| prisma_client, | |
| proxy_config, | |
| store_model_in_db, | |
| ) | |
| _allowed_ips: List = general_settings.get("allowed_ips", []) | |
| if ip_address.ip not in _allowed_ips: | |
| _allowed_ips.append(ip_address.ip) | |
| general_settings["allowed_ips"] = _allowed_ips | |
| else: | |
| raise HTTPException(status_code=400, detail="IP address already exists") | |
| if prisma_client is None: | |
| raise Exception("No DB Connected") | |
| if store_model_in_db is not True: | |
| raise HTTPException( | |
| status_code=500, | |
| detail={ | |
| "error": "Set `'STORE_MODEL_IN_DB='True'` in your env to enable this feature." | |
| }, | |
| ) | |
| # Load existing config | |
| config = await proxy_config.get_config() | |
| verbose_proxy_logger.debug("Loaded config: %s", config) | |
| if "general_settings" not in config: | |
| config["general_settings"] = {} | |
| if "allowed_ips" not in config["general_settings"]: | |
| config["general_settings"]["allowed_ips"] = [] | |
| if ip_address.ip not in config["general_settings"]["allowed_ips"]: | |
| config["general_settings"]["allowed_ips"].append(ip_address.ip) | |
| await proxy_config.save_config(new_config=config) | |
| return { | |
| "message": f"IP {ip_address.ip} address added successfully", | |
| "status": "success", | |
| } | |
| async def delete_allowed_ip(ip_address: IPAddress): | |
| from litellm.proxy.proxy_server import general_settings, proxy_config | |
| _allowed_ips: List = general_settings.get("allowed_ips", []) | |
| if ip_address.ip in _allowed_ips: | |
| _allowed_ips.remove(ip_address.ip) | |
| general_settings["allowed_ips"] = _allowed_ips | |
| else: | |
| raise HTTPException(status_code=404, detail="IP address not found") | |
| # Load existing config | |
| config = await proxy_config.get_config() | |
| verbose_proxy_logger.debug("Loaded config: %s", config) | |
| if "general_settings" not in config: | |
| config["general_settings"] = {} | |
| if "allowed_ips" not in config["general_settings"]: | |
| config["general_settings"]["allowed_ips"] = [] | |
| if ip_address.ip in config["general_settings"]["allowed_ips"]: | |
| config["general_settings"]["allowed_ips"].remove(ip_address.ip) | |
| await proxy_config.save_config(new_config=config) | |
| return {"message": f"IP {ip_address.ip} deleted successfully", "status": "success"} | |
| async def _get_settings_with_schema( | |
| settings_key: str, | |
| settings_class: Any, | |
| config: dict, | |
| ) -> dict: | |
| """ | |
| Common utility function to get settings with schema information. | |
| Args: | |
| settings_key: The key in litellm_settings to get | |
| settings_class: The Pydantic class to use for schema | |
| config: The config dictionary | |
| """ | |
| from pydantic import TypeAdapter | |
| litellm_settings = config.get("litellm_settings", {}) or {} | |
| settings_data = litellm_settings.get(settings_key, {}) or {} | |
| # Create the settings object | |
| settings = settings_class(**(settings_data)) | |
| # Get the schema | |
| schema = TypeAdapter(settings_class).json_schema(by_alias=True) | |
| # Convert to dict for response | |
| settings_dict = settings.model_dump() | |
| # Add descriptions to the response | |
| result = { | |
| "values": settings_dict, | |
| "field_schema": {"description": schema.get("description", ""), "properties": {}}, | |
| } | |
| # Add property descriptions | |
| for field_name, field_info in schema["properties"].items(): | |
| result["field_schema"]["properties"][field_name] = { | |
| "description": field_info.get("description", ""), | |
| "type": field_info.get("type", "string"), | |
| } | |
| # Add nested object descriptions | |
| for def_name, def_schema in schema.get("definitions", {}).items(): | |
| result["field_schema"][def_name] = { | |
| "description": def_schema.get("description", ""), | |
| "properties": { | |
| prop_name: {"description": prop_info.get("description", "")} | |
| for prop_name, prop_info in def_schema.get("properties", {}).items() | |
| }, | |
| } | |
| return result | |
| async def get_internal_user_settings(): | |
| """ | |
| Get all SSO settings from the litellm_settings configuration. | |
| Returns a structured object with values and descriptions for UI display. | |
| """ | |
| from litellm.proxy.proxy_server import proxy_config | |
| # Load existing config | |
| config = await proxy_config.get_config() | |
| return await _get_settings_with_schema( | |
| settings_key="default_internal_user_params", | |
| settings_class=DefaultInternalUserParams, | |
| config=config, | |
| ) | |
| async def get_default_team_settings(): | |
| """ | |
| Get all SSO settings from the litellm_settings configuration. | |
| Returns a structured object with values and descriptions for UI display. | |
| """ | |
| from litellm.proxy.proxy_server import proxy_config | |
| # Load existing config | |
| config = await proxy_config.get_config() | |
| return await _get_settings_with_schema( | |
| settings_key="default_team_params", | |
| settings_class=DefaultTeamSSOParams, | |
| config=config, | |
| ) | |
| async def _update_litellm_setting( | |
| settings: Union[DefaultInternalUserParams, DefaultTeamSSOParams], | |
| settings_key: str, | |
| in_memory_var: Any, | |
| success_message: str, | |
| ): | |
| """ | |
| Common utility function to update `litellm_settings` in both memory and config. | |
| Args: | |
| settings: The settings object to update | |
| settings_key: The key in litellm_settings to update | |
| in_memory_var: The in-memory variable to update | |
| success_message: Message to return on success | |
| """ | |
| from litellm.proxy.proxy_server import proxy_config | |
| # Update the in-memory settings | |
| in_memory_var = settings.model_dump(exclude_none=True) | |
| # Load existing config | |
| config = await proxy_config.get_config() | |
| # Update config with new settings | |
| if "litellm_settings" not in config: | |
| config["litellm_settings"] = {} | |
| config["litellm_settings"][settings_key] = settings.model_dump(exclude_none=True) | |
| # Save the updated config | |
| await proxy_config.save_config(new_config=config) | |
| return { | |
| "message": success_message, | |
| "status": "success", | |
| "settings": in_memory_var, | |
| } | |
| async def update_internal_user_settings(settings: DefaultInternalUserParams): | |
| """ | |
| Update the default internal user parameters for SSO users. | |
| These settings will be applied to new users who sign in via SSO. | |
| """ | |
| return await _update_litellm_setting( | |
| settings=settings, | |
| settings_key="default_internal_user_params", | |
| in_memory_var=litellm.default_internal_user_params, | |
| success_message="Internal user settings updated successfully", | |
| ) | |
| async def update_default_team_settings(settings: DefaultTeamSSOParams): | |
| """ | |
| Update the default team parameters for SSO users. | |
| These settings will be applied to new teams created from SSO. | |
| """ | |
| return await _update_litellm_setting( | |
| settings=settings, | |
| settings_key="default_team_params", | |
| in_memory_var=litellm.default_team_params, | |
| success_message="Default team settings updated successfully", | |
| ) | |
| async def get_sso_settings(): | |
| """ | |
| Get all SSO configuration settings from the environment variables. | |
| Returns a structured object with values and descriptions for UI display. | |
| """ | |
| import os | |
| from litellm.proxy.proxy_server import proxy_config | |
| # Load existing config to get both environment variables and general settings | |
| config = await proxy_config.get_config() | |
| general_settings = config.get("general_settings", {}) or {} | |
| environment_variables = config.get("environment_variables", {}) or {} | |
| # Get user_email from general_settings | |
| proxy_admin_email = general_settings.get("proxy_admin_email", None) | |
| # Helper function to get env var value (first from config, then from environment) | |
| def get_env_value(env_var_name: str): | |
| return environment_variables.get(env_var_name) or os.getenv(env_var_name) | |
| # Get current environment variables for SSO | |
| sso_config = SSOConfig( | |
| google_client_id=get_env_value("GOOGLE_CLIENT_ID"), | |
| google_client_secret=get_env_value("GOOGLE_CLIENT_SECRET"), | |
| microsoft_client_id=get_env_value("MICROSOFT_CLIENT_ID"), | |
| microsoft_client_secret=get_env_value("MICROSOFT_CLIENT_SECRET"), | |
| microsoft_tenant=get_env_value("MICROSOFT_TENANT"), | |
| generic_client_id=get_env_value("GENERIC_CLIENT_ID"), | |
| generic_client_secret=get_env_value("GENERIC_CLIENT_SECRET"), | |
| generic_authorization_endpoint=get_env_value("GENERIC_AUTHORIZATION_ENDPOINT"), | |
| generic_token_endpoint=get_env_value("GENERIC_TOKEN_ENDPOINT"), | |
| generic_userinfo_endpoint=get_env_value("GENERIC_USERINFO_ENDPOINT"), | |
| proxy_base_url=get_env_value("PROXY_BASE_URL"), | |
| user_email=proxy_admin_email, # Get from config instead of environment | |
| ) | |
| # Get the schema for UI display | |
| from pydantic import TypeAdapter | |
| schema = TypeAdapter(SSOConfig).json_schema(by_alias=True) | |
| # Convert to dict for response | |
| sso_dict = sso_config.model_dump() | |
| # Add descriptions to the response | |
| result = { | |
| "values": sso_dict, | |
| "field_schema": {"description": schema.get("description", ""), "properties": {}}, | |
| } | |
| # Add property descriptions | |
| for field_name, field_info in schema["properties"].items(): | |
| result["field_schema"]["properties"][field_name] = { | |
| "description": field_info.get("description", ""), | |
| "type": field_info.get("type", "string"), | |
| } | |
| return result | |
| async def update_sso_settings(sso_config: SSOConfig): | |
| """ | |
| Update SSO configuration by saving to both environment variables and config file. | |
| """ | |
| from litellm.proxy.proxy_server import proxy_config | |
| import os | |
| # Update environment variables | |
| env_var_mapping = { | |
| 'google_client_id': 'GOOGLE_CLIENT_ID', | |
| 'google_client_secret': 'GOOGLE_CLIENT_SECRET', | |
| 'microsoft_client_id': 'MICROSOFT_CLIENT_ID', | |
| 'microsoft_client_secret': 'MICROSOFT_CLIENT_SECRET', | |
| 'microsoft_tenant': 'MICROSOFT_TENANT', | |
| 'generic_client_id': 'GENERIC_CLIENT_ID', | |
| 'generic_client_secret': 'GENERIC_CLIENT_SECRET', | |
| 'generic_authorization_endpoint': 'GENERIC_AUTHORIZATION_ENDPOINT', | |
| 'generic_token_endpoint': 'GENERIC_TOKEN_ENDPOINT', | |
| 'generic_userinfo_endpoint': 'GENERIC_USERINFO_ENDPOINT', | |
| 'proxy_base_url': 'PROXY_BASE_URL', | |
| } | |
| # Load existing config | |
| config = await proxy_config.get_config() | |
| # Update config with new environment variables | |
| if "environment_variables" not in config: | |
| config["environment_variables"] = {} | |
| # Update general_settings for user_email (admin email) | |
| if "general_settings" not in config: | |
| config["general_settings"] = {} | |
| # Update environment variables in config and in memory | |
| sso_data = sso_config.model_dump(exclude_none=True) | |
| for field_name, value in sso_data.items(): | |
| if field_name == 'user_email' and value is not None: | |
| # Store user_email in general_settings instead of environment variables | |
| config["general_settings"]["proxy_admin_email"] = value | |
| elif field_name in env_var_mapping and value is not None: | |
| env_var_name = env_var_mapping[field_name] | |
| # Update in config | |
| config["environment_variables"][env_var_name] = value | |
| # Update in runtime environment | |
| os.environ[env_var_name] = value | |
| # Save the updated config | |
| await proxy_config.save_config(new_config=config) | |
| return { | |
| "message": "SSO settings updated successfully", | |
| "status": "success", | |
| "settings": sso_data, | |
| } | |