# 010 - Milionar TTS

**Status:** COMPLETED
**Updated:** 2026-02-22 23:25

---

## Ucel

Text-to-speech pro hru Milionar. AI hlas cte otazky, odpovedi a feedback jako TV moderator. Podporuje OpenAI (gpt-4o-mini-tts) a ElevenLabs (flash v2.5, v3).

---

## File Map

| Soubor | Radku | Role |
|--------|-------|------|
| [millionaire_tts.py](file:///Users/chudy/Library/Application%20Support/Kodi/addons/plugin.video.milionar/wcs/games/millionaire_tts.py) | 330 | Orchestrace -- compose text + play |
| [TTSClient.py](file:///Users/chudy/Library/Application%20Support/Kodi/addons/plugin.video.milionar/wcs/ai/TTSClient.py) | 76 | OpenAI TTS API klient |
| [ElevenLabsTTSClient.py](file:///Users/chudy/Library/Application%20Support/Kodi/addons/plugin.video.milionar/wcs/ai/ElevenLabsTTSClient.py) | 112 | ElevenLabs TTS API klient |
| [moderator_styles/](file:///Users/chudy/Library/Application%20Support/Kodi/addons/plugin.video.milionar/wcs/games/moderator_styles) | 5 SKILL.md | TTS instrukce per styl |

---

## Architektura

```
MillionaireGameController
    |-- tts_welcome(welcome_text, rules_text)
    |-- tts_question(moderator_intro, question_text, options)
    |-- tts_feedback(result_text, transition_text, explanation)
    |
    v
millionaire_tts.py (orchestrace)
    |-- _load_tts_settings() → nacte co je zapnute
    |-- compose_*_tts() → sestavi text z enabled casti
    |-- play_tts(text) → background thread
    |
    v
TTSClient.generate_tts() NEBO ElevenLabsTTSClient.generate_tts()
    |
    v
WAV/MP3 soubor → xbmc.Player().play()
```

---

## Nastaveni (addon settings)

### Provider

| Setting ID | Typ | Popis |
|------------|-----|-------|
| `milionar_tts_provider` | string | `openai` / `elevenlabs` |

### OpenAI

| Setting ID | Typ | Popis |
|------------|-----|-------|
| `openai_api_key` | string | API klic |
| `milionar_tts_model` | string | Model (default `gpt-4o-mini-tts-2025-03-20`) |
| `milionar_tts_voice` | string | Hlas (`alloy`, `echo`, `fable`, `onyx`, `nova`, `shimmer`) |

### ElevenLabs

| Setting ID | Typ | Popis |
|------------|-----|-------|
| `milionar_tts_elevenlabs_api_key` | string | API klic |
| `milionar_tts_elevenlabs_model` | string | `eleven_flash_v2_5` nebo `eleven_v3` |
| `milionar_tts_elevenlabs_voice` | string | `Adam`, `Rachel`, `Antoni`, `Josh`, `Charlotte`, `Aria` |

### Co se cte (granularni)

| Setting ID | Bool | Popis |
|------------|------|-------|
| `milionar_tts_question_intro` | true | Moderator uvod k otazce |
| `milionar_tts_question_text` | true | Text otazky |
| `milionar_tts_question_options` | true | Cteni moznosti A-D |
| `milionar_tts_feedback_result` | true | Vysledek (spravne/spatne) |
| `milionar_tts_feedback_transition` | true | Prechodovy text |
| `milionar_tts_welcome` | true | Uvitaci text |

---

## Klicova rozhrani

### millionaire_tts.py -- high-level triggery

```python
tts_welcome(welcome_text, rules_text="")
tts_question(moderator_intro, question_text, options)
tts_feedback(result_text, transition_text, explanation="")
play_tts(text)                    # Low-level: spusti TTS v background threadu
stop_tts()                        # Zastavi prehravani
is_tts_playing()                  # Kontrola stavu
wait_for_tts_completion(timeout=30)  # Blokuje do dokonceni (pro autoplay)
```

### Compose funkce (interni)

```python
compose_question_tts(settings, moderator_intro, question_text, options)
compose_feedback_tts(settings, result_text, transition_text, explanation)
compose_welcome_tts(settings, welcome_text, rules_text)
```

Compose spoji jen enabled casti s prirozenyma pauzama (tecky, carky).

### Option formatting styles (nahodne vybrane)

4 styly how options are read:
1. `"A: odpoved, B: odpoved, C: odpoved, D: odpoved"` (cteni pismen)
2. `"odpoved, odpoved, odpoved, odpoved"` (bez pismen)
3. `"Za A: ..., Za B: ..., Za C: ..., Za D: ..."` (formalni)
4. `"A jako odpoved, B jako odpoved, ..."` (konverzacni)

### TTSClient.py (OpenAI)

```python
generate_tts(question_text, voice="alloy", style=None, instructions=None, language="cz")
# → vraci cestu k WAV: special://temp/tts_milionar.wav
```

- Model: z nastaveni `milionar_tts_model`
- Instructions: z `moderator_styles.get_tts_instructions()` nebo default
- Output: WAV format

### ElevenLabsTTSClient.py

```python
generate_tts(text, voice_name="Adam", model_id="eleven_flash_v2_5")
# → vraci cestu k MP3: special://temp/tts_milionar_el.mp3
```

Voice settings per model:
- `eleven_flash_v2_5`: stability=0.5, similarity=0.75, style=0.0
- `eleven_v3`: stability=0.0 (Creative), similarity=0.75, style=0.45

ElevenLabs v3 podporuje audio tagy: `[excited]`, `[laughs]`, `[pauses]`.
`strip_audio_tags()` je odstraní z UI textu.

---

## Playback mechanismus

1. `play_tts(text)` → daemon thread `_tts_worker()`
2. Nastavi `_tts_active` event
3. Zvoli provider (OpenAI/ElevenLabs) podle nastaveni
4. Zavola `generate_tts()` → stahne audio do temp souboru
5. `xbmc.Player().play(audio_path)` → prehrani
6. Ceka na dokonceni prehravani (polling `isPlaying()`)
7. Clearuje `_tts_active` event

### Autoplay synchronizace

`wait_for_tts_completion(timeout)`:
- Pouziva `_tts_active` event (set v `play_tts`, clear po dokonceni)
- Fallback: `xbmc.Player().isPlaying()` check
- Autoplay ceka na TTS pred odpovedí na otazku

---

## Moderator styles a TTS instrukce

5 stylů v `moderator_styles/`:

| Styl | TTS instrukce (zkracene) |
|------|-------------------------|
| professional | Energetic TV host, build suspense |
| dramatic | Deep dramatic voice, theatrical pauses |
| comedian | Light humorous tone, witty delivery |
| friendly | Warm supportive voice, encouraging |
| mysterious | Low mysterious voice, enigmatic pauses |

`moderator_styles/__init__.py` → `get_tts_instructions()` nacte z vybraneho stylu.

---

## Integrace s Milionarem

| Game state | TTS trigger | Co cte |
|------------|------------|--------|
| Welcome screen | `tts_welcome()` | Moderator uvitani + pravidla |
| Otazka | `tts_question()` | Intro + otazka + moznosti |
| Feedback (spravne) | `tts_feedback()` | Vysledek + prechod na dalsi |
| Game over (spatne) | `tts_feedback()` | Vysledek + vysvetleni |
| Lifeline tip | `play_tts()` | Rada od rezisera |

TTS je vzdy non-blocking (background thread). UI se aktualizuje nezavisle.
