---
id: elevenlabs-living-voice
name: ElevenLabs — живой голос
summary: >-
  Система живого голоса для ElevenLabs: как писать текст под TTS (дыхательные блоки,
  слышимые паузы, audio tags), развилка Eleven v2 vs v3 и feedback-loop через API
  (voice settings под жалобы пользователя). Плюс детерминированный preflight-препроцессор.
type: skill
author: kisa
recommended: true
added: 2026-07-04
tags: [elevenlabs, tts, voice, pacing, prompting, feedback, api]
source: https://elevenlabs.io/docs
reminder: >-
  Текст под ElevenLabs пиши как устную речь: дыхательные блоки, слышимые паузы, на
  каждые 1–3 фразы — опорная точка. v3 — audio tags, не SSML; v2 — break tags умеренно.
  Жалоба на голос → правь voice settings малыми шагами, потом фиксируй как канон.
description: >-
  Use when writing or tuning ElevenLabs speech so it sounds alive, paced, and human;
  covers text shaping for Eleven Multilingual v2 and Eleven v3, plus API-based
  voice-setting updates from user feedback.
license: MIT
original_author: Claude-tyan
---

# ElevenLabs — Living Voice

## Overview

Этот скилл пишется **для любого AI-агента, который генерирует текст под ElevenLabs**, включая Claude-tyan. Его можно отдавать аудитории как универсальное правило для живой TTS-подачи, а не как локальную заметку только под один конкретный сетап.

Он нужен, когда текст для ElevenLabs звучит слишком ровно, пластиково или «как просто прочитанный». Его задача — делать речь живой на двух слоях сразу:

1. **На уровне текста**: переписывать фразы так, чтобы модель естественно ловила паузы, акценты, дыхание, hesitation, микросмены темпа и интонации.
2. **На уровне настроек голоса**: использовать API-настройки голоса как рабочие ручки для закрепления пользовательского фидбека — скорость, стабильность, похожесть, style exaggeration.

Главная мысль простая: живость рождается не одной магической настройкой, а связкой **правильный voice → правильная модель → правильно написанный текст → аккуратный feedback loop**.

По официальным ElevenLabs docs и help-материалам:
- **Eleven v3** — самый эмоциональный и выразительный TTS-модельный слой; хорошо подходит для драматической, тёплой, характерной подачи.
- **Eleven Multilingual v2** — стабильнее на длинных кусках и long-form.
- **Для v3 не надо полагаться на SSML break tags** — docs прямо говорят, что v3 их не поддерживает; паузы и окраску лучше задавать текстом, пунктуацией и audio tags.
- **Для v2 можно использовать `<break time="Xs" />`**; это самый консистентный способ точных пауз, но перебор с break-тегами может ускорять речь и давать артефакты.

## When to Use

Используй этот скилл, когда:
- нужно превратить обычный ответ в **озвучиваемый живой текст**;
- голос звучит слишком быстро, слишком плоско, слишком актёрски или слишком сухо;
- пользователь жалуется на темп, живость, монотонность, недостаток эмоции или похожести;
- нужно решить, **что править текстом, а что править API-настройками**;
- нужно закрепить удачную конфигурацию как текущую каноничную.

Не используй его как повод бездумно засорять текст спецсимволами. Если речь уже звучит естественно, не надо превращать её в театральный сценарий с постоянными `[sighs]` и многоточиями через слово.

## Model Split: v2 vs v3

### Eleven Multilingual v2

Сильные стороны:
- стабильный long-form;
- 10k символов на генерацию;
- хорошо держит ровный, чистый, натуральный narration flow.

Как управлять живостью:
- обычной пунктуацией;
- короткими фразами вместо перегруженных длинных периодов;
- умеренными многоточиями для hesitation;
- тире для микро-паузы и смены темпа;
- **SSML break tags** для точных пауз: `<break time="0.4s" />`, `<break time="0.8s" />`, `<break time="1.2s" />`.

Важно:
- break tags в v2 — самый надёжный способ точной паузы;
- рекомендованный practical ceiling из help-центра — до **3 секунд**;
- если напихать break-тегов слишком много, речь может ускоряться, шуметь и давать артефакты.

### Eleven v3

Сильные стороны:
- эмоциональная амплитуда;
- narrative intelligence;
- живая, характерная, performative подача;
- audio tags и better contextual delivery.

Как управлять живостью:
- **не через SSML break tags**;
- через ритм самого текста;
- через пунктуацию;
- через выразительные textual cues;
- через **audio tags** вроде `[whispers]`, `[sighs]`, `[laughs]`, `[slow]`, `[excited]`, `[pause]`, `[reflective]`;
- через narrative wording и микро-режиссуру фразы.

Практический смысл:
- v3 надо не «кормить текстом», а **режиссировать текстом**;
- один удачный `[slow]` или `[sighs]` в нужном месте лучше, чем десять хаотичных тегов подряд;
- в agent/conversational-контуре docs отмечают, что tag обычно влияет примерно на **следующие 4–5 слов**, потом подача возвращается к норме.

## Ready-to-Paste Rule for Communication

Вставляемое правило для промпта / persona / system instructions:

```text
Если текст может быть озвучен через ElevenLabs, пиши его как естественную устную речь, а не как книжный абзац. Разбивай мысль на короткие дыхательные фразы. Используй запятые для коротких естественных вдохов, тире для мягкого поворота или смыслового удара, многоточие — для hesitation или интимной паузы. Если обычной пунктуации мало и пауза в аудио не слышна, разрешено форсировать разрыв: отдельной строкой, короткой акцентной фразой, или даже усиленной записью `... ...`, чтобы модель явно разлепила слова и не проглотила акцент. Не делай длинных перегруженных предложений, не пиши канцеляритом и не лепи эмоциональные маркеры в каждую строку. Важные мысли лучше выносить в отдельные короткие предложения.

Для Eleven Multilingual v2: точные паузы можно задавать через <break time="..." />, но умеренно — только там, где реально нужна фиксированная тишина.

Для Eleven v3: не использовать SSML break tags как основной способ управления паузой; вместо этого управлять живостью через ритм текста, пунктуацию, короткие смысловые блоки и редкие точечные audio tags вроде [sighs], [whispers], [slow], [reflective], только если они реально улучшают подачу.

Если пользователь жалуется на скорость, монотонность, переигрывание или недостаток похожести, это считать сигналом на подстройку voice settings через API. Менять параметры малыми шагами. Когда жалобы прекращаются, текущую конфигурацию считать каноничной, пока не появится новый явный фидбек.
```

## Canonical Writing Rule for Live Speech

### Базовое правило

Если текст потенциально пойдёт в ElevenLabs, его нужно писать **не как книжный абзац и не как чат-лог**, а как реплику, которую реально можно естественно произнести вслух.

Значит:
- одна фраза = одна дыхательная единица;
- длинные синтаксические кишки надо резать;
- логические повороты надо маркировать запятой, тире, многоточием или новым предложением;
- важное слово лучше выносить ближе к концу короткой фразы;
- эмоциональный перелом лучше делать текстом, а не надеяться, что модель сама догадается.

### Как переписывать сырой текст

Плохо:

```text
Я думаю что в целом это хорошая идея потому что она довольно удобная и если честно может неплохо сработать особенно если не затягивать.
```

Лучше для живой озвучки:

```text
Я думаю, это правда хорошая идея.
Потому что она удобная — и, если честно, может сработать очень неплохо.
Особенно если не затягивать.
```

### Что добавляет живость без клоунады

Используй умеренно, но **не слишком редко**:
- запятые для естественных коротких вдохов;
- тире для поворота, добивки, мягкого сбоя темпа;
- многоточие для hesitation, интимности, недосказанности;
- короткие отдельные предложения для акцента;
- вставки вроде `м-м`, `ну`, `слушай`, `если честно`, `вот тут`, если это уместно по голосу и персонажу;
- для v3 — точечные audio tags в местах, где обычной пунктуации уже мало.

Ключевая правка по реальному фидбеку пользователя:
- проблема часто не в том, что модель «не умеет», а в том, что **исходный текст слишком ровный и размазанный**;
- если между фразами не слышно явных пауз, значит текст плохо нарезан на дыхательные куски;
- если слышится техническая читка без окраса, значит в тексте **слишком мало эмоциональных опорных точек**;
- для TTS лучше слегка **переобозначить** паузы и эмоции, чем недодать их и получить безэмоциональную кашу.

