Spaces:
Paused
Paused
| # +-----------------------------------------------+ | |
| # | | | |
| # | Give Feedback / Get Help | | |
| # | https://github.com/BerriAI/litellm/issues/new | | |
| # | | | |
| # +-----------------------------------------------+ | |
| # | |
| # Thank you users! We ❤️ you! - Krrish & Ishaan | |
| import copy | |
| from typing import TYPE_CHECKING, Any, Optional | |
| import litellm | |
| from litellm.integrations.custom_logger import CustomLogger | |
| from litellm.secret_managers.main import str_to_bool | |
| from litellm.types.utils import StandardCallbackDynamicParams | |
| if TYPE_CHECKING: | |
| from litellm.litellm_core_utils.litellm_logging import ( | |
| Logging as _LiteLLMLoggingObject, | |
| ) | |
| LiteLLMLoggingObject = _LiteLLMLoggingObject | |
| else: | |
| LiteLLMLoggingObject = Any | |
| def redact_message_input_output_from_custom_logger( | |
| litellm_logging_obj: LiteLLMLoggingObject, result, custom_logger: CustomLogger | |
| ): | |
| if ( | |
| hasattr(custom_logger, "message_logging") | |
| and custom_logger.message_logging is not True | |
| ): | |
| return perform_redaction(litellm_logging_obj.model_call_details, result) | |
| return result | |
| def perform_redaction(model_call_details: dict, result): | |
| """ | |
| Performs the actual redaction on the logging object and result. | |
| """ | |
| # Redact model_call_details | |
| model_call_details["messages"] = [ | |
| {"role": "user", "content": "redacted-by-litellm"} | |
| ] | |
| model_call_details["prompt"] = "" | |
| model_call_details["input"] = "" | |
| # Redact streaming response | |
| if ( | |
| model_call_details.get("stream", False) is True | |
| and "complete_streaming_response" in model_call_details | |
| ): | |
| _streaming_response = model_call_details["complete_streaming_response"] | |
| for choice in _streaming_response.choices: | |
| if isinstance(choice, litellm.Choices): | |
| choice.message.content = "redacted-by-litellm" | |
| elif isinstance(choice, litellm.utils.StreamingChoices): | |
| choice.delta.content = "redacted-by-litellm" | |
| # Redact result | |
| if result is not None and isinstance(result, litellm.ModelResponse): | |
| _result = copy.deepcopy(result) | |
| if hasattr(_result, "choices") and _result.choices is not None: | |
| for choice in _result.choices: | |
| if isinstance(choice, litellm.Choices): | |
| choice.message.content = "redacted-by-litellm" | |
| elif isinstance(choice, litellm.utils.StreamingChoices): | |
| choice.delta.content = "redacted-by-litellm" | |
| return _result | |
| else: | |
| return {"text": "redacted-by-litellm"} | |
| def should_redact_message_logging(model_call_details: dict) -> bool: | |
| """ | |
| Determine if message logging should be redacted. | |
| """ | |
| _request_headers = ( | |
| model_call_details.get("litellm_params", {}).get("metadata", {}) or {} | |
| ) | |
| request_headers = _request_headers.get("headers", {}) | |
| possible_request_headers = [ | |
| "litellm-enable-message-redaction", # old header. maintain backwards compatibility | |
| "x-litellm-enable-message-redaction", # new header | |
| ] | |
| is_redaction_enabled_via_header = False | |
| for header in possible_request_headers: | |
| if bool(request_headers.get(header, False)): | |
| is_redaction_enabled_via_header = True | |
| break | |
| # check if user opted out of logging message/response to callbacks | |
| if ( | |
| litellm.turn_off_message_logging is not True | |
| and is_redaction_enabled_via_header is not True | |
| and _get_turn_off_message_logging_from_dynamic_params(model_call_details) | |
| is not True | |
| ): | |
| return False | |
| if request_headers and bool( | |
| request_headers.get("litellm-disable-message-redaction", False) | |
| ): | |
| return False | |
| # user has OPTED OUT of message redaction | |
| if _get_turn_off_message_logging_from_dynamic_params(model_call_details) is False: | |
| return False | |
| return True | |
| def redact_message_input_output_from_logging( | |
| model_call_details: dict, result, input: Optional[Any] = None | |
| ) -> Any: | |
| """ | |
| Removes messages, prompts, input, response from logging. This modifies the data in-place | |
| only redacts when litellm.turn_off_message_logging == True | |
| """ | |
| if should_redact_message_logging(model_call_details): | |
| return perform_redaction(model_call_details, result) | |
| return result | |
| def _get_turn_off_message_logging_from_dynamic_params( | |
| model_call_details: dict, | |
| ) -> Optional[bool]: | |
| """ | |
| gets the value of `turn_off_message_logging` from the dynamic params, if it exists. | |
| handles boolean and string values of `turn_off_message_logging` | |
| """ | |
| standard_callback_dynamic_params: Optional[ | |
| StandardCallbackDynamicParams | |
| ] = model_call_details.get("standard_callback_dynamic_params", None) | |
| if standard_callback_dynamic_params: | |
| _turn_off_message_logging = standard_callback_dynamic_params.get( | |
| "turn_off_message_logging" | |
| ) | |
| if isinstance(_turn_off_message_logging, bool): | |
| return _turn_off_message_logging | |
| elif isinstance(_turn_off_message_logging, str): | |
| return str_to_bool(_turn_off_message_logging) | |
| return None | |
| def redact_user_api_key_info(metadata: dict) -> dict: | |
| """ | |
| removes any user_api_key_info before passing to logging object, if flag set | |
| Usage: | |
| SDK | |
| ```python | |
| litellm.redact_user_api_key_info = True | |
| ``` | |
| PROXY: | |
| ```yaml | |
| litellm_settings: | |
| redact_user_api_key_info: true | |
| ``` | |
| """ | |
| if litellm.redact_user_api_key_info is not True: | |
| return metadata | |
| new_metadata = {} | |
| for k, v in metadata.items(): | |
| if isinstance(k, str) and k.startswith("user_api_key"): | |
| pass | |
| else: | |
| new_metadata[k] = v | |
| return new_metadata | |