code: def _save_detector_config(
      detector: ConfigurableDetector, filepath: Union[str, os.PathLike]
  ):
      """
      Save a drift detector. The detector is saved as a yaml config file. Artefacts such as
      `preprocess_fn`, models, embeddings, tokenizers etc are serialized, and their filepaths are
      added to the config file.
  
      The detector can be loaded again by passing the resulting config file or filepath to `load_detector`.
  
      Parameters
      ----------
      detector
          The detector to save.
      filepath
          File path to save serialized artefacts to.
      """
      # detector name
      detector_name = detector.__class__.__name__
  
      # Process file paths
      filepath = Path(filepath)
      if not filepath.is_dir():
          logger.warning(
              "Directory {} does not exist and is now created.".format(
                  filepath
              )
          )
          filepath.mkdir(parents=True, exist_ok=True)
  
      # Get the detector config (with artefacts still within it)
      if hasattr(detector, "get_config"):
          cfg = (
              detector.get_config()
          )  # TODO - remove once all detectors have get_config
          cfg = validate_config(cfg, resolved=True)
      else:
          raise NotImplementedError(
              f"{detector_name} does not yet support config.toml based saving."
          )
  
      # Save state if an online detector and online state exists (self.t > 0)
      if isinstance(detector, StatefulDetectorOnline):
          if detector.t > 0:
              detector.save_state(filepath.joinpath(STATE_PATH))
  
      # Save x_ref
      save_path = filepath.joinpath(X_REF_FILENAME)
      np.save(str(save_path), cfg["x_ref"])
      cfg.update({"x_ref": X_REF_FILENAME})
  
      # Save c_ref
      c_ref = cfg.get("c_ref")
      if c_ref is not None:
          save_path = filepath.joinpath(C_REF_FILENAME)
          np.save(str(save_path), cfg["c_ref"])
          cfg.update({"c_ref": C_REF_FILENAME})
  
      # Save preprocess_fn
      preprocess_fn = cfg.get("preprocess_fn")
      if preprocess_fn is not None:
          logger.info("Saving the preprocess_fn function.")
          preprocess_cfg = _save_preprocess_config(
              preprocess_fn, cfg["input_shape"], filepath
          )
          cfg["preprocess_fn"] = preprocess_cfg
  
      # Serialize kernels
      for kernel_str in ("kernel", "x_kernel", "c_kernel"):
          kernel = cfg.get(kernel_str)
          if kernel is not None:
              cfg[kernel_str] = _save_kernel_config(
                  kernel, filepath, Path(kernel_str)
              )
              if (
                  "proj" in cfg[kernel_str]
              ):  # serialise proj from DeepKernel - do here as need input_shape
                  cfg[kernel_str]["proj"], _ = _save_model_config(
                      cfg[kernel_str]["proj"],
                      base_path=filepath,
                      input_shape=cfg["input_shape"],
                  )
  
      # ClassifierDrift and SpotTheDiffDrift specific artefacts.
      # Serialize detector model
      model = cfg.get("model")
      if model is not None:
          model_cfg, _ = _save_model_config(
              model, base_path=filepath, input_shape=cfg["input_shape"]
          )
          cfg["model"] = model_cfg
  
      # Serialize optimizer
      optimizer = cfg.get("optimizer")
      if optimizer is not None:
          cfg["optimizer"] = _save_optimizer_config(optimizer)
  
      # Serialize device
      device = cfg.get("device")
      if device is not None:
          cfg["device"] = save_device_pt(device)
  
      # Serialize dataset
      dataset = cfg.get("dataset")
      if dataset is not None:
          dataset_cfg, dataset_kwargs = _serialize_object(
              dataset, filepath, Path("dataset")
          )
          cfg.update({"dataset": dataset_cfg})
          if len(dataset_kwargs) != 0:
              cfg["dataset"]["kwargs"] = dataset_kwargs
  
      # Serialize reg_loss_fn
      reg_loss_fn = cfg.get("reg_loss_fn")
      if reg_loss_fn is not None:
          reg_loss_fn_cfg, _ = _serialize_object(
              reg_loss_fn, filepath, Path("reg_loss_fn")
          )
          cfg["reg_loss_fn"] = reg_loss_fn_cfg
  
      # Save initial_diffs
      initial_diffs = cfg.get("initial_diffs")
      if initial_diffs is not None:
          save_path = filepath.joinpath("initial_diffs.npy")
          np.save(str(save_path), initial_diffs)
          cfg.update({"initial_diffs": "initial_diffs.npy"})
  
      # Save config
      write_config(cfg, filepath)
  
imports: import logging
  import os
  import shutil
  import warnings
  from functools import partial
  from pathlib import Path
  from typing import Callable, Optional, Tuple, Union, Any, Dict, TYPE_CHECKING
  import dill
  import numpy
  import toml
  from transformers import PreTrainedTokenizerBase
  from alibi_detect.saving._typing import VALID_DETECTORS
  from alibi_detect.saving.loading import _replace, validate_config, STATE_PATH
  from alibi_detect.saving.registry import registry
  from alibi_detect.utils._types import supported_models_all, supported_models_tf, supported_models_torch, supported_models_sklearn
  from alibi_detect.base import Detector, ConfigurableDetector, StatefulDetectorOnline
  from alibi_detect.saving._tensorflow import save_detector_legacy, save_model_config_tf, save_optimizer_config_tf
  from alibi_detect.saving._pytorch import save_model_config_pt, save_device_pt
  from alibi_detect.saving._sklearn import save_model_config_sk
label_desc: Use image node_id 3 for calling a global function with example usage: _save_detector_config(detector, filepath) without return types