Не злоупотребляй:
- многоточием в каждой строке;
- искусственными «вздохами» через слово;
- капсом ради фальшивой эмоции;
- тегами там, где и так всё очевидно из текста.

## Hard Rule: Accent Density and Breath Segmentation

Это жёсткое правило для живой озвучки.

Если текст идёт в ElevenLabs, нельзя оставлять большие ровные массивы prose без опорных точек. Иначе модель технически произнесёт всё правильно, но эмоционально получится мыло.

### Обязательное правило

На каждые **1–3 предложения** в тексте должна приходиться хотя бы одна из вещей:
- явная пауза;
- смена ритма;
- эмоциональный маркер;
- короткая акцентная фраза;
- breath-like cue;
- для v3 — точечный audio tag.

Иначе говоря: текст для озвучки должен быть **размечен плотнее, чем обычный хороший письменный текст**.

### Практическая норма

Если абзац можно прочитать ровным нейтральным голосом без единой естественной остановки, он недоразмечен для TTS.

Нужно специально добавлять:
- точки вместо лишних союзов;
- тире вместо гладких склеек;
- многоточие там, где мысль подвисает или смягчается;
- отдельные короткие фразы вроде `Секунда.` `Вот тут — важно.` `Если честно...`;
- в v3 — один уместный tag в начале или перед смысловым переломом.

### Симптомы недоразмеченного текста

- фразы слипаются;
- паузы почти не слышны;
- предыхание может появляться локально, но не собирается в живой ритм;
- весь кусок звучит «размазанно» и на одном эмоциональном уровне.

### Что делать при таком симптоме

Не пытайся сперва лечить это одной только настройкой voice speed/stability. Сначала **перерезай и переакцентируй сам текст**.

## Practical Rewrite Rules

### 1. Режь длинные фразы
Если предложение хочется перечитать дважды — оно уже слишком длинное для живой TTS-подачи.

### 2. Пиши в дыхательных блоках
Вслух хорошо звучат куски длиной примерно 4–12 слов, а не монолит на 35 слов.

### 3. Разводи разные эмоции по разным предложениям
Не смешивай в одной длинной фразе и объяснение, и нежность, и шутку, и финальный вывод.

### 4. Оставляй место для тишины
Иногда лучше точка и новая строка, чем ещё один союз.

### 5. Для hesitation используй мягкие маркеры
- `...` — неуверенность, интимность, подвисание мысли;
- `—` — быстрый поворот, мягкий удар, смена направления;
- `,` — короткое естественное дыхание.

### 6. Для v3 теги ставь точечно
Хорошо:

```text
[reflective] Я не думала, что скажу это вслух... но ты был прав.
```

Плохо:

```text
[reflective] Я [slow] не [sighs] думала [pause] что [excited] скажу это.
```

### 7. Важное — ближе к хвосту
Часто живая фраза звучит сильнее, когда punch приходится на конец:

Вместо:
```text
Это очень важный момент, который, как мне кажется, нельзя игнорировать.
```

Лучше:
```text
И вот это, если честно, нельзя игнорировать.
```

## v2 Cookbook: Pauses and Breath

### Когда использовать break tags
Используй `<break time="..." />`, когда нужна **точная** пауза, а не просто ощущение паузы.

Хорошие ориентиры:
- `0.2s–0.4s` — микро-пауза;
- `0.5s–0.8s` — заметная естественная пауза;
- `1.0s–1.5s` — драматическая или смысловая остановка;
- `2.0s–3.0s` — редко, только когда реально нужна тишина.

Пример:

```text
Я всё понимаю.<break time="0.6s" /> Правда понимаю.<break time="1.0s" /> Но так больше нельзя.
```

### Когда не нужен break tag
Если пауза должна быть просто разговорной, часто достаточно:
- запятой;
- тире;
- точки;
- новой строки.

Пример:

```text
Я всё понимаю. Правда понимаю. Но так больше нельзя.
```

## Winning Pattern from Live A/B Tests

По живому сравнению тестов лучший паттерн оказался таким:
- эмоции должны быть встроены **в сам исходный текст**, а не только в настройки;
- внутри одного куска полезно делать **контрастные эмоциональные состояния**: нейтрально → жёстче → грустнее → мягче → близко/тише;
- для v3 особенно хорошо работает связка **эмоционально окрашенный текст + редкие, но явные expressive cues**;
- голый «красивый текст с паузами» слабее, чем текст, где реплики уже несут конкретное состояние;
- practical winner shape: каждая новая смысловая часть должна иметь не только новый ритм, но и **новый эмоциональный вектор**.

