"""gr.BrowserState() component.""" from __future__ import annotations import secrets import string from typing import Any from gradio_client.documentation import document from pydantic import BaseModel as PydanticBaseModel from gradio.components.base import Component from gradio.events import Events def _to_json_serializable(value: Any) -> Any: """Convert a value to a JSON-serializable form. Pydantic BaseModel instances are converted to dicts via model_dump(), since they cannot be directly serialized by orjson and would otherwise fall back to str() representation. """ if isinstance(value, PydanticBaseModel): return value.model_dump() return value @document() class BrowserState(Component): EVENTS = [Events.change] """ Special component that stores state in the browser's localStorage in an encrypted format. """ def __init__( self, default_value: Any = None, *, storage_key: str | None = None, secret: str | None = None, render: bool = True, ): """ Parameters: default_value: the default value that will be used if no value is found in localStorage. Should be a json-serializable value. storage_key: the key to use in localStorage. If None, a random key will be generated. secret: the secret key to use for encryption. If None, a random key will be generated (recommended). render: should always be True, is included for consistency with other components. """ self.default_value = _to_json_serializable(default_value) self.secret = secret or "".join( secrets.choice(string.ascii_letters + string.digits) for _ in range(16) ) self.storage_key = storage_key or "".join( secrets.choice(string.ascii_letters + string.digits) for _ in range(16) ) self._value_description = "any json-serializable value" super().__init__(render=render) def preprocess(self, payload: Any) -> Any: """ Parameters: payload: Value from local storage Returns: Passes value through unchanged """ if payload is None: return self.default_value return payload def postprocess(self, value: Any) -> Any: """ Parameters: value: Value to store in local storage Returns: Passes value through unchanged, converting Pydantic models to dicts """ return _to_json_serializable(value) def api_info(self) -> dict[str, Any]: return {"type": {}, "description": "any json-serializable value"} def example_payload(self) -> Any: return "test" def example_value(self) -> Any: return "test" def breaks_grouping(self) -> bool: """BrowserState components should not break wrapper grouping chains.""" return False