# Processadores multimodais

Um processor combina um tokenizer com um ou mais processadores de modalidade, como um processador de imagem, processador de vídeo ou extrator de recursos. Ele expõe um único método `__call__` que encaminha cada entrada para o componente adequado e mescla as saídas em um único dicionário.

Alguns modelos multimodais intercalam texto com imagens, vídeos ou áudio. Para esses modelos, o [ProcessorMixin](/docs/transformers/main/pt/main_classes/processors#transformers.ProcessorMixin) pode substituir tokens de espaço reservado, como `<image>`, `<video>` e `<audio>`, pelo padrão de tokens esperado pelo modelo.

## Adicionando um novo processador

Defina uma classe de processador criando `src/transformers/models/<model>/processing_<my_model_name>.py` e subclasse `ProcessorMixin`. Certifique-se de definir um objeto `TypedDict` com valores padrão e atribuí-lo como `cls.valid_processor_kwargs`

```python
from ...processing_utils import ProcessorMixin, ProcessingKwargs, Unpack

class MyModelProcessorKwargs(ProcessingKwargs, total=False):
    images_kwargs: MyModelImageProcessorKwargs
    _defaults = {
        "text_kwargs": {"padding": True},
        "images_kwargs": {"do_convert_rgb": True},
    }

class MyModelProcessor(ProcessorMixin):
    valid_processor_kwargs = MyModelProcessorKwargs

    def __init__(self, image_processor, tokenizer, chat_template=None, **kwargs):
        self.image_token = tokenizer.image_token
        self.image_token_id = tokenizer.image_token_id
        super().__init__(
            image_processor=image_processor,
            tokenizer=tokenizer,
            chat_template=chat_template,
            **kwargs,
        )
```

Implemente `replace_<modality>_token` se necessário. Ele recebe o dicionário de saída completo do subprocessador e o índice da entrada atual, e retorna a string de substituição expandida para essa entrada. A string de substituição é o que o modelo espera na sequência de entrada.

Se o modelo não usa repetição de placeholders de forma alguma (nenhum `image_token` definido), você não precisa sobrescrever este método. Deixe `self.image_token` não definido e a classe base ignorará a substituição por completo.

```python
def replace_image_token(self, image_inputs: dict, image_idx: int) -> str:
    num_crops = image_inputs["num_crops"][image_idx]
    return f"{self.boi_token}{self.image_token * self.num_image_tokens * num_crops}{self.eoi_token}"
```

Opcionalmente, substitua os métodos `prepare_inputs_layout` e `validate_inputs`. Isso é necessário se o modelo exigir uma estrutura de entrada específica antes do início do processamento, como a reordenação de imagens em uma lista aninhada, ou uma validação específica do modelo além das verificações comuns.

```python
def prepare_inputs_layout(self, images=None, text=None, videos=None, audio=None, **kwargs):
    # Call `super()` to apply common preparation steps first 
    images, text, videos, audio = super().prepare_inputs_layout(images, text, videos, audio)
    if images is not None:
        images = make_nested_list_of_images(images)
    return images, text, videos, audio

def validate_inputs(self, images=None, text=None, videos=None, audio=None, **kwargs):
    super().validate_inputs(images=images, text=text, **kwargs)
    if text is not None and images is not None:
        n_tokens = [s.count(self.image_token) for s in text]
        n_images = [len(img_list) for img_list in images]
        if n_tokens != n_images:
            raise ValueError(
                f"Number of {self.image_token} tokens in text {n_tokens} does not match "
                f"number of images {n_images}."
            )
```

> [!TIP]
> Consulte [Gemma4Processor](/docs/transformers/main/pt/model_doc/gemma4#transformers.Gemma4Processor) e [Qwen2VLProcessor](/docs/transformers/main/pt/model_doc/qwen2_vl#transformers.Qwen2VLProcessor) como referência.

## Testes

Todos os processadores multimodais devem ter uma classe de teste que herda de `ProcessorTesterMixin`. Este mixin fornece um conjunto padrão de testes que cobre tokenização, processamento de imagem, loteamento e codificação de ida e volta.

```python
# tests/models/my_model_name/test_processor_<my_model_name>.py

from transformers.testing_utils import require_vision
from transformers.utils import is_vision_available
from ...test_processing_common import ProcessorTesterMixin

if is_vision_available():
    from transformers import MyModelProcessor

@require_vision
class MyModelProcessorTest(ProcessorTesterMixin, unittest.TestCase):
    processor_class = MyModelProcessor

    def get_processor(self):
        return MyModelProcessor.from_pretrained("hf-internal-testing/my-model-test")
```

