code: def convert_slice_metrics_to_proto(
      metrics: Tuple[
          slicer.SliceKeyOrCrossSliceKeyType, metric_types.MetricsDict
      ],
      add_metrics_callbacks: Optional[
          List[types.AddMetricsCallbackType]
      ],
  ) -> metrics_for_slice_pb2.MetricsForSlice:
      """Converts the given slice metrics into serialized proto MetricsForSlice.
  
      Args:
        metrics: The slice metrics.
        add_metrics_callbacks: A list of metric callbacks. This should be the same
          list as the one passed to tfma.Evaluate().
  
      Returns:
        The MetricsForSlice proto.
  
      Raises:
        TypeError: If the type of the feature value in slice key cannot be
          recognized.
      """
      result = metrics_for_slice_pb2.MetricsForSlice()
      slice_key, slice_metrics = metrics
  
      if slicer.is_cross_slice_key(slice_key):
          result.cross_slice_key.CopyFrom(
              slicer.serialize_cross_slice_key(slice_key)
          )
      else:
          result.slice_key.CopyFrom(
              slicer.serialize_slice_key(slice_key)
          )
  
      slice_metrics = slice_metrics.copy()
  
      if metric_keys.ERROR_METRIC in slice_metrics:
          logging.warning(
              "Error for slice: %s with error message: %s ",
              slice_key,
              slice_metrics[metric_keys.ERROR_METRIC],
          )
          result.metrics[
              metric_keys.ERROR_METRIC
          ].debug_message = slice_metrics[metric_keys.ERROR_METRIC]
          return result
  
      # Convert the metrics from add_metrics_callbacks to the structured output if
      # defined.
      if add_metrics_callbacks and (
          not any(
              isinstance(k, metric_types.MetricKey)
              for k in slice_metrics
          )
      ):
          for add_metrics_callback in add_metrics_callbacks:
              if hasattr(
                  add_metrics_callback, "populate_stats_and_pop"
              ):
                  add_metrics_callback.populate_stats_and_pop(
                      slice_key, slice_metrics, result.metrics
                  )
      for key in sorted(slice_metrics):
          value = slice_metrics[key]
          if isinstance(value, types.ValueWithTDistribution):
              unsampled_value = value.unsampled_value
              (
                  _,
                  lower_bound,
                  upper_bound,
              ) = math_util.calculate_confidence_interval(value)
              confidence_interval = (
                  metrics_for_slice_pb2.ConfidenceInterval(
                      lower_bound=convert_metric_value_to_proto(
                          lower_bound
                      ),
                      upper_bound=convert_metric_value_to_proto(
                          upper_bound
                      ),
                      standard_error=convert_metric_value_to_proto(
                          value.sample_standard_deviation
                      ),
                      degrees_of_freedom={
                          "value": value.sample_degrees_of_freedom
                      },
                  )
              )
              metric_value = convert_metric_value_to_proto(
                  unsampled_value
              )
              if isinstance(key, metric_types.MetricKey):
                  result.metric_keys_and_values.add(
                      key=key.to_proto(),
                      value=metric_value,
                      confidence_interval=confidence_interval,
                  )
              else:
                  # For v1 we continue to populate bounded_value for backwards
                  # compatibility. If metric can be stored to double_value metrics,
                  # replace it with a bounded_value.
                  # TODO(b/171992041): remove the string-typed metric key branch once v1
                  # code is removed.
                  if metric_value.WhichOneof("type") == "double_value":
                      # setting bounded_value clears double_value in the same oneof scope.
                      metric_value.bounded_value.value.value = (
                          unsampled_value
                      )
                      metric_value.bounded_value.lower_bound.value = (
                          lower_bound
                      )
                      metric_value.bounded_value.upper_bound.value = (
                          upper_bound
                      )
                      metric_value.bounded_value.methodology = (
                          metrics_for_slice_pb2.BoundedValue.POISSON_BOOTSTRAP
                      )
                  result.metrics[key].CopyFrom(metric_value)
          elif isinstance(value, metrics_for_slice_pb2.BoundedValue):
              metric_value = metrics_for_slice_pb2.MetricValue(
                  double_value=wrappers_pb2.DoubleValue(
                      value=value.value.value
                  )
              )
              confidence_interval = (
                  metrics_for_slice_pb2.ConfidenceInterval(
                      lower_bound=metrics_for_slice_pb2.MetricValue(
                          double_value=wrappers_pb2.DoubleValue(
                              value=value.lower_bound.value
                          )
                      ),
                      upper_bound=metrics_for_slice_pb2.MetricValue(
                          double_value=wrappers_pb2.DoubleValue(
                              value=value.upper_bound.value
                          )
                      ),
                  )
              )
              result.metric_keys_and_values.add(
                  key=key.to_proto(),
                  value=metric_value,
                  confidence_interval=confidence_interval,
              )
          else:
              metric_value = convert_metric_value_to_proto(value)
              if isinstance(key, metric_types.MetricKey):
                  result.metric_keys_and_values.add(
                      key=key.to_proto(), value=metric_value
                  )
              else:
                  # TODO(b/171992041): remove the string-typed metric key branch once v1
                  # code is removed.
                  result.metrics[key].CopyFrom(metric_value)
      return result
  
imports: import itertools
  import os
  from typing import Any, Dict, Iterable, Iterator, List, Optional, Tuple, Union
  from absl import logging
  import apache_beam
  import numpy
  import pyarrow
  import tensorflow
  from tensorflow_model_analysis import constants
  from tensorflow_model_analysis.api import types
  from tensorflow_model_analysis.evaluators import evaluator
  from tensorflow_model_analysis.evaluators import metrics_validator
  from tensorflow_model_analysis.metrics import calibration_plot
  from tensorflow_model_analysis.metrics import confusion_matrix_plot
  from tensorflow_model_analysis.metrics import metric_specs
  from tensorflow_model_analysis.metrics import metric_types
  from tensorflow_model_analysis.post_export_metrics import metric_keys
  from tensorflow_model_analysis.proto import config_pb2
  from tensorflow_model_analysis.proto import metrics_for_slice_pb2
  from tensorflow_model_analysis.proto import validation_result_pb2
  from tensorflow_model_analysis.slicer import slicer_lib
  from tensorflow_model_analysis.utils import math_util
  from tensorflow_model_analysis.writers import writer
  from google.protobuf import wrappers_pb2
label_desc: Use image node_id 10 for calling a global function with example usage: convert_slice_metrics_to_proto(metrics, add_metrics_callbacks) and returns: result, result