## Usando Blocos Personalizados com Mellon

[Mellon](https://github.com/cubiq/Mellon) é uma interface de fluxo de trabalho visual que se integra ao Modular Diffusers e foi projetada para fluxos de trabalho baseados em nós.

> [!WARNING]
> Mellon está em desenvolvimento inicial e ainda não está pronto para uso em produção. Considere isso um vislumbre de como a integração funciona!

Blocos personalizados funcionam no Mellon sem necessidade de configuração adicional - basta adicionar um `mellon_pipeline_config.json` ao seu repositório. Este arquivo de configuração informa ao Mellon como renderizar os parâmetros do seu bloco como componentes de interface.

É assim que ele aparece em ação com o bloco [Gemini Prompt Expander](https://huggingface.co/diffusers/gemini-prompt-expander-mellon):

![Mellon custom block demo](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/modular_demo_dynamic.gif)

Para usar um bloco personalizado modular de diffusers no Mellon:
1. Arraste um **Dynamic Block Node** da seção ModularDiffusers
2. Insira o `repo_id` (por exemplo, `diffusers/gemini-prompt-expander-mellon`)
3. Clique em **Carregar Bloco Personalizado**
4. O nó se transforma para mostrar as entradas e saídas do seu bloco

Agora, vamos ver como criar essa configuração para o seu próprio bloco personalizado.

## Etapas para criar uma configuração do Mellon

1. **Especifique os tipos Mellon para seus parâmetros** - Cada `InputParam`/`OutputParam` precisa de um tipo que informe ao Mellon qual componente de interface a renderizar (por exemplo, `"textbox"`, `"dropdown"`, `"image"`).
2. **Gerar `mellon_pipeline_config.json`** - Use nossa utilidade para gerar um modelo de configuração e enviá-lo para seu repositório no Hub.
3. **(Opcional) Ajustar manualmente a configuração** - Ajuste fino da configuração gerada para suas necessidades específicas.

## Especifique os tipos Mellon para os parâmetros

Os tipos Mellon determinam como cada parâmetro é renderizado na interface. Se você não especificar um tipo para um parâmetro, ele usará o padrão `"custom"`, que é renderizado como um ponto de conexão simples. Você pode ajustar isso a qualquer momento na configuração gerada.

| Tipo | Entrada/Saída | Descrição |
|------|--------------|-------------|
| `image` | Ambos | Imagem (PIL Image) |
| `video` | Ambos | Vídeo |
| `text` | Ambos | Exibição de texto |
| `textbox` | Entrada | Entrada de texto |
| `dropdown` | Entrada | Menu de seleção em lista suspensa |
| `slider` | Entrada | Slider para valores numéricos |
| `number` | Entrada | Entrada numérica |
| `checkbox` | Entrada | Alternância booleana |

Para parâmetros que exigem mais configuração (como menus suspensos com opções ou controles deslizantes com valores mín/máx), passe uma instância de `MellonParam` diretamente em vez de uma string. Você pode usar um dos métodos de classe abaixo ou criar um totalmente personalizado com `MellonParam(name, label, type, ...)`.

| Método | Descrição |
|--------|-------------|
| `MellonParam.Input.image(name)` | Entrada de imagem |
| `MellonParam.Input.textbox(name, default)` | Entrada de texto como textarea |
| `MellonParam.Input.dropdown(name, options, default)` | Seleção em menu suspenso |
| `MellonParam.Input.slider(name, default, min, max, step)` | Slider para valores numéricos |
| `MellonParam.Input.number(name, default, min, max, step)` | Entrada numérica (sem controle deslizante) |
| `MellonParam.Input.seed(name, default)` | Entrada de semente com botão de aleatorização |
| `MellonParam.Input.checkbox(name, default)` | Caixa de seleção booleana |
| `MellonParam.Input.model(name)` | Entrada do modelo para componentes do diffusers |
| `MellonParam.Output.image(name)` | Saída de imagem |
| `MellonParam.Output.video(name)` | Saída de vídeo |
| `MellonParam.Output.text(name)` | Saída de texto |
| `MellonParam.Output.model(name)` | Saída do modelo para componentes do diffusers |

Escolha um dos métodos abaixo para especificar um tipo Mellon.

### Usando `metadata` em definições de bloco

Se você está definindo um bloco personalizado do zero, adicione `metadata={"mellon": "<type>"}` diretamente às suas definições de `InputParam` e `OutputParam`. Se você está editando um bloco personalizado existente do Hub, consulte [Editando blocos personalizados](./custom_blocks#editing-custom-blocks) para saber como baixá-lo localmente.

```python
class GeminiPromptExpander(ModularPipelineBlocks):
    
    @property
    def inputs(self) -> List[InputParam]:
        return [
            InputParam(
                "prompt",
                type_hint=str,
                required=True,
                description="Prompt to use",
                metadata={"mellon": "textbox"},  # Text input
            )
        ]
    
    @property
    def intermediate_outputs(self) -> List[OutputParam]:
        return [
            OutputParam(
                "prompt",
                type_hint=str,
                description="Expanded prompt by the LLM",
                metadata={"mellon": "text"},  # Text output
            ),
            OutputParam(
                "old_prompt",
                type_hint=str,
                description="Old prompt provided by the user",
<CopyLLMTxtMenu containerStyle="float: inline-end; margin-inline-start: 10px; display: inline-flex; position: relative; z-index: 10;"></CopyLLMTxtMenu>

                # No metadata - we don't want to render this in UI
            )
        ]
```

Para ter controle total sobre a configuração da interface, passe uma instância de `MellonParam` diretamente:
```python
from diffusers.modular_pipelines.mellon_node_utils import MellonParam

InputParam(
    "mode",
    type_hint=str,
    default="balanced",
    metadata={"mellon": MellonParam.Input.dropdown("mode", options=["fast", "balanced", "quality"])},
)
```

### Usando `input_types` e `output_types` ao gerar a configuração

Se você está trabalhando com um pipeline existente ou prefere manter as definições de seus blocos limpas, especifique os tipos ao gerar a configuração usando o argumento `input_types/output_types`:
```python
from diffusers.modular_pipelines.mellon_node_utils import MellonPipelineConfig

mellon_config = MellonPipelineConfig.from_custom_block(
    blocks,
    input_types={"prompt": "textbox"},
    output_types={"prompt": "text"}
)
```

> [!NOTE]
> Quando `metadata` e `input_types`/`output_types` são especificados, os argumentos substituem `metadata`.

## Gere e envie a configuração do Mellon

Depois de adicionar metadados ao seu bloco, gere o modelo de configuração padrão do Mellon e envie-o para o Hub:

```python
from diffusers import ModularPipelineBlocks
from diffusers.modular_pipelines.mellon_node_utils import MellonPipelineConfig

# load your custom blocks from your local dir
blocks = ModularPipelineBlocks.from_pretrained("/path/local/folder", trust_remote_code=True)

# Generate the default config template
mellon_config = MellonPipelineConfig.from_custom_block(blocks)
# push the default template to `repo_id`, you will need to pass the same local folder path so that it will save the config locally first
mellon_config.save(
    local_dir="/path/local/folder",
    repo_id= repo_id,
    push_to_hub=True
)
```

Isso cria um arquivo `mellon_pipeline_config.json` no seu repositório.

## Revise e ajuste a configuração

O template gerado é um ponto de partida - você pode querer ajustá-lo para suas necessidades. Vamos analisar a configuração gerada para o Gemini Prompt Expander:

```json
{
  "label": "Gemini Prompt Expander",
  "default_repo": "",
  "default_dtype": "",
  "node_params": {
    "custom": {
      "params": {
        "prompt": {
          "label": "Prompt",
          "type": "string",
          "display": "textarea",
          "default": ""
        },
        "out_prompt": {
          "label": "Prompt",
          "type": "string",
          "display": "output"
        },
        "old_prompt": {
          "label": "Old Prompt",
          "type": "custom",
          "display": "output"
        },
        "doc": {
          "label": "Doc",
          "type": "string",
          "display": "output"
        }
      },
      "input_names": ["prompt"],
      "model_input_names": [],
      "output_names": ["out_prompt", "old_prompt", "doc"],
      "block_name": "custom",
      "node_type": "custom"
    }
  }
}
```

### Compreendendo a Estrutura

O dicionário `params` define como cada elemento de interface é renderizado. As listas `input_names`, `model_input_names` e `output_names` mapeiam esses elementos de interface para a interface de entrada/saída dos [ModularPipelineBlocks](/docs/diffusers/v0.43.0/pt/api/modular_diffusers/pipeline_blocks#diffusers.ModularPipelineBlocks) subjacentes:

| Configuração do Mellon | ModularPipelineBlocks |
|---------------|----------------------|
| `input_names` | propriedade `inputs` |
| `model_input_names` | propriedade `expected_components` |
| `output_names` | propriedade `intermediate_outputs` |

Neste exemplo: `prompt` é a única entrada. Não há componentes de modelo, e as saídas incluem `out_prompt`, `old_prompt` e `doc`.

Agora, vamos examinar o dicionário `params`:

- **`prompt`**: Um parâmetro de entrada com `display: "textarea"` (renderizado como uma caixa de entrada de texto), `label: "Prompt"` (exibido na interface) e `default: ""` (inicia vazio). O campo `type: "string"` é importante no Mellon porque determina quais nós podem ser conectados entre si - apenas tipos correspondentes podem ser vinculados com "noodles".

- **`out_prompt`**: A saída do prompt expandido. O prefixo `out_` foi adicionado automaticamente porque a entrada e a saída compartilham o mesmo nome (`prompt`), evitando conflitos de nomenclatura na configuração. Ele possui `display: "output"`, o que o renderiza como um soquete de saída.

- **`old_prompt`**: Tem `type: "custom"` porque não especificamos metadados. Isso é renderizado como um ponto simples na interface. Como não queremos realmente expor isso na interface, podemos removê-lo.

- **`doc`**: A saída da documentação, adicionada automaticamente a todos os blocos personalizados.

### Fazendo Ajustes

Remova `old_prompt` de `params` e `output_names`, pois você não precisará usá-lo.

```json
{
  "label": "Gemini Prompt Expander",
  "default_repo": "",
  "default_dtype": "",
  "node_params": {
    "custom": {
      "params": {
        "prompt": {
          "label": "Prompt",
          "type": "string",
          "display": "textarea",
          "default": ""
        },
        "out_prompt": {
          "label": "Prompt",
          "type": "string",
          "display": "output"
        },
        "doc": {
          "label": "Doc",
          "type": "string",
          "display": "output"
        }
      },
      "input_names": ["prompt"],
      "model_input_names": [],
      "output_names": ["out_prompt", "doc"],
      "block_name": "custom",
      "node_type": "custom"
    }
  }
}
```

Veja a configuração final em [diffusers/gemini-prompt-expander-mellon](https://huggingface.co/diffusers/gemini-prompt-expander-mellon).

