code: def _preprocess(opt, datapath, datatype, version):
      """
      MultiDoGo conversations take place between an "agent" and a customer". Labeled
      customer data is stored in one set of files while the agent data is in another.
      There is a common conversation ID between the two, but the conversations are not
      listed in a consistent way between the documents. Since we'll have to do work to
      associate the data between the files anyway, we might as well process the data into
      a new file that'll be easier to deal with.
  
      Stores the data as <multidogo_data_path>/processed/<domain>/<datatype>.txt.
      Will skip preprocessing if this file already exists.
      """
      domains = opt.get("domains", DOMAINS)
      intent_type = opt.get("intent_type", TURN_INTENT)
  
      for domain in domains:
          out_dir = get_processed_multidogo_folder(
              datapath, domain, datatype, intent_type
          )
          if build_data.built(out_dir, version):
              continue
          print(
              f"    Preprocessing '{domain}' data for '{datatype}' with '{intent_type}' intent labels."
          )
  
          Path(out_dir).mkdir(parents=True, exist_ok=True)
  
          # The agent responses for *all* datatypes are in one file.
          # We need to iterate through the datatype file to know which lines
          # we'll actually need... so build a quick lookup table to know which
          # lines in the tsv file we'll need to care about so we're not scanning
          # through the whole thing a bunch
          unannotated_id_map = _build_conversation_span_map(
              _get_unannotated_tsv_data(datapath, domain)
          )
  
          # Actually do the work of collating all of the conversations + annotations
          # For turn + sentence intent labels, we do two passes, one for sentence
          # then one for turn so that we do not add two sets of labels for the
          # same conversation ID. We can use this forced structure to do the
          # separate categories of turn intent and sentence intent labels.  We
          # also do a bit of chuking
          file_idx = 0
          seen_conversations_set = set()
          if (
              intent_type == TURN_AND_SENTENCE_INTENT
              or intent_type == SENTENCE_INTENT
          ):
              (
                  file_idx,
                  seen_conversations_set,
              ) = _aggregate_and_write_conversations(
                  intent_type,
                  SENTENCE_INTENT,
                  datapath,
                  domain,
                  datatype,
                  unannotated_id_map,
                  start_file_idx=file_idx,
                  skip_ids=set(),
              )
  
          if (
              intent_type == TURN_AND_SENTENCE_INTENT
              or intent_type == TURN_INTENT
          ):
              _, _ = _aggregate_and_write_conversations(
                  intent_type,
                  TURN_INTENT,
                  datapath,
                  domain,
                  datatype,
                  unannotated_id_map,
                  start_file_idx=file_idx,
                  skip_ids=seen_conversations_set,
              )
  
          # mark that we've built this combinations
          build_data.mark_done(out_dir, version_string=version)
  
imports: import parlai.core.build_data
  from parlai.core.build_data import DownloadableFile
  import csv
  from itertools import islice
  from pathlib import Path
  import os
  import json
  import re
  import tqdm
label_desc: Use image node_id 1 for calling a global function with example usage: _preprocess(opt, datapath, datatype, version) without return types