Руководство
API-руководство recraft-v4-styles/text-to-image: curl, Python и асинхронный опрос
Полный разбор запроса с использованием референсных изображений стиля на HiAPI
Что умеет recraft-v4-styles/text-to-image
recraft-v4-styles/text-to-image — это эндпоинт генерации изображений по референсу стиля. Вы передаёте ему текстовый промпт с описанием желаемого содержимого, а также одно или несколько референсных изображений, задающих внешний вид. Модель объединяет оба входа: промпт задаёт содержимое и композиционный замысел, референсы — визуальный стиль.
При выборе эндпоинта это различие важно. Когда внешний вид полностью описывается словами — например, «плоская векторная иллюстрация кофейной чашки, два цвета, жирный контур» — правильный инструмент — генерация по текстовому промпту. Однако в реальной продуктовой работе большинство сценариев связано с фирменным стилем, который трудно описать, но легко показать. Готовый ключевой визуал, ранее утверждённый рендер или образец дизайн-системы задают спецификацию стиля гораздо точнее, чем абзац прилагательных. Именно эту нишу и закрывает данный эндпоинт.
С точки зрения разработчика, рассматривайте его как преобразование с двумя входами: промпт + референс стиля -> изображение. Всё в интеграции вытекает из этой формы. Вы не просто сериализуете строку, а собираете небольшой многосоставный payload, в котором референсные изображения являются полноценным входом. Код построения запроса должен относиться к ним именно так, а слой валидации — отклонять задачи, где есть только промпт и нет пригодных референсов стиля, ещё до того, как задача покинет ваш сервис.
Эндпоинт асинхронный. Отправка запроса возвращает задачу, затем вы опрашиваете её, а итоговое изображение приходит в виде URL, а не встроенных байтов. Это осознанное решение для задач генерации изображений: генерация занимает достаточно долго, и удержание открытого HTTP-соединения расточительно и ненадёжно. Как только вы приняли жизненный цикл «отправка-опрос-скачивание», вся остальная интеграция — обычная работа с API.
Разбор одного рабочего запроса
Прежде чем писать код, разложите поля по группам. Запрос к recraft-v4-styles/text-to-image состоит из трёх логических частей.
Промпт
Промпт — это ваша инструкция по содержимому. Пишите его вокруг того, что должно быть на изображении: субъект, композиция, кадрирование, количество объектов, обработка фона. Не тратьте бюджет промпта на прилагательные стиля, которые уже передают референсы; конфликт сигналов между промптом и референсом часто даёт размытый результат. Держите промпт коротким, конкретным и проверяемым.
Входные референсы стиля
Именно эта часть отличает данный эндпоинт от обычного вызова генерации по тексту. Референсы стиля — это изображения, передаваемые вместе с промптом и задающие визуальный язык. При их подборе относитесь к ним как к тщательно отобранному набору, а не как к свалке картинок:
- Согласованность важнее количества. Несколько референсов с единым цельным внешним видом научат модель большему, чем множество разностильных референсов.
- Разрешение и кадрирование важны. Референсы должны быть репрезентативны для желаемого результата, а не миниатюрами или сильно обрезанными фрагментами.
- Они должны быть доступны. Если вы передаёте референсы как URL, эти URL должны быть публично доступны на момент запроса. Подписанная ссылка, истекающая через шестьдесят секунд, приведёт к провалу медленной задачи.
Храните набор референсов в конфигурации, а не разбрасывайте по коду, чтобы можно было версионировать его вместе с брендовыми активами.
Опции вывода
Остальные поля описывают артефакт, который вы хотите получить, — это переключатели, влияющие на возвращаемое изображение, а не на его содержимое. Точные имена параметров и допустимые значения приведены на справочной странице эндпоинта; читайте их там, а не угадывайте, и сосредоточьте их в одном месте кода, чтобы изменение спецификации затрагивало один файл.
Полезная привычка: собирайте JSON-тело в виде словаря/объекта на выбранном языке, один раз логируйте его на уровне отладки при первом запуске и просматривайте его структуру глазами, прежде чем винить модель в плохом результате.
Вызов через curl
Начните с curl. Он убирает все библиотечные абстракции между вами и проводным форматом, поэтому если запрос неверен, вы сразу это увидите.
Отправка — это POST-запрос с JSON-телом и заголовком авторизации, несущим ваш API-ключ HiAPI:
curl -sS -X POST "https://api.hiapi.ai/v1/recraft-v4-styles/text-to-image" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "a ceramic coffee cup on a linen tablecloth, soft daylight",
"style_references": [
"https://your-cdn.example.com/style/ref-01.png"
]
}'
Несколько замечаний о том, что вы видите:
- Держите ключ в переменной окружения (
$HIAPI_API_KEY) и никогда не встраивайте его в историю shell или коммитимые скрипты. - Payload
-d— это чистый JSON. Правила кавычек в shell — частый источник проблем; если вы получаете ошибку разбора, выведите тело запроса в файл и используйте-d @body.json. - Имена полей, показанные здесь, следуют разбору запроса из предыдущего раздела; перед публикацией сверьте точные имена и допустимые опции вывода на справочной странице эндпоинта.
Ответ — не изображение. Это подтверждение задачи: идентификатор, обозначающий только что поставленную в очередь генерацию, и поле статуса, сообщающее, что она ещё не завершена. При первом запуске внимательно прочитайте тело ответа и запишите имя поля, в котором хранится ID задачи, — эта строка является дескриптором для всех последующих действий. Сохраните её. Если первый ответ содержит объект ошибки, остановитесь и исправьте запрос; опрос ID, который вы так и не получили, — самый частый тупик.
Тот же запрос на Python
Перенесите вызов curl на Python один раз, и у вас появится переиспользуемый примитив. В примере ниже используется requests и в точности повторяется тело запроса.
import os
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
STYLE_REFERENCES = [
"https://your-cdn.example.com/style/ref-01.png",
]
def submit_generation(prompt: str) -> dict:
body = {
"prompt": prompt,
"style_references": STYLE_REFERENCES,
}
resp = requests.post(
f"{BASE_URL}/recraft-v4-styles/text-to-image",
headers=HEADERS,
json=body,
timeout=30,
)
resp.raise_for_status()
return resp.json()
if __name__ == "__main__":
job = submit_generation(
"a ceramic coffee cup on a linen tablecloth, soft daylight"
)
print(job)
При доработке этого кода стоит сохранить два проектных решения:
- Всегда задавайте таймаут. Отправка должна возвращаться быстро; если она зависает, вам нужно исключение, а не застрявший процесс.
- Возвращайте разобранный JSON, а не объект ответа. Нижестоящий код должен зависеть от payload задачи, а не от внутренностей
requests. Это делает замену транспортного слоя в будущем тривиальной.
Как указано выше, определяйте набор референсов на уровне модуля или конфигурации. Когда фирменный стиль эволюционирует, вы обновляете один список, а не ищете по местам вызова. И держите построение тела запроса в одной функции, чтобы любое поле, требуемое эндпоинтом, добавлялось в одном месте.
Опрос асинхронного результата
Генерация асинхронна, поэтому отправленная задача проходит через несколько состояний до завершения. Вашему клиенту нужен цикл ожидания, который проверяет статус, делает паузы между проверками и в конце концов сдаётся.
import time
def wait_for_result(job_id: str, timeout_s: int = 300, interval_s: float = 3.0) -> dict:
deadline = time.monotonic() + timeout_s
delay = interval_s
while time.monotonic() < deadline:
resp = requests.get(
f"{BASE_URL}/recraft-v4-styles/text-to-image/{job_id}",
headers=HEADERS,
timeout=30,
)
resp.raise_for_status()
data = resp.json()
status = data.get("status")
if status in ("succeeded", "failed"):
return data
time.sleep(delay)
delay = min(delay * 1.5, 15.0)
raise TimeoutError(f"job {job_id} did not finish in {timeout_s}s")
В этом цикле важно следующее:
- Считайте неизвестные статусы ожидающими. Сравнивайте с явными терминальными статусами, а не со списком разрешённых промежуточных; если платформа добавит промежуточное состояние, ваш цикл продолжит ждать, а не упадёт.
- Делайте задержки с ростом. Фиксированный опрос раз в секунду в течение пяти минут — это пять минут бесполезных запросов. Начинайте с малого интервала, умножайте его и ограничивайте сверху.
- Ограничивайте время ожидания. Каждому циклу нужен дедлайн, и дедлайн должен проявляться в виде исключения, которое вызывающий код может обработать.
- Ветвитесь по ошибке. Терминальный статус ошибки несёт диагностику. Логируйте полное тело ответа — в этом разница между «оно сломалось» и «URL референса вернул 403».
Если вы обрабатываете много изображений, не спите в обработчике веб-запроса. Отправьте задачу, сохраните ID задачи и позвольте фоновому рабочему процессу или планировщику управлять опросом. Справочная страница эндпоинта документирует точные значения статусов и путь опроса; проверяйте её при каждом обновлении клиента.
Скачивание и сохранение вывода
Когда задача достигает терминального статуса успеха, ответ содержит URL сгенерированного изображения. Этот URL — точка передачи между API и вашим слоем хранения.
Получите его как байты и запишите туда, куда нужно:
def download_image(url: str, dest_path: str) -> None:
resp = requests.get(url, timeout=60)
resp.raise_for_status()
with open(dest_path, "wb") as f:
f.write(resp.content)
Для любого сценария за пределами локальных экспериментов не оставляйте артефакт просто на возвращённом URL. Рассматривайте сгенерированное изображение как временный указатель и копируйте его в хранилище, которое вы контролируете, — объектное хранилище, источник вашего CDN или медиапайплайн. Причины три:
- Время жизни. URL сгенерированного вывода не гарантирует бессрочную сохранность. Повторное скачивание с устаревшего URL во время повторов — потенциальный тихий сбой.
- Стабильные ключи. Вашему приложению нужен детерминированный идентификатор, который можно положить в строку базы данных, а не URL, меняющийся при каждой повторной генерации.
- Прослеживаемость. Хранение промпта, версии набора референсов стиля и ID задачи вместе с изображением позволяет позже воспроизвести или проверить любой актив. Сохраняйте эти метаданные в сопутствующей записи или столбце базы данных.
При загрузке в объектное хранилище передавайте тело ответа потоком, а не буферизуйте большое изображение целиком в памяти, и устанавливайте тип содержимого из заголовков ответа. Если вы отдаёте изображение клиентам через свой CDN, на этом шаге также применяются заголовки кеширования.
Устранение неполадок первого запуска
Большинство первых попыток проваливается несколькими предсказуемыми способами. Проверяйте их по порядку.
Тело запроса отклонено
Ошибки класса 400 обычно означают некорректный JSON или отсутствие обязательного поля. Сначала запустите версию с curl и проверьте точное тело, которое вы отправляете. Частые проблемы: shell-кавычки ломают JSON, поле, которое API ожидает массивом, отправляется строкой, или значение опции вывода выходит за допустимый диапазон. Справочная страница эндпоинта — авторитетный источник имён полей и значений; сравните ваше тело с ней буквально.
У вас есть промпт, но нет пригодных референсов стиля
Эндпоинт построен вокруг референсов стиля. Если ваш запрос содержит промпт, но референсы пусты, недоступны или возвращают ошибку авторизации при получении, задача либо будет отклонена, либо выдаст результат, игнорирующий задуманный вами внешний вид. Проверьте каждый URL референса, получив его тем же клиентом без учётных данных, который использовала бы платформа. Референс, требующий cookie сессии или подписанной строки запроса, считается повреждённым.
Вы так и не получили ID задачи
Ответ на отправку — это подтверждение, а не изображение. Если ваш код ожидает байты изображения в первом ответе, он будет падать при каждом запуске. Разберите ответ, извлеките ID задачи и только затем начинайте опрос. Логируйте полный ответ на отправку в первые несколько запусков, чтобы видеть его форму.
Вы опрашиваете слишком часто
Сотни проверок статуса за минуту не ускорят завершение задачи, а лишь повысят вероятность срабатывания ограничения частоты. Используйте возрастающие интервалы с верхним пределом и один рабочий процесс на задачу. Если вы отправляете много задач, добавьте небольшое ограничение параллелизма, чтобы всплеск отправок не превратился во всплеск опросов.
Задача завершилась, но скачивание не удалось
403 или 404 при получении выходного URL обычно означает, что URL истёк или задача провалилась после проверки статуса, которую вы неверно прочитали. Убедитесь, что терминальный статус — успех, затем перечитайте ответ, чтобы получить фактическое поле вывода. Сохраняйте артефакт сразу, как только он доступен, а не откладывайте скачивание.
Решайте эти проблемы в порядке работы пайплайна — отправка, опрос, скачивание, — и сбои первого запуска почти всегда сводятся к очевидным исправлениям. Справочная страница эндпоинта и его схемы запросов — самый быстрый способ подтвердить любой вопрос по полям.
Похожие статьи
Все статьи →-
Руководство
Как вызвать hailuo-2.3-fast/image-to-video через HiAPI API: практика с curl и Python
Первый рабочий запрос к быстрому и недорогому уровню генерации видео по изображению — от ID модели до загрузки MP4
-
Руководство
Как вызывать hailuo-2.3/text-to-video через API HiAPI: curl, Python и рабочие примеры запросов
-
Руководство
Использование Kandinsky 6.0 Pro для преобразования текста в видео на HiAPI: руководство по curl и Python
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата