Руководство
Как вызвать muse-image-1.0/image-to-image в HiAPI API: curl, Python и один рабочий пример запроса
Что на самом деле отправляет запрос image-to-image
Прежде чем писать первую строку кода, полезно разобраться, что ожидает вызов image-to-image. В отличие от чисто текстового запроса text-to-image, где промпт — единственный творческий вход, muse-image-1.0/image-to-image требует исходное изображение плюс инструкцию, как его преобразовать.
Как минимум, ваша полезная нагрузка запроса включает:
model: идентификаторmuse-image-1.0/image-to-image.image: исходное изображение, которое вы хотите отредактировать. Обычно оно отправляется в виде строки в кодировке base64 или по публично доступному URL — в зависимости от того, какую форму принимает эндпоинт. Сверьтесь с входной схемой модели, чтобы подтвердить точное имя поля и формат.prompt: текстовое описание правки, которую вы хотите выполнить. Указывайте конкретно, что изменить и что сохранить.- Необязательные параметры, такие как strength или guidance (если модель их предоставляет), позволяют управлять тем, насколько сильно выход отличается от исходного изображения. Точный набор параметров зависит от модели, поэтому обязательно сверяйтесь со справочником API, а не догадывайтесь.
Ключевой сдвиг в мышлении: вы не генерируете с нуля, а задаёте отправную точку и направление. Расплывчатые промпты вроде "make it better" дают непредсказуемые результаты, потому что у модели слишком много свободы. А промпт вроде "replace the sky with a sunset and keep the buildings unchanged" даёт модели чёткое ограничение.
Кроме того, заранее проверьте ограничения на изображение — поддерживаемые форматы, максимальный размер и объём файла. Если ваше исходное изображение — PNG на 12 МБ, возможно, сначала придётся уменьшить его разрешение или конвертировать в JPEG, чтобы запрос был принят. Правильная обработка изображения до отправки избавит вас от лишнего круга обмена и запутанного сообщения об ошибке.
Как только у вас есть исходное изображение и чёткий промпт для редактирования, можно делать первый вызов.
Отправляем первый запрос через curl
Самый быстрый способ проверить интеграцию — отправить запрос прямо из терминала. Точный путь эндпоинта и схема полезной нагрузки определены в справочнике API модели; приведённый ниже пример показывает общую форму, чтобы вы могли адаптировать её под текущую спецификацию.
curl -X POST https://api.hiapi.ai/v1/images/edits \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "muse-image-1.0/image-to-image",
"image": "https://your-bucket.example.com/source.jpg",
"prompt": "replace the sky with a warm sunset, keep the buildings unchanged",
"strength": 0.6
}'
Замените $HIAPI_API_KEY переменной окружения, а не вставляйте ключ напрямую. Если ваш инструмент это поддерживает, экспортируйте ключ в сессии оболочки, чтобы он не остался в истории команд.
Возвращённый ответ будет содержать идентификатор задания. Поскольку редактирование изображений требует интенсивных вычислений, API обычно не возвращает готовое изображение в том же ответе. Вместо этого вы получаете ID задания и статус. Сохраните этот ID — на следующем шаге вы будете использовать его для опроса результата.
Если вызов завершился неудачно, внимательно прочитайте тело ответа с ошибкой. 400 обычно означает неверный формат полезной нагрузки или неподдерживаемый формат изображения. 401 означает отсутствующий или неверный ключ. 429 означает, что вы отправляете запросы слишком быстро. Исправлять эти проблемы на этапе терминала гораздо проще, чем отлаживать их в полноценном приложении.
Тот же запрос на Python
После успешного вызова curl преобразуйте его в небольшую функцию Python. Использование requests делает пример с минимумом зависимостей и простым для переноса.
import os
import requests
HIAPI_API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1/images/edits"
def submit_edit(image_url: str, prompt: str, strength: float = 0.6) -> str:
payload = {
"model": "muse-image-1.0/image-to-image",
"image": image_url,
"prompt": prompt,
"strength": strength,
}
headers = {
"Authorization": f"Bearer {HIAPI_API_KEY}",
"Content-Type": "application/json",
}
response = requests.post(BASE_URL, json=payload, headers=headers, timeout=30)
response.raise_for_status()
data = response.json()
return data["id"]
Несколько замечаний об этой функции:
- Параметр
timeoutпредотвращает бесконечное зависание скрипта при сбое сети. Для вызова отправки 30 секунд — с запасом, но при необходимости можно скорректировать. raise_for_status()преобразует HTTP-ошибки в исключения, чтобы вы могли перехватывать их в одном месте.- Возврат только ID задания позволяет функции оставаться сосредоточенной. Логика опроса должна быть в отдельной функции.
Если вы хотите отправлять исходное изображение в виде байтов, а не по URL, прочитайте файл, закодируйте его в base64 и поместите результат в поле image. Перед переключением сверьтесь с документацией, какой формат ожидается, поскольку эти две кодировки не всегда взаимозаменяемы.
Эта функция намеренно оставлена минимальной. В реальном сервисе вы добавите логирование, обработку повторных попыток и проверку типов, но основная схема запроса — именно та, что вы видите здесь.
Обработка асинхронных заданий и опрос результата
Редактирование изображений требует времени — обычно от нескольких секунд до десятков секунд, в зависимости от промпта и разрешения. API обрабатывает это так: принимает запрос, возвращает ID задания и выполняет работу в фоне. Ваша задача — периодически проверять, пока статус не станет терминальным.
Опрос звучит просто, но наивный цикл, срабатывающий каждые 100 мс, будет расходовать квоту и может вызвать ограничение частоты. Используйте разумный интервал и верхний предел попыток:
import time
import requests
def poll_job(job_id: str, interval: float = 2.0, max_attempts: int = 30) -> dict:
url = f"https://api.hiapi.ai/v1/jobs/{job_id}"
headers = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}
for attempt in range(max_attempts):
response = requests.get(url, headers=headers, timeout=15)
response.raise_for_status()
data = response.json()
status = data["status"]
if status == "succeeded":
return data
if status == "failed":
raise RuntimeError(data.get("error", "job failed"))
time.sleep(interval)
raise TimeoutError(f"job {job_id} did not finish after {max_attempts} attempts")
Двухсекундный интервал — разумная отправная точка. Если ваши задания обычно завершаются за пять секунд, можно сначала опрашивать чаще, а затем постепенно увеличивать интервал. Если они обычно занимают больше времени, снизьте частоту опроса, чтобы избежать лишних вызовов.
Верхний предел попыток — ваша страховка. Без него зависшее задание может зациклиться навсегда. При достижении предела выбрасывайте явную ошибку, чтобы вызывающий код знал, что операция истекла по времени, а не зависла молча.
В производственной среде рассмотрите возможность вынести опрос в фоновый worker или очередь, чтобы ваш поток обработки запросов не блокировался в ожидании завершения рендеринга изображения.
Скачивание и хранение выходного изображения
Когда задание достигает статуса succeeded, ответ содержит одно или несколько выходных изображений, обычно в виде URL. Ваш следующий шаг — скачать изображение и сохранить его надёжно.
def download_image(result: dict, dest_path: str) -> None:
image_url = result["output"][0]["url"]
response = requests.get(image_url, timeout=30)
response.raise_for_status()
with open(dest_path, "wb") as f:
f.write(response.content)
Несколько практических соображений:
- Выходные URL могут быть временными. Рассматривайте их как недолговечные ресурсы и скачивайте вовремя, а не храните URL в качестве единственной ссылки.
- Записывайте файл в бинарном режиме. Ответ с изображением не является текстом; открытие в режиме
"w"повредит данные. - Перед объявлением успеха проверьте, что файл не пустой. Загрузка нулевого размера обычно означает, что URL истёк или запрос заблокирован.
Для любого сценария за пределами локального скрипта направляйте скачивание потоком прямо в ваше хранилище, а не сохраняйте сначала на диск. Большинство SDK объектного хранилища принимают файлоподобные объекты или байтовые потоки, поэтому вы можете передать response.raw или response.content в вызов загрузки без промежуточного файла.
Наконец, записывайте ID задания вместе с сохранённым объектом. Если выход позже окажется повреждён или вам понадобится воспроизвести конкретную правку, ID задания вместе с исходными входными данными позволит вам проследить, что было отправлено.
Типичные точки сбоя и способы их устранения
Большинство проблем интеграции относятся к нескольким категориям. Вот как диагностировать каждую из них.
Запрос отклонён до создания задания
Ошибка 400 при отправке обычно означает неверную полезную нагрузку. Проверьте, что model в точности равен muse-image-1.0/image-to-image, что image доступен или корректно закодирован в base64, и что prompt — непустая строка. Если изображение задано URL, убедитесь, что он публично доступен — приватный bucket или истёкший подписанный URL не пройдут проверку.
Задание завершилось неудачей во время обработки
Если опрос возвращает статус failed, прочитайте сообщение об ошибке в теле ответа. Частые причины включают слишком большое изображение, промпт, нарушающий политику контента, или значения параметров вне допустимого диапазона. Уменьшите размер изображения и упростите промпт, чтобы изолировать причину.
Тайм-аут опроса
Если вы достигли верхнего предела попыток без терминального статуса, задание может действительно требовать больше времени или, возможно, зависло. Во-первых, увеличьте max_attempts и сверьтесь со справочником API, чтобы узнать типичное время обработки. Если задания продолжают истекать по времени, проверьте, не является ли исходное изображение аномально большим. Не просто убирайте верхний предел попыток — ограниченные повторные попытки предотвращают молчаливое бесконечное зацикливание.
Ограничение частоты
Ответ 429 означает, что вы отправляете запросы слишком быстро. Снизьте темп, соблюдайте любой заголовок retry-after и разнесите одновременные отправки по времени. Если вы обрабатываете пакет изображений, обрабатывайте их последовательно или используйте меньшее ограничение параллелизма, а не отправляйте всё сразу.
Вывод отсутствует или обрезан
Если задание успешно, но скачанный файл пуст, возможно, выходной URL истёк между опросом и скачиванием. Скачивайте сразу после успеха. Если изображение повреждено, убедитесь, что вы записываете в бинарном режиме и не применяете к потоку текстовую кодировку.
Отладка становится проще, когда вы записываете полезную нагрузку запроса, ID задания и переходы статусов. С этими тремя сведениями почти любую неудачу можно проследить до источника.
Имея форму запроса, шаблоны curl и Python, логику опроса и шаг скачивания, вы получаете рабочий конвейер для использования muse-image-1.0/image-to-image в HiAPI API. Начните с примера в терминале, перенесите его в скрипт, а повторные попытки и логирование добавьте после того, как основной путь стабилизируется.
Похожие статьи
Все статьи →-
Руководство
Как вызвать 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
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата