diff --git a/README.md b/README.md index 7700322..b7bc836 100644 --- a/README.md +++ b/README.md @@ -102,28 +102,43 @@ npx n8n start ### Chat → Message a Model -Отправляет `POST /v1/chat/completions` и возвращает JSON-ответ как есть. +Отправляет `POST /v1/chat/completions`. Принимает текст и/или картинки, возвращает ответ модели. | Поле | Описание | | --- | --- | | **Model** | список читается из `GET /v1/models` (только текстовые модели; картинные скрыты) | -| **Prompt** | сообщение пользователя | +| **Prompt** | сообщение пользователя. Можно оставить пустым, если приложены картинки | +| **Input Images** | сколько угодно картинок, каждая — Binary File (из предыдущего узла) или Image URL | | **Options → System Prompt** | системная инструкция | | **Options →** остальное | temperature, topP, max tokens, JSON-ответ, Service Tier Fast, Extra Body, Timeout | +| **Chat Reply** | включите, если узел стоит последним после Chat Trigger — ответ уйдёт прямо в чат | -Текст ответа доступен как `{{ $json.choices[0].message.content }}`, расход токенов — `{{ $json.usage }}`. +Результат: `{{ $json.text }}` — текст ответа, `{{ $json.usage }}` — токены, `{{ $json.model }}`, `{{ $json.finishReason }}`. Если мультимодальная модель вернула ещё и картинку, она придёт бинарным полем `data` плюс ссылками в `{{ $json.images }}`. -### Image → Generate an Image +Картинки нужны vision-модели: GPT, Claude, Gemini. Для «что на фото» достаточно **Input Images** и короткого промпта. -Отправляет `POST /v1/images/generations` и кладёт результат **в бинарное поле** (по умолчанию `data`, PNG). +### Image → Generate an Image / Edit an Image + +`POST /v1/images/generations` — генерация по промпту, `POST /v1/images/edits` — правка готовой картинки (уходит multipart-ом вместе с исходником и, при необходимости, маской). | Поле | Описание | | --- | --- | -| **Model** | по умолчанию `gpt-image-2`, список — только картинные модели; можно вписать ID выражением | -| **Prompt** | описание картинки | -| **Put Output File in Field** | имя бинарного свойства | +| **Model** | `gpt-image-2.5-sunburst` для актуальной модели, по умолчанию `gpt-image-2`; можно вписать ID выражением | +| **Prompt** | описание картинки или правки | +| **Input Image (Binary Property)** | только для Edit: бинарное поле с исходной картинкой | +| **Mask (Binary Property)** | только для Edit: маска, прозрачные пиксели которой помечают область правки | +| **Put Output File in Field** | имя бинарного поля с результатом, по умолчанию `data` | +| **Options → Size** | auto, 1024x1024, 1536x1024, 1024x1536, 2048x2048 или своё значение выражением (стороны кратны 16, максимум 3840, соотношение не более 3:1) | +| **Options → Quality** | auto / low / medium / high | +| **Options → Number of Images** | сколько картинок вернуть за один запрос | +| **Options → Output Format / Compression** | png / jpeg / webp и степень сжатия 0–100 | +| **Options → Background** | auto / opaque / transparent (прозрачность — только png и webp) | +| **Options → Input Fidelity / Moderation** | насколько точно следовать исходнику (Edit) / фильтр контента (Generate) | +| **Chat Reply** | ответ для чата: картинка уйдёт в чат как markdown-разметка | -Дальше файл уходит в **Write Binary File**, в Telegram, в S3 и т. д. Долгие генерации узел ждёт до 5 минут. +Каждая сгенерированная картинка — отдельный элемент: бинарное поле `data`, `data1`, `data2`… Дальше файл уходит в **Write Binary File**, в Telegram, в S3 и т. д. + +С включённым **Chat Reply** узел отдаёт один элемент с полем `output`. Chat Trigger (Response Mode → *When Last Node Finishes*) сразу покажет текст или картинку в чате — Code-узел для этого не нужен. Долгие генерации узел ждёт до 5 минут. ### Model → List Models @@ -156,7 +171,7 @@ npm run mock # мок TeamoRouter на http://127.0.0.1:4123/v1 (кл `npm test` запускает два набора: 1. `test/validate-nodes.mjs` — имитирует загрузку пакета n8n: проверяет описание узлов, наличие иконок, реализацию `loadOptionsMethod`, ссылки на credential, тип соединения `ai_languageModel` у саб-узла. -2. `test/run-node-tests.mjs` — поднимает мок роутера (`test/mock-server.mjs`, без зависимостей) и прогоняет скомпилированные узлы с настоящим HTTP и настоящим `@langchain/openai`: список моделей и фильтрация картинных, `supplyData` + реальный вызов модели, проброс опций (`service_tier`, `extra_body`, лимиты), обе операции у обычного узла, генерация изображения в бинарном виде, разбор ошибок 401/402/404, `Continue On Fail` и таймаут. +2. `test/run-node-tests.mjs` — поднимает мок роутера (`test/mock-server.mjs`, без зависимостей) и прогоняет скомпилированные узлы с настоящим HTTP и настоящим `@langchain/openai`: список моделей и фильтрация картинных, `supplyData` + реальный вызов модели, проброс опций (`service_tier`, `extra_body`, лимиты), чат с текстом и картинками (multimodal), правка картинки через multipart, генерация в бинарном виде и в markdown для чата, разбор ошибок 401/402/404, `Continue On Fail` и таймаут. Тесты не требуют ключа TeamoRouter. Модели `fail-401`, `fail-402`, `fail-404`, `fail-500` в моке принудительно отдают ошибку, `slow-model` отвечает через 2,5 с. @@ -164,7 +179,7 @@ npm run mock # мок TeamoRouter на http://127.0.0.1:4123/v1 (кл ## 7. Первый запуск и диагностика -* Пакет собран и проверен автотестами (см. `npm test`), но **в живом n8n ещё не запускался** — первый запуск делайте на тестовом воркфлоу. +* Пакет собран и проверен автотестами (см. `npm test`). Первый запуск всё равно делайте на тестовом воркфлоу. * При установке через `Settings → Community nodes` интерфейс может показать предупреждение о сообщественном узле — это нормально. * Если n8n пишет, что узел не загрузился, проверьте `Help → About` (версия n8n) и логи контейнера: чаще всего причина — недоступная peer-зависимость `n8n-workflow` (Вариант Б, шаг 3). @@ -279,28 +294,43 @@ Useful when the router already serves a new model but the list in the UI has not ### Chat → Message a Model -Sends `POST /v1/chat/completions` and returns the JSON answer as is. +Sends `POST /v1/chat/completions`. Takes text and/or images and returns the model's answer. | Field | Description | | --- | --- | | **Model** | the list is read from `GET /v1/models` (text models only; image models are hidden) | -| **Prompt** | the user message | +| **Prompt** | the user message. May be left empty when images are attached | +| **Input Images** | any number of images, each a Binary File (from an earlier node) or an Image URL | | **Options → System Prompt** | system instruction | | **Options →** the rest | temperature, topP, max tokens, JSON answer, Service Tier Fast, Extra Body, Timeout | +| **Chat Reply** | turn it on when the node is the last one after a Chat Trigger — the answer goes straight to the chat | -The answer text is available as `{{ $json.choices[0].message.content }}`, the token usage as `{{ $json.usage }}`. +The answer text is available as `{{ $json.text }}`, the token usage as `{{ $json.usage }}`, plus `{{ $json.model }}` and `{{ $json.finishReason }}`. If a multimodal model answers with an image too, it arrives as the binary field `data` with the links in `{{ $json.images }}`. -### Image → Generate an Image +Images need a vision model: GPT, Claude or Gemini. For “what is in this picture” the **Input Images** field and a short prompt are enough. -Sends `POST /v1/images/generations` and puts the result into a **binary field** (`data` by default, PNG). +### Image → Generate an Image / Edit an Image + +`POST /v1/images/generations` creates an image from a prompt, `POST /v1/images/edits` changes an existing one (sent as multipart together with the source image and, optionally, a mask). | Field | Description | | --- | --- | -| **Model** | `gpt-image-2` by default; the list contains image models only; the ID can be entered as an expression | -| **Prompt** | description of the image | -| **Put Output File in Field** | name of the binary property | +| **Model** | `gpt-image-2.5-sunburst` for the current model, `gpt-image-2` by default; the ID can be entered as an expression | +| **Prompt** | description of the image, or of the change to apply | +| **Input Image (Binary Property)** | Edit only: the binary field holding the source image | +| **Mask (Binary Property)** | Edit only: a mask whose transparent pixels mark the area to change | +| **Put Output File in Field** | name of the binary property that holds the result, `data` by default | +| **Options → Size** | auto, 1024x1024, 1536x1024, 1024x1536, 2048x2048, or your own value as an expression (sides multiple of 16, at most 3840, aspect ratio at most 3:1) | +| **Options → Quality** | auto / low / medium / high | +| **Options → Number of Images** | how many images to return per request | +| **Options → Output Format / Compression** | png / jpeg / webp and a compression level of 0–100 | +| **Options → Background** | auto / opaque / transparent (transparency needs png or webp) | +| **Options → Input Fidelity / Moderation** | how closely to follow the source (Edit) / the content filter (Generate) | +| **Chat Reply** | chat answer: the image is sent to the chat as markdown | -The file can then go to **Write Binary File**, Telegram, S3, and so on. Long generations are awaited for up to 5 minutes. +Every generated image becomes its own item: the binary field `data`, `data1`, `data2`…, so the file can go to **Write Binary File**, Telegram, S3, and so on. + +With **Chat Reply** turned on the node returns a single item with an `output` field. A Chat Trigger (Response Mode → *When Last Node Finishes*) then shows the text or the image in the chat — no Code node needed. Long generations are awaited for up to 5 minutes. ### Model → List Models @@ -333,7 +363,7 @@ npm run mock # mock TeamoRouter on http://127.0.0.1:4123/v1 (key: test `npm test` runs two suites: 1. `test/validate-nodes.mjs` — imitates n8n loading the package: checks the node descriptions, the presence of the icons, the implementation of every `loadOptionsMethod`, the credential references, and the `ai_languageModel` connection type of the sub-node. -2. `test/run-node-tests.mjs` — starts the mock router (`test/mock-server.mjs`, dependency-free) and drives the compiled nodes with real HTTP and real `@langchain/openai`: the model list and the filtering of image models, `supplyData` plus a real model call, the passing of options (`service_tier`, `extra_body`, limits), both operations of the regular node, image generation into a binary field, the handling of 401/402/404 errors, `Continue On Fail` and the timeout. +2. `test/run-node-tests.mjs` — starts the mock router (`test/mock-server.mjs`, dependency-free) and drives the compiled nodes with real HTTP and real `@langchain/openai`: the model list and the filtering of image models, `supplyData` plus a real model call, the passing of options (`service_tier`, `extra_body`, limits), a chat with text and images (multimodal), an image edit over multipart, generation into a binary field and into markdown for the chat, the handling of 401/402/404 errors, `Continue On Fail` and the timeout. The tests need no TeamoRouter key. The `fail-401`, `fail-402`, `fail-404` and `fail-500` models in the mock return an error on purpose, and `slow-model` answers after 2.5 s. @@ -341,7 +371,7 @@ The tests need no TeamoRouter key. The `fail-401`, `fail-402`, `fail-404` and `f ## 7. First run and troubleshooting -* The package is built and covered by the automated tests (see `npm test`), but it **has not been run inside a live n8n yet** — do the first run on a test workflow. +* The package is built and covered by the automated tests (see `npm test`). Do the first run on a test workflow anyway. * When installing through `Settings → Community nodes`, the UI may show a warning about a community node — that is normal. * If n8n reports that the node failed to load, check `Help → About` (the n8n version) and the container logs: the usual cause is the unreachable `n8n-workflow` peer dependency (Option B, step 3).