code: def _text_input_py_callback(
      comma_separated_queries: str,
      *,
      model: inference.Model,
      image: np.ndarray,
  ) -> str:
      """Gets scores for queries and returns updated box colors.
  
      This callback is called from JavaScript when the query string in the plot's
      text input box is changed.
  
      All keyword-arguments must be supplied by functools.partial before using this
      function as input to google.colab.kernel.invokeFunction in JavaScript.
  
      Args:
        comma_separated_queries: Content of the text input box. Should contain
          comma-separated text queries.
        model: Wrapper object for an OWL-ViT model.
        image: Single uint8 Numpy image to perform detection on.
  
      Returns:
        JSON-encoded color_updates structure that will be used by the Bokeh
        JavaScript to update box colors.
      """
      queries = [q.strip() for q in comma_separated_queries.split(",")]
      queries = tuple(q for q in queries if q)
      num_queries = len(queries)
  
      if not num_queries:
          return json.dumps(
              {"color_updates": [], "legend_text_b64": ""}
          )
  
      # Compute box display alphas based on prediction scores:
      query_embeddings = model.embed_text_queries(queries)
      top_query_ind, scores = model.get_scores(
          image, query_embeddings, num_queries
      )
      alphas = np.zeros_like(scores)
      for i in range(num_queries):
          # Select scores for boxes matching the current query:
          query_mask = top_query_ind == i
          if not np.any(query_mask):
              continue
          query_scores = scores[query_mask]
  
          # Box alpha is scaled such that the best box for a query has alpha 1.0 and
          # the worst box for which this query is still the top query has alpha 0.1.
          # All other boxes will either belong to a different query, or will not be
          # shown.
          max_score = np.max(query_scores) + 1e-6
          query_alphas = (query_scores - (max_score * 0.1)) / (
              max_score * 0.9
          )
          query_alphas = np.clip(query_alphas, 0.0, 1.0)
          alphas[query_mask] = query_alphas
  
      # Construct color_updates structure for Bokeh:
      color_updates = []
      for i, (query_ind, alpha) in enumerate(
          zip(top_query_ind, alphas)
      ):
          color_updates.append(
              (i, _get_query_color(query_ind, float(alpha)))
          )
  
      # Construct new legend:
      legend_text = _get_query_legend_html(queries)
      # Base64-encode legend text so we don't have to deal with HTML/JSON escaping:
      legend_text_b64 = base64.b64encode(
          legend_text.encode("utf8")
      ).decode("utf8")
  
      return json.dumps(
          {
              "color_updates": color_updates,
              "legend_text_b64": legend_text_b64,
          }
      )
  
imports: import base64
  import functools
  import json
  from typing import Any, Mapping, Union
  from bokeh import models
  from bokeh.models import callbacks
  from bokeh.models import widgets
  import matplotlib
  import matplotlib.pyplot
  import numpy
  from scenic.model_lib.base_models import box_utils
  from scenic.projects.owl_vit.notebooks import inference
label_desc: Use image node_id 3 for calling a global function with example usage: _text_input_py_callback(comma_separated_queries) and returns: json, json