class_docstr: This class partitions the dataset into chains of conversations.
  Each chain is comprised of a list of conversation rounds.
  Each round within a conversation is represented as a triplet:
   (system, prompt, answer).
  
  The resulting structure of the chains is conditional on
  the DataFrame's structure and configuration:
  
  - Without a 'parent_id' in the DataFrame, each conversation chain is a single round.
   So, for every `i`-th row in the DataFrame, 0 <= `i` < len(df),
   the chain would look like: [(system_i, prompt_i, answer_i)]
  
  - With a 'parent_id' in the DataFrame and
    if `cfg.dataset.limit_chained_samples` is set to False,
    each chain encapsulates all preceding conversations
    for every `i`-th row in the DataFrame,
    0 <= `i` < len(df).
    The resultant chain would take shape:
        [(system_start_conversation_i,
          prompt_start_conversation_i,
          answer_start_conversation_i),
         ...,
         (system_i, prompt_i, answer_i)]
  
  - With a 'parent_id' in the DataFrame and
    if `cfg.dataset.limit_chained_samples` is set to True,
    each conversation chain incorporates only full conversations.
    The chain hence condenses into:
        [(system_start_conversation_i,
          prompt_start_conversation_i,
          answer_start_conversation_i),
         ...,
        (system_end_conversation_i,
         prompt_end_conversation_i,
         answer_end_conversation_i)]
    where `i` represents complete conversations only.
class_docstr_tok: ["This","class","partitions","the","dataset","into","chains","of","conversations",".","Each","chain","is","comprised","of","a","list","of","conversation","rounds",".","Each","round","within","a","conversation","is","represented","as","a","triplet",":","(","system",",","prompt",",","answer",")",".","The","resulting","structure","of","the","chains","is","conditional","on","the","DataFrame","'s","structure","and","configuration",":","-","Without","a","'parent_id","'","in","the","DataFrame",",","each","conversation","chain","is","a","single","round",".","So",",","for","every","`","i","`","-th","row","in","the","DataFrame",",","0","<","=","`","i","`","<","len","(","df",")",",","the","chain","would","look","like",":","[","(","system_i",",","prompt_i",",","answer_i",")","]","-","With","a","'parent_id","'","in","the","DataFrame","and","if","`","cfg.dataset.limit_chained_samples","`","is","set","to","False",",","each","chain","encapsulates","all","preceding","conversations","for","every","`","i","`","-th","row","in","the","DataFrame",",","0","<","=","`","i","`","<","len","(","df",")",".","The","resultant","chain","would","take","shape",":","[","(","system_start_conversation_i",",","prompt_start_conversation_i",",","answer_start_conversation_i",")",",","...",",","(","system_i",",","prompt_i",",","answer_i",")","]","-","With","a","'parent_id","'","in","the","DataFrame","and","if","`","cfg.dataset.limit_chained_samples","`","is","set","to","True",",","each","conversation","chain","incorporates","only","full","conversations",".","The","chain","hence","condenses","into",":","[","(","system_start_conversation_i",",","prompt_start_conversation_i",",","answer_start_conversation_i",")",",","...",",","(","system_end_conversation_i",",","prompt_end_conversation_i",",","answer_end_conversation_i",")","]","where","`","i","`","represents","complete","conversations","only","."]
docstr: Gets the conversation chain IDs for the given DataFrame.
  E.g. if conversation_chain_ids = [[13, 44, 8], ...],
  then the first conversation chain consists of
  [df.iloc[13], df.iloc[44], df.iloc[8]]
  with
      - df.iloc[13] denotes the first round of the conversation
      - df.iloc[44] denotes the second round of the conversation
      - df.iloc[8] denotes the end of the conversation
  if limit_chained_samples is True, df.iloc[13] will have no parent_id,
  i.e. it is the start of the conversation.
docstr_tok: ["Gets","the","conversation","chain","IDs","for","the","given","DataFrame",".","E.g",".","if","conversation_chain_ids","=","[","[","13",",","44",",","8","]",",","...","]",",","then","the","first","conversation","chain","consists","of","[","df.iloc","[","13","]",",","df.iloc","[","44","]",",","df.iloc","[","8","]","]","with","-","df.iloc","[","13","]","denotes","the","first","round","of","the","conversation","-","df.iloc","[","44","]","denotes","the","second","round","of","the","conversation","-","df.iloc","[","8","]","denotes","the","end","of","the","conversation","if","limit_chained_samples","is","True",",","df.iloc","[","13","]","will","have","no","parent_id",",","i.e",".","it","is","the","start","of","the","conversation","."]
code: def get_conversation_chain_ids(self, cfg, df):
      """
      Gets the conversation chain IDs for the given DataFrame.
      E.g. if conversation_chain_ids = [[13, 44, 8], ...],
      then the first conversation chain consists of
      [df.iloc[13], df.iloc[44], df.iloc[8]]
      with
          - df.iloc[13] denotes the first round of the conversation
          - df.iloc[44] denotes the second round of the conversation
          - df.iloc[8] denotes the end of the conversation
      if limit_chained_samples is True, df.iloc[13] will have no parent_id,
      i.e. it is the start of the conversation.
      """
      if (
          cfg.dataset.parent_id_column in ["None", None]
          # Handle case where train Dataframe has conversation chains,
          # but val Dataframe does not
          or cfg.dataset.parent_id_column not in df.columns
      ):
          # no parent id column, so each triplet (system_i, prompt_i, answer_i)
          # is a conversation chain
          return [[idx] for idx in range(len(df))]
  
      assert "id" in df.columns, (
          f"id column required for conversation chaining, "
          f"DataFrame only has {df.columns}."
      )
      # sample and parent ids can have any dtype, such as str, int, float, etc.
      # id column can be int, while parent_id column can be float
      # (as some values are NaN) so we cast id to the same dtype
      sample_ids = (
          df["id"]
          .astype(df[cfg.dataset.parent_id_column].dtype)
          .tolist()
      )
      parent_ids = df[cfg.dataset.parent_id_column].tolist()
      # Some datasets may include parent ids that are not in the dataset.
      sample_ids_set = set(sample_ids)
      parent_ids = [
          idx if idx in sample_ids_set else "None" for idx in parent_ids
      ]
  
      id2parent_id = {
          idx: parent_id
          for idx, parent_id in zip(sample_ids, parent_ids)
          if parent_id not in [None, "None"]
          and (
              not isinstance(parent_id, float)
              or (not np.isnan(parent_id) and not np.isinf(parent_id))
          )
      }
      if cfg.dataset.limit_chained_samples:
          # end id == id is not a parent id of another conversation id
          valid_parent_ids = set(id2parent_id.values())
          conversation_end_ids = [
              idx for idx in sample_ids if idx not in valid_parent_ids
          ]
      else:
          conversation_end_ids = sample_ids
      conversation_chain_ids = [
          self.get_conversation_ids(id2parent_id, conversation_end_id)
          for conversation_end_id in conversation_end_ids
      ]
      # map from df["id"] to enumeration index
      dataframeid2idx = {id: idx for idx, id in enumerate(sample_ids)}
      conversation_chain_ids = [
          [
              dataframeid2idx[conversation_id]
              for conversation_id in conversation_ids
          ]
          for conversation_ids in conversation_chain_ids
      ]
      return conversation_chain_ids
  
file_path: h2o-llmstudio/llm_studio/src/datasets/conversation_chain_handler.py
imports: import logging
  from typing import Dict, List
  import numpy
  from llm_studio.src.datasets.text_utils import get_texts
  from llm_studio.src.utils.utils import PatchedAttribute
label_desc: Use image node_id 2 for calling the ConversationChainHandler obj's underlying member method code with example usage: obj.get_conversation_chain_ids(cfg, df) and returns: conversation_chain_ids, unknown