code: def merge_with_defaults(
      config_dict: ModelConfigDict,
  ) -> ModelConfigDict:
      # Recursive merge of the features, except that if we find a dictionary containing
      # an explicit "type" key, we ignore defaults if they don't match.
      defaults = config_dict.get(DEFAULTS)
      if not defaults:
          return config_dict
  
      config_dict = copy.deepcopy(config_dict)
      _merge_features_(
          config_dict.get(INPUT_FEATURES, []), defaults, {DECODER, LOSS}
      )
      _merge_features_(
          config_dict.get(OUTPUT_FEATURES, []),
          defaults,
          {ENCODER, PREPROCESSING},
      )
      return config_dict
  
imports: import copy
  import logging
  import sys
  import warnings
  from typing import Any, Dict, List, Mapping, Set, TYPE_CHECKING
  from marshmallow import ValidationError
  from transformers import AutoConfig
  from ludwig.api_annotations import DeveloperAPI
  from ludwig.constants import CATEGORY, COMBINED, DECODER, DEFAULTS, ENCODER, GRID_SEARCH, INPUT_FEATURES, LOSS, MODEL_ECD, MODEL_LLM, OUTPUT_FEATURES, PARAMETERS, PREPROCESSING, SEQUENCE, SPACE, TEXT, TYPE
  from ludwig.features.feature_utils import compute_feature_hash
  from ludwig.schema.features.utils import output_config_registry
  from ludwig.schema.hyperopt.scheduler import BaseHyperbandSchedulerConfig
  from ludwig.schema.llms.generation import LLMGenerationConfig
  from ludwig.schema.trainer import ECDTrainerConfig
  from ludwig.types import HyperoptConfigDict, ModelConfigDict
  from ludwig.utils.data_utils import get_sanitized_feature_name
  from ludwig.utils.llm_utils import get_context_len
label_desc: Use image node_id 1 for calling a global function with example usage: merge_with_defaults(config_dict) and returns: config_dict, config_dict