code: def make_input_from_dict(
      sentence_id: SentenceId,
      input_dict: Dict,
      translator: "Translator",
  ) -> TranslatorInput:
      """
      Returns a TranslatorInput object from a JSON object, serialized as a string.
  
      :param sentence_id: Sentence id.
      :param input_dict: A dict that must contain a key "text", mapping to the input text, and optionally a key "factors"
             that maps to a list of strings, each of which representing a factor sequence for the input text.
             Constraints and an avoid list can also be added through the "constraints" and "avoid" keys.
      :param translator: A translator object.
      :return: A TranslatorInput.
      """
      try:
          tokens = input_dict[C.JSON_TEXT_KEY]
          tokens = list(utils.get_tokens(tokens))
          factors = input_dict.get(C.JSON_FACTORS_KEY)
          source_prefix_tokens = input_dict.get(
              C.JSON_SOURCE_PREFIX_KEY
          )
          source_prefix_tokens = (
              list(utils.get_tokens(source_prefix_tokens))
              if source_prefix_tokens is not None
              else None
          )
          if (
              source_prefix_tokens is not None
              and not source_prefix_tokens
          ):
              logger.warning(
                  f"Empty string is specified as a source prefix for input '{input_dict[C.JSON_SOURCE_PREFIX_KEY]}'."
              )
          source_prefix_factors = input_dict.get(
              C.JSON_SOURCE_PREFIX_FACTORS_KEY
          )
          if (
              source_prefix_factors is not None
              and not source_prefix_tokens
          ):
              logger.error(
                  "Source prefix factors cannot be specified when source prefix is not specified"
              )
              return _bad_input(sentence_id, reason=str(input_dict))
          if source_prefix_factors is not None and not factors:
              logger.error(
                  "Source prefix factors cannot be specified when source factors are not specified"
              )
              return _bad_input(sentence_id, reason=str(input_dict))
          if source_prefix_tokens is not None and (
              factors is not None and not source_prefix_factors
          ):
              logger.error(
                  "Source prefix factors need to be also specified together with source factors"
              )
              return _bad_input(sentence_id, reason=str(input_dict))
  
          if isinstance(factors, list):
              factors = [
                  list(utils.get_tokens(factor)) for factor in factors
              ]
              lengths = [len(f) for f in factors]
              if not all(length == len(tokens) for length in lengths):
                  logger.error(
                      "Factors have different length than input text: %d vs. %s",
                      len(tokens),
                      str(lengths),
                  )
                  return _bad_input(sentence_id, reason=str(input_dict))
  
          if isinstance(source_prefix_factors, list):
              source_prefix_factors = [
                  list(utils.get_tokens(spf))
                  for spf in source_prefix_factors
              ]
              for source_prefix_factor in source_prefix_factors:
                  if not source_prefix_factor:
                      logger.warning(
                          f"Empty list is specified as source prefix factors for input '%s'.",
                          input_dict[C.JSON_TEXT_KEY],
                      )
              lengths = [
                  len(source_prefix_factor)
                  for source_prefix_factor in source_prefix_factors
              ]
              if not all(
                  len(source_prefix_tokens) == length
                  for length in lengths
              ):
                  logger.error(
                      "Source prefix has %d tokens but there are %s prefix factors",
                      len(source_prefix_tokens),
                      str(lengths),
                  )
                  return _bad_input(sentence_id, reason=str(input_dict))
              if len(source_prefix_factors) != len(factors):
                  logger.error(
                      "There is mismatch in source factors %d and prefix factors %d",
                      len(factors),
                      len(source_prefix_factors),
                  )
                  return _bad_input(sentence_id, reason=str(input_dict))
  
          target_prefix_tokens = input_dict.get(
              C.JSON_TARGET_PREFIX_KEY
          )
          target_prefix_tokens = (
              list(utils.get_tokens(target_prefix_tokens))
              if target_prefix_tokens is not None
              else None
          )
          if (
              target_prefix_tokens is not None
              and not target_prefix_tokens
          ):
              logger.warning(
                  f"Empty string is specified as a target prefix for input '{input_dict[C.JSON_TEXT_KEY]}'."
              )
  
          target_prefix_factors = input_dict.get(
              C.JSON_TARGET_PREFIX_FACTORS_KEY
          )
          if isinstance(target_prefix_factors, list):
              target_prefix_factors = [
                  list(utils.get_tokens(tpf))
                  for tpf in target_prefix_factors
              ]
              if (
                  len(target_prefix_factors)
                  != translator.num_target_factors - 1
              ):
                  logger.error(
                      "Must provide target prefix for each target factor. Given: %s required: %s",
                      len(target_prefix_factors),
                      translator.num_target_factors - 1,
                  )
                  return _bad_input(sentence_id, reason=str(input_dict))
  
          use_target_prefix_all_chunks = input_dict.get(
              C.JSON_USE_TARGET_PREFIX_ALL_CHUNKS_KEY, True
          )
          keep_target_prefix_key = input_dict.get(
              C.JSON_KEEP_TARGET_PREFIX_KEY, True
          )
          # Lexicon for vocabulary selection/restriction:
          # This is only populated when using multiple lexicons and the lexicon name is given, in which case the
          # restrict_lexicon key must exist and the value (name) must map to one of the translator's known lexicons.
          restrict_lexicon = None
          restrict_lexicon_name = input_dict.get(
              C.JSON_RESTRICT_LEXICON_KEY, None
          )
          if (
              isinstance(translator.restrict_lexicon, dict)
              and restrict_lexicon_name is not None
          ):
              restrict_lexicon = translator.restrict_lexicon.get(
                  restrict_lexicon_name, None
              )
              if restrict_lexicon is None:
                  logger.error(
                      "Unknown restrict_lexicon '%s'. Choices: %s"
                      % (
                          restrict_lexicon_name,
                          " ".join(sorted(translator.restrict_lexicon)),
                      )
                  )
                  return _bad_input(sentence_id, reason=str(input_dict))
  
          # List of phrases to prevent from occurring in the output
          avoid_list = input_dict.get(C.JSON_AVOID_KEY)
  
          # List of phrases that must appear in the output
          constraints = input_dict.get(C.JSON_CONSTRAINTS_KEY)
  
          # If there is overlap between positive and negative constraints, assume the user wanted
          # the words, and so remove them from the avoid_list (negative constraints)
          if constraints is not None and avoid_list is not None:
              avoid_set = set(avoid_list)
              overlap = set(constraints).intersection(avoid_set)
              if len(overlap) > 0:
                  logger.warning(
                      "Overlap between constraints and avoid set, dropping the overlapping avoids"
                  )
                  avoid_list = list(avoid_set.difference(overlap))
  
          # Convert to a list of tokens
          if isinstance(avoid_list, list):
              avoid_list = [
                  list(utils.get_tokens(phrase))
                  for phrase in avoid_list
              ]
          if isinstance(constraints, list):
              constraints = [
                  list(utils.get_tokens(constraint))
                  for constraint in constraints
              ]
  
          return TranslatorInput(
              sentence_id=sentence_id,
              tokens=tokens,
              factors=factors,
              source_prefix_tokens=source_prefix_tokens,
              source_prefix_factors=source_prefix_factors,
              target_prefix_tokens=target_prefix_tokens,
              target_prefix_factors=target_prefix_factors,
              use_target_prefix_all_chunks=use_target_prefix_all_chunks,
              keep_target_prefix_key=keep_target_prefix_key,
              restrict_lexicon=restrict_lexicon,
              constraints=constraints,
              avoid_list=avoid_list,
              pass_through_dict=input_dict,
          )
  
      except Exception as e:
          logger.exception(e, exc_info=True)  # type: ignore
          return _bad_input(sentence_id, reason=str(input_dict))
  
imports: import copy
  import itertools
  import json
  import logging
  from dataclasses import dataclass
  from functools import partial
  from typing import Any, Callable, Dict, Generator, List, Optional, Set, Tuple, Union
  import numpy
  import torch
  from .None import constants
  from .None import lexicon
  from .None import utils
  from .None import vocab
  from .beam_search import CandidateScorer, get_search_algorithm, GreedySearch, SearchResult
  from .data_io import tokens2ids, get_prepended_token_length
  from .model import SockeyeModel
label_desc: Use image node_id 6 for calling a global function with example usage: make_input_from_dict(sentence_id, input_dict, translator) and returns: TranslatorInput, _bad_input, _bad_input, _bad_input, _bad_input, _bad_input, _bad_input, _bad_input, _bad_input, _bad_input