code: def semgrexify_html(orig_html: str, semgrex_sentence) -> str:
      """
      Modifies the HTML of a sentence's dependency visualization, highlighting words involved in the
      semgrex_sentence search queries and adding the label of the word inside of the match.
  
  
      @param orig_html: unedited HTML of a sentence's dependency visualization.
      @param semgrex_sentence: a Semgrex result object containing the matches to a provided query.
      @return: edited HTML containing the visual changes described above.
      """
      tracker = {}  # keep track of which words have multiple labels
      DEFAULT_TSPAN_COUNT = 2  # the original displacy html assigns two <tspan> objects per <text> object
      CLOSING_TSPAN_LEN = 8  # </tspan> is 8 chars long
      colors = [
          "#4477AA",
          "#66CCEE",
          "#228833",
          "#CCBB44",
          "#EE6677",
          "#AA3377",
          "#BBBBBB",
      ]  # colorblind-friendly scheme
      css_bolded_class = (
          "<style> .bolded{font-weight: bold;} </style>\n"
      )
      opening_svg_end_idx = orig_html.find("\n")
      # insert the new style class
      orig_html = (
          orig_html[: opening_svg_end_idx + 1]
          + css_bolded_class
          + orig_html[opening_svg_end_idx + 1 :]
      )
  
      # Color and bold words involved in each Semgrex match
      for query in semgrex_sentence.result:
          for i, match in enumerate(query.match):
              color = colors[i]
              paired_dy = 2
              for node in match.node:
                  name, match_index = node.name, node.matchIndex
                  # edit existing <tspan> to change color and bold the text
                  start = find_nth(
                      orig_html, "<text", match_index
                  )  # finds start of svg <text> of interest
                  if (
                      match_index not in tracker
                  ):  # if we've already bolded and colored, keep the first color
                      tspan_start = orig_html.find(
                          "<tspan", start
                      )  # finds start of the first svg <tspan> inside of the <text>
                      tspan_end = orig_html.find(
                          "</tspan>", start
                      )  # finds start of the end of the above <tspan>
                      tspan_substr = (
                          orig_html[
                              tspan_start : tspan_end
                              + CLOSING_TSPAN_LEN
                              + 1
                          ]
                          + "\n"
                      )
                      # color and bold words in the search hit
                      edited_tspan = tspan_substr.replace(
                          'class="displacy-word"', 'class="bolded"'
                      ).replace(
                          'fill="currentColor"', f'fill="{color}"'
                      )
                      # insert edited <tspan> object into html string
  
                      # TODO: DEBUG. This code has a bug in it that causes the svg to not end on an input like
                      # "The Wimbledon grass-court tennis tournament banned players, resulting in players hating others."
                      # to malfunction and add another <svg> copy to the tail-end of the first svg rendering.
                      # This bug has been patched in the end of this function, but need to find out what is going on.
                      orig_html = (
                          orig_html[:tspan_start]
                          + edited_tspan
                          + orig_html[
                              tspan_end + CLOSING_TSPAN_LEN + 2 :
                          ]
                      )
  
                      tracker[match_index] = DEFAULT_TSPAN_COUNT
  
                  # next, we have to insert the new <tspan> object for the label
                  # Copy old <tspan> to copy formatting when creating new <tspan> later
                  prev_tspan_start = (
                      find_nth(
                          orig_html[start:],
                          "<tspan",
                          tracker[match_index] - 1,
                      )
                      + start
                  )  # find the previous <tspan> start index
                  prev_tspan_end = (
                      find_nth(
                          orig_html[start:],
                          "</tspan>",
                          tracker[match_index] - 1,
                      )
                      + start
                  )  # find the prev </tspan> start index
                  prev_tspan = orig_html[
                      prev_tspan_start : prev_tspan_end
                      + CLOSING_TSPAN_LEN
                      + 1
                  ]
  
                  # Find spot to insert new tspan
                  closing_tspan_start = (
                      find_nth(
                          orig_html[start:],
                          "</tspan>",
                          tracker[match_index],
                      )
                      + start
                  )
                  up_to_new_tspan = orig_html[
                      : closing_tspan_start + CLOSING_TSPAN_LEN + 1
                  ]
                  rest = orig_html[
                      closing_tspan_start + CLOSING_TSPAN_LEN + 1 :
                  ]
  
                  # Calculate proper x value in svg
                  x_value_start = prev_tspan.find('x="')
                  x_value_end = (
                      prev_tspan[x_value_start + 3 :].find('"') + 3
                  )  # 3 is the length of the 'x="' substring
                  x_value = prev_tspan[
                      x_value_start + 3 : x_value_end + x_value_start
                  ]
  
                  # Calculate proper y value in svg
                  DEFAULT_DY_VAL, dy = 2, 2
                  if (
                      paired_dy != DEFAULT_DY_VAL
                      and node == match.node[1]
                  ):  # we're on the second node and need to adjust height to match the paired node
                      dy = paired_dy
                  if node == match.node[0]:
                      paired_node_level = 2
                      if (
                          match.node[1].matchIndex in tracker
                      ):  # check if we need to adjust heights of labels
                          paired_node_level = tracker[
                              match.node[1].matchIndex
                          ]
                          dif = tracker[match_index] - paired_node_level
                          if dif > 0:  # current node has more labels
                              paired_dy = DEFAULT_DY_VAL * dif + 1
                              dy = DEFAULT_DY_VAL
                          else:  # paired node has more labels, adjust this label down
                              dy = DEFAULT_DY_VAL * (abs(dif) + 1)
                              paired_dy = DEFAULT_DY_VAL
  
                  # Insert new <tspan> object
                  new_tspan = f'  <tspan class="displacy-word" dy="{dy}em" fill="{color}" x={x_value}>{name[: 3].title()}.</tspan>\n'  # abbreviate label names to 3 chars
                  orig_html = up_to_new_tspan + new_tspan + rest
                  tracker[match_index] += 1
  
          # process out extra term if present -- TODO: Figure out why the semgrexify_html function lines 164-168 cause a duplication bug
          end = find_nth(haystack=orig_html, needle="</svg", n=1)
          LENGTH_OF_END_SVG = (
              7  # </svg> has length 6 so add 1 to the end too
          )
          if len(orig_html) > end + LENGTH_OF_END_SVG:
              orig_html = orig_html[: end + LENGTH_OF_END_SVG]
  
      return orig_html
  
imports: import os
  import argparse
  import stanza
  import sys
  from stanza.server.semgrex import Semgrex
  from stanza.models.common.constant import is_right_to_left
  import spacy
  from spacy import displacy
  from spacy.tokens import Doc
  from IPython.display import display, HTML
  import typing
  from typing import List, Tuple, Any
  from utils import find_nth, round_base
label_desc: Use image node_id 2 for calling a global function with example usage: semgrexify_html(orig_html, semgrex_sentence) and returns: orig_html