code: def wer_details_by_utterance(
      ref_dict,
      hyp_dict,
      compute_alignments=False,
      scoring_mode="strict",
  ):
      """Computes a wealth WER info about each single utterance.
  
      This info can then be used to compute summary details (WER, SER).
  
      Arguments
      ---------
      ref_dict : dict
          Should be indexable by utterance ids, and return the reference tokens
          for each utterance id as iterable
      hyp_dict : dict
          Should be indexable by utterance ids, and return
          the hypothesis tokens for each utterance id as iterable
      compute_alignments : bool
          Whether alignments should also be saved.
          This also saves the tokens themselves, as they are probably
          required for printing the alignments.
      scoring_mode : {'strict', 'all', 'present'}
          How to deal with missing hypotheses (reference utterance id
          not found in hyp_dict).
  
          * 'strict': Raise error for missing hypotheses.
          * 'all': Score missing hypotheses as empty.
          * 'present': Only score existing hypotheses.
  
      Returns
      -------
      list
          A list with one entry for every reference utterance. Each entry is a
          dict with keys:
  
          * "key": utterance id
          * "scored": (bool) Whether utterance was scored.
          * "hyp_absent": (bool) True if a hypothesis was NOT found.
          * "hyp_empty": (bool) True if hypothesis was considered empty
            (either because it was empty, or not found and mode 'all').
          * "num_edits": (int) Number of edits in total.
          * "num_ref_tokens": (int) Number of tokens in the reference.
          * "WER": (float) Word error rate of the utterance.
          * "insertions": (int) Number of insertions.
          * "deletions": (int) Number of deletions.
          * "substitutions": (int) Number of substitutions.
          * "alignment": If compute_alignments is True, alignment as list,
            see ``speechbrain.utils.edit_distance.alignment``.
            If compute_alignments is False, this is None.
          * "ref_tokens": (iterable) The reference tokens
            only saved if alignments were computed, else None.
          * "hyp_tokens": (iterable) the hypothesis tokens,
            only saved if alignments were computed, else None.
  
      Raises
      ------
      KeyError
          If scoring mode is 'strict' and a hypothesis is not found.
      """
      details_by_utterance = []
      for key, ref_tokens in ref_dict.items():
          # Initialize utterance_details
          utterance_details = {
              "key": key,
              "scored": False,
              "hyp_absent": None,
              "hyp_empty": None,
              "num_edits": None,
              "num_ref_tokens": len(ref_tokens),
              "WER": None,
              "insertions": None,
              "deletions": None,
              "substitutions": None,
              "alignment": None,
              "ref_tokens": ref_tokens if compute_alignments else None,
              "hyp_tokens": None,
          }
          if key in hyp_dict:
              utterance_details.update({"hyp_absent": False})
              hyp_tokens = hyp_dict[key]
          elif scoring_mode == "all":
              utterance_details.update({"hyp_absent": True})
              hyp_tokens = []
          elif scoring_mode == "present":
              utterance_details.update({"hyp_absent": True})
              details_by_utterance.append(utterance_details)
              continue  # Skip scoring this utterance
          elif scoring_mode == "strict":
              raise KeyError(
                  "Key "
                  + key
                  + " in reference but missing in hypothesis and strict mode on."
              )
          else:
              raise ValueError("Invalid scoring mode: " + scoring_mode)
          # Compute edits for this utterance
          table = op_table(ref_tokens, hyp_tokens)
          ops = count_ops(table)
          # Take into account "" outputs as empty
          if ref_tokens[0] == "" and hyp_tokens[0] == "":
              num_ref_tokens = 0
          else:
              num_ref_tokens = len(ref_tokens)
          # Update the utterance-level details if we got this far:
          utterance_details.update(
              {
                  "scored": True,
                  "hyp_empty": True
                  if len(hyp_tokens) == 0
                  else False,  # This also works for e.g. torch tensors
                  "num_edits": sum(ops.values()),
                  "num_ref_tokens": num_ref_tokens,
                  "WER": 100.0 * sum(ops.values()) / len(ref_tokens),
                  "insertions": ops["insertions"],
                  "deletions": ops["deletions"],
                  "substitutions": ops["substitutions"],
                  "alignment": alignment(table)
                  if compute_alignments
                  else None,
                  "ref_tokens": ref_tokens
                  if compute_alignments
                  else None,
                  "hyp_tokens": hyp_tokens
                  if compute_alignments
                  else None,
              }
          )
          details_by_utterance.append(utterance_details)
      return details_by_utterance
  
file_path: speechbrain/speechbrain/utils/edit_distance.py
imports: import collections
label_desc: Use image node_id 8 for calling a global function with example usage: wer_details_by_utterance(ref_dict, hyp_dict, compute_alignments, scoring_mode) and returns: details_by_utterance