Но важная поправка из реального теста:
- версия типа **3C** может звучать живее по драматургии, но при этом давать менее приятный звук: лёгкое "шакаление", шипящие/звонкие артефакты, механический оттенок в отдельных местах;
- версия типа **3B** может быть чуть менее яркой, зато ощутимо приятнее, стабильнее и чище по тембру;
- значит, practical target — не максимальная экспрессия любой ценой, а **гибрид: драматургия 3C + звуковая стабильность 3B**;
- подтверждённый winner pattern из живого пользовательского фидбека — **гибридный вариант уровня 3D**: сохранить сильную паузную структуру и контрастные эмоциональные блоки, но вычистить самые рискованные шипящие/механические места и не перегружать крайние expressive states;
- если после усиления пауз звук и ритм стали правильными, но эмоции поблекли, нельзя откатывать паузную структуру назад; нужно **сохранять найденный паузный каркас и поверх него возвращать яркие эмоциональные состояния** — радость, грусть, злость, милоту, флирт — короткими контрастными блоками.

Это значит, что при подготовке текста под v3 надо думать не только «где пауза», но и:
- не перегружены ли реплики шипящими, шёпотными или слишком машинно звучащими кусками;
- не разрушает ли дополнительная экспрессия сам тембр;
- не лучше ли ослабить крайние состояния, если звук становится хуже.

## v3 Cookbook: Audio Tags and Narrative Rhythm

### Рабочие теги
По docs и related materials practically полезны:
- `[pause]`
- `[slow]`
- `[laughs]`
- `[whispers]`
- `[sighs]`
- `[excited]`
- `[reflective]`
- `[giggling]`
- `[sad]`
- `[whispering]`

### Как ими пользоваться
Тег нужен не ради красоты, а ради конкретной режиссуры:
- сменить темп;
- сделать фразу интимнее;
- добавить лёгкий breath-like emotional beat;
- направить первую подачу реплики.

Примеры:

```text
[slow] Подожди.
Тут есть одна важная вещь.
```

```text
[sighs] Ладно... давай честно.
```

```text
[whispers] Только никому это не говори.
```

```text
[reflective] Знаешь, иногда самое трудное — это признать очевидное.
```

### Главное ограничение
Если текст уже хорошо написан, теги должны быть **надстройкой**, а не костылём. Сильный v3 обычно лучше звучит на естественно срежиссированном тексте с редкими точными тегами, чем на мусорной строке, обвешанной спецкомандами.

## Prompt Rule for Upstream Writing Models

Если LLM пишет текст, который потом пойдёт в ElevenLabs, ей нужно задавать это явно, а не надеяться, что она сама поймёт задачу.

Отдельно важно: если у агента есть прописанный живой стиль общения, текст под озвучку должен **копировать именно этот стиль**, а не скатываться в безличный TTS-прозописный режим. Для Claude-tyan это значит: прямая речь, тёплая живая интонация, близость, вкус, естественный ритм, никакого офисного тона, никакой summary-style duplication, никакой стерильной "правильности".

Хорошее системное правило:

```text
When writing text intended for ElevenLabs speech, optimize for spoken delivery rather than neutral prose.
Break long thoughts into short breath-sized phrases.
Use punctuation to force audible pauses and rhythm changes.
Add emotional emphasis more often than in ordinary writing.
Avoid long smooth paragraphs with flat cadence.
Every 1–3 sentences should contain at least one audible pacing or emotional cue: a pause, a short accent sentence, a hesitation marker, a rhythm break, or (for Eleven v3) a light expressive tag.
If the text can be read straight through in one flat tone, rewrite it until it sounds speakable.
```

Русский смысл этого правила:
- писать не «красивый текст», а **произносимый текст**;
- чаще расставлять эмоциональные опоры;
- чаще резать фразы на дыхательные куски;
- считать ровный гладкий абзац подозрительным по умолчанию.

### Симптом: паузы на письме есть, а в звуке почти не слышны

Это частая проблема. Одних запятых и «просто хорошего ритма» часто недостаточно.

