code: def teach(
      dataset,
      vectors_path,
      seeds,
      threshold=0.85,
      n_similar=100,
      batch_size=5,
      case_sensitive=False,
      resume=False,
  ):
      """
      Bootstrap a terminology list using sense2vec. Prodigy will suggest similar
      terms based on the the most similar phrases from sense2vec, and the
      suggestions will be adjusted as you annotate and accept similar phrases. For
      each seed term, the best matching sense according to the sense2vec vectors
      will be used.
  
      If no similar terms are found above the given threshold, the threshold is
      lowered by 0.1 and similar terms are requested again.
      """
      log("RECIPE: Starting recipe sense2vec.teach", locals())
      s2v = Sense2Vec().from_disk(vectors_path)
      log("RECIPE: Loaded sense2vec vectors", vectors_path)
      html_template = "<span style='font-size: {{theme.largeText}}px'>{{word}}</span>"
      accept_keys = []
      seen = set()
      seed_tasks = []
      for seed in seeds:
          key = s2v.get_best_sense(seed)
          if key is None:
              msg.warn(f"Can't find seed term '{seed}' in vectors")
              continue
          accept_keys.append(key)
          best_word, best_sense = s2v.split_key(key)
          seen.add(best_word if case_sensitive else best_word.lower())
          task = {
              "text": key,
              "word": best_word,
              "sense": best_sense,
              "meta": {"score": 1.0, "sense": best_sense},
              "answer": "accept",
          }
          seed_tasks.append(set_hashes(task))
      if len(accept_keys) == 0:
          msg.fail(
              "No seeds available. This typically happens if none of your seed "
              "terms are found in the vectors. Try using more generic terms or "
              "different vectors that cover the expressions you're looking for.",
              exits=1,
          )
      print(f"Starting with seed keys: {accept_keys}")
      DB = connect()
      if dataset not in DB:
          DB.add_dataset(dataset)
      dataset_hashes = DB.get_task_hashes(dataset)
      DB.add_examples(
          [
              st
              for st in seed_tasks
              if st[TASK_HASH_ATTR] not in dataset_hashes
          ],
          datasets=[dataset],
      )
  
      if resume:
          prev = DB.get_dataset(dataset)
          prev_accept_keys = [
              eg["text"] for eg in prev if eg["answer"] == "accept"
          ]
          prev_words = [
              eg["word"] if case_sensitive else eg["word"].lower()
              for eg in prev
          ]
          accept_keys += prev_accept_keys
          seen.update(set(prev_words))
          log(
              f"RECIPE: Resuming from {len(prev)} previous examples in dataset {dataset}"
          )
  
      def update(answers):
          """Updates accept_keys so that the stream can find new phrases."""
          log(f"RECIPE: Updating with {len(answers)} answers")
          for answer in answers:
              phrase = answer["text"]
              if answer["answer"] == "accept":
                  accept_keys.append(phrase)
  
      def get_stream():
          """Continue querying sense2vec whenever we get a new phrase and
          presenting examples to the user with a similarity above the threshold
          parameter."""
          nonlocal threshold
          while True:
              log(
                  f"RECIPE: Looking for {n_similar} phrases most similar to "
                  f"{len(accept_keys)} accepted keys"
              )
              most_similar = s2v.most_similar(accept_keys, n=n_similar)
              log(
                  f"RECIPE: Found {len(most_similar)} most similar phrases"
              )
              n_skipped = 0
              n_duplicate = 0
              for key, score in most_similar:
                  if score > threshold:
                      word, sense = s2v.split_key(key)
                      if (case_sensitive and word in seen) or (
                          not case_sensitive and word.lower() in seen
                      ):
                          n_duplicate += 1
                          continue
                      seen.add(word if case_sensitive else word.lower())
                      # Make sure the score is a regular float, otherwise server
                      # may fail when trying to serialize it to/from JSON
                      meta = {"score": float(score), "sense": sense}
                      yield {
                          "text": key,
                          "word": word,
                          "sense": sense,
                          "meta": meta,
                      }
                  else:
                      n_skipped += 1
              if n_skipped:
                  log(
                      f"RECIPE: Skipped {n_skipped} phrases below threshold {threshold}"
                  )
              if n_skipped == len(most_similar) - n_duplicate:
                  # No most similar phrases were found that are above the
                  # threshold, so lower the threshold if it's not already 0 or
                  # return empty list so Prodigy shows "no tasks available"
                  new_threshold = threshold - 0.1
                  if new_threshold <= 0.0:
                      log(
                          f"RECIPE: No suggestions for threshold {threshold:.2}"
                      )
                      return []
                  log(
                      f"RECIPE: Lowering threshold from {threshold:.2} to {new_threshold:.2}"
                  )
                  threshold = new_threshold
  
      stream = get_stream()
  
      return {
          "view_id": "html",
          "dataset": dataset,
          "stream": stream,
          "update": update,
          "config": {
              "batch_size": batch_size,
              "html_template": html_template,
          },
      }
  
file_path: sense2vec/sense2vec/prodigy_recipes.py
imports: import prodigy
  from prodigy.components.db import connect
  from prodigy.util import log, split_string, set_hashes, TASK_HASH_ATTR, INPUT_HASH_ATTR
  import murmurhash
  from sense2vec import Sense2Vec
  import srsly
  import spacy
  import random
  from wasabi import msg
  from collections import defaultdict, Counter
  import copy
  import catalogue
label_desc: Use image node_id 1 for calling a global function with example usage: teach(dataset, vectors_path, seeds, threshold, n_similar, batch_size, case_sensitive, resume) and returns: dict, list