[docs]classGeneratorStateLogger:__doc__=r"""Log the generator states especially the prompt states update history to a file. Each generator should has its unique and identifiable name to be logged. One file can log multiple generators' states. We use _trace_map to store the states and track any changes and updates and save it to a file. Args: save_dir(str, optional): The directory to save the trace file. Default is "./traces/" project_name(str, optional): The project name. Default is None. filename(str, optional): The file path to save the trace. Default is "generator_state_trace.json" """_generator_names:set=set()# TODO: create a logger base class to avoid code duplicationdef__init__(self,save_dir:Optional[str]=None,project_name:Optional[str]=None,filename:Optional[str]=None,):self.filepath=save_diror"./traces/"self.project_name=project_nameifproject_name:self.filepath=os.path.join(self.filepath,project_name)# TODO: make this a generator state instead of just the prompt as right nowos.makedirs(self.filepath,exist_ok=True)self.filename=filenameor"generator_state_trace.json"self.filepath=os.path.join(self.filepath,self.filename)self._trace_map:Dict[str,List[GeneratorStatesRecord]]=({}# generator_name: [prompt_states])# load previous records if the file existsifos.path.exists(self.filepath):self.load(self.filepath)
[docs]deflog_prompt(self,generator:"Generator",name:str):r"""Log the prompt states of the generator with the given name."""self._generator_names.add(name)prompt_states:Dict=(generator.prompt.to_dict())# TODO: log all states of the generator instead of just the prompttry:ifnamenotinself._trace_map:self._trace_map[name]=[GeneratorStatesRecord(prompt_states=prompt_states,time_stamp=datetime.now().isoformat(),)]self.save(self.filepath)else:# compare the last record with the new recordlast_record=self._trace_map[name][-1]new_prompt_record=GeneratorStatesRecord(prompt_states=prompt_states,time_stamp=datetime.now().isoformat())iflast_record!=new_prompt_record:self._trace_map[name].append(new_prompt_record)self.save(self.filepath)exceptExceptionase:raiseException(f"Error logging prompt states for {name}")frome
[docs]defload(self,filepath:str):ifos.stat(filepath).st_size==0:logging.info(f"File {filepath} is empty.")returnwithopen(filepath,"r")asf:content=f.read().strip()ifnotcontent:logging.info(f"File {filepath} is empty after stripping.")returnself._trace_map=json.loads(content)# convert each dict record to PromptRecordforname,recordsinself._trace_map.items():self._trace_map[name]=[GeneratorStatesRecord.from_dict(record)forrecordinrecords]