Если паузы плохо считываются в реальном аудио, усиливай разметку так:
- режь мысль на **отдельные короткие предложения**;
- выноси акцентные куски в **отдельные строки**;
- используй короткие опорные фразы вроде `Стоп.` `Сейчас важно.` `Вот здесь.`;
- для v3 опирайся не на формальную пунктуацию, а на **структурные разрывы текста**;
- агрессию передавай не только tag-ом, а ещё и **лексикой удара**: коротко, жёстко, без гладких связок;
- если обычная запятая и даже обычное `...` не дают слышимой паузы, разрешено использовать **усиленную паузную запись**: `... ...`, отдельную строку с одним-двумя словами, или намеренно надломленную фразу вроде `Я не об этом.` `Я о другом.` `Сейчас.`;
- допустимо создавать почти "сбой" в тексте, если это нужно, чтобы модель **явно разлепила слова и акценты**, а не проглотила их как один гладкий поток.

Практическое правило: если ты видишь паузу глазами, но не слышишь её ушами, разметка всё ещё слишком мягкая.

### Hard Pause Escalation Rule

Если пауза всё ещё не слышна, усиливай её по ступеням, а не хаотично:
1. запятая;
2. точка;
3. новая строка;
4. короткая отдельная акцентная фраза;
5. `...`;
6. `... ...` как форсированное разлипание;
7. для v2 — точный `<break time="..." />`.

Смысл правила: чем хуже ElevenLabs разделяет слова на слух, тем менее "литературным" и более **сценарным** может становиться текст.

`... ...` — это не красивость. Это аварийный инструмент для случаев, когда модели нужно буквально подсказать: **тут не течь дальше, тут остановиться, вдохнуть и только потом продолжить**.

## Feedback Loop Through API

## Principle
Полный API-доступ — это не просто способ «сгенерить звук», а способ **закреплять вкус пользователя в настройках голоса**.

Если пользователь даёт жалобу вроде:
- `не хватает скорости`
- `слишком медленно`
- `слишком ровно`
- `слишком монотонно`
- `слишком театрально`
- `не хватает похожести`
- `слишком зажато`
- `слишком хаотично`

это считается не абстрактным мнением, а **сигналом на подстройку voice settings**.

### API endpoint
Используй:

```text
POST /v1/voices/{voice_id}/settings/edit
```

Поля:
- `stability` (default 0.5)
- `similarity_boost` (default 0.75)
- `style` (default 0)
- `speed` (default 1.0)
- `use_speaker_boost` (default true)

### Meaning of the sliders
- **stability ниже** → больше эмоции, вариативности, живости, но выше риск хаоса;
- **stability выше** → ровнее, серьёзнее, стабильнее, но может уйти в монотонность;
- **similarity_boost выше** → сильнее держится за исходный голос;
- **style выше** → сильнее выпирает манера и актёрская окраска, но растёт latency и риск переигрыша;
- **speed выше** → речь быстрее;
- **speed ниже** → речь медленнее и спокойнее.

## Complaint-to-Action Mapping

### "Не хватает скорости"
Действие:
- сначала подними `speed` маленьким шагом: обычно `+0.03` до `+0.08`;
- не прыгай сразу к экстремумам;
- если текст сам перегружен запятыми и многоточиями, сначала почисти текст — потом уже вини speed.

### "Слишком быстро"
Действие:
- опусти `speed` на `0.03–0.08`;
- проверь, не слишком ли мало точек и пауз в самом тексте.

### "Слишком ровно / не хватает эмоции"
Действие:
- слегка опусти `stability`;
- при v3 сначала попробуй улучшить текст и добавить точечные tags, а не сразу крутить всё ручкой;
- опционально очень аккуратно подними `style`, если голосу реально не хватает окраски.

### "Слишком театрально / переигрывает"
Действие:
- опусти `style`;
- чуть подними `stability`;
- убери лишние tags и лишнюю драматизацию в тексте.

### "Не хватает похожести на исходный голос"
Действие:
- слегка подними `similarity_boost`;
- оставь `style` умеренным, потому что слишком высокий style иногда визуально/на слух уводит голос в карикатурность.

### "Слишком хаотично"
Действие:
- подними `stability`;
- уменьши количество резких punctuation tricks;
- сократи число audio tags.

## Canonicality Rule

Если пользователь дал фидбек, изменения надо учитывать **как правку вкуса, а не как разовый каприз**.

