code: def lexicon_to_fst(
      lexicon: Lexicon,
      token2id: Dict[str, int],
      word2id: Dict[str, int],
      sil_token: str = "SIL",
      sil_prob: float = 0.5,
      need_self_loops: bool = False,
  ) -> k2.Fsa:
      """Convert a lexicon to an FST (in k2 format) with optional silence at
      the beginning and end of each word.
      Args:
        lexicon:
          The input lexicon. See also :func:`read_lexicon`
        token2id:
          A dict mapping tokens to IDs.
        word2id:
          A dict mapping words to IDs.
        sil_token:
          The silence token.
        sil_prob:
          The probability for adding a silence at the beginning and end
          of the word.
        need_self_loops:
          If True, add self-loop to states with non-epsilon output symbols
          on at least one arc out of the state. The input label for this
          self loop is `token2id["#0"]` and the output label is `word2id["#0"]`.
      Returns:
        Return an instance of `k2.Fsa` representing the given lexicon.
      """
      assert sil_prob > 0.0 and sil_prob < 1.0
      # CAUTION: we use score, i.e, negative cost.
      sil_score = math.log(sil_prob)
      no_sil_score = math.log(1.0 - sil_prob)
  
      start_state = 0
      loop_state = 1  # words enter and leave from here
      sil_state = (
          2  # words terminate here when followed by silence; this state
      )
      # has a silence transition to loop_state.
      next_state = 3  # the next un-allocated state, will be incremented as we go.
      arcs = []
  
      assert token2id["<eps>"] == 0
      assert word2id["<eps>"] == 0
  
      eps = 0
  
      sil_token = token2id[sil_token]
  
      arcs.append([start_state, loop_state, eps, eps, no_sil_score])
      arcs.append([start_state, sil_state, eps, eps, sil_score])
      arcs.append([sil_state, loop_state, sil_token, eps, 0])
  
      for word, tokens in lexicon:
          assert len(tokens) > 0, f"{word} has no pronunciations"
          cur_state = loop_state
  
          word = word2id[word]
          tokens = [token2id[i] for i in tokens]
  
          for i in range(len(tokens) - 1):
              w = word if i == 0 else eps
              arcs.append([cur_state, next_state, tokens[i], w, 0])
  
              cur_state = next_state
              next_state += 1
  
          # now for the last token of this word
          # It has two out-going arcs, one to the loop state,
          # the other one to the sil_state.
          i = len(tokens) - 1
          w = word if i == 0 else eps
          arcs.append(
              [cur_state, loop_state, tokens[i], w, no_sil_score]
          )
          arcs.append([cur_state, sil_state, tokens[i], w, sil_score])
  
      if need_self_loops:
          disambig_token = token2id["#0"]
          disambig_word = word2id["#0"]
          arcs = add_self_loops(
              arcs,
              disambig_token=disambig_token,
              disambig_word=disambig_word,
          )
  
      final_state = next_state
      arcs.append([loop_state, final_state, -1, -1, 0])
      arcs.append([final_state])
  
      arcs = sorted(arcs, key=lambda arc: arc[0])
      arcs = [[str(i) for i in arc] for arc in arcs]
      arcs = [" ".join(arc) for arc in arcs]
      arcs = "\n".join(arcs)
  
      fsa = k2.Fsa.from_str(arcs, acceptor=False)
      return fsa
  
file_path: espnet/egs2/americasnlp22/asr1/pyscripts/k2/prepare_lang.py
imports: import argparse
  import math
  from collections import defaultdict
  from pathlib import Path
  from typing import Any, Dict, List, Tuple
  import k2
  import torch
  from icefall.lexicon import read_lexicon, write_lexicon
  from espnet2.utils.types import str2bool
label_desc: Use image node_id 9 for calling a global function with example usage: lexicon_to_fst(lexicon, token2id, word2id, sil_token, sil_prob, need__loops) and returns: fsa