Речь и изображения
Кроме текстовых моделей во Flow есть три ноды, которые работают с файлами: Речь → Текст расшифровывает аудио, Текст → Речь озвучивает текст, Генерация изображения рисует картинку. Все три устроены одинаково: вы выбираете модель из общего медиа-каталога, нода сама находит нужного провайдера, вызывает его и кладёт результат в файловое хранилище воркспейса.
На бесплатном тарифе медиа-ноды доступны, но упираются в две вещи сразу: 100 кредитов в месяц без права уходить в минус (генерация картинок расходует их заметно быстрее текста) и публикация только в веб-чат — телеграм-бот, вебхук и расписание доступны на платном. Актуальные лимиты — на странице Тарифные лимиты.
Каталог медиа-моделей
Медиа-каталог отдельный от каталога текстовых моделей (Каталог моделей) и собирается из живого API вендора, поэтому конкретные модели приходят и уходят между релизами. Сегодня доступно 38 моделей для изображений, 18 для синтеза речи и 4 для распознавания.
Пересчитать по репозиторию:
grep -o "modality: \(image\|tts\|stt\)" backend/config/media/openrouter.yaml | sort | uniq -c
Форма ноды меняется вместе с моделью
Это первое, что удивляет. Собственных полей у медиа-ноды немного, и они одни и те же при любой модели: Модель и необязательный ID подключения со своим ключом есть у всех трёх; у генерации изображения к ним добавляется Промпт, а у изображения и синтеза речи — ещё Режим ноды и настройки работы в роли инструмента агента. Зато всё, что описывает саму картинку или голос — размер, качество, число изображений, голос, формат, — приезжает из выбранной модели: каждая запись каталога несёт собственное описание параметров, и редактор строит форму по нему. Смените модель — часть этих полей исчезнет, часть появится, значения по умолчанию станут другими.
Настройки ноды «Генерация изображения»
Size, Quality и Number of images приходят из выбранной модели
Используется, когда вход 'prompt' не подключён
Пусто — ключ платформы
Так сделано потому, что вендоры не договорились между собой: у одной модели картинки
задаются размером 1024x1024, у другой — соотношением сторон 16:9, у третьей есть
прозрачный фон и уровень сжатия. Держать объединение всех параметров в одной форме
значило бы показывать поля, которые выбранная модель отвергнет ошибкой 400.
Практические следствия:
- Параметры не переносятся между моделями. Ключ, которого нет в схеме новой модели, при запуске молча отбрасывается, а не отправляется провайдеру.
- Список параметров — это то, что вендор про модель сообщил. Он неполон: например, какие именно форматы аудио принимает конкретный синтез речи, discovery не раскрывает, и такие частности приходится править вручную в каталоге платформы.
- Свободные текстовые параметры рендерятся как шаблоны. В подсказку для распознавания
речи можно подставить
{{ variables.glossary }}. Параметры со списком значений (голос, формат, размер) шаблонами не рендерятся: подстановка могла бы только превратить допустимое значение в недопустимое.
Распознавание речи
На вход — файл (audio), на выходе — текст. Файл может прийти откуда угодно: вложение
из чата, голосовое сообщение из телеграма, файл из хранилища. Параметров у моделей
распознавания минимум — язык и необязательная подсказка с именами и жаргоном, которая
заметно улучшает расшифровку на терминах.
- Исполнение + данные
- Исполнение + данные + стрим
Синтез речи
На вход — текст, на выходе — аудиофайл. Главная особенность: голос почти везде
обязателен и публикуется отдельно для каждой модели. Голоса не общие — у одного
вендора это Zephyr и Puck, у другого aura-2-thalia-en, и список у каждой модели
свой. Поэтому голос — тоже параметр модели, а не поле ноды: каталог подставляет первый
голос по умолчанию, чтобы только что добавленная нода запускалась без ручной настройки.
Из 18 моделей синтеза у 12 каталог перечисляет конкретные голоса выпадающим списком; у остальных голос — свободная строка (там вендор ждёт идентификатор голоса из вашего личного кабинета, в том числе клонированного). Пересчитать:
python3 -c "import yaml;m=yaml.safe_load(open('backend/config/media/openrouter.yaml'))['models'];t=[x for x in m if x['modality']=='tts'];print(len(t), sum(1 for x in t if x['param_schema']['properties']['voice'].get('enum')))"
Генерация изображений
Одна нода закрывает оба режима, и переключателя между ними нет:
- По тексту (text2img) — вход
imageничем не занят, картинка рисуется по промпту. - По тексту и картинке (img2img, правка) — во вход
imageприходит файл, и он уезжает провайдеру как референс. Режим определяется наличием ребра, а не галочкой в настройках.
Промпт берётся из подключённого входа prompt, а если вход не подключён или пришёл
пустым — из поля в настройках ноды. Параметр «число изображений» есть у большинства
моделей, поэтому выход images — это список файлов, а не один файл.
- Исполнение + данные
- Данные
Порт image пропадает у моделей, которые референс не принимают. Это не сбой
редактора: способность принимать входную картинку объявлена у каждой модели каталога, и
нода спрашивает у сервера свой фактический набор портов при смене модели. Сегодня среди
38 моделей изображений таких нет — но каталог перегенерируется из ответа вендора целиком,
поэтому порт может исчезнуть после очередного обновления, и это не поломка. Если ребро
уже было нарисовано и вы выбрали такую модель, запуск честно упадёт с сообщением «модель
не принимает входное изображение», а не отправит байты, которые провайдер проигнорирует.
python3 -c "import yaml;m=yaml.safe_load(open('backend/config/media/openrouter.yaml'))['models'];i=[x for x in m if x['modality']=='image'];print(len(i), sum(1 for x in i if not ((x.get('capabilities') or {}).get('accepts_input_image') or (x.get('capabilities') or {}).get('requires_input_image'))))"
Ещё один честный отказ: если провайдер ответил успехом, но без картинки (обычно это
срабатывание его же контентной политики), нода считается упавшей, а не успешной с пустым
результатом. Ветку on_error у неё можно включить, как у любой ноды-шага.
Куда девается сгенерированный файл
Ни одна из трёх нод не возвращает байты в граф. Результат сохраняется в
файловое хранилище воркспейса, а по проводу едет ссылка:
метаданные (имя, mime-тип, размер) и локатор вида filestore://…. Байты подгружаются
только тем, кому они действительно нужны — например, когда файл уходит модели или
пользователю.
Так сделано по трём причинам: результат виден в разделе Файлы и не теряется вместе с логом выполнения; журнал выполнения не раздувается вложенным base64; и один и тот же файл можно передавать между нодами, не копируя его.
Чтобы файл увидел пользователь, соедините выход ноды со входом files ноды Выход —
это отдельный порт именно для файлов (Вход и выход). В чате
картинка покажется картинкой, аудио — проигрывателем, остальное — вложением.
- Исполнение + данные
- Исполнение + данные + стрим
- Данные
Картинка и озвучка как инструменты агента
Генерация изображения и Текст → Речь умеют работать не шагом графа, а инструментом, который агент вызывает сам, когда сочтёт нужным. Переключатель — поле режима работы в настройках ноды: в режиме шага у ноды обычные порты запуска и результата, в режиме инструмента — только выход подключения к агенту. Подробно про этот механизм — Инструменты агента.
Что важно знать про инструментальный режим:
- Файл прикрепляется к ответу агента автоматически — соединять ноду с Выход не нужно.
- Аргументы инструмента не умеют нести байты, поэтому «перерисуй это фото» работает иначе: агент подставляет как референс картинку, которую пользователь приложил к этому ходу диалога (отключается флажком в дополнительных настройках).
- Показывать ли результат самой модели — отдельный флажок, по умолчанию выключенный: вставленная в диалог картинка стоит входных токенов на каждом следующем обращении.
Распознавание речи инструментом быть не умеет, и это осознанно: аудио от пользователя и так приезжает вложением хода, отдельный инструмент для него ничего бы не добавил.
Ключи провайдера
| Откуда ключ | Что настроить | Когда применяется |
|---|---|---|
| Ключ платформы | переменная окружения OPENROUTER_API_KEY на сервере | по умолчанию, поле интеграции пустое |
| Свой ключ (BYO) | интеграция вида OpenRouter в разделе «Интеграции» и выбор её в поле ноды | когда выбрана в настройках конкретной ноды |
Ключ выбирается на каждой ноде отдельно, полем в разделе дополнительных настроек (— выберите подключение — означает «ключ платформы»). Интеграция заводится в Настройки → Интеграции кнопкой Добавить интеграцию; см. Интеграции.
Медиа-ключ — это интеграция отдельного вида, и запрет на подключение своих LLM-моделей на бесплатном тарифе на неё не распространяется; действует только общий лимит на число интеграций. Про подключение собственных текстовых моделей — Свои модели.
Каталог загружается и без ключа: модели видны в списке, ошибка приходит при запуске. Пустой список моделей у ноды означает, что каталог не загрузился вовсе — это проблема установки, а не настройки воркфлоу.
Сколько это стоит
Каждая генерация — отдельная строка расхода Генерация медиа в разделе Использование. Цена берётся одним из двух способов:
- Провайдер сообщил стоимость запроса — списывается она, переведённая в кредиты по общему курсу с наценкой платформы. Так считаются изображения.
- Провайдер стоимость не сообщил — списывается фиксированная ставка за вызов. Так устроен синтез речи: он отвечает готовым аудиофайлом, в котором никакого поля со стоимостью нет.
Обе ветки откалиброваны так, чтобы типичный вызов стоил примерно одинаково независимо от того, повезло ли со стоимостью в ответе. Как устроены кредиты в целом — Кредиты и расход.
Если вы используете свой ключ, генерация в кредитах не тарифицируется — вы уже заплатили провайдеру напрямую. Оплачивается только сам запуск воркфлоу.
Если не получилось
| Симптом | Причина | Что делать |
|---|---|---|
| «Unknown media model» при запуске | модель исчезла из каталога вендора | открыть ноду и выбрать модель заново |
| Список моделей в ноде пуст | каталог не загрузился | проверить установку сервера; настройкой воркфлоу это не лечится |
| Ошибка про отсутствие ключа | нет ни ключа платформы, ни интеграции | указать интеграцию OpenRouter в поле ноды |
| Порт входной картинки пропал | выбранная модель не принимает референс | выбрать модель, которая умеет img2img |
| «Модель не принимает входное изображение» | ребро осталось от прежней модели | удалить ребро или вернуть прежнюю модель |
| Нода упала, хотя провайдер ответил успехом | ответ без картинки — обычно контентная политика | переформулировать промпт |
| Файл сгенерировался, но пользователь его не видит | выход не подключён к порту files ноды Exit | соединить с портом files |