code: def __call__(self, obs):
      user = torch.tensor(obs["user"]).float().unsqueeze(0)
  
      doc_obs = obs["doc"]
  
      if self.discrete_keys or self.box_keys:
          # Dict space
          discrete_features: List[torch.Tensor] = []
          for k, n in self.discrete_keys:
              vals = torch.tensor([v[k] for v in doc_obs.values()])
              assert vals.shape == (self.num_docs,)
              discrete_features.append(F.one_hot(vals, n).float())
  
          box_features: List[torch.Tensor] = []
          for k, d in self.box_keys:
              vals = np.vstack([v[k] for v in doc_obs.values()])
              assert vals.shape == (self.num_docs, d)
              box_features.append(torch.tensor(vals).float())
  
          doc_features = torch.cat(
              discrete_features + box_features, dim=1
          ).unsqueeze(0)
      else:
          # Simply a Box space
          vals = np.vstack(list(doc_obs.values()))
          doc_features = torch.tensor(vals).float().unsqueeze(0)
  
      # This comes from ValueWrapper
      value = (
          torch.tensor(
              [v["value"] for v in obs["augmentation"].values()]
          )
          .float()
          .unsqueeze(0)
      )
  
      candidate_docs = rlt.DocList(
          float_features=doc_features, value=value
      )
      return rlt.FeatureData(
          float_features=user, candidate_docs=candidate_docs
      )
  
file_path: ReAgent/reagent/gym/preprocessors/default_preprocessors.py
imports: import logging
  from typing import List, Tuple
  import numpy
  import reagent.core.types
  import torch
  import torch.nn.functional
  from gym import Env, spaces
label_desc: Use image node_id 3 for calling the RecsimObsPreprocessor obj's underlying member method code with example usage: obj.__call__(obs) and returns: rlt