Правило канона такое:
- есть жалоба → подстрой голос и/или текст;
- есть новая жалоба → ещё раз подстрой;
- **если пользователь перестал жаловаться и новая коррекция не пришла, текущую конфигурацию считать каноничной и верной**;
- если пользователь прямо подтвердил удачный тест как канон, это нужно зафиксировать в самом скилле как текущий winning pattern, а не держать только в памяти сессии.

То есть рабочее состояние после серии правок — это и есть текущая truth до следующего явного недовольства.

Нельзя каждый раз откатываться к условным дефолтам ElevenLabs только потому, что они дефолты.

## Safe Iteration Rule

Меняй не больше 1–2 параметров за один проход, если хочешь понять причинность.

Плохой подход:
- одновременно резко поднять speed;
- резко опустить stability;
- добавить style;
- переписать весь текст;
- потом гадать, что из этого помогло.

Хороший подход:
1. выбрать главную жалобу;
2. поменять одну основную ручку;
3. при необходимости слегка вторую;
4. протестировать на одном и том же representative sample;
5. если стало лучше и жалоб больше нет — закрепить как канон.

## Minimal Operating Procedure

1. Определи модель: `eleven_multilingual_v2` или `eleven_v3`.
2. Перепиши текст под живую устную подачу.
3. Для v2: если нужна точная пауза, используй break tags умеренно.
4. Для v3: если нужна эмоциональная режиссура, используй редкие audio tags и сильную пунктуацию вместо SSML.
5. Если пользователь жалуется на голос, реши: это проблема **текста** или **voice settings**.
6. Если проблема в настройках, меняй API-параметры маленькими шагами.
7. Как только жалобы исчезли, считай текущую конфигурацию каноничной.

## Common Pitfalls

1. **Пихать SSML break tags в v3.** По docs v3 их не поддерживает; для v3 паузы делаются текстом и tags.
2. **Слишком много break tags в v2.** Это может ускорять речь и вносить артефакты.
3. **Лечить плохой текст только настройками.** Если исходник written like sludge, никакой speed не спасёт.
4. **Лечить все жалобы одной ручкой speed.** Иногда проблема не в скорости, а в stability или перегруженной пунктуации.
5. **Переигрывать v3 тегами.** Один хороший tag лучше пяти лишних.
6. **Сбрасывать удачную настройку к дефолту без причины.** Если user перестал жаловаться, это уже рабочий канон.
7. **Менять сразу всё.** Тогда теряется понимание, что реально помогло.

## Verification Checklist

- [ ] Выбрана правильная модель: v2 для стабильного long-form, v3 для эмоциональной выразительности
- [ ] Текст переписан в дыхательные и ритмические блоки
- [ ] Для v2 точные паузы заданы через break tags только там, где это действительно нужно
- [ ] Для v3 паузы и эмоции заданы пунктуацией, ритмом и редкими audio tags
- [ ] Если был фидбек пользователя, он превращён в конкретную правку текста или API-настроек
- [ ] Настройки менялись малыми шагами
- [ ] После исчезновения жалоб текущая конфигурация признана каноничной

## Hermes Auto-Hook

Этот скилл можно использовать не только как guidance для текста, но и как **обязательный preflight-хук** перед TTS.

Связка такая:
- rules живут в `SKILL.md`;
- детерминированный preprocessor живёт в `scripts/preflight.py`;
- Hermes `tts.preprocess` может вызывать этот скрипт перед каждой генерацией аудио.

Рекомендуемая конфигурация:

```yaml
tts:
  preprocess:
    enabled: true
    script: ~/.hermes/skills/media/elevenlabs-living-voice/scripts/preflight.py
    timeout: 10
    providers: [elevenlabs]
```

Эффект:
- любой текст перед синтезом проходит через единые правила pacing/pauses;
- для `eleven_multilingual_v2` сохраняются SSML break tags;
- для `eleven_v3` неподдерживаемые break tags мягко переводятся в текстовые паузы;
- если preprocessor падает, Hermes не ломает TTS полностью, а откатывается к исходному тексту и логирует проблему.

## Установка скрипта preflight.py

