code: def _build_step_card(
      self,
      eval_metrics,
      pred_and_error_df,
      model_schema,
      run_id,
      model_uri,
      worst_examples_df,
      train_df,
      output_directory,
      leaderboard_df=None,
      tuning_df=None,
      calibrated_plot=None,
  ):
      import pandas as pd
      from sklearn import set_config
      from sklearn.utils import estimator_html_repr
  
      card = BaseCard(self.recipe_name, self.name)
      # Tab 0: model performance summary.
      metric_df = (
          get_merged_eval_metrics(
              eval_metrics,
              ordered_metric_names=[
                  self.primary_metric,
                  *self.user_defined_custom_metrics.keys(),
              ],
          )
          .reset_index()
          .rename(columns={"index": "Metric"})
      )
  
      def row_style(row):
          if (
              row.Metric == self.primary_metric
              or row.Metric in self.user_defined_custom_metrics
          ):
              return pd.Series("font-weight: bold", row.index)
          else:
              return pd.Series("", row.index)
  
      metric_table_html = BaseCard.render_table(
          metric_df.style.format(
              {"training": "{:.6g}", "validation": "{:.6g}"}
          ).apply(row_style, axis=1)
      )
  
      # Tab 1: Model performance.
      card.add_tab(
          "Model Performance",
          "<h3 class='section-title'>Summary Metrics (Validation)</h3>{{ METRICS }} ",
      ).add_html("METRICS", metric_table_html)
  
      if not self.skip_data_profiling:
          # Tab 2: Prediction and error data profile.
          pred_and_error_df_profile = get_pandas_data_profiles(
              [
                  [
                      "Predictions and Errors (Validation Dataset)",
                      pred_and_error_df.reset_index(drop=True),
                  ]
              ]
          )
          card.add_tab(
              "Data Profile (Predictions)", "{{PROFILE}}"
          ).add_pandas_profile("PROFILE", pred_and_error_df_profile)
      # Tab 3: Model architecture.
      set_config(display="diagram")
      model_repr = estimator_html_repr(
          mlflow.sklearn.load_model(
              os.path.join(
                  model_uri,
                  "artifacts",
                  TrainStep.SKLEARN_MODEL_ARTIFACT_RELATIVE_PATH,
              )
          )
      )
      card.add_tab("Model Architecture", "{{MODEL_ARCH}}").add_html(
          "MODEL_ARCH", model_repr
      )
  
      # Tab 4: Inferred model (transformer + estimator) schema.
      def render_schema(inputs, title):
          from mlflow.types import ColSpec
  
          table = BaseCard.render_table(
              {
                  "Name": "  " + (spec.name or "-"),
                  "Type": repr(spec.type)
                  if isinstance(spec, ColSpec)
                  else repr(spec),
              }
              for spec in inputs
          )
          return (
              f'<div style="margin: 5px"><h2>{title}</h2>{table}</div>'
          )
  
      schema_tables = [
          render_schema(model_schema.inputs.inputs, "Inputs")
      ]
      if model_schema.outputs:
          schema_tables += [
              render_schema(model_schema.outputs.inputs, "Outputs")
          ]
  
      card.add_tab("Model Schema", "{{MODEL_SCHEMA}}").add_html(
          "MODEL_SCHEMA",
          '<div style="display: flex">{tables}</div>'.format(
              tables="\n".join(schema_tables)
          ),
      )
  
      # Tab 5: Examples with Largest Prediction Error
      if not worst_examples_df.empty:
          (
              card.add_tab(
                  "Worst Predictions", "{{ WORST_EXAMPLES_TABLE }}"
              ).add_html(
                  "WORST_EXAMPLES_TABLE",
                  BaseCard.render_table(worst_examples_df),
              )
          )
  
      if calibrated_plot:
          calibrated_plot_location = os.path.join(
              output_directory, "calibrated_plot_location"
          )
          calibrated_plot.figure_.savefig(
              calibrated_plot_location, format="png"
          )
          (
              card.add_tab(
                  "Prob. Calibration", "{{ CALIBRATED_PLOT }}"
              ).add_image("CALIBRATED_PLOT", calibrated_plot_location)
          )
  
      # Tab 6: Worst predictions profile vs train profile.
      if not self.skip_data_profiling:
          worst_prediction_profile = get_pandas_data_profiles(
              [
                  [
                      "Worst Predictions",
                      worst_examples_df.reset_index(drop=True),
                  ],
                  ["Train", train_df.reset_index(drop=True)],
              ]
          )
          card.add_tab(
              "Data Profile (Worst vs Train)",
              "{{ WORST_EXAMPLES_COMP }}",
          ).add_pandas_profile(
              "WORST_EXAMPLES_COMP", worst_prediction_profile
          )
  
      # Tab 7: Leaderboard
      if leaderboard_df is not None:
          (
              card.add_tab(
                  "Leaderboard", "{{ LEADERBOARD_TABLE }}"
              ).add_html(
                  "LEADERBOARD_TABLE",
                  BaseCard.render_table(
                      leaderboard_df, hide_index=False
                  ),
              )
          )
  
      # Tab 8: Best Parameters (AutoML and Tuning)
      is_automl_run = self.step_config["using"].startswith("automl")
      best_parameters_yaml = os.path.join(
          output_directory, "best_parameters.yaml"
      )
  
      if os.path.exists(best_parameters_yaml):
          best_parameters_card_tab = card.add_tab(
              f"Best Parameters {' (AutoML)' if is_automl_run else ''}",
              "{{ BEST_PARAMETERS }} ",
          )
  
          if is_automl_run:
              automl_estimator_str = (
                  f"<b>Best estimator:</b><br>"
                  f"<pre>{self.best_estimator_name}</pre><br>"
                  f"<b>Best estimator class:</b><br>"
                  f"<pre>{self.best_estimator_class}</pre><br><br>"
              )
          else:
              automl_estimator_str = ""
  
          with open(best_parameters_yaml) as f:
              best_parameters = f.read()
          best_parameters_card_tab.add_html(
              "BEST_PARAMETERS",
              f"{automl_estimator_str}<b>Best parameters:</b><br>"
              f"<pre>{best_parameters}</pre><br><br>",
          )
  
      # Tab 9: HP trials
      if tuning_df is not None:
          tuning_trials_card_tab = card.add_tab(
              "Tuning Trials",
              "{{ SEARCH_SPACE }}"
              + "{{ TUNING_TABLE_TITLE }}"
              + "{{ TUNING_TABLE }}",
          )
          tuning_params = yaml.dump(
              self.step_config["tuning"]["parameters"]
          )
          tuning_trials_card_tab.add_html(
              "SEARCH_SPACE",
              f"<b>Tuning search space:</b> <br><pre>{tuning_params}</pre><br><br>",
          )
          tuning_trials_card_tab.add_html(
              "TUNING_TABLE_TITLE", "<b>Tuning results:</b><br>"
          )
          tuning_trials_card_tab.add_html(
              "TUNING_TABLE",
              BaseCard.render_table(
                  tuning_df.style.apply(
                      lambda row: pd.Series(
                          "font-weight: bold", row.index
                      ),
                      axis=1,
                      subset=tuning_df.index[0],
                  ),
                  hide_index=True,
              ),
          )
  
      # Tab 10: Warning log outputs.
      warning_output_path = os.path.join(
          output_directory, "warning_logs.txt"
      )
      if os.path.exists(warning_output_path):
          warnings_output_tab = card.add_tab(
              "Warning Logs", "{{ STEP_WARNINGS }}"
          )
          with open(warning_output_path) as f:
              warnings_output_tab.add_html(
                  "STEP_WARNINGS", f"<pre>{f.read()}</pre>"
              )
  
      # Tab 11: Run summary.
      run_card_tab = card.add_tab(
          "Run Summary",
          "{{ RUN_ID }} "
          + "{{ MODEL_URI }}"
          + "{{ EXE_DURATION }}"
          + "{{ LAST_UPDATE_TIME }}",
      )
      model_uri_path = f"runs:/{run_id}/train/model"
      run_url = get_databricks_run_url(
          tracking_uri=mlflow.get_tracking_uri(),
          run_id=run_id,
      )
      model_url = get_databricks_run_url(
          tracking_uri=mlflow.get_tracking_uri(),
          run_id=run_id,
          artifact_path=re.sub(rf"^.*?{run_id}", "", model_uri_path),
      )
  
      if run_url is not None:
          run_card_tab.add_html(
              "RUN_ID",
              f"<b>MLflow Run ID:</b> <a href={run_url}>{run_id}</a><br><br>",
          )
      else:
          run_card_tab.add_markdown(
              "RUN_ID", f"**MLflow Run ID:** `{run_id}`"
          )
  
      if model_url is not None:
          run_card_tab.add_html(
              "MODEL_URI",
              f"<b>MLflow Model URI:</b> <a href={model_url}>{model_uri_path}</a>",
          )
      else:
          run_card_tab.add_markdown(
              "MODEL_URI", f"**MLflow Model URI:** `{model_uri_path}`"
          )
  
      return card
  
imports: import datetime
  import importlib
  import logging
  import os
  import re
  import shutil
  import sys
  import warnings
  import cloudpickle
  import yaml
  import mlflow
  from mlflow.entities import SourceType, ViewType
  from mlflow.environment_variables import MLFLOW_RECIPES_EXECUTION_TARGET_STEP_NAME
  from mlflow.exceptions import BAD_REQUEST, INVALID_PARAMETER_VALUE, MlflowException
  from mlflow.models import Model
  from mlflow.recipes.artifacts import DataframeArtifact, HyperParametersArtifact, ModelArtifact, RunArtifact
  from mlflow.recipes.cards import BaseCard
  from mlflow.recipes.step import BaseStep, StepClass
  from mlflow.recipes.utils.execution import get_step_output_path
  from mlflow.recipes.utils.metrics import _get_builtin_metrics, _get_custom_metrics, _get_error_fn, _get_extended_task, _get_model_type_from_template, _get_primary_metric, _load_custom_metrics, transform_multiclass_metrics_dict
  from mlflow.recipes.utils.step import get_merged_eval_metrics, get_pandas_data_profiles, validate_classification_config
  from mlflow.recipes.utils.tracking import TrackingConfig, apply_recipe_tracking_config, get_recipe_tracking_config, get_run_tags_env_vars, log_code_snapshot
  from mlflow.recipes.utils.wrapped_recipe_model import WrappedRecipeModel
  from mlflow.tracking import MlflowClient
  from mlflow.tracking.fluent import _get_experiment_id
  from mlflow.utils.databricks_utils import get_databricks_env_vars, get_databricks_run_url
  from mlflow.utils.file_utils import TempDir
  from mlflow.utils.mlflow_tags import MLFLOW_RECIPE_PROFILE_NAME, MLFLOW_RECIPE_STEP_NAME, MLFLOW_RECIPE_TEMPLATE_NAME, MLFLOW_SOURCE_TYPE
  from mlflow.utils.string_utils import strip_prefix
label_desc: Use image node_id 14 for calling the TrainStep obj's underlying member method code with example usage: obj._build_step_card(eval_metrics, pred_and_error_df, model_schema, run_id, model_uri, worst_examples_df, train_df, output_directory, leaderboard_df, tuning_df, calibrated_plot) and returns: card, str, title, str, table, str, pd, pd