code: def preprocess_llama_2(
      sources,
      tokenizer: transformers.PreTrainedTokenizer,
      has_image: bool = False,
  ) -> Dict:
      conv = conversation_lib.default_conversation.copy()
      roles = {"human": conv.roles[0], "gpt": conv.roles[1]}
  
      # Apply prompt templates
      conversations = []
      for i, source in enumerate(sources):
          if roles[source[0]["from"]] != conv.roles[0]:
              # Skip the first one if it is not from human
              source = source[1:]
  
          conv.messages = []
          for j, sentence in enumerate(source):
              role = roles[sentence["from"]]
              assert role == conv.roles[j % 2], f"{i}"
              conv.append_message(role, sentence["value"])
          conversations.append(conv.get_prompt())
  
      # Tokenize conversations
  
      if has_image:
          input_ids = torch.stack(
              [
                  tokenizer_image_token(
                      prompt, tokenizer, return_tensors="pt"
                  )
                  for prompt in conversations
              ],
              dim=0,
          )
      else:
          input_ids = tokenizer(
              conversations,
              return_tensors="pt",
              padding="longest",
              max_length=tokenizer.model_max_length,
              truncation=True,
          ).input_ids
  
      targets = input_ids.clone()
  
      assert conv.sep_style == conversation_lib.SeparatorStyle.LLAMA_2
  
      # Mask targets
      sep = "[/INST] "
      for conversation, target in zip(conversations, targets):
          total_len = int(target.ne(tokenizer.pad_token_id).sum())
  
          rounds = conversation.split(conv.sep2)
          cur_len = 1
          target[:cur_len] = IGNORE_INDEX
          for i, rou in enumerate(rounds):
              if rou == "":
                  break
  
              parts = rou.split(sep)
              if len(parts) != 2:
                  break
              parts[0] += sep
  
              if has_image:
                  round_len = len(tokenizer_image_token(rou, tokenizer))
                  instruction_len = (
                      len(tokenizer_image_token(parts[0], tokenizer))
                      - 2
                  )
              else:
                  round_len = len(tokenizer(rou).input_ids)
                  instruction_len = (
                      len(tokenizer(parts[0]).input_ids) - 2
                  )
  
              target[cur_len : cur_len + instruction_len] = IGNORE_INDEX
  
              cur_len += round_len
          target[cur_len:] = IGNORE_INDEX
  
          if cur_len < tokenizer.model_max_length:
              if cur_len != total_len:
                  target[:] = IGNORE_INDEX
                  print(
                      f"WARNING: tokenization mismatch: {cur_len} vs. {total_len}."
                      f" (ignored)"
                  )
  
      return dict(
          input_ids=input_ids,
          labels=targets,
      )
  
imports: import os
  import copy
  import random
  from dataclasses import dataclass, field
  import json
  import logging
  import pathlib
  from typing import Dict, Optional, Sequence, List
  import pickle
  import math
  import torch
  import transformers
  from llamavid.constants import IGNORE_INDEX, IMAGE_TOKEN_INDEX, DEFAULT_IMAGE_TOKEN, DEFAULT_IM_START_TOKEN, DEFAULT_IM_END_TOKEN
  from torch.utils.data import Dataset
  from llamavid.train.llava_trainer import LLaVATrainer
  from llamavid import conversation
  from llamavid.model import *
  from llava.mm_utils import tokenizer_image_token
  from PIL import Image
  from decord import VideoReader, cpu
label_desc: Use image node_id 14 for calling a global function with example usage: preprocess_llama_2(sources, tokenizer, has_image) and returns: dict