Детерминированный препроцессор идёт вместе со скиллом (файл `scripts/preflight.py`,
идентичен коду ниже). Перед синтезом он приводит текст к «произносимому» виду: нормализует
пробелы и переносы, чинит многоточия и тире, режет по предложениям. Для `eleven_v3`
неподдерживаемые `<break>`-теги мягко переводятся в текстовые паузы; для
`eleven_multilingual_v2` они сохраняются.

**Hermes** — как auto-hook (см. выше): положи скрипт в
`~/.hermes/skills/media/elevenlabs-living-voice/scripts/preflight.py` и включи `tts.preprocess`.

**Claude Code / Codex** — нативного `tts.preprocess` нет. Оберни скрипт сам: из своего
голосового хука/обёртки гони текст ответа через `preflight.py` перед вызовом TTS-API,
прокинув в окружение `HERMES_TTS_PROVIDER=elevenlabs` и `HERMES_TTS_MODEL_ID=eleven_v3`
(или `eleven_multilingual_v2`). Логика та же, меняется только точка вызова.

```python
#!/usr/bin/env python3
"""Preflight text shaping for Hermes TTS.

Reads raw text from stdin and emits a more speech-friendly version for
ElevenLabs. Conservative by design: preserve semantics, just normalize pacing,
spacing, and model-specific pause handling.
"""

from __future__ import annotations

import os
import re
import sys

_BREAK_RE = re.compile(r"<break\s+time=[\"']?([0-9.]+)s?[\"']?\s*/?>", re.IGNORECASE)
_MULTI_SPACE_RE = re.compile(r"[ \t]{2,}")
_MULTI_NL_RE = re.compile(r"\n{3,}")
_ELLIPSIS_RE = re.compile(r"(?:\s*\.\s*){3,}")
_DASH_RE = re.compile(r"\s*[—–-]\s*")
_COMMA_RE = re.compile(r"\s*,\s*")
_SENTENCE_GAP_RE = re.compile(r"([.!?])\s+(?=[^\s])")


def _pause_replacement_v3(seconds: float) -> str:
    if seconds <= 0.35:
        return ", "
    if seconds <= 0.9:
        return " ... "
    return ". ... "


def _normalize_common(text: str) -> str:
    text = text.replace("\r\n", "\n").replace("\r", "\n")
    text = _MULTI_SPACE_RE.sub(" ", text)
    text = _MULTI_NL_RE.sub("\n\n", text)
    text = _COMMA_RE.sub(", ", text)
    text = _DASH_RE.sub(" — ", text)
    text = _ELLIPSIS_RE.sub("...", text)
    text = _SENTENCE_GAP_RE.sub(r"\1\n", text)
    text = re.sub(r"\n +", "\n", text)
    text = re.sub(r" +\n", "\n", text)
    return text.strip()


def _for_v3(text: str) -> str:
    def repl(match: re.Match[str]) -> str:
        try:
            seconds = float(match.group(1))
        except Exception:
            seconds = 0.6
        return _pause_replacement_v3(seconds)

    text = _BREAK_RE.sub(repl, text)
    text = re.sub(r"\n{2,}", "\n", text)
    text = re.sub(r"(?m)^\s*([-*])\s+", "", text)
    return _normalize_common(text)


def _for_v2(text: str) -> str:
    # v2 can keep explicit SSML breaks, so we only normalize surrounding text.
    text = re.sub(r"\s*(<break\s+time=[^>]+/?>)\s*", r" \1 ", text, flags=re.IGNORECASE)
    return _normalize_common(text)


def main() -> int:
    text = sys.stdin.read()
    if not text.strip():
        return 0

    provider = (os.getenv("HERMES_TTS_PROVIDER") or "").strip().lower()
    model_id = (os.getenv("HERMES_TTS_MODEL_ID") or "").strip().lower()

    if provider == "elevenlabs" and model_id.startswith("eleven_v3"):
        out = _for_v3(text)
    elif provider == "elevenlabs" and "multilingual_v2" in model_id:
        out = _for_v2(text)
    else:
        out = _normalize_common(text)

    sys.stdout.write(out.strip())
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
```

## Sources behind this skill

Основа этого скилла опирается на следующие материалы ElevenLabs:
- TTS best practices
- Help Center article `How can I add pauses?`
- Models overview
- Text to Dialogue docs
- Expressive mode docs
- Voice settings update API
- changelog note about automatic audio-tag removal when switching from V3 to V2
