Spaces:
Paused
Paused
| from typing import Any, Dict | |
| from fastapi import APIRouter, Depends, HTTPException, Request | |
| import litellm | |
| from litellm._logging import verbose_proxy_logger | |
| from litellm.caching.caching import RedisCache | |
| from litellm.litellm_core_utils.safe_json_dumps import safe_dumps | |
| from litellm.litellm_core_utils.sensitive_data_masker import SensitiveDataMasker | |
| from litellm.proxy._types import ProxyErrorTypes, ProxyException | |
| from litellm.proxy.auth.user_api_key_auth import user_api_key_auth | |
| from litellm.types.caching import CachePingResponse, HealthCheckCacheParams | |
| masker = SensitiveDataMasker() | |
| router = APIRouter( | |
| prefix="/cache", | |
| tags=["caching"], | |
| ) | |
| def _extract_cache_params() -> Dict[str, Any]: | |
| """ | |
| Safely extracts and cleans cache parameters. | |
| The health check UI needs to display specific cache parameters, to show users how they set up their cache. | |
| eg. | |
| { | |
| "host": "localhost", | |
| "port": 6379, | |
| "redis_kwargs": {"db": 0}, | |
| "namespace": "test", | |
| } | |
| Returns: | |
| Dict containing cleaned and masked cache parameters | |
| """ | |
| if litellm.cache is None: | |
| return {} | |
| try: | |
| cache_params = vars(litellm.cache.cache) | |
| cleaned_params = ( | |
| HealthCheckCacheParams(**cache_params).model_dump() if cache_params else {} | |
| ) | |
| return masker.mask_dict(cleaned_params) | |
| except (AttributeError, TypeError) as e: | |
| verbose_proxy_logger.debug(f"Error extracting cache params: {str(e)}") | |
| return {} | |
| async def cache_ping(): | |
| """ | |
| Endpoint for checking if cache can be pinged | |
| """ | |
| litellm_cache_params: Dict[str, Any] = {} | |
| cleaned_cache_params: Dict[str, Any] = {} | |
| try: | |
| if litellm.cache is None: | |
| raise HTTPException( | |
| status_code=503, detail="Cache not initialized. litellm.cache is None" | |
| ) | |
| litellm_cache_params = masker.mask_dict(vars(litellm.cache)) | |
| # remove field that might reference itself | |
| litellm_cache_params.pop("cache", None) | |
| cleaned_cache_params = _extract_cache_params() | |
| if litellm.cache.type == "redis": | |
| ping_response = await litellm.cache.ping() | |
| verbose_proxy_logger.debug( | |
| "/cache/ping: ping_response: " + str(ping_response) | |
| ) | |
| # add cache does not return anything | |
| await litellm.cache.async_add_cache( | |
| result="test_key", | |
| model="test-model", | |
| messages=[{"role": "user", "content": "test from litellm"}], | |
| ) | |
| verbose_proxy_logger.debug("/cache/ping: done with set_cache()") | |
| return CachePingResponse( | |
| status="healthy", | |
| cache_type=str(litellm.cache.type), | |
| ping_response=True, | |
| set_cache_response="success", | |
| litellm_cache_params=safe_dumps(litellm_cache_params), | |
| health_check_cache_params=cleaned_cache_params, | |
| ) | |
| else: | |
| return CachePingResponse( | |
| status="healthy", | |
| cache_type=str(litellm.cache.type), | |
| litellm_cache_params=safe_dumps(litellm_cache_params), | |
| ) | |
| except Exception as e: | |
| import traceback | |
| error_message = { | |
| "message": f"Service Unhealthy ({str(e)})", | |
| "litellm_cache_params": safe_dumps(litellm_cache_params), | |
| "health_check_cache_params": safe_dumps(cleaned_cache_params), | |
| "traceback": traceback.format_exc(), | |
| } | |
| raise ProxyException( | |
| message=safe_dumps(error_message), | |
| type=ProxyErrorTypes.cache_ping_error, | |
| param="cache_ping", | |
| code=503, | |
| ) | |
| async def cache_delete(request: Request): | |
| """ | |
| Endpoint for deleting a key from the cache. All responses from litellm proxy have `x-litellm-cache-key` in the headers | |
| Parameters: | |
| - **keys**: *Optional[List[str]]* - A list of keys to delete from the cache. Example {"keys": ["key1", "key2"]} | |
| ```shell | |
| curl -X POST "http://0.0.0.0:4000/cache/delete" \ | |
| -H "Authorization: Bearer sk-1234" \ | |
| -d '{"keys": ["key1", "key2"]}' | |
| ``` | |
| """ | |
| try: | |
| if litellm.cache is None: | |
| raise HTTPException( | |
| status_code=503, detail="Cache not initialized. litellm.cache is None" | |
| ) | |
| request_data = await request.json() | |
| keys = request_data.get("keys", None) | |
| if litellm.cache.type == "redis": | |
| await litellm.cache.delete_cache_keys(keys=keys) | |
| return { | |
| "status": "success", | |
| } | |
| else: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"Cache type {litellm.cache.type} does not support deleting a key. only `redis` is supported", | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"Cache Delete Failed({str(e)})", | |
| ) | |
| async def cache_redis_info(): | |
| """ | |
| Endpoint for getting /redis/info | |
| """ | |
| try: | |
| if litellm.cache is None: | |
| raise HTTPException( | |
| status_code=503, detail="Cache not initialized. litellm.cache is None" | |
| ) | |
| if litellm.cache.type == "redis" and isinstance( | |
| litellm.cache.cache, RedisCache | |
| ): | |
| client_list = litellm.cache.cache.client_list() | |
| redis_info = litellm.cache.cache.info() | |
| num_clients = len(client_list) | |
| return { | |
| "num_clients": num_clients, | |
| "clients": client_list, | |
| "info": redis_info, | |
| } | |
| else: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"Cache type {litellm.cache.type} does not support flushing", | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=503, | |
| detail=f"Service Unhealthy ({str(e)})", | |
| ) | |
| async def cache_flushall(): | |
| """ | |
| A function to flush all items from the cache. (All items will be deleted from the cache with this) | |
| Raises HTTPException if the cache is not initialized or if the cache type does not support flushing. | |
| Returns a dictionary with the status of the operation. | |
| Usage: | |
| ``` | |
| curl -X POST http://0.0.0.0:4000/cache/flushall -H "Authorization: Bearer sk-1234" | |
| ``` | |
| """ | |
| try: | |
| if litellm.cache is None: | |
| raise HTTPException( | |
| status_code=503, detail="Cache not initialized. litellm.cache is None" | |
| ) | |
| if litellm.cache.type == "redis" and isinstance( | |
| litellm.cache.cache, RedisCache | |
| ): | |
| litellm.cache.cache.flushall() | |
| return { | |
| "status": "success", | |
| } | |
| else: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"Cache type {litellm.cache.type} does not support flushing", | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=503, | |
| detail=f"Service Unhealthy ({str(e)})", | |
| ) | |