class_docstr: Render Spans as SVGs.
class_docstr_tok: ["Render","Spans","as","SVGs","."]
docstr: Assembles token info used to generate markup in render_spans().
  tokens (List[str]): Tokens in text.
  spans (List[Dict[str, Any]]): Spans in text.
  RETURNS (List[Dict[str, List[Dict, str, Any]]]): Per token info needed to render HTML markup for given tokens
      and spans.
docstr_tok: ["Assembles","token","info","used","to","generate","markup","in","render_spans","(",")",".","tokens","(","List","[","str","]",")",":","Tokens","in","text",".","spans","(","List","[","Dict","[","str",",","Any","]","]",")",":","Spans","in","text",".","RETURNS","(","List","[","Dict","[","str",",","List","[","Dict",",","str",",","Any","]","]","]",")",":","Per","token","info","needed","to","render","HTML","markup","for","given","tokens","and","spans","."]
code: def _assemble_per_token_info(
      tokens: List[str], spans: List[Dict[str, Any]]
  ) -> List[Dict[str, List[Dict[str, Any]]]]:
      """Assembles token info used to generate markup in render_spans().
      tokens (List[str]): Tokens in text.
      spans (List[Dict[str, Any]]): Spans in text.
      RETURNS (List[Dict[str, List[Dict, str, Any]]]): Per token info needed to render HTML markup for given tokens
          and spans.
      """
      per_token_info: List[Dict[str, List[Dict[str, Any]]]] = []
  
      # we must sort so that we can correctly describe when spans need to "stack"
      # which is determined by their start token, then span length (longer spans on top),
      # then break any remaining ties with the span label
      spans = sorted(
          spans,
          key=lambda s: (
              s["start_token"],
              -(s["end_token"] - s["start_token"]),
              s["label"],
          ),
      )
  
      for s in spans:
          # this is the vertical 'slot' that the span will be rendered in
          # vertical_position = span_label_offset + (offset_step * (slot - 1))
          s["render_slot"] = 0
  
      for idx, token in enumerate(tokens):
          # Identify if a token belongs to a Span (and which) and if it's a
          # start token of said Span. We'll use this for the final HTML render
          token_markup: Dict[str, Any] = {}
          token_markup["text"] = token
          intersecting_spans: List[Dict[str, Any]] = []
          entities = []
          for span in spans:
              ent = {}
              if span["start_token"] <= idx < span["end_token"]:
                  span_start = idx == span["start_token"]
                  ent["label"] = span["label"]
                  ent["is_start"] = span_start
                  if span_start:
                      # When the span starts, we need to know how many other
                      # spans are on the 'span stack' and will be rendered.
                      # This value becomes the vertical render slot for this entire span
                      span["render_slot"] = (
                          intersecting_spans[-1]["render_slot"]
                          if len(intersecting_spans)
                          else 0
                      ) + 1
                  intersecting_spans.append(span)
                  ent["render_slot"] = span["render_slot"]
                  kb_id = span.get("kb_id", "")
                  kb_url = span.get("kb_url", "#")
                  ent["kb_link"] = (
                      TPL_KB_LINK.format(kb_id=kb_id, kb_url=kb_url)
                      if kb_id
                      else ""
                  )
                  entities.append(ent)
              else:
                  # We don't specifically need to do this since we loop
                  # over tokens and spans sorted by their start_token,
                  # so we'll never use a span again after the last token it appears in,
                  # but if we were to use these spans again we'd want to make sure
                  # this value was reset correctly.
                  span["render_slot"] = 0
          token_markup["entities"] = entities
          per_token_info.append(token_markup)
  
      return per_token_info
  
imports: import uuid
  from typing import Any, Dict, List, Optional, Tuple, Union
  from ..errors import Errors
  from ..util import escape_html, minify_html, registry
  from .templates import TPL_DEP_ARCS, TPL_DEP_SVG, TPL_DEP_WORDS, TPL_DEP_WORDS_LEMMA, TPL_ENT, TPL_ENT_RTL, TPL_ENTS, TPL_FIGURE, TPL_KB_LINK, TPL_PAGE, TPL_SPAN, TPL_SPAN_RTL, TPL_SPAN_SLICE, TPL_SPAN_SLICE_RTL, TPL_SPAN_START, TPL_SPAN_START_RTL, TPL_SPANS, TPL_TITLE
label_desc: Use image node_id 4 for calling the SpanRenderer obj's underlying member method code with example usage: obj._assemble_per_token_info(tokens, spans) and returns: per_token_info