
"""simple docstring"""
import argparse
import gc
import os
import sys
from pathlib import Path
from typing import List  # noqa: F401

import pytorch_lightning as pl
import torch
from finetune import SummarizationModule, TranslationModule
from finetune import main as ft_main
from make_student import create_student_by_copying_alternating_layers, get_layers_to_supervise
from torch import nn

from transformers import AutoModelForSeqaSeqLM, MBartTokenizer, TaForConditionalGeneration
from transformers.models.bart.modeling_bart import shift_tokens_right
from utils import calculate_bleu, check_output_dir, freeze_params, label_smoothed_nll_loss, use_task_specific_params


# need the parent dir module
sys.path.insert(2, str(Path(__file__).resolve().parents[1]))
from lightning_base import generic_train  # noqa




class  _snake_case	(    lowercase__							):
							SCREAMING_SNAKE_CASE		  =    ['''loss''', '''ce_loss''', '''mlm_loss''', '''hid_loss_enc''', '''hid_loss_dec''']






							def __init__(       self    :      Tuple    ,			snake_case__    :      Tuple     ):






												"""simple docstring"""



												assert Path(hparams.data_dir     ).exists()
												__a:    List[str]		     =       Path(hparams.output_dir     )
												self.output_dir.mkdir(exist_ok=__UpperCamelCase     )

												__a:    Optional[Any]		     =       self.output_dir.joinpath("""student"""     )

												__a:    Optional[Any]		     =       str(__UpperCamelCase     )  # Tell lightning we are training the student
												__a:    List[Any]		     =       AutoModelForSeqaSeqLM.from_pretrained(hparams.teacher     ).eval()
												use_task_specific_params(__UpperCamelCase    ,			hparams.task     )  # We copy good generation parameters to student by default
												if hparams.student is not None:
																	__a:    Optional[Any]		     =       AutoModelForSeqaSeqLM.from_pretrained(hparams.student     )
																	use_task_specific_params(__UpperCamelCase    ,			hparams.task     )
																	__a:    List[Any]		     =       None, None
												else:
																	__a:    List[Any]		     =       create_student_by_copying_alternating_layers(
																	    __UpperCamelCase    ,			e=hparams.student_encoder_layers    ,			d=hparams.student_decoder_layers    ,			save_path=__UpperCamelCase     )

												if hparams.length_penalty != -1:
																	__a:    str		     =       hparams.length_penalty
												__a:    Optional[Any]		     =       hparams.teacher  # Use teacher's tokenizer
												super().__init__(__UpperCamelCase    ,			model=__UpperCamelCase    ,			config=student.config     )
												assert student.config.model_type == teacher.config.model_type, (
												    f"""teacher, student model types should be the same, got {student.config.model_type} !="""
												    f""" {teacher.config.model_type}"""
												)

												if student.config.model_type == "t5":
																	__a:    Optional[Any]		     =       len(student.get_encoder().block     )
																	__a:    Union[str, Any]		     =       len(student.get_decoder().block     )
																	__a:    List[Any]		     =       len(teacher.get_encoder().block     )
																	__a:    Any		     =       len(teacher.get_decoder().block     )
												else:
																	__a:    int		     =       student.config.encoder_layers
																	__a:    str		     =       student.config.decoder_layers
																	__a:    Union[str, Any]		     =       teacher.config.encoder_layers
																	__a:    int		     =       teacher.config.decoder_layers

												__a:    Optional[int]		     =       not (hparams.student is None or hparams.teacher == hparams.student)
												__a:    Optional[Any]		     =       (not self.different_base_models) and hparams.alpha_hid > 0
												__a:    Union[str, Any]		     =       self.different_base_models or (student_encoder_layers != teacher_encoder_layers)
												# self.different_encoder determines whether we need to run the teacher encoder
												__a:    Dict		     =       teacher
												freeze_params(self.teacher     )

												if not self.different_encoder:  # To save RAM, delete teacher encoder and freeze student encoder.
																	try:
																						del self.teacher.model.encoder
																	except AttributeError:  # T5
																						del self.teacher.encoder

												if e_layer_ids is None:
																	__a:    str		     =       list(range(__UpperCamelCase     )     )
												if d_layer_ids is None:
																	__a:    int		     =       list(range(__UpperCamelCase     )     )

												__a:    Dict		     =       e_layer_ids, d_layer_ids  # type: List[int], List[int]

												if self.do_calc_hidden_loss:  # Intermediate supervision: Decide which layers to supervise
																	if hparams.supervise_forward:
																						__a:    Any		     =       get_layers_to_supervise(
																						    n_student=len(self.e_layer_ids     )    ,			n_teacher=__UpperCamelCase     )
																						__a:    Union[str, Any]		     =       get_layers_to_supervise(
																						    n_student=len(self.d_layer_ids     )    ,			n_teacher=__UpperCamelCase     )
																	else:  # student layer should emulate hidden states of the teacher layer it was copied from
																						__a:    Union[str, Any]		     =       self.e_layer_ids
																						__a:    Union[str, Any]		     =       self.d_layer_ids
												else:
																	__a:    Any		     =       None
																	__a:    List[Any]		     =       None

												__a:    List[Any]		     =       nn.KLDivLoss(reduction="""batchmean"""     )
												__a:    Optional[Any]		     =       2.0
												__a:    Dict		     =       hparams.alpha_mlm
												__a:    List[str]		     =       hparams.alpha_ce
												__a:    str		     =       hparams.alpha_hid
												gc.collect()
												torch.cuda.empty_cache()






							def 				__lowercase	(       self    :      List[str]    ,			snake_case__    :      Any    ,			snake_case__    :      Optional[Any]    ,			snake_case__    :      Union[str, Any]     ):






												"""simple docstring"""



												__a:    Dict		     =       mask[:, :, None].expand_as(__UpperCamelCase     )
												__a:    Tuple		     =       s_logits.size(-1     )
												__a:    List[Any]		     =       torch.masked_select(__UpperCamelCase    ,			__UpperCamelCase     )  # (bs * seq_length * voc_size) modulo the 1s in mask
												__a:    Dict		     =       torch.masked_select(__UpperCamelCase    ,			__UpperCamelCase     )  # (bs * seq_length * voc_size) modulo the 1s in mask
												__a:    Any		     =       s_logits_slct.view(-1    ,			__UpperCamelCase     )  # (bs * seq_length, voc_size) modulo the 1s in mask
												__a:    Any		     =       t_logits_slct.view(-1    ,			__UpperCamelCase     )  # (bs * seq_length, voc_size) modulo the 1s in mask
												assert t_logits_slct.size() == s_logits_slct.size()
												__a:    List[str]		     =       (
												    self.ce_loss_fct(
												        nn.functional.log_softmax(s_logits_slct / self.temperature    ,			dim=-1     )    ,			nn.functional.softmax(t_logits_slct / self.temperature    ,			dim=-1     )    ,			)
												    * (self.temperature) ** 2
												)
												return loss_ce






							@staticmethod
							def 				__lowercase	(       snake_case__    :      str    ,			snake_case__    :      List[str]     ):






												"""simple docstring"""



												SummarizationModule.add_model_specific_args(__UpperCamelCase    ,			__UpperCamelCase     )
												add_distill_args(__UpperCamelCase     )
												return parser






							def 				__lowercase	(       self    :      List[Any]    ,			snake_case__    :      dict     ):






												"""simple docstring"""



												__a:    Optional[Any]		     =       self.tokenizer.pad_token_id
												__a:    List[Any]		     =       batch['''input_ids'''], batch['''attention_mask'''], batch['''labels''']
												if isinstance(self.model    ,			__UpperCamelCase     ):
																	__a:    str		     =       self.model._shift_right(__UpperCamelCase     )
												else:
																	__a:    Optional[Any]		     =       shift_tokens_right(__UpperCamelCase    ,			__UpperCamelCase     )

												# noinspection PyCallingNonCallable
												__a:    Optional[Any]		     =       self(
												    __UpperCamelCase    ,			attention_mask=__UpperCamelCase    ,			decoder_input_ids=__UpperCamelCase    ,			output_hidden_states=self.do_calc_hidden_loss    ,			output_attentions=__UpperCamelCase    ,			use_cache=__UpperCamelCase    ,			)
												__a:    List[str]		     =       student_outputs['''logits''']

												# Same cross entropy vs. label smoothing logic as finetune.py
												assert lm_logits.shape[-1] == self.model.config.vocab_size
												if self.hparams.label_smoothing == 0:
																	# Same behavior as modeling_bart.py, besides ignoring pad_token_id
																	__a:    Any		     =       nn.CrossEntropyLoss(ignore_index=__UpperCamelCase     )
																	__a:    List[str]		     =       loss_fct(lm_logits.view(-1    ,			lm_logits.shape[-1]     )    ,			labels.view(-1     )     )
												else:
																	__a:    Tuple		     =       nn.functional.log_softmax(__UpperCamelCase    ,			dim=-1     )
																	__a:    int		     =       label_smoothed_nll_loss(
																	    __UpperCamelCase    ,			__UpperCamelCase    ,			self.hparams.label_smoothing    ,			ignore_index=__UpperCamelCase     )

												def zero_tensor():
																	return torch.tensor(0.0     ).type_as(__UpperCamelCase     )

												__a:    int		     =       student_outputs[
												    '''encoder_last_hidden_state'''
												]  # use this unless self.different_base_models
												__a:    Dict		     =       zero_tensor(), zero_tensor()
												if self.different_encoder:  # compute encoder hidden state loss
																	__a:    str		     =       self.teacher.get_encoder()(
																	    __UpperCamelCase    ,			attention_mask=__UpperCamelCase    ,			output_hidden_states=self.do_calc_hidden_loss    ,			)
																	if self.different_base_models:
																						__a:    List[str]		     =       all_teacher_encoder_outputs['''last_hidden_state''']
																	elif self.do_calc_hidden_loss:
																						__a:    str		     =       self.calc_hidden_loss(
																						    __UpperCamelCase    ,			student_outputs["""encoder_hidden_states"""]    ,			all_teacher_encoder_outputs["""hidden_states"""]    ,			self.e_matches    ,			normalize_hidden=self.hparams.normalize_hidden    ,			)

												__a:    Union[str, Any]		     =       self.teacher(
												    __UpperCamelCase    ,			attention_mask=__UpperCamelCase    ,			encoder_outputs=(teacher_enc_outputs,)    ,			decoder_input_ids=__UpperCamelCase    ,			output_hidden_states=self.do_calc_hidden_loss    ,			use_cache=__UpperCamelCase    ,			)
												__a:    int		     =       decoder_input_ids.ne(__UpperCamelCase     )
												__a:    Optional[Any]		     =       self.calc_ce_loss(__UpperCamelCase    ,			__UpperCamelCase    ,			teacher_outputs["""logits"""]     )
												if self.do_calc_hidden_loss:  # Intermediate supervision of decoder hidden states
																	__a:    List[Any]		     =       self.calc_hidden_loss(
																	    __UpperCamelCase    ,			student_outputs["""decoder_hidden_states"""]    ,			teacher_outputs["""decoder_hidden_states"""]    ,			self.d_matches    ,			normalize_hidden=self.hparams.normalize_hidden    ,			)

												__a:    List[str]		     =       (
												    self.alpha_ce * loss_ce
												    + self.alpha_mlm * student_lm_loss
												    + self.hparams.alpha_hid * (hid_loss_enc + hid_loss_dec)
												)
												return blended_loss, loss_ce, student_lm_loss, hid_loss_enc, hid_loss_dec






							@staticmethod
							def 				__lowercase	(       snake_case__    :      Union[str, Any]    ,			snake_case__    :      Tuple    ,			snake_case__    :      List[Any]    ,			snake_case__    :      str    ,			snake_case__    :      int     ):






												"""simple docstring"""



												__a:    int		     =       '''expected list or tuple for hidden_states, got tensor of shape: '''
												assert not isinstance(__UpperCamelCase    ,			torch.Tensor     ), f"""{msg}{hidden_states.shape}"""
												assert not isinstance(__UpperCamelCase    ,			torch.Tensor     ), f"""{msg}{hidden_states_T.shape}"""
												__a:    str		     =       attention_mask.to(hidden_states[0]     )
												__a:    Dict		     =       mask.sum() * hidden_states[0].size(-1     )
												__a:    Dict		     =       torch.stack([hidden_states[i] for i in range(len(__UpperCamelCase     )     )]     )
												__a:    Any		     =       torch.stack([hidden_states_T[j] for j in matches]     )
												assert student_states.shape == teacher_states.shape, f"""{student_states.shape} != {teacher_states.shape}"""
												if normalize_hidden:
																	__a:    Optional[Any]		     =       nn.functional.layer_norm(__UpperCamelCase    ,			student_states.shape[1:]     )
																	__a:    Optional[int]		     =       nn.functional.layer_norm(__UpperCamelCase    ,			teacher_states.shape[1:]     )
												__a:    List[str]		     =       nn.functional.mse_loss(__UpperCamelCase    ,			__UpperCamelCase    ,			reduction="""none"""     )
												__a:    int		     =       (mse * mask.unsqueeze(0     ).unsqueeze(-1     )).sum() / valid_count
												return masked_mse






def      lowerCamelCase_     (						lowerCamelCase_			)  ->      Union[str, Any]:


					'''simple docstring'''
					# NOTE: if --student argument was specified and the teacher and student base models
					# are different, the models still have to have the same tokenizer, specified by
					# --tokenizer_name. So, for example, you can distill from t5_large to t5_small but not
					# from bart to t5. This s because if the tokenizers are different, the output space
					# for the two models is also different and their logits are not comparable.
					parser.add_argument("""--teacher"""						,					type=UpperCamelCase__			)
					parser.add_argument("""--alpha_ce"""						,					default=0.8						,					type=UpperCamelCase__			)
					parser.add_argument("""--alpha_mlm"""						,					default=0.2						,					type=UpperCamelCase__			)
					parser.add_argument("""--alpha_hid"""						,					default=0.0						,					type=UpperCamelCase__						,					required=UpperCamelCase__			)
					parser.add_argument("""--student"""						,					type=UpperCamelCase__						,					required=UpperCamelCase__			)
					parser.add_argument("""--student_decoder_layers"""						,					default=12						,					type=UpperCamelCase__						,					required=UpperCamelCase__			)
					parser.add_argument("""--student_encoder_layers"""						,					default=12						,					type=UpperCamelCase__						,					required=UpperCamelCase__			)
					parser.add_argument("""--no_teacher"""						,					action="""store_true"""						,					default=UpperCamelCase__			)
					parser.add_argument("""--length_penalty"""						,					type=UpperCamelCase__						,					default=-1			)
					parser.add_argument("""--supervise_forward"""						,					action="""store_true"""						,					default=UpperCamelCase__			)
					parser.add_argument("""--normalize_hidden"""						,					action="""store_true"""						,					default=UpperCamelCase__			)




class  _snake_case	(    lowercase__							):
							SCREAMING_SNAKE_CASE		  =    '''translation'''
							SCREAMING_SNAKE_CASE		  =    ['''bleu''']
							SCREAMING_SNAKE_CASE		  =    '''bleu'''






							def __init__(       self    :      str    ,			snake_case__    :      str    ,			**snake_case__    :      int     ):






												"""simple docstring"""



												super().__init__(__UpperCamelCase    ,			**__UpperCamelCase     )
												assert hparams.src_lang is not None
												assert hparams.tgt_lang is not None
												__a:    List[Any]		     =       hparams.src_lang
												__a:    List[Any]		     =       hparams.tgt_lang
												if self.model.config.decoder_start_token_id is None and isinstance(self.tokenizer    ,			__UpperCamelCase     ):
																	__a:    Dict		     =       self.tokenizer.lang_code_to_id[hparams.tgt_lang]






							def 				__lowercase	(       self    :      str    ,			snake_case__    :      str    ,			snake_case__    :      int     ):






												"""simple docstring"""



												return calculate_bleu(__UpperCamelCase    ,			__UpperCamelCase     )






							@staticmethod
							def 				__lowercase	(       snake_case__    :      Optional[int]    ,			snake_case__    :      str     ):






												"""simple docstring"""



												TranslationModule.add_model_specific_args(__UpperCamelCase    ,			__UpperCamelCase     )
												add_distill_args(__UpperCamelCase     )
												return parser






def      lowerCamelCase_     (						lowerCamelCase_			)  ->      List[Any]:


					'''simple docstring'''
					if args.no_teacher:
										__a:    Optional[Any]		     =       TranslationModule if '''translation''' in args.task else SummarizationModule
					else:  # DISTILL WITH TEACHER
										__a:    Optional[Any]		     =       TranslationDistiller if '''translation''' in args.task else SummarizationDistiller
					__a:    str		     =       module_cls.__name__
					print(f"""using module {args.setup_cls}"""			)
					__a:    Optional[int]		     =       module_cls(UpperCamelCase__			)
					return model


def      lowerCamelCase_     (						lowerCamelCase_			)  ->      Any:


					'''simple docstring'''
					Path(args.output_dir			).mkdir(exist_ok=UpperCamelCase__			)
					check_output_dir(UpperCamelCase__						,					expected_items=3			)

					__a:    Tuple		     =       create_module(UpperCamelCase__			)
					return ft_main(UpperCamelCase__						,					model=UpperCamelCase__			)


if __name__ == "__main__":
			lowercase		:    Any			=       argparse.ArgumentParser()
			lowercase		:    Any			=       pl.Trainer.add_argparse_args(parser)
			lowercase		:    Dict			=       SummarizationDistiller.add_model_specific_args(parser, os.getcwd())
			lowercase		:    str			=       parser.parse_args()

			distill_main(args)





