POST /orders /chunks /preview
Dry-run разбиения текста на чанки и расчёта стоимости — БЕЗ создания заказа. Тот же
расчёт, что использует POST /orders: сверяйте здесь разбиение/цену перед реальной
отправкой. Не тратит токен-квоту ключа — preview бесплатен.
Поправки к спецификации · 2
Предпросмотр чанков доступен по API-ключу
В машинной документации
llm.md§12 сказано, что предпросмотр чанков — эндпоинт веб-кабинета и по ключу вернёт401. Это неверно: три операции предпросмотра входят в публичный контур и требуют праваorders.read— так их описывают и OpenAPI, и §7.1 той жеllm.md. Если ИИ-ассистент сошлётся на §12 — он ошибается.Тарификация разметки
[шёпот]и<break/>не согласованаТри места в спеке утверждают, что теги разметки (
[шёпот],<break/>) не тарифицируются, а описание поляbillable_length— что тарифицируются. Пока расхождение не разрешено бэкендом, считайте худший случай: закладывайте символы разметки в оценку стоимости. Точную цену конкретного текста даётPOST /orders/chunks/preview— он возвращает уже посчитанную длину.
Единый ready-конверт для sync и async путей:
- 200
status=ready— TTS-текст ≤ 50 000 символов (и любой non-TTS): расчёт готов сразу, тело содержитsummary(итоги по всему тексту) + первую страницуchunks[]+page(мета пагинации). - 202
status=processing— TTS-текст длиннее порога: расчёт уходит в фон, тело содержит толькоpreview_id. Результат приходит WS-событием.readyна каналprivate-chunks.preview.{userId}(авторизация —POST /broadcasting/auth, как и для остальных приватных каналов), либо подтяните вручнуюGET /orders/chunks/preview/{previewId}.
Инкрементальный re-preview: передайте preview_id предыдущего ответа как
previous_preview_id вместе с новым input_text — пересчитается только
окрестность правки, результат идентичен полному расчёту.
Настройки заказа: передайте тот же config_override, что уйдёт в POST /orders, —
превью режет по конфигу шаблона с ним, как заказ (настройки, влияющие на рез, действуют
и здесь). Значение, которое создание заказа отбило бы 422, превью тоже отбивает.
Паузы/капы: превышение лимитов пауз (>500 шт., >3600с суммарно, >10с одна) или
размера заказа (>1500 фрагментов) НЕ роняет запрос — приходит summary.caps_ok=false
caps_exceeded. Это отличает preview отPOST /orders, где то же превышение даёт422.
Кэш превью общий с веб-сессией того же аккаунта (если владелец ключа пользуется и сайтом): одинаковый текст+шаблон+режим, уже посчитанный в браузере, вернётся мгновенно.
Требуемое право ключа: orders.read (preview не мутирует данные — логически чтение).
На этой странице(4)
Тело запроса
Dry-run preview разбиения текста на чанки — без создания заказа. input_text обязателен (preview по inline-тексту; файлы — async-путь).
config_override — тот же объект, что уйдёт в POST /orders (с 25.09.2026): размер
чанка и режим провайдера в нём меняют рез, и превью без него показывало границы
конфига шаблона, а не боевого реза ({@see AcceptsConfigOverride}).
{
"template_id": "9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c",
"task_type": "string",
"input_text": "string",
"previous_preview_id": "string",
"text_hash": "string",
"generation_mode": "default",
"config_override": []
}Поля
ID предыдущего preview для инкрементального ре-чанка (пересчёт только хвоста правки).
sha256(input_text) от фронта — необязательная серверная верификация целостности.
Режим генерации ЭТОГО превью — то же значение, что уйдёт в
config_override.generation_mode при создании заказа. Отсутствие = default.
Сервис, не объявивший ключ в validation_schema, режим игнорирует
(см. Service::resolveGenerationMode) — как и на боевом пути.
Настройки генерации поверх конфига шаблона — тот же JSON-объект, что уйдёт в создание заказа; настройки, влияющие на рез, применяются к превью так же, как к заказу. Посторонние ключи отбрасываются.
Возможные ответы
200status=ready: summary + первая страница чанков + мета пагинации
status=ready: summary + первая страница чанков + мета пагинации
"string"Признак успеха. Решение принимайте по HTTP-коду: у любого ответа 2xx здесь true, а ошибка приходит телом другой формы, где этого поля может не быть вовсе.
Пояснение для человека, на языке аккаунта. Показать пользователю можно; разбирать программно — нет: формулировки меняются без предупреждения и кодом ошибки не являются.
dataобязательноеПолезная нагрузка ответа.
object
Полезная нагрузка ответа.
Всегда ready у кода 200 — расчёт готов.
Контентный идентификатор превью (sha256 от текста+шаблона+режима+версии алгоритма). Используйте для инкрементального re-preview (previous_preview_id) и для пагинации (GET .../{previewId}).
summaryобязательноеИтоги по всему тексту — не только по текущей странице чанков.
object
Итоги по всему тексту — не только по текущей странице чанков.
Сколько всего чанков в разбиении.
Суммарная billable-длина по всем чанкам, в символах (паузы и указания диктору не считаются).
Суммарная стоимость в токенах — та же величина, что спишет POST /orders за идентичный текст.
Фактически озвучиваемая длина ДО добора до минимального тарифицируемого объёма — для честного показа «сколько символов».
Минимальный тарифицируемый объём (0 — минимума нет). Если voiced_length меньше этого порога, стоимость всё равно посчитана по порогу.
Число пауз в тексте ({{pause}}/<break/>). Паузы бесплатны — в стоимость не входят.
Суммарная длительность тишины, секунды.
Санитарные капы заказа не превышены. false НЕ роняет превью (в отличие от POST /orders, где то же самое даёт 422) — только предупреждает.
Какой именно кап превышен: count (пауз больше 500), single (одна пауза длиннее 10с), total (суммарная тишина больше 3600с) или chunks (заказ даёт больше 1500 фрагментов — столько система не соберёт в один файл). null — капы в порядке.
В тексте не осталось ничего произносимого (только теги/паузы/скобочные ремарки). POST /orders с таким текстом вернёт 422.
Индексы чанков, чей текст уже отбивался контентной политикой и лежит в блоклисте. Пустой массив — блокировок нет.
Есть ли хотя бы один заблокированный чанк — то же самое, что blocked_chunks !== [], в булевом виде для удобства.
paragraphsобязательноеnull — превью не абзацное (то же значение generation_mode, что и в заказе, отвечает за это поле). В абзацном режиме — агрегат по каждому абзацу.
может быть nullarray<object>
null — превью не абзацное (то же значение generation_mode, что и в заказе, отвечает за это поле). В абзацном режиме — агрегат по каждому абзацу.
Порядковый номер абзаца, с нуля.
Сколько чанков внутри этого абзаца (длинный абзац может занять несколько чанков).
Сквозной index первого чанка абзаца — по нему абзац находится в постраничном data.chunks, даже если его чанки попали на другую страницу.
Сырая длина текста абзаца в символах, включая теги/паузы.
Billable-длина абзаца — минимальный тарифицируемый объём в абзацном режиме считается ПО КАЖДОМУ абзацу отдельно, поэтому короткие абзацы могут стоить дороже, чем тот же текст, разрезанный сплошняком.
Стоимость абзаца в токенах.
Число абзацев, или null вне абзацного режима. Остаётся числом даже когда paragraphs схлопнут по WS-капу.
Стоимость в LMC (валюто-независимая база). Поле может ОТСУТСТВОВАТЬ (не null), если денежный якорь не удалось посчитать (best-effort, не критично для превью).
Стоимость, пересчитанная в валюту отображения аккаунта — та же мультивалютная разбивка, что и в остальном публичном API (amount/amount_formatted по коду валюты). Поле может ОТСУТСТВОВАТЬ, если cost_lmc не посчитан или курс недоступен.
chunksобязательноеТолько ТЕКУЩАЯ страница (см. data.page), не весь список — используйте пагинацию (GET .../{previewId}?page=) для остальных.
array<object>
Только ТЕКУЩАЯ страница (см. data.page), не весь список — используйте пагинацию (GET .../{previewId}?page=) для остальных.
Сквозной номер чанка по всему тексту (не сбрасывается на границах абзацев).
Текст чанка ровно в том виде, в каком его получит voice-провайдер.
Начало чанка в НОРМАЛИЗОВАННОМ входном тексте (символьное смещение). Нормализация — та же, что применяет POST /orders перед резом.
Конец чанка в нормализованном тексте (полуинтервал: end не входит в чанк).
Сырая длина текста чанка в символах, ВКЛЮЧАЯ теги/паузы.
Billable-длина чанка (без пауз, после добора до минимума при его наличии) — сумма по всем чанкам страницы не обязана совпадать с total_effective_length (та считается по ВСЕМ чанкам, не только странице).
Стоимость чанка в токенах.
Номер абзаца, которому принадлежит чанк, или null вне абзацного режима.
pageобязательноеМета пагинации ТЕКУЩЕЙ страницы data.chunks.
object
Мета пагинации ТЕКУЩЕЙ страницы data.chunks.
Номер текущей страницы, считая с 1.
Размер страницы (сколько чанков запрошено/использовано по умолчанию).
Всего чанков в разбиении (по всем страницам).
Есть ли ещё страницы после текущей.
202status=processing: расчёт в фоне, вернётся preview_id (результат — WS .ready)
status=processing: расчёт в фоне, вернётся preview_id (результат — WS .ready)
"string"Признак успеха. Решение принимайте по HTTP-коду: у любого ответа 2xx здесь true, а ошибка приходит телом другой формы, где этого поля может не быть вовсе.
Пояснение для человека, на языке аккаунта. Показать пользователю можно; разбирать программно — нет: формулировки меняются без предупреждения и кодом ошибки не являются.
dataобязательноеПолезная нагрузка ответа.
object
Полезная нагрузка ответа.
Всегда processing у кода 202 — расчёт идёт в фоне.
Идентификатор превью. Используйте для подписки на WS-канал private-chunks.preview.{userId} (событие .ready) либо для ручного поллинга GET /orders/chunks/preview/{previewId}.
401Невалидный или отсутствующий X-API-KEY
Невалидный или отсутствующий X-API-KEY
{
"success": false,
"message": "API key is missing. Provide it in the X-API-KEY header.",
"data": null
}Всегда false в ответах об ошибке.
Текст ошибки на языке ключа (задаётся заголовком X-Locale).
Всегда null, когда запрос отклонён до обработки.
403У ключа нет права orders.read
У ключа нет права orders.read
{
"success": false,
"message": "This API key does not have permission to perform this action."
}Всегда false в ответах об ошибке.
Текст ошибки на языке ключа (задаётся заголовком X-Locale).
422Ошибка валидации (input_text обязателен) или reason=template_model_outdated — шаблон или config_override несут настройки прежней схемы сервиса, как у создания заказа
Ошибка валидации (input_text обязателен) или reason=template_model_outdated — шаблон или config_override несут настройки прежней схемы сервиса, как у создания заказа
{
"message": "string",
"errors": {
"key": [
"string"
]
}
}Errors overview.
errorsобязательноеA detailed description of each field that failed validation.
object
A detailed description of each field that failed validation.
429Превышен лимит запросов preview для этого ключа
Превышен лимит запросов preview для этого ключа
{
"success": false,
"message": "Too many attempts. Please wait a moment and try again.",
"reason": "rate_limit_exceeded",
"error_code": "rate_limit_exceeded",
"retry_after": 30
}Всегда false в ответах об ошибке.
Текст ошибки на языке ключа (задаётся заголовком X-Locale).
Машиночитаемая причина отказа — по ней ветвите обработку, а не по тексту сообщения.
Тот же машинный код, что в reason, — второе имя поля. Значения всегда совпадают; ветвитесь по любому из них.
Через сколько секунд имеет смысл повторить запрос (то же значение — в заголовке Retry-After).
События, которые это порождает
Ход выполнения приезжает по WebSocket: опрашивать заказ в цикле не обязательно. Подписка требует того же права, что и чтение заказов.
Рядом
Об этом словами
Соседние операции
Скормить страницу ИИ
спека 0.0.1