## Использование пользовательских блоков с Mellon

[Mellon](https://github.com/cubiq/Mellon) — это визуальный интерфейс для создания рабочих процессов, интегрированный с Modular Diffusers и предназначенный для работы на основе узлов.

> [!WARNING]
> Mellon находится на ранней стадии разработки и пока не готов к использованию в продакшене. Рассматривайте это как предварительный обзор того, как работает интеграция!

Пользовательские блоки работают в Mellon «из коробки» — достаточно добавить в ваш репозиторий файл `mellon_pipeline_config.json`. Этот конфигурационный файл указывает Mellon, как отображать параметры вашего блока в виде компонентов пользовательского интерфейса.

Вот как это выглядит в действии с блоком [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)

Чтобы использовать модульный кастомный блок diffusers в Mellon:
1. Перетащите **Dynamic Block Node** из раздела ModularDiffusers
2. Введите `repo_id` (например, `diffusers/gemini-prompt-expander-mellon`)
3. Нажмите **Load Custom Block**
4. Узел трансформируется, чтобы показать входные и выходные данные вашего блока

Теперь разберём, как создать такую конфигурацию для собственного пользовательского блока.

## Шаги для создания конфигурации Mellon

1. **Укажите типы Mellon для ваших параметров** - Для каждого `InputParam`/`OutputParam` требуется тип, который сообщает Mellon, какой компонент интерфейса нужно отобразить (например, `"textbox"`, `"dropdown"`, `"image"`).
2. **Создание `mellon_pipeline_config.json`** — используйте нашу утилиту для создания шаблона конфигурации и загрузки его в ваш репозиторий на Hub.
3. **(Необязательно) Ручная настройка конфигурации** — Отрегулируйте сгенерированную конфигурацию под ваши конкретные задачи.

## Укажите типы Mellon для параметров

Типы Mellon определяют, как каждый параметр отображается в интерфейсе. Если вы не укажете тип для параметра, по умолчанию будет использован `"custom"`, который отображается как простая точка соединения. Вы всегда можете изменить это позже в сгенерированной конфигурации.

| Тип | Вход/выход | Описание |
|------|--------------|-------------|
| `image` | Оба | Изображение (PIL Image) |
| `video` | Оба | Видео |
| `text` | Оба | Отображение текста |
| `textbox` | Вход | Ввод текста |
| `dropdown` | Вход | Меню выпадающего списка |
| `slider` | Вход | Слайдер для числовых значений |
| `number` | Вход | Числовой ввод |
| `checkbox` | Вход | Переключатель типа Boolean |

Для параметров, требующих более сложной настройки (например, выпадающих списков с вариантами или ползунков с минимальным и максимальным значениями), передавайте экземпляр `MellonParam` напрямую, а не строку. Вы можете использовать один из методов класса, приведённых ниже, или создать полностью настраиваемый параметр с помощью `MellonParam(name, label, type, ...)`.

| Метод | Описание |
|--------|-------------|
| `MellonParam.Input.image(name)` | Входные данные изображения |
| `MellonParam.Input.textbox(name, default)` | Ввод текста в textarea |
| `MellonParam.Input.dropdown(name, options, default)` | Выбор из выпадающего списка |
| `MellonParam.Input.slider(name, default, min, max, step)` | Слайдер для числовых значений |
| `MellonParam.Input.number(name, default, min, max, step)` | Числовой ввод (без ползунка) |
| `MellonParam.Input.seed(name, default)` | Ввод начального значения с кнопкой случайной генерации |
| `MellonParam.Input.checkbox(name, default)` | Логический флажок |
| `MellonParam.Input.model(name)` | Входные данные модели для компонентов diffusers |
| `MellonParam.Output.image(name)` | Вывод изображения |
| `MellonParam.Output.video(name)` | Видеовыход |
| `MellonParam.Output.text(name)` | Вывод текста |
| `MellonParam.Output.model(name)` | Вывод модели для компонентов diffusers |

Выберите один из методов ниже, чтобы указать тип Mellon.

### Использование `metadata` в определениях блоков

Если вы создаёте собственный блок с нуля, добавьте `metadata={"mellon": "<type>"}` непосредственно в определения `InputParam` и `OutputParam`. Если вы редактируете существующий собственный блок из Hub, см. [Редактирование собственных блоков](./custom_blocks#editing-custom-blocks), чтобы узнать, как скачать его локально.

```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
            )
        ]
```

Для полного контроля над конфигурацией UI передайте экземпляр `MellonParam` напрямую:
```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"])},
)
```

### Использование `input_types` и `output_types` при генерации конфигурации

Если вы работаете с существующим конвейером или предпочитаете сохранять определения блоков чистыми, укажите типы при генерации конфигурации с помощью аргумента `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]
> Если указаны и `metadata`, и `input_types`/`output_types`, аргументы переопределяют `metadata`.

## Сгенерировать и отправить конфигурацию Mellon

После добавления метаданных в ваш блок сгенерируйте шаблон конфигурации Mellon по умолчанию и отправьте его в 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
)
```

Это создаёт файл `mellon_pipeline_config.json` в вашем репозитории.

## Проверьте и откорректируйте конфигурацию

Сгенерированный шаблон является отправной точкой — при необходимости вы можете скорректировать его под свои задачи. Разберём сгенерированную конфигурацию для 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"
    }
  }
}
```

### Понимание структуры

Словарь `params` определяет, как каждый элемент интерфейса отображается. Списки `input_names`, `model_input_names` и `output_names` сопоставляют эти элементы интерфейса с интерфейсом ввода/вывода базовых блоков [ModularPipelineBlocks](/docs/diffusers/v0.43.0/ru/api/modular_diffusers/pipeline_blocks#diffusers.ModularPipelineBlocks):

| Конфигурация Mellon | ModularPipelineBlocks |
|---------------|----------------------|
| `input_names` | свойство `inputs` |
| `model_input_names` | свойство `expected_components` |
| `output_names` | свойство `intermediate_outputs` |

В этом примере: `prompt` — единственный вход. Компоненты модели отсутствуют, а выходные данные включают `out_prompt`, `old_prompt` и `doc`.

Теперь рассмотрим словарь `params`:

- **`prompt`**: входной параметр с `display: "textarea"` (отображается как текстовое поле), `label: "Prompt"` (показывается в интерфейсе) и `default: ""` (начинается пустым). Поле `type: "string"` важно в Mellon, поскольку оно определяет, какие узлы можно соединять между собой — «нудлами» можно связывать только узлы с совпадающими типами.

- **`out_prompt`**: Развёрнутый вывод промпта. Префикс `out_` был добавлен автоматически, так как вход и выход имеют одинаковое имя (`prompt`), что позволяет избежать конфликтов имён в конфигурации. У него указано `display: "output"`, что отображается как выходной сокет.

- **`old_prompt`**: имеет `type: "custom"`, так как мы не указали метаданные. В интерфейсе это отображается как простая точка. Поскольку мы не хотим выставлять это в интерфейсе, мы можем удалить его.

- **`doc`**: Вывод документации, автоматически добавляемый во все пользовательские блоки.

### Внесение изменений

Уберите `old_prompt` из `params` и `output_names`, так как он больше не понадобится.

```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"
    }
  }
}
```

См. итоговую конфигурацию в [diffusers/gemini-prompt-expander-mellon](https://huggingface.co/diffusers/gemini-prompt-expander-mellon).