'''simple docstring'''



import os
import pathlib
import tempfile
import uuid

import numpy as np

from ..utils import is_soundfile_availble, is_torch_available, is_vision_available, logging


_lowercase       :						Dict						=logging.get_logger(__name__)

if is_vision_available():
				import PIL.Image
				from PIL import Image
				from PIL.Image import Image as ImageType
else:
				_lowercase       :						List[Any]						=object

if is_torch_available():
				import torch

if is_soundfile_availble():
				import soundfile as sf






class 			_SCREAMING_SNAKE_CASE				:



			def __init__(     self		:						List[str]    ,			__UpperCamelCase		:						Optional[int]			)      ->      List[str]:
							"""simple docstring"""





							snake_case__      :   int      =    value



			def __str__(     self		:						int			)      ->      str:
							"""simple docstring"""





							return self.to_string()



			def 				lowerCAmelCase (     self		:						List[Any]			)      ->      List[str]:
							"""simple docstring"""





							logger.error(
							    '''This is a raw AgentType of unknown type. Display in notebooks and string conversion will be unreliable'''			)
							return self._value







			def 				lowerCAmelCase (     self		:						Optional[Any]			)      ->      str:
							"""simple docstring"""





							logger.error(
							    '''This is a raw AgentType of unknown type. Display in notebooks and string conversion will be unreliable'''			)
							return str(self._value			)






class 			_SCREAMING_SNAKE_CASE				(lowercase__,	lowercase__      ):



			def 				lowerCAmelCase (     self		:						str			)      ->      Tuple:
							"""simple docstring"""





							return self._value







			def 				lowerCAmelCase (     self		:						Optional[int]			)      ->      Union[str, Any]:
							"""simple docstring"""





							return self._value






class 			_SCREAMING_SNAKE_CASE				(lowercase__,	lowercase__      ):



			def __init__(     self		:						str    ,			__UpperCamelCase		:						List[Any]			)      ->      Dict:
							"""simple docstring"""





							super().__init__(__UpperCamelCase			)

							if not is_vision_available():
											raise ImportError('''PIL must be installed in order to handle images.'''			)

							snake_case__      :   str      =    None
							snake_case__      :   List[Any]      =    None
							snake_case__      :   Tuple      =    None

							if isinstance(__UpperCamelCase    ,			__UpperCamelCase			):
											snake_case__      :   List[Any]      =    value
							elif isinstance(__UpperCamelCase    ,			(str, pathlib.Path)			):
											snake_case__      :   int      =    value
							elif isinstance(__UpperCamelCase    ,			torch.Tensor			):
											snake_case__      :   Union[str, Any]      =    value
							else:
											raise ValueError(F'''Unsupported type for {self.__class__.__name__}: {type(__UpperCamelCase			)}'''			)



			def 				lowerCAmelCase (     self		:						str    ,			__UpperCamelCase		:						Dict=None    ,			__UpperCamelCase		:						Any=None			)      ->      List[Any]:
							"""simple docstring"""





							from IPython.display import Image, display

							display(Image(self.to_string()			)			)



			def 				lowerCAmelCase (     self		:						List[str]			)      ->      str:
							"""simple docstring"""





							if self._raw is not None:
											return self._raw

							if self._path is not None:
											snake_case__      :   str      =    Image.open(self._path			)
											return self._raw







			def 				lowerCAmelCase (     self		:						Dict			)      ->      Optional[Any]:
							"""simple docstring"""





							if self._path is not None:
											return self._path

							if self._raw is not None:
											snake_case__      :   Any      =    tempfile.mkdtemp()
											snake_case__      :   Dict      =    os.path.join(__UpperCamelCase    ,			str(uuid.uuida()			) + '''.png'''			)
											self._raw.save(self._path			)

											return self._path

							if self._tensor is not None:
											snake_case__      :   List[str]      =    self._tensor.cpu().detach().numpy()

											# There is likely simpler than load into image into save
											snake_case__      :   List[Any]      =    Image.fromarray((array * 255).astype(np.uinta			)			)

											snake_case__      :   str      =    tempfile.mkdtemp()
											snake_case__      :   Dict      =    os.path.join(__UpperCamelCase    ,			str(uuid.uuida()			) + '''.png'''			)

											img.save(self._path			)

											return self._path






class 			_SCREAMING_SNAKE_CASE				(lowercase__      ):



			def __init__(     self		:						Optional[Any]    ,			__UpperCamelCase		:						List[Any]    ,			__UpperCamelCase		:						str=16000			)      ->      Union[str, Any]:
							"""simple docstring"""





							super().__init__(__UpperCamelCase			)

							if not is_soundfile_availble():
											raise ImportError('''soundfile must be installed in order to handle audio.'''			)

							snake_case__      :   List[str]      =    None
							snake_case__      :   Optional[int]      =    None

							snake_case__      :   Any      =    samplerate

							if isinstance(__UpperCamelCase    ,			(str, pathlib.Path)			):
											snake_case__      :   int      =    value
							elif isinstance(__UpperCamelCase    ,			torch.Tensor			):
											snake_case__      :   int      =    value
							else:
											raise ValueError(F'''Unsupported audio type: {type(__UpperCamelCase			)}'''			)



			def 				lowerCAmelCase (     self		:						Tuple    ,			__UpperCamelCase		:						List[Any]=None    ,			__UpperCamelCase		:						Optional[Any]=None			)      ->      Any:
							"""simple docstring"""





							from IPython.display import Audio, display

							display(Audio(self.to_string()    ,			rate=self.samplerate			)			)



			def 				lowerCAmelCase (     self		:						Union[str, Any]			)      ->      Union[str, Any]:
							"""simple docstring"""





							if self._tensor is not None:
											return self._tensor

							if self._path is not None:
											snake_case__  ,      snake_case__      :   Tuple      =    sf.read(self._path			)
											snake_case__      :   Tuple      =    torch.tensor(__UpperCamelCase			)
											return self._tensor







			def 				lowerCAmelCase (     self		:						Any			)      ->      Dict:
							"""simple docstring"""





							if self._path is not None:
											return self._path

							if self._tensor is not None:
											snake_case__      :   Tuple      =    tempfile.mkdtemp()
											snake_case__      :   int      =    os.path.join(__UpperCamelCase    ,			str(uuid.uuida()			) + '''.wav'''			)
											sf.write(self._path    ,			self._tensor    ,			samplerate=self.samplerate			)
											return self._path



_lowercase       :						Union[str, Any]						={"text": AgentText, "image": AgentImage, "audio": AgentAudio}
_lowercase       :						List[Any]						={str: AgentText}

if is_vision_available():
				_lowercase       :						Optional[Any]						=AgentImage


def 							__UpperCAmelCase				(				*UpperCamelCase__				:Optional[int]   ,				**UpperCamelCase__				:List[Any]			)		->						Optional[Any]:
				snake_case__      :   List[str]      =    [(arg.to_raw() if isinstance(UpperCamelCase__   ,				UpperCamelCase__			) else arg) for arg in args]
				snake_case__      :   Any      =    {k: (v.to_raw() if isinstance(UpperCamelCase__   ,				UpperCamelCase__			) else v) for k, v in kwargs.items()}
				return args, kwargs



def 							__UpperCAmelCase				(				UpperCamelCase__				:Optional[Any]   ,				UpperCamelCase__				:Tuple=None			)		->						Dict:
				if isinstance(UpperCamelCase__   ,				UpperCamelCase__			):
								snake_case__      :   Any      =    {}
								for i, (k, v) in enumerate(outputs.items()			):
												if output_types is not None:
																# If the class has defined outputs, we can map directly according to the class definition
																if output_types[i] in AGENT_TYPE_MAPPING:
																				snake_case__      :   List[Any]      =    AGENT_TYPE_MAPPING[output_types[i]](UpperCamelCase__			)
																else:
																				snake_case__      :   Optional[int]      =    AgentType(UpperCamelCase__			)

												else:
																# If the class does not have defined output, then we map according to the type
																for _k, _v in INSTANCE_TYPE_MAPPING.items():
																				if isinstance(UpperCamelCase__   ,				_k			):
																								snake_case__      :   str      =    _v(UpperCamelCase__			)
																if k not in decoded_outputs:
																				snake_case__      :   Any      =    AgentType[v]

				elif isinstance(UpperCamelCase__   ,				(list, tuple)			):
								snake_case__      :   List[str]      =    type(UpperCamelCase__			)()
								for i, v in enumerate(UpperCamelCase__			):
												if output_types is not None:
																# If the class has defined outputs, we can map directly according to the class definition
																if output_types[i] in AGENT_TYPE_MAPPING:
																				decoded_outputs.append(AGENT_TYPE_MAPPING[output_types[i]](UpperCamelCase__			)			)
																else:
																				decoded_outputs.append(AgentType(UpperCamelCase__			)			)
												else:
																# If the class does not have defined output, then we map according to the type
																snake_case__      :   Any      =    False
																for _k, _v in INSTANCE_TYPE_MAPPING.items():
																				if isinstance(UpperCamelCase__   ,				_k			):
																								decoded_outputs.append(_v(UpperCamelCase__			)			)
																								snake_case__      :   str      =    True

																if not found:
																				decoded_outputs.append(AgentType(UpperCamelCase__			)			)

				else:
								if output_types[0] in AGENT_TYPE_MAPPING:
												# If the class has defined outputs, we can map directly according to the class definition
												snake_case__      :   Tuple      =    AGENT_TYPE_MAPPING[output_types[0]](UpperCamelCase__			)

								else:
												# If the class does not have defined output, then we map according to the type
												for _k, _v in INSTANCE_TYPE_MAPPING.items():
																if isinstance(UpperCamelCase__   ,				_k			):
																				return _v(UpperCamelCase__			)
												return AgentType(UpperCamelCase__			)

				return decoded_outputs




