//  [python]
def reply_data_loader(batch_size, data_path, config: Config, train=True):
    with open(data_path, 'r') as reader:
        data = json.load(reader)
    if batch_size != 1:
        raise ValueError("only support batch_size=1!")

    if train:
        random.shuffle(data)

    if config.multi_modal:
        if "layoutlmv2" in config.encoder_model_type:
            processor = AutoProcessor.from_pretrained(config.encoder_model_type, revision="no_ocr")
        elif "clip" in config.encoder_model_type:
            processor = AutoProcessor.from_pretrained(config.encoder_model_type)
        else:
            processor = ViTFeatureExtractor()

    tokenizer = AutoTokenizer.from_pretrained(config.encoder_model_type)
    if config.history == "all" or config.history == "action":
        tokenizer.add_tokens(list(ActionToIdx.keys()))

    input_ids = []
    attention_masks = []
    token_type_ids = []
    reply_texts = []
    bbox_s = []

    for d in data:
        if d["action"] != "response":
            continue
        input_id = []
        token_type_id = []
        attention_mask = []
        bbox = []
        item_input_id = []
        item_attention_mask = []

        dialogue_text_list = d["dialog"].copy()
        dialogue_text_list.reverse()

        history_flag = False
        if config.history == "all" or config.history == "action":
            action_history = d["action_history"]

            if len(action_history) != 0:
                action_lists = []
                for action_history_ in action_history:
                    action_lists.append(f"[{action_history_['action_info'].split('|')[1]}]")
                action_lists = action_lists[-3:]
                action_infos = " ".join(action_lists)

                dialogue_text_list = [action_infos] + dialogue_text_list

                dialogue_text = tokenizer.sep_token.join(dialogue_text_list)
                if "layoutlmv2" in config.encoder_model_type:
                    dialog_token = tokenizer([dialogue_text], boxes=fake_box,
                                             max_length=config.dialog_seq_length, truncation=True)
                else:
                    dialog_token = tokenizer(dialogue_text, max_length=config.dialog_seq_length, truncation=True)

                input_id += dialog_token["input_ids"]
                token_type_id += dialog_token["token_type_ids"]
                attention_mask += dialog_token["attention_mask"]
                max_page_length = 512 - len(dialog_token["input_ids"])
                bbox += [[0, 0, 1000, 1000]]
                bbox += [[0, 0, 0, 0]] * (len(dialog_token["input_ids"]) - 1)
                history_flag = True

        if not history_flag:
            dialogue_text = tokenizer.sep_token.join(dialogue_text_list)
            if "layoutlmv2" in config.encoder_model_type:
                dialog_token = tokenizer([dialogue_text], boxes=fake_box,
                                         max_length=config.dialog_seq_length, truncation=True)
            else:
                dialog_token = tokenizer(dialogue_text, max_length=config.dialog_seq_length, truncation=True)

            input_id += dialog_token["input_ids"]
            token_type_id += dialog_token["token_type_ids"]
            attention_mask += dialog_token["attention_mask"]
            max_page_length = 512 - len(dialog_token["input_ids"])
            bbox += [[0, 0, 1000, 1000]]
            bbox += [[0, 0, 0, 0]] * (len(dialog_token["input_ids"]) - 1)

        items = d["items"]
        text = d["response"]

        for item in items:
            item_text = item["text"]
            if "layoutlmv2" in config.encoder_model_type:
                item_text_token = tokenizer([item_text], boxes=fake_box, add_special_tokens=False)
            else:
                item_text_token = tokenizer(item_text, add_special_tokens=False)
            if len(item_text_token["input_ids"]) == 0:
                item_text = item["type"].split(".")[-1]
                if "layoutlmv2" in config.encoder_model_type:
                    item_text_token = tokenizer([item_text], boxes=fake_box, add_special_tokens=False)
                else:
                    item_text_token = tokenizer(item_text, add_special_tokens=False)
            item_input_id += item_text_token["input_ids"]
            item_attention_mask += item_text_token["attention_mask"]
            border = item["border"]
            resize_border = [int(border[0]*1000/1440), int(border[1]*1000/2560),
                             int(border[2]*1000/1440), int(border[3]*1000/2560)]
            bbox += [resize_border] * len(item_text_token["input_ids"])
            if len(item_input_id) > max_page_length:
                break
        if len(item_input_id) > max_page_length:
            item_input_id = item_input_id[:max_page_length]
            item_attention_mask = item_attention_mask[:max_page_length]
            bbox = bbox[:512]
        input_id += item_input_id
        attention_mask += item_attention_mask
        token_type_id += [1] * len(item_input_id)

        input_ids.append(input_id)
        attention_masks.append(attention_mask)
        token_type_ids.append(token_type_id)
        bbox_s.append(bbox)

        if config.multi_modal:
            image_path = d["screenshot_history"][-1]
            image = Image.open(image_path).convert("RGB")
            image_feature = extract_image_feature(config, image, processor)

            if config.history == "all" or config.history == "screen":
                image_histories = d["screenshot_history"]
                if len(image_histories) == 2:
                    image_history = image_histories[-2]
                    image = Image.open(image_history).convert("RGB")
                    image_feature = torch.cat([extract_image_feature(config, image, processor), image_feature],
                                              dim=0)
                elif len(image_histories) >= 3:
                    image_history = image_histories[-2]
                    image = Image.open(image_history).convert("RGB")
                    image_feature = torch.cat([extract_image_feature(config, image, processor), image_feature],
                                              dim=0)
                    image_history = image_histories[-3]
                    image = Image.open(image_history).convert("RGB")
                    image_feature = torch.cat([extract_image_feature(config, image, processor), image_feature],
                                              dim=0)

        if "layoutlmv2" in config.encoder_model_type:
            reply_text_tokenized = tokenizer([text], boxes=fake_box, padding=True)["input_ids"]
        else:
            reply_text_tokenized = tokenizer(text, padding=True)["input_ids"]

        reply_texts.append(reply_text_tokenized)

        if config.multi_modal:
            yield torch.tensor(input_ids), \
                  image_feature, \
                  torch.tensor(attention_masks), \
                  torch.tensor(token_type_ids), \
                  torch.tensor(bbox_s), \
                  torch.tensor(reply_texts),
        else:
            yield torch.tensor(input_ids), \
                  torch.tensor(attention_masks), \
                  torch.tensor(token_type_ids), \
                  torch.tensor(bbox_s), \
                  torch.tensor(reply_texts),

        input_ids = []
        attention_masks = []
        token_type_ids = []
        bbox_s = []
        reply_texts = []