code: def run(self):
      opt = self.opt
      if int(len(self.opt["agent_suffixes"])) % 2 != 0:
          raise RuntimeError("Agent suffix input should be even")
      suffixes = {}
      for i in range(int(len(self.opt["agent_suffixes"]) / 2)):
          agent = self.opt["agent_suffixes"][2 * i]
          suffix = self.opt["agent_suffixes"][2 * i + 1]
          suffixes[agent] = suffix
  
      with PathManager.open(opt["report_path"]) as r:
          report = json.load(r)["report"]
      tod_metrics = report["tod_metrics"]
  
      if opt["num_conversations"] > -1:
          tod_metrics = tod_metrics[: opt["num_conversations"]]
  
      source = self.opt["source_file"].replace(".jsonl", "")
      if self.opt["out_file"]:
          out = self.opt["out_file"]
      else:
          if (
              "conversations" in source
          ):  # just to make sure we don't overwrite anything...
              out = source.replace(
                  "conversations", "cleaned_conversations"
              )
          else:
              out = "cleaned_" + source
  
      speakers = []
      with PathManager.open(out + ".jsonl", "w") as f:
          conversations = Conversations(source + ".jsonl")
          for i, conversation in enumerate(conversations):
              if (
                  opt["num_conversations"] >= 0
                  and i >= opt["num_conversations"]
              ):
                  break
              cleaned_dialog = []
              for parlay_round in conversation.episode["dialog"]:
                  cleaned_parlay_round = []
                  for turn in parlay_round:
                      turn_type = self._get_turn_type(turn)
                      if turn_type in self.opt["included_speakers"]:
                          if turn_type in suffixes:
                              turn["id"] += suffixes[turn_type]
                          if turn["id"] not in speakers:
                              speakers.append(turn["id"])
                          cleaned_parlay_round.append(turn)
                  if len(cleaned_parlay_round) > 0:
                      cleaned_dialog.append(cleaned_parlay_round)
              convo = {}
              convo["dialog"] = cleaned_dialog
              convo["metadata_path"] = Metadata._get_path(out)
              convo["context"] = [
                  {
                      "synthetic_task_success": tod_metrics[i][
                          "synthetic_task_success"
                      ],
                      "goal_text": tod_metrics[i]["goal"]["text"],
                  }
              ]
              json_convo = json.dumps(convo)
              f.write(json_convo + "\n")
  
          old_meta = Metadata(source + ".jsonl")
          Metadata.save_metadata(
              out,
              old_meta.opt,
              old_meta.self_chat,
              speakers,
              **old_meta.extra_data,
          )
  
file_path: ParlAI/projects/tod_simulator/scripts/cleanup_conversation.py
imports: from parlai.core.params import ParlaiParser
  from parlai.utils.conversations import Conversations, Metadata
  from parlai.utils.io import PathManager
  from parlai.core.script import ParlaiScript, register_script
  from parlai.core.tod.tod_core import TodAgentType, TOD_AGENT_TYPE_TO_PREFIX
  import json
label_desc: Use image node_id 3 for calling the ConversationCleanup obj's underlying member method code with example usage: obj.run() without return types