code: def main(cfg: AudioEvaluationConfig):
      torch.set_grad_enabled(False)
  
      if is_dataclass(cfg):
          cfg = OmegaConf.structured(cfg)
  
      if cfg.audio_dir is not None:
          raise RuntimeError(
              "Evaluation script requires ground truth audio to be passed via a manifest file. "
              "If manifest file is available, submit it via `dataset_manifest` argument."
          )
  
      if not os.path.exists(cfg.dataset_manifest):
          raise FileNotFoundError(
              f"The dataset manifest file could not be found at path : {cfg.dataset_manifest}"
          )
  
      if cfg.target_dataset_dir is None:
          # Assume the target data is available in the same directory as the input data
          cfg.target_dataset_dir = os.path.dirname(cfg.dataset_manifest)
      elif not os.path.isdir(cfg.target_dataset_dir):
          raise FileNotFoundError(
              f"Target dataset dir could not be found at path : {cfg.target_dataset_dir}"
          )
  
      # Setup metrics
      metrics = get_metrics(cfg)
  
      # Processing
      if not cfg.only_score_manifest:
          # Process audio using the configured model and save in the output directory
          process_cfg = process_audio.main(cfg)  # type: ProcessConfig
  
          # Release GPU memory if it was used during transcription
          if torch.cuda.is_available():
              torch.cuda.empty_cache()
  
          logging.info("Finished processing audio.")
      else:
          # Score the input manifest, no need to run a model
          cfg.output_filename = cfg.dataset_manifest
          process_cfg = cfg
  
      # Evaluation
      with tempfile.TemporaryDirectory() as tmp_dir:
          # Prepare a temporary manifest with processed audio and target
          temporary_manifest_filepath = os.path.join(
              tmp_dir, "manifest.json"
          )
  
          num_files = 0
  
          with open(
              process_cfg.output_filename, "r"
          ) as f_processed, open(
              temporary_manifest_filepath, "w", encoding="utf-8"
          ) as f_tmp:
              for line_processed in f_processed:
                  data_processed = json.loads(line_processed)
  
                  if cfg.processed_key not in data_processed:
                      raise ValueError(
                          f"Processed key {cfg.processed_key} not found in manifest: {process_cfg.output_filename}."
                      )
  
                  if cfg.target_key not in data_processed:
                      raise ValueError(
                          f"Target key {cfg.target_key} not found in manifest: {process_cfg.output_filename}."
                      )
  
                  item = {
                      "processed": manifest.get_full_path(
                          audio_file=data_processed[cfg.processed_key],
                          manifest_file=process_cfg.output_filename,
                      ),
                      "target": manifest.get_full_path(
                          audio_file=data_processed[cfg.target_key],
                          data_dir=cfg.target_dataset_dir,
                      ),
                      "duration": data_processed.get("duration"),
                  }
  
                  # Double-check files exist
                  for key in ["processed", "target"]:
                      if not os.path.isfile(item[key]):
                          raise ValueError(
                              f'File for key "{key}" not found at: {item[key]}.\nCurrent item: {item}'
                          )
  
                  # Warn if we're comparing the same files
                  if item["target"] == item["processed"]:
                      logging.warning(
                          "Using the same file as processed and target: %s",
                          item["target"],
                      )
  
                  # Write the entry in the temporary manifest file
                  f_tmp.write(json.dumps(item) + "\n")
  
                  num_files += 1
  
          # Prepare dataloader
          config = {
              "manifest_filepath": temporary_manifest_filepath,
              "sample_rate": cfg.sample_rate,
              "input_key": "processed",
              "input_channel_selector": cfg.processed_channel_selector,
              "target_key": "target",
              "target_channel_selector": cfg.target_channel_selector,
              "batch_size": min(cfg.batch_size, num_files),
              "num_workers": cfg.num_workers,
          }
          temporary_dataloader = get_evaluation_dataloader(config)
  
          # Calculate metrics
          for eval_batch in tqdm(
              temporary_dataloader, desc="Evaluating"
          ):
              (
                  processed_signal,
                  processed_length,
                  target_signal,
                  target_length,
              ) = eval_batch
  
              if not torch.equal(processed_length, target_length):
                  raise RuntimeError(f"Length mismatch.")
  
              for name, metric in metrics.items():
                  metric.update(
                      preds=processed_signal,
                      target=target_signal,
                      input_length=target_length,
                  )
  
      # Convert to a dictionary with name: value
      metrics_value = {
          name: metric.compute().item()
          for name, metric in metrics.items()
      }
  
      logging.info("Finished running evaluation.")
  
      # Show results
      logging.info("Summary\n")
      logging.info("Data")
      logging.info("\tmanifest:           %s", cfg.output_filename)
      logging.info("\ttarget_dataset_dir: %s", cfg.target_dataset_dir)
      logging.info("\tnum_files:          %s", num_files)
      logging.info("Metrics")
      for name, value in metrics_value.items():
          logging.info("\t%10s: \t%6.2f", name, value)
  
      # Inject the metric name and score into the config, and return the entire config
      with open_dict(cfg):
          cfg.metrics_value = metrics_value
  
      return cfg
  
imports: import json
  import os
  import tempfile
  from dataclasses import dataclass, field, is_dataclass
  from typing import List, Optional
  import process_audio
  import torch
  from omegaconf import OmegaConf, open_dict
  from torchmetrics.audio.pesq import PerceptualEvaluationSpeechQuality
  from torchmetrics.audio.sdr import ScaleInvariantSignalDistortionRatio, SignalDistortionRatio
  from torchmetrics.audio.stoi import ShortTimeObjectiveIntelligibility
  from tqdm import tqdm
  from nemo.collections.asr.data import audio_to_audio_dataset
  from nemo.collections.asr.metrics.audio import AudioMetricWrapper
  from nemo.collections.common.parts.preprocessing import manifest
  from nemo.core.config import hydra_runner
  from nemo.utils import logging
label_desc: Use image node_id 3 for calling a global function with example usage: main(cfg) and returns: cfg