Руководство
Как вызывать gemini-3.1-flash-tts на HiAPI: curl, Python и рабочий запрос
Что gemini-3.1-flash-tts может сделать для вас на HiAPI
gemini-3.1-flash-tts — это модель преобразования текста в речь, доступная через единый API HiAPI. Вы отправляете текст и конфигурацию голоса, а платформа возвращает сгенерированное аудио. Поскольку модель доступна через единый, согласованный интерфейс, вам не нужно интегрировать каждую модель отдельно — одинаковые заголовки аутентификации, одинаковый базовый URL и одинаковый шаблон асинхронных задач применимы ко всем TTS-моделям на платформе.
Выбирайте эту модель, когда вам нужны:
- Многоголосое озвучивание. Сценарии, диалоги или контент в стиле подкаста, где разные фрагменты должны звучать как разные голоса.
- Быстрая обработка. Серия
flashориентирована на генерацию с низкой задержкой, что особенно важно для интерактивных приложений или пакетных задач с жёсткими SLA. - Предсказуемый интерфейс интеграции. Одна форма запроса покрывает всё — от одной строки текста до сценариев с несколькими говорящими.
Если ваше приложение уже вызывает другие модели HiAPI, добавление голосовых функций сводится к замене идентификатора модели и настройке тела запроса — не нужен новый SDK и не нужен новый процесс получения учётных данных.
Предварительные условия и настройка аутентификации
Перед первым вызовом убедитесь, что у вас есть:
- Учётная запись HiAPI и API-ключ. Сгенерируйте ключ в консоли. Относитесь к нему как к секрету — не коммитьте его в систему контроля версий.
- Базовый URL HiAPI. Все запросы отправляются на один и тот же хост; различаются только пути каждого эндпоинта.
- Инструмент для выполнения HTTP-запросов.
curlдля быстрого тестирования, а также Python 3.9+ и библиотекаrequestsдля скриптов.
Аутентификация выполняется путём передачи bearer-токена в заголовке Authorization:
Authorization: Bearer $HIAPI_API_KEY
Храните ключ в переменной окружения, а не в исходном коде:
export HIAPI_API_KEY="your_key_here"
Каждый описанный ниже эндпоинт — отправка задачи, проверка статуса и получение файла — использует один и тот же заголовок. Если вы получили 401, значит заголовок отсутствует, имеет неверный формат или ключ был отозван. Обновите ключ в консоли, а не используйте один и тот же ключ в разных средах.
Формирование тела запроса для многоголосовой речи
Тело запроса — это JSON. Как минимум оно должно содержать идентификатор модели и входные данные. Для многоголосового вывода вам нужно добавить конфигурацию говорящих, сопоставляющую именованных говорящих с голосами, и разметить входной текст тегами говорящих.
Типичное тело запроса выглядит так:
{
"model": "gemini-3.1-flash-tts",
"input": {
"text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
"multi_speaker": true,
"speakers": [
{ "name": "Host", "voice": "voice_a" },
{ "name": "Guest", "voice": "voice_b" }
]
}
}
Ключевые моменты, на которых легко споткнуться:
- Имена говорящих должны совпадать точно. Поле
nameв массивеspeakersдолжно в точности совпадать с тегом, используемым в тексте (в данном примере — в квадратных скобках). Несовпадение регистра — самая частая причина сбоя многоголосового рендеринга. - Каждый тег должен быть объявлен. Если в тексте упоминается
[Narrator], но говорящий сname: "Narrator"не определён, запрос будет отклонён. - Идентификаторы голосов берутся из каталога голосов платформы. Используйте идентификаторы, предоставляемые HiAPI, а не придумывайте свои. Для задач с одним говорящим опустите
multi_speakerиspeakersи вместо этого укажите одно полеvoice. - Текст отправляется одной строкой. Длинные сценарии не проблема, но учитывайте ограничения на запрос, задокументированные на платформе.
После проверки тела запроса задача принимается и возвращается идентификатор задачи, который вы будете использовать для опроса.
Запуск с помощью curl
Сохраните приведённое выше тело запроса в payload.json, затем отправьте:
curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d @payload.json
Ответ содержит объект задачи с полями id и status (обычно queued или processing):
{ "id": "job_abc123", "status": "queued" }
Чтобы проверить прогресс, получите задачу по ID:
curl "$HIAPI_BASE_URL/v1/audio/speech/jobs/job_abc123" \
-H "Authorization: Bearer $HIAPI_API_KEY"
Когда status становится succeeded, ответ содержит ссылку на аудиофайл (URL или ID файла), который можно скачать последующим запросом — см. раздел об опросе ниже. Если задача не удалась, status будет failed, а поле error объяснит причину.
Для быстрых экспериментов можно пропустить файл и передать JSON напрямую:
curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gemini-3.1-flash-tts","input":{"text":"Hello from HiAPI.","voice":"voice_a"}}'
Запуск с помощью Python
Версия на Python использует requests и небольшую вспомогательную функцию, чтобы цикл опроса оставался читаемым. Тело запроса идентично примеру с curl.
import os
import time
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ["HIAPI_BASE_URL"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
payload = {
"model": "gemini-3.1-flash-tts",
"input": {
"text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
"multi_speaker": True,
"speakers": [
{"name": "Host", "voice": "voice_a"},
{"name": "Guest", "voice": "voice_b"},
],
},
}
resp = requests.post(
f"{BASE_URL}/v1/audio/speech/jobs",
headers={**HEADERS, "Content-Type": "application/json"},
json=payload,
timeout=30,
)
resp.raise_for_status()
job = resp.json()
job_id = job["id"]
print("submitted", job_id)
while True:
r = requests.get(f"{BASE_URL}/v1/audio/speech/jobs/{job_id}", headers=HEADERS, timeout=30)
r.raise_for_status()
status = r.json()
if status["status"] in ("succeeded", "failed"):
break
time.sleep(2)
if status["status"] == "failed":
raise RuntimeError(status.get("error"))
print("audio ready:", status["output"])
Замечания:
- Тайм-ауты важны. Явно задавайте тайм-аут для каждого запроса; зависший цикл опроса хуже, чем цикл, который завершился с ошибкой.
- Не опрашивайте слишком часто. Для коротких сценариев разумна двухсекундная пауза; для длинных сценариев следует увеличивать интервал.
- Поместите тело запроса в функцию. В реальном коде параметризуйте текст, говорящих и голоса, чтобы повторно использовать одну и ту же логику отправки для задач с одним говорящим.
Опрос асинхронных задач и скачивание аудио
Генерация речи асинхронна: вы отправляете задачу, затем проверяете статус, пока задача не достигнет терминального состояния. Существует два терминальных состояния — succeeded и failed. Все остальные состояния следует рассматривать как «продолжайте ждать».
Надёжная программа опроса должна:
- Ограничивать общее время ожидания. Даже быстрая модель может оказаться в очереди после другой работы. Остановитесь после разумного предела и верните ID задачи, чтобы вызывающая сторона могла повторить попытку.
- Использовать экспоненциальную задержку. Начните с одной-двух секунд и удваивайте до верхнего предела. Это позволяет избежать чрезмерной нагрузки на API при длительных задачах.
- Явно обрабатывать ошибки. Когда
status == "failed", прочитайте полеerrorи зафиксируйте его — оно обычно указывает на проблему в теле запроса (необъявленный говорящий, пустой текст, неподдерживаемый голос).
При успешном выполнении задачи ответ со статусом содержит ссылку на вывод. Скачайте его с тем же заголовком аутентификации:
out = status["output"]
audio = requests.get(out["url"], headers=HEADERS, timeout=60)
audio.raise_for_status()
with open("narration.wav", "wb") as f:
f.write(audio.content)
Если в ответе возвращается ID файла, а не URL, получите его через соответствующий эндпоинт файлов на HiAPI. Сохраняйте исходный ID задачи вместе с сохранённым файлом — это единственный надёжный способ позже проследить неудачный рендеринг до его запроса.
Понимание оплаты по символам
На HiAPI gemini-3.1-flash-tts тарифицируется по количеству символов входного текста. Нет компонентов оплаты за запрос или за минуту, которые нужно моделировать — стоимость задачи растёт вместе с объёмом отправляемого текста, что делает оценку простой: общее количество символов во всех сценариях, умноженное на текущую ставку за символ.
Практические следствия:
- Оценивайте до запуска. Суммируйте ожидаемый месячный объём текста и сверьте его с текущей ставкой, указанной на панели тарифов. Не встраивайте ставку в код; считывайте её с платформы во время сборки или храните в конфигурации.
- Длинный контент определяет стоимость. Десятиминутное озвучивание — это в основном стоимость текста. Если вы создаёте аудиокниги или учебные материалы, сначала смоделируйте объём.
- Повторные попытки стоят денег. Задачи, завершившиеся с ошибкой после генерации, в зависимости от характера ошибки всё равно могут тарифицироваться. Выполняйте клиентскую валидацию перед отправкой — проверяйте, что каждый тег говорящего объявлен, а текст не пуст.
- Активно кэшируйте. Если один и тот же сценарий рендерится повторно (например, для демонстрации или тестового стенда), сохраняйте сгенерированное аудио и переиспользуйте его, а не платите повторно за одни и те же символы.
Актуальные ставки и любые уровни объёма см. на панели тарифов на сайте — это единственный источник истины.
Типичные точки отказа и способы их устранения
Большинство проблем интеграции сводятся к нескольким категориям. Проверяйте их по порядку.
401 Unauthorized
Ваш заголовок Authorization отсутствует или имеет неверный формат. Убедитесь, что ключ задан в окружении, а содержимое заголовка в точности равно Bearer <key>. Если ключ был обновлён, обновите и окружение.
400 Bad Request — неизвестный говорящий
Текст содержит тег [Name], не объявленный в speakers, или регистр не совпадает. Сделайте тег и поле name побайтово идентичными.
400 Bad Request — пустой или слишком большой ввод
Пустой текст не проходит валидацию сразу. Очень длинные сценарии могут превышать лимит на запрос; разбейте их на несколько задач, а не обрезайте.
400 Bad Request — недопустимый идентификатор голоса
Имена голосов должны браться из каталога платформы. Копируйте идентификаторы точно; не придумывайте собственные удобные названия.
Задача застревает в состоянии processing
Обычно это очередь, а не баг. Применяйте задержку и общий тайм-аут. Если это продолжается значительно дольше обычного, запишите ID задачи и один раз повторите с меньшим телом запроса, чтобы понять, не в размере ли проблема.
Задача failed с ошибкой генерации
Прочитайте поле error. Оно обычно указывает на проблему с контентом или конфигурацией, а не на временный сбой. Исправьте тело запроса, отправьте повторно и избегайте слепых циклов повторных попыток — каждая попытка может тарифицироваться по символам.
Аудио скачивается, но не воспроизводится
Прежде чем предполагать повреждение файла, проверьте content type скачанного файла. Сохраняйте с правильным расширением, соответствующим возвращённому формату, и проверьте, что длина в байтах не равна нулю. Усечённый файл обычно означает, что запрос на скачивание был прерван — повторите скачивание, а не генерацию.
С этими проверками большинство проблем интеграции первого дня решаются за минуты, а не за часы.
Похожие статьи
Все статьи →-
Руководство
Как вызвать 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
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата