transcript · git:20260914.10e33a4 · 2026-09-14 · sha256 5fc74c5aa902781d

transcript git:20260914.10e33a4A

Immutable. This exact content never changes and is served at /api/v1/blob/5fc74c5aa902781d.

---
name: transcript
description: Skill se použije, když uživatel zadá "/transcript", nebo když chce přepsat zvukové i obrazové nahrávky (MP3, M4A, WAV, AAC, MP4, MOV…) do Markdownu – přepis a strukturované shrnutí schůzky/nahrávky. Přepis běží kompletně lokálně a offline (whisper.cpp). Výsledkem je přepis; má-li se z nahrávky stát trvalá znalost v knowledge base, je na to /learn, který si přepis vyžádá sám.
allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, Agent, AskUserQuestion, Skill]
---

# Transcript

## Co skill dělá

Lokální, offline přepis nahrávek do Markdownu. Nic neopouští počítač (rozpoznání řeči běží přes [whisper.cpp](https://github.com/ggml-org/whisper.cpp)).

Skill se **nespouští s přepínači**. Volá se cestou k souboru a volným popisem:

```
/transcript ~/Desktop/schuzka.m4a Přepiš mi schůzku s Janou Novákovou nad nastavením intranetu
```

Ten volný popis není dekorace. Vytáhneš z něj jména a názvy do slovníku (krok 3), takže **čím konkrétnější popis, tím míň zkomolených jmen**.

Než se pustíš do práce, projdeš s uživatelem krátkého průvodce. Teprve pak se přepisuje.

**Nahrávku, ze které se má stát znalost, umí `/learn` vzít i rovnou** – přepis si od tebe vyžádá sám a **tři otázky průvodce** (co má vzniknout, model, mluvčí) si zodpoví za uživatele, takže je neopakuj. **Všechno ostatní se ptej dál**, i když zadání přišlo odtamtud: jazyk, **jestli je víc nahrávek jedna rozřezaná schůzka**, **datum nahrávky, když mu metadata odporují**, hranici u dvojjazyčné nahrávky, kolizi jmen i existující výstupy v adresáři. Ty odpovědi `/learn` nemá odkud vzít a tichá volba za uživatele by u existujícího přepisu znamenala přepsat starší práci.

**Přepisem to nemusí končit.** Nese-li nahrávka znalost, která má přežít i po tom, co se přepis zapomene – výklad na školení, konzultace, cizí prezentace –, nabídni v závěru `/learn`: zapracuje ji do znalostní báze místo toho, aby zůstala v samostatném souboru na disku.

## Jak je to postavené uvnitř

**Rozpoznávání řeči dělá whisper.cpp, rozlišování mluvčích pyannote a řezání ffmpeg – a všechno tohle je implementační detail, ne rozhraní.** Totéž platí pro rozdělení práce mezi skripty v adresáři skillu (jejich soupis drží *Soubory skillu* níž), pro jména proměnných prostředí, kterými se řídí, i pro naměřená nastavení v [`internals.md`](internals.md). Kdyby whisper nahradil jiný rozpoznávač, skripty se slily do jednoho nebo se přepínač přejmenoval, nikdo mimo tenhle adresář to nemá poznat.

**Závazné je naopak tohle a nesmí se změnit tiše:**

- **Nic neopouští počítač.** Celý přepis běží lokálně a offline; je to důvod, proč skill existuje.
- **Tvar výstupu** – přepis a shrnutí v Markdownu podle *Formát souhrnného MD* a *Pravidla shrnutí* níž.
- **Zdrojová nahrávka zůstává nedotčená.** Skill k ní smí jen číst; mezivýstupy se po dokončení uklidí.
- **Průvodce se ptá, místo aby volil za uživatele** – zvlášť tam, kde by tichá volba přepsala existující přepis.

## Vstup a výstup

- **Vstup:** soubory zadané v promptu. Když prompt žádný soubor neuvádí, vezmi všechny nahrávky v aktuálním adresáři. **Je-li jich víc, nejdřív zjisti, jestli to není jedna schůzka rozřezaná na části** – viz krok 1; pak se spojí a dál se pracuje s jedním souborem. Podporované formáty:
  - **zvuk:** `mp3`, `m4a`, `wav`, `aac`, `flac`, `ogg`, `opus`, `m4b`,
  - **video:** `mp4`, `mov`, `m4v`, `mkv`, `webm`, `avi`.

  Video se nijak neliší – zvuková stopa se z něj vytáhne při převodu na WAV a dál se s ní pracuje stejně. **Je to běžný případ, ne výjimka:** záznam hovoru z Meetu nebo Teamsů se stahuje jako MP4. Obraz se nikam nepřenáší; z videa vzniká jen text.

  Když soubor zvukovou stopu nemá, převod na WAV selže a `transcribe.sh` to zapíše jako `### FAILED zaznam-<n> prevod-na-wav` – ohlas to uživateli a pokračuj dalšími. Když nenajdeš nic, oznam to a skonči.
- **Výstup – vše vzniká v adresáři vstupní nahrávky, nezakládá se žádný podadresář a nic se nikam nepřesouvá:**
  - `<název>.md` – vyčištěný doslovný přepis (viz [Pravidla doslovného přepisu](#pravidla-doslovného-přepisu)),
  - `<název>.srt` – tentýž obsah s časovými značkami, syrový z whisperu,
  - `<název>.vtt` – titulky se značkou `<v Jméno>`, protože SRT pole pro mluvčího nemá. Vzniká **vedle** SRT, jen s rozlišením mluvčích,
  - `<název>.json` – strojově čitelné úseky s časem, mluvčím a textem. Taky jen s rozlišením mluvčích,
  - `YYYYMMDD - Výstižný název.md` – jedno společné shrnutí napříč všemi nahrávkami (viz [Formát souhrnného MD](#formát-souhrnného-md)).

  Které z nich vzniknou, vybere uživatel v průvodci.

  **`<název>` je jméno vstupní nahrávky bez přípony.** U schůzky spojené z několika částí je to jméno, které uživatel zvolil v kroku 1 – sada výstupů je pak jedna jediná, ne jedna na každou původní část.
- **Mezivýstupy** vznikají viditelně v adresáři a **po dokončení se uklidí** (viz krok 10): `<název>.txt` od whisperu, skrytý `.transcript-glossary.md`, `whisper-progress.log`, u spojené schůzky `<název>.wav` z `join.sh` a při rozlišování mluvčích navíc `<název>.wav` (u spojené schůzky k němu ještě `<název>.16k.wav`), `<název>.diarization.json` nebo `<název>.16k.diarization.json` a `.speakers.json`. Zdrojové audio zůstává.

  **Bez rozlišování mluvčích žádný viditelný WAV nevzniká.** `transcribe.sh` si ho v tom případě pojmenuje skrytě (`.<název>.tmp.wav`) a smaže ho hned po zpracování každé nahrávky, ne až v úklidu. **U spojené schůzky to neplatí** – ta je WAV od začátku, protože ho vyrobil `join.sh`, a leží v adresáři až do úklidu bez ohledu na to, jestli se mluvčí rozlišují.

---

## Postup

### 1. Zjisti si fakta o vstupu

Ještě než se na cokoliv zeptáš, potřebuješ délku a datum – bez délky neumíš nabídnout odhady časů v prvním kroku průvodce.

```bash
ffprobe -v error -show_entries format=duration -of csv=p=0 <audio>
ffprobe -v error -show_entries format_tags=creation_time -of csv=p=0 <audio>
```

Datum `YYYYMMDD` vezmi z metadat, **projdou-li kontrolou níž**. Obvykle je stejné napříč soubory; když ne, vezmi z prvního. Když metadata s datem chybí, použij dnešek.

**Metadatům s datem ale nevěř bez kontroly.** `creation_time` bývá u exportovaných souborů **časem exportu, ne nahrávání** – diktafon, mobil i konferenční nástroj ho přepíšou ve chvíli, kdy soubor posíláš do počítače. Chyba se přitom nijak neprojeví: datum vypadá věrohodně a nikdo ho nezpochybní.

**U částí jedné schůzky to jde ověřit strojově, tak to udělej vždycky** – tedy jakmile uživatel v následujícím podkroku potvrdí, že o rozřezanou schůzku jde. Spočítej **rozpětí mezi nejstarším a nejmladším `creation_time`** a porovnej ho s **délkou nejkratší části**. Je-li rozpětí menší, nemůže jít o čas nahrávání: mezi začátky dvou po sobě jdoucích částí musí uplynout aspoň tolik, kolik trvá ta první z nich. Metadata jsou pak nepoužitelná nejen pro datum, ale **i pro určení pořadí**, a na datum se musíš **zeptat**.

**Neporovnávej rozpětí se součtem délek všech částí.** Vyjde to menší pokaždé, i u naprosto poctivých metadat – rozpětí mezi krajními časy z principu jednu část nepokrývá, takže by kontrola hlásila poplach vždycky a nic by neznamenala.

Doloženo: tři části jedné schůzky nesly časy vzniku v rozmezí 48 sekund, přestože dohromady trvaly 59 minut, a přepis kvůli tomu dostal datum o šest dní vedle.

**Na samostatné nahrávky tuhle kontrolu nepouštěj.** Dvě konzultace vyexportované krátce po sobě ji neprojdou, přestože jejich metadata můžou být v pořádku – kritérium stojí na tom, že části mají na sebe časově navazovat, a to u samostatných nahrávek neplatí.

Kde kontrolu udělat nejde – u jednoho souboru i u samostatných nahrávek – aspoň **řekni nahlas, jaké datum používáš a odkud je**, stejně jako u jazyka. Kdo vidí, že nesedí, ozve se.

**Na datu visí víc než jméno souboru se shrnutím.** Váže se k němu každý relativní údaj, který v hovoru padne („do konce týdne“, „příští čtvrtek“), takže chyba v něm posune všechny termíny v úkolech.

**Je-li nahrávek víc, zjisti délku a datum u každé zvlášť.** Délky potřebuješ hned pro kontrolu metadat níž a obojí pak pro určení pořadí částí.

#### Když je nahrávek víc, zeptej se, jestli je to jedna schůzka

**Víc souborů neznamená víc schůzek.** Nejčastější důvod, proč jich je v adresáři víc, je jedna a tatáž schůzka rozpadlá na části: diktafon se na pár vteřin zastavil, nahrávání se restartovalo, hovor spadl a pokračoval. Taková schůzka se **spojí hned na začátku** a od té chvíle se s ní zachází jako s jednou dlouhou nahrávkou – jeden přepis, jedno SRT, jedna diarizace, jedno shrnutí.

Spojit se to musí **před přepisem, ne po něm**. Diarizace nad částmi zvlášť dá v každé vlastní sadu nálepek, takže `SPEAKER_00` z první části není tentýž člověk jako `SPEAKER_00` z druhé – museli by se pojmenovávat několikrát a stejně by se nedalo spolehlivě říct, kdo z nich je kdo. Nad spojeným zvukem má pyannote navíc na každého mluvčího delší vzorek, takže i samotné rozlišení vyjde stabilněji.

**Automaticky se to nepozná, tak se ptej pokaždé, když vidíš víc než jednu nahrávku.** Délky ani metadata nerozhodnou: dvě samostatné konzultace z jednoho odpoledne vypadají úplně stejně jako jeden rozřezaný call.

| Pořadí | Label | Description |
|---|---|---|
| 1. | `Jedna schůzka na části` | Spojím je do jedné nahrávky – vznikne jeden přepis, jedno SRT a jedna diarizace se společnými mluvčími. |
| 2. | `Samostatné nahrávky` | Každá se přepíše zvlášť a bude mít vlastní přepis. Shrnutí je i tak jedno společné. |

**První v pořadí dej tu možnost, pro kterou něco svědčí** – pro spojení mluví navazující časy vzniku, jména se společným základem a rostoucím číslem nebo to, že jedna část končí uprostřed věty. Nesvědčí-li pro ně nic, dej první `Samostatné nahrávky`.

##### Pořadí částí urči podle jmen, teprve pak podle metadat

Části se spojí přesně v tom pořadí, v jakém je předáš, a **špatné pořadí se nepozná jinak než přečtením přepisu**, kde na sebe věty přestanou navazovat. Urči ho v tomhle pořadí – vyhrává první signál, který je k dispozici:

1. **Číslo ve jméně souboru.** Diktafony nahrávky číslují vzestupně (`Záznam 4`, `Záznam 5`, `Záznam 7`), takže soubory se **společným základem jména a rostoucím číslem** nesou pořadí přímo v sobě. Je to nejspolehlivější signál, protože ho na rozdíl od metadat nepřepíše export. Čísla nemusí jít po sobě – chybějící kus řady znamená jen nahrávku, která se smazala nebo sem nepatří.
2. **`creation_time` z metadat**, ale **jen když projde kontrolou metadat z úvodu kroku 1**. Neprojde-li – tedy leží-li časy blíž u sebe než součet délek –, není to čas nahrávání a o pořadí nevypovídá vůbec nic. Pak ho nepoužívej ani jako druhou volbu.
3. **Zeptej se**, když nesedí ani jedno nebo si oba signály odporují.

**Vypiš výsledné pořadí i s délkami a řekni, podle čeho jsi ho určil.** U bodu 1 stačí, aby se uživatel podíval. **U bodu 2 si pořadí nech potvrdit** – metadata sice kontrolou prošla, ale je to slabší signál než čísla ve jménech. U bodu 3 se bez odpovědi nepokračuje.

**Čísla porovnávej jako čísla, ne jako text.** Lexikograficky se `záznam 10` dostane před `záznam 2` – tohle je jediné řazení podle jména, které je zakázané.

```bash
<skill>/join.sh <workdir> <název> <audio1> <audio2> ...
```

Vypíše cestu ke spojenému souboru a jeho délku. Sám si ověří, že výsledek délkou sedí na součet částí – když ne, nevrátí nic a soubor smaže, protože spojení, které tiše přijde o část, by se jinak poznalo až jako záhadně chybějící kus přepisu. Existující soubor nepřepíše.

**Na `<název>` se zeptej**, protože ho ponesou všechny výstupy až po `<název>.md`. Navrhni jméno adresáře – ten bývá pojmenovaný po schůzce – a nech uživatele potvrdit, nebo napsat vlastní.

**Skončí-li `join.sh` nenulově, nespojuj nic ručně a rozhodni podle důvodu:**

| Co skript hlásí | Co udělej |
|---|---|
| `už existuje` | zeptej se na jiný název, nebo si nech potvrdit smazání toho, co tam leží |
| `nesedí to` (délka proti součtu částí) | **zastav se a řekni to uživateli.** Některá část se nepřevedla celá; spojovat dál by znamenalo přepisovat neúplný zvuk |
| `nepovedlo se převést` | ohlas, která část a že nejspíš nemá zvukovou stopu; zeptej se, jestli ji vynechat, nebo skončit |
| `aspoň dvě nahrávky` | chyba v zadání na tvé straně – předal jsi míň než dva soubory, takže se nemá co spojovat |
| cokoliv jiného | skript vypsal důvod na chybový výstup; **přečti ho a řekni ho uživateli doslova**, nespojuj ručně a nepokoušej se to obejít. U selhání po převodu (`Spojení nahrávek selhalo`, `nedá se přečíst`) si skript spojený soubor sám smazal, takže v adresáři nic nezbylo |

Spojený soubor je **mezivýstup**: zdrojové nahrávky zůstávají nedotčené a úklid v kroku 10 ho smaže. Od téhle chvíle je vstupem **jeden soubor** a všechny další kroky se k němu chovají jako k jediné nahrávce – detekce jazyka, odhad času, přepis, diarizace i úklid.

#### Zjisti jazyk nahrávky

```bash
<skill>/detect-lang.sh <audio>          # vypíše např.:  cs 0.993
```

Whisper má jazyk zakódovaný v modelu a pozná ho ze zvuku dřív, než začne dekódovat slova. Vzorkuje se na **třech místech** (čtvrtina, půlka, tři čtvrtiny), protože začátky bývají pozdravy a šoupání židlí a jeden vzorek zprostředka nepozná nahrávku, která se v půlce přepne do jiného jazyka. U nahrávek **kratších než dvě minuty** stačí jeden vzorek zprostředka. Trvá to zhruba sedm sekund na vzorek, takže se to dělá vždycky.

Podle jistoty se zachovej takhle:

| Výsledek | Co udělej |
|---|---|
| jistota ≥ 0,9, jazyk `cs` | **neptej se a nic nehlas**, jeď dál |
| jistota ≥ 0,9, jiný jazyk | **neptej se, ale řekni to nahlas**: „Detekoval jsem angličtinu, přepisuji anglicky.“ Kdo nesouhlasí, ozve se |
| jistota < 0,9 | **teprve tady se zeptej**, s detekovaným jazykem jako první možností |
| skript selhal | vezmi výchozí `cs` a řekni, že detekce neproběhla |
| výstup obsahuje `mixed:` | **přebíjí všechny řádky výš** – jdi na *Když je nahrávka dvojjazyčná* a zeptej se, i kdyby jistota byla vysoká |

**U víc samostatných nahrávek pusť detekci na každou zvlášť.** Když vyjdou různé jazyky, nespojuj je do jednoho běhu – `transcribe.sh` bere jeden jazyk na celý běh, takže je pusť po skupinách podle jazyka a řekni to uživateli. **U schůzky spojené v předchozím podkroku ji pouštíš jednou, nad spojeným souborem** – tři vzorky pak padnou napříč celým hovorem, ne třikrát do jedné jeho části.

Jazyk pak předej jako `WHISPER_LANG` v kroku 6 a **zapiš ho do `.transcript-glossary.md`**. Neurčuje totiž jen rozpoznávání, ale i to, podle jakých pravidel se v kroku 9 opravuje pravopis a v jakém jazyce vzniká shrnutí.

#### Když je nahrávka dvojjazyčná

`detect-lang.sh` vzorkuje na **třech místech** (čtvrtina, půlka, tři čtvrtiny). Když se vzorky neshodnou, přidá na konec `mixed:cs,en`.

```
en 0.999 mixed:cs,en
```

**Whisper bere jeden jazyk na běh**, takže tohle skill sám nespraví. Musí to ale říct nahlas a nabídnout, co s tím:

1. **Přepsat po částech** – uživatel řekne, kolikátá minuta je zlom, ty nahrávku rozřízneš a pustíš dvakrát, každou část se svým jazykem:

   ```bash
   <skill>/split.sh <workdir> <audio> <zlom>     # zlom jako MM:SS nebo v sekundách
   ```

   Vypíše cesty obou částí (`<název>-1.*`, `<název>-2.*`), každou na jeden řádek; zlom mimo nahrávku odmítne. **Řez má vlastní skript schválně**, i když je to jen dvojí volání ffmpegu: skripty skillu jsou v oprávněních pokryté jedním wildcardem, kdežto povolit `ffmpeg` napřímo znamená pustit nástroj, který umí přepisovat soubory (`-y`) – na rozdíl od čtecího `ffprobe`. Přepisy pak spojíš do jednoho `<název>.md` s mezinadpisem u zlomu. **Pozor na dvě věci:** časy v SRT druhé části začínají od nuly, takže se nedají použít pro diarizaci ani pro `merge.py`, a části `<název>-1.*` a `<název>-2.*` maže úklid v kroku 10 jmenovitě, takže na ně nezapomeň v jeho seznamu.
2. **Přepsat celé v převažujícím jazyce** a **napsat do poznámky na konci přepisu**, která část je nespolehlivá.

**Nerozhoduj sám, zeptej se.** Skript umí zjistit, *že* se jazyk mění, ale ne *kde* – hranici zná jedině uživatel. Časově se ty varianty skoro neliší (přepisuje se týž objem zvuku, jen se dvakrát načte model); liší se tím, kolik práce je kolem a jestli je přijatelné mít kus přepisu nespolehlivý.

**Krátká vsuvka v jiném jazyce mixed nevyvolá** – tři vzorky ji minou. Když se to stane, projeví se to až při čištění jako pasáž, která nedává smysl.

### 2. Průvodce, krok první: model

Spočítej odhad běhu pro obě varianty. Tempo drží `rate.py`, který se sám kalibruje podle skutečnosti:

```bash
python3 <skill>/rate.py eta turbo    <délka_v_sekundách>
python3 <skill>/rate.py eta large-v3 <délka_v_sekundách>
```

Zeptej se přes `AskUserQuestion`. **První možnost je vždy ta nejpravděpodobnější**, aby stačil Enter:

| Pořadí | Label | Description |
|---|---|---|
| 1. | `Turbo · ~M:SS` | Výchozí volba. Rychlé, na běžnou mluvu stejně dobré. Se slovníkem jmen zvládne i vlastní jména. |
| 2. | `large-v3 · ~M:SS` | Zhruba 3× pomalejší. Sáhni po něm u špatného zvuku, překřikování nebo když na přesnosti jmen záleží víc než na čase. |

Odhady dosaď skutečné, ne zástupné. Když samostatných nahrávek zpracováváš víc, počítej ze součtu délek; u spojené schůzky je to prostě délka spojeného souboru.

### 3. Průvodce, krok druhý: slovník jmen

**Tohle je nejcennější krok celého skillu.** Whisper dostane seznam vlastních jmen a termínů předem (`--prompt`) a přestane je komolit už při rozpoznávání. Oprava dodatečně je principiálně slabší, protože vymyšlená oprava vypadá stejně věrohodně jako správná.

Návrhy sestav ze čtyř zdrojů:

1. **volný popis v promptu** – jména, firmy a produkty, které uživatel sám napsal,
2. **kontext projektu**, ve kterém běžíš – `CLAUDE.md`, `docs/`, `README.md`, názvy v `content/`,
3. **předchozí komunikace v téhle session**,
4. **[`mishearings.md`](mishearings.md)** – zkomoleniny, které whisper dělá soustavně u každého, kdo mluví o daném oboru. Vezmi jen oddíl odpovídající oboru a jazyku nahrávky. **Do promptu jde správný tvar, nikdy zkomolenina** – tu by se model naučil.

Rozděl je do **tří domén** a nabídni je jako jednu otázku s `multiSelect: true`. Konkrétní termíny vypiš v `description` každé možnosti, ať uživatel vidí, co odsouhlasuje:

| Pořadí | Label | Co do ní patří |
|---|---|---|
| 1. | `Jména lidí` | účastníci, kolegové, zmínění lidé |
| 2. | `Značky, produkty, weby` | firmy, nástroje, domény, názvy prostorů |
| 3. | `Odborné termíny` | žargon oboru, interní pojmy, zkratky |

Volbu „Other“ doplní `AskUserQuestion` samo – tudy uživatel dopíše, co jsi netrefil.

Prázdnou skupinu vůbec nenabízej. Když nemáš návrh ani do jedné, otázku přeskoč a zeptej se rovnou na vlastní termíny.

#### Rešerši dělej naplno, do promptu vybírej

Tyhle dvě věci se pletou, a je to rozdíl mezi dobrým a špatným výsledkem.

**Rešerši dělej naplno.** Vytěž ze zdrojů úplně všechno – klidně stovky jmen, názvů, zkratek a interních pojmů. Nic nezahazuj.

**Do `WHISPER_PROMPT` vyber to, co v nahrávce opravdu zazní**, seřazené podle důležitosti. Vybírej podle dvou věcí naráz: **jak často to padne** a **jak snadno se to komolí**. Obecná slova, která model umí sám, do promptu nepatří – neuškodí, ale místo zabírají.

**Počet položek pravidlem omezený není.** Dřív tu stálo „nejvýš deset“ s odůvodněním, že delší seznam ředí účinek, a **měření to vyvrátilo** (tabulka sedmi běhů je v [`internals.md`](internals.md)). Platí jedině **technický strop whisperu: `n_text_ctx/2`, tedy 224 tokenů.** `n_text_ctx` je 448 u turba i u `large-v3` – ověřeno výpisem whisperu při načtení obou modelů, takže strop je pro obě volby stejný. Změřeno na češtině: jednadvacet termínů (306 znaků) zabere 123 tokenů, takže se vejde **zhruba 38 termínů**.

**Přeteče-li prompt, whisper zahodí jeho začátek**, ne konec – v kódu `prompt_past0.assign(… + (n - n_tokens), … + n)`, tedy „use only the last N tokens“. Řazení podle důležitosti od nejdůležitějšího tedy pomůže jen tehdy, když se slovník do stropu vejde; při přetečení by usekl přesně to, na čem záleží. **Drž se proto bezpečně pod hranicí** místo spoléhání na pořadí.

Ořez je v našem řetězu **tichý**: whisper na něj varuje, ale `transcribe.sh` běží s `-np`, které výpis potlačí.

To je strop daný modelem, ne doporučení: **složení celého seznamu rozhoduje víc než jeho délka a nedá se odhadnout dopředu.** Dva jednadvacetipoložkové slovníky nad touž nahrávkou daly 5/5 a 0/5.

Vybrané položky slep čárkami do jednoho řetězce a předej jako `WHISPER_PROMPT`.

#### Zbytek rešerše si ulož

Všechno ostatní, co jsi našel, zapiš do `<workdir>/.transcript-glossary.md`:

```markdown
# Kontextový slovník – <název nahrávky>

## Jazyk
cs (detekováno v kroku 1, jistota 0,99)

## Mluvčí
(doplní krok 8, když se rozlišují)

## V promptu whisperu
Nazev.cz, Značka, interní pojem, místní jméno, …

## Jména lidí
Jana Nováková, Petr Svoboda, …

## Značky, produkty, weby, místa
Nazev.cz, Značka, s. r. o., …

## Odborné a interní termíny
zkratky oboru, interní pojmy, názvy rolí a útvarů, …

## Zdroje
prompt / docs/structure.md / session
```

Tenhle soubor je vstup pro čištění v kroku 9. **Whisperu dáváš výběr, tobě při čištění to nestačí** – tam potřebuješ úplný kontext, abys poznal, co je zkomolenina a co interní žargon. Bez něj hádáš.

### 4. Průvodce, krok třetí: co má vzniknout

`AskUserQuestion` s `multiSelect: true`, v tomhle pořadí:

| Pořadí | Label | Description |
|---|---|---|
| 1. | `Doslovný přepis (MD)` | Vyčištěný, bez „ehm“, s kapitolami a opravenými názvy. |
| 2. | `Strukturované shrnutí (MD)` | Témata, závěry, na konci domluvy a úkoly. |
| 3. | `Časovaný přepis (SRT)` | Syrový z whisperu, s časy. Na dohledání místa v nahrávce. |
| 4. | `Rozlišit mluvčí (VTT, JSON)` | Viz níž – jen odhad času, nic víc. |

Když uživatel nevybere nic, ber to jako **první tři**. Rozlišení mluvčích je vždycky vědomá volba, nikdy výchozí stav.

#### Popisek u čtvrté položky

Drž ho holý. Spočítej odhad a napiš jen ten:

```
Přidá ~M:SS.
```

Odhad vezmi z `python3 <skill>/rate.py eta diarize <délka_v_sekundách>`.

**U delší nahrávky připiš, že je to spodní hranice** – tempo diarizace s délkou klesá, takže odhad zkalibrovaný na kratším běhu ten delší podstřelí. Proč a o kolik, drží [`internals.md`](internals.md); hranice „delší“ tam zatím opřená o měření není, naměřené jsou jen dva body.

Jestli diarizační závislosti jsou, zjistíš `<skill>/check-deps.sh --diarize <model z kroku 2>`. **Model do příkazu doplň**, jinak skript zkontroluje výchozí `turbo` a vrátí chybu kvůli němu, i když s pyannote je všechno v pořádku. Tohle je jediné volání kontroly před krokem 5; tam se pak spouští znovu i s modelem, který si uživatel vybral.

**Když pyannote nebo token chybí**, přilep za odhad druhou větu: `Vyžaduje doinstalování pyannote a token na HuggingFace.` Když je všechno na místě, tuhle větu **vynech** – uživatele nezajímá, co má.

#### Když je čtvrtá položka zaškrtnutá, zeptej se na počet mluvčích

Druhá otázka v témže kroku. Pevný počet dělá výrazně míň chyb než automatický odhad a uživatel ho zná:

| Pořadí | Label | Description |
|---|---|---|
| 1. | `Dva` | Nejčastější případ, rozhovor. |
| 2. | `Tři až čtyři` | |
| 3. | `Pět a víc` | |
| 4. | `Ať si to zjistí samo` | Míň přesné, ale nemusíte počítat. |

U „tří až čtyř“ a „pěti a víc“ se doptej na přesné číslo, nebo předej `auto` – rozsah pyannote nebere.

### 5. Ověř závislosti

Teď naplno, se všemi volbami z průvodce:

```bash
<skill>/check-deps.sh <model>              # bez rozlišení mluvčích
<skill>/check-deps.sh --diarize <model>    # s ním
```

Když skončí nenulově, vypiš uživateli, co chybí, nabídni instalaci (skript vypsal přesné příkazy) a po jeho souhlasu ji proveď. Skill potřebuje:

- **ffmpeg** – `brew install ffmpeg` (převod audia na WAV),
- **python3** – kalibrace tempa i statistika diarizace stojí na něm,
- **whisper.cpp** – `brew install whisper-cpp` (poskytuje `whisper-cli`),
- **model** – `turbo` (~1,5 GB) nebo `large-v3` (~2,9 GB) v `~/.whisper-models/`,
- **VAD model Silero** (~865 kB) – detekce řeči, viz níž,
- **jen pro rozlišení mluvčích:** `pyannote.audio` ve vlastním venv (**1,2 GB**, změřeno po instalaci) a token na HuggingFace v `~/.whisper-models/hf-token` (nebo v proměnné `HF_TOKEN`).

**Diarizaci nikdy nedoinstaluj sám bez řečí.** Kromě velikosti stažení po uživateli chce dvě věci, které za něj nikdo neudělá: založit token a **odsouhlasit licence tří gated repozitářů v prohlížeči** (`check-deps.sh --diarize` je vypíše jmenovitě). Vypiš mu obojí a počkej. Když to odmítne, pokračuj bez rozlišení mluvčích – zbytek skillu funguje beze změny.

Instalace předpokládá [Homebrew](https://brew.sh). Vyvinuto a testováno na macOS.

### 6. Spusť přepis na pozadí

```bash
WHISPER_MODEL=<turbo|large-v3> \
WHISPER_LANG=<kód jazyka z kroku 1> \
WHISPER_PROMPT="<slovník oddělený čárkami>" \
WHISPER_KEEP_WAV=<0|1> \
<skill>/transcribe.sh <workdir> <workdir>/whisper-progress.log <audio1> <audio2> ...
```

`<workdir>` = adresář vstupní nahrávky. Vzniknou v něm `<název>.txt`, `<název>.srt` a `whisper-progress.log`.

**Skončí-li skript kódem 2 s hláškou o kolizi jmen, ptej se – nerozhoduj sám.** Nastane to, když dvě nahrávky v jednom běhu sdílejí základ jména (`porada.m4a` a `porada.mp4`): výstupy se jmenují podle basename bez přípony, takže by si `.txt` i `.srt` navzájem přepsaly a obě by se přitom ohlásily jako hotové. Skript proto nic nespustí a v logu nechá `### COLLISION <základ>`. (U schůzky spojené v kroku 1 tohle nastat nemůže – do běhu jde jediný soubor.)

Polož **jednu otázku přes `AskUserQuestion`** se dvěma volbami:

- **Zahrnout příponu** – pustíš totéž znovu s `WHISPER_KEEP_EXT=1` a výstupy ponesou i příponu (`porada.m4a.txt`, `porada.mp4.txt`). Zbytek běhu je stejný.
- **Zastavit** – uživatel si nahrávky přejmenuje sám a spustí to znovu. Skonči a řekni, které soubory kolidují.

**Nevybírej za něj ani jedno.** Delší jméno nese celý řetěz až do finálního `<název>.md`, takže je to volba o tom, jak se budou jmenovat výsledné dokumenty – a to ví jen on.

**Skončí-li skript kódem 3, v adresáři už leží výstupy z dřívějška** – `<název>.txt`, `.srt`, `.md`, `.vtt`, `.json` nebo `.wav`. Whisper i ffmpeg přepisují bez ptaní, takže by hodinový přepis zmizel beze stopy; skript proto zase nic nespustí a do logu zapíše `### EXISTING <soubory>`. Znovu polož **jednu otázku přes `AskUserQuestion`**, tentokrát se třemi volbami:

- **Přepsat** – `WHISPER_ON_EXISTING=overwrite`. Správná volba, když se tatáž nahrávka přepisuje znovu po opravě.
- **Přidat rozlišení** – `WHISPER_ON_EXISTING=suffix`. Nové výstupy dostanou `-2`, `-3` podle prvního volného jména a staré zůstanou ležet.
- **Zastavit** – uživatel si soubory ukliď sám a spustí to znovu. Vypiš, které to jsou.

**Ani tady nevybírej za něj.** Rozdíl mezi „přepsat“ a „nechat vedle“ je rozdíl mezi ztrátou předchozí práce a nepořádkem v adresáři, a co je v tu chvíli menší zlo, ví jen on.

**`WHISPER_KEEP_WAV=1` nastav právě tehdy, když se bude rozlišovat mluvčí.** Diarizace jede nad tímtéž WAV a bez toho by se musel vyrábět znovu. Jinak nech `0`, ať se po sobě uklidí hned. Běh na pozadí upozorní na dokončení (marker `### ALL DONE` v logu).

`WHISPER_CHUNK_MIN` nech nenastavené. Je to náprava podle kroku 7, ne volba pro běžný běh.

**VAD je vždy zapnutý** a není na co se ptát. Vyřazuje ticho, čímž zabíjí celou třídu halucinací („Titulky vytvořil…“, dokola tatáž věta) a zároveň zrychluje běh. Práh je nastavený konzervativně (`-vt 0.35`, `-vp 200`), aby neuřízl tiché mluvčí. Vypnout ho jde přes `WHISPER_VAD=0`, ale sahej po tom jen jako po nápravě podle kroku 7.

Chyba jednoho souboru neshodí zbytek běhu – zapíše se `### FAILED` a pokračuje se dalším. Po doběhnutí zkontroluj, jestli v logu nějaké `### FAILED` není, a **ohlas ho uživateli**. Po běhu po úsecích hledej navíc `### CHUNKSTAT zaznam-N <ok>/<z>`: **soubor s přeskočeným úsekem dostane `### DONE` jako každý jiný**, takže ztráta se jinak nepozná. Nesedí-li obě čísla, řekni uživateli, kolik úseků chybí.

### 7. Zkontroluj, kolik zvuku se přepsalo

V logu je pro každý úspěšně přepsaný soubor řádek:

```
### SPEECHSTAT <n> <sekund_řeči> <celkem_sekund> <procent>
```

**Pozor, co to číslo je.** Je to součet délek titulků v SRT dělený délkou nahrávky, tedy **kolik zvuku whisper opravdu přepsal** – ne výstup VAD. Stejné číslo vznikne i s `WHISPER_VAD=0`. Nízký podíl proto neukazuje na VAD sám o sobě; může za ním být i tichý mluvčí, šum nebo dlouhé pauzy.

Slouží jako **hrubá pojistka, ne diagnóza**. Když podíl vyjde nezvykle nízko, ohlas ho uživateli s konkrétním číslem a nabídni opakovaný běh s `WHISPER_VAD=0` jako první věc, kterou lze vyloučit. **Nerozhoduj o tom sám** – u nahrávky s dlouhými pauzami je nízký podíl v pořádku. Naměřeno zatím jen na dvou nahrávkách (94 % a 96 % u běžné schůzky dvou lidí), takže žádnou pevnou hranici tenhle skill nestanovuje. **Nepleť si to s čísly u VAD modelu v [`internals.md`](internals.md)** (94,4 % a 96,9 %) – ta jsou z jiného měření, ze dvou nastavení nad jednou a toutéž nahrávkou.

#### Když se v přepisu objeví halucinační smyčka

Dokola tatáž věta, „Titulky vytvořil…“ a podobné nesmysly. VAD a `-sns` je vyřazují už při rozpoznávání a na měřených nahrávkách žádná nevznikla – když se přesto objeví, je **náprava druhý běh po úsecích**:

```bash
WHISPER_CHUNK_MIN=5 <ostatní proměnné jako v kroku 6> <skill>/transcribe.sh …
```

**Pět minut je rozumný začátek, ne doporučená hodnota.** Kratší úsek znamená víc řezů uprostřed vět a víc načtení modelu, delší zase větší ztrátu, když jeden úsek spadne. Pod dvě minuty nechoď – režie načítání modelu by převážila samotný přepis.

Model začíná u každého úseku bez kontextu, takže se smyčka nemá jak šířit dál. **Ta samá volba je jediná záchrana i tehdy, když whisper spadne uprostřed dlouhé nahrávky:** bez ní se ztratí přepis celého souboru, s ní se přeskočí jen postižený úsek (`### CHUNKFAILED zaznam-N i/z` v logu) a zbytek se přepíše.

**Nezapínej to sám a nikdy jako výchozí.** Na každé hranici úseku vzniká řez uprostřed věty – v ostrém testu se okolo něj jedna replika zopakovala nadvakrát. Platí se tím za odstraněnou smyčku, ne za lepší přepis. Zároveň platí, že po takovém běhu **`SPEECHSTAT` klesne o zhruba tolik, kolik zabíraly přeskočené úseky** – nízké číslo je tady informace, ne poplach.

### 8. Rozliš mluvčí – jen když si to uživatel vybral

Druhý, **samostatný průchod** nad WAV z kroku 6. Když spadne, přepis tím nepřichází vniveč – ohlas selhání a pokračuj krokem 9 bez mluvčích.

```bash
<skill>/diarize.sh <workdir> <workdir>/whisper-progress.log <workdir>/<název>.wav <počet|auto>
```

**Jméno WAV ověř, nepredikuj.** Když byl vstupem sám WAV v pracovním adresáři – což u schůzky spojené v kroku 1 platí vždycky, protože `join.sh` vyrábí právě WAV –, dal mu `transcribe.sh` příponu `.16k`; pak se jmenuje `<název>.16k.wav` a `diarize.sh` z něj odvodí `<název>.16k.diarization.json`. **Mění se tím dva soubory z příkazu výš:** cesta k WAV, kterou předáváš `diarize.sh`, i diarizační JSON, který z ní odvodí. **SRT a výstupní základ pro `merge.py` zůstávají** odvozené ze jména vstupní nahrávky.

Do logu přibude `### DIARSTAT <mluvčích> <úseků>` a `### DIARIZE ELAPSED`, ze kterého se kalibruje tempo. Při chybě `### DIARIZE FAILED <důvod>`. Když diarizace proběhla, ale statistika se z JSONu nepřečetla, stojí v logu `### DIARSTAT-FAILED <chyba>` a v `DIARSTAT` je `?` místo čísel – **neuváděj pak počet mluvčích jako nulu**, ta hodnota není známá.

#### Spoj mluvčí s textem

```bash
python3 <skill>/merge.py <workdir>/<název>.srt <workdir>/<název>.diarization.json <workdir>/<název>
```

Vznikne `<název>.json` a `<název>.vtt`. **Oba nesou syrový text z whisperu, ne vyčištěný** – jsou navázané na časové značky, takže přepsat v nich text by je rozešlo s nahrávkou. Vyčištěný text žije jen v `<název>.md`. Neopravuj je ručně.

Přiřazuje se podle **největšího časového překryvu**, protože whisperovy segmenty nekopírují střídání mluvčích. Když je překryv slabý nebo těsný, replika zůstane bez mluvčího – `merge.py` vypíše kolik takových je (`### MERGESTAT <celkem> <nepřiřazeno> <mluvčích>`).

**Nepřiřazené repliky nedoplňuj odhadem.** Chybné přiřazení vypadá stejně věrohodně jako správné a propíše se až do úkolů ve shrnutí, kde je z něj tvrzení, kdo co slíbil.

#### Zeptej se, kdo je kdo

Až teď, protože dřív nebylo co pojmenovat. Pro každého mluvčího jedna otázka; **návrhy vytáhni z přepisu** – z představování, z oslovování, z toho, kdo o kom mluví ve třetí osobě – a ze slovníku z kroku 3.

**U dvou mluvčích se ptej jednou na dvojici**, ne dvakrát zvlášť. Buď přiřazení sedí, nebo je prohozené – dvě otázky by byly zbytečné kliknutí navíc. Od tří mluvčích výš dej otázku každému.

Vždycky nabídni i možnost nechat mluvčí anonymní. Anonymní mluvčí je lepší než špatně pojmenovaný.

Jména ulož do `<workdir>/.speakers.json` a pusť `merge.py` znovu s `--names`, ať se propíšou do obou výstupů. Zapiš je i do `.transcript-glossary.md`, aby s nimi počítalo čištění i shrnutí.

### 9. Vyrob výstupy, které si uživatel vybral

**Doslovný přepis.** Pro každou nahrávku zpracuj její `<název>.txt` do `<název>.md` dle [Pravidel doslovného přepisu](#pravidla-doslovného-přepisu). U více nebo delších nahrávek to udělej **paralelně přes subagenty** (jeden na soubor; u spojené schůzky, kde je soubor jediný, rozděl vstup na zhruba stejně velké souvislé části a dej každému agentovi jednu, s překryvem pár vět, ať se na švu neztratí replika. **Rozlišovali-li se mluvčí, dělej řez mezi replikami v `<název>.json`** – ten je nese i se jmény, takže agent dostane rovnou dialog. Jinak děl `<název>.txt` po řádcích. **Nedělej řez podle kapitol:** ty ve vstupu nejsou, mezinadpisy vznikají teprve tím čištěním, které má agent udělat) na **výchozím modelu s `low`** (Volba modelu a effortu podle `~/.claude/RULES.md`, *Model a effort podle úkolu*). Nejlevnější model sem nepatří: oprava přeslechů je úsudek a **vymyšlená věta v přepisu vypadá stejně věrohodně jako správná** – nepozná se jinak než poslechem nahrávky.

**Každému subagentovi předej celý `.transcript-glossary.md`**, ne jen ten výběr, který šel do promptu. Tady platí opak než u whisperu: čím víc kontextu, tím líp. Rozdíl mezi „tohle je zkomolenina, opravím ji“ a „tohle je jejich interní pojem, nechám ho být“ se dá udělat jedině proti úplnému slovníku. Nech si od subagenta vrátit i **stručný brief pro shrnutí** – témata, závěry a kdo co slíbil. Shrnutí pak píšeš z briefů a slovníku, ne z celých přepisů znovu.

Fáze opravy přeslechů zůstává, i když se slovník použil. Slovník zmenší počet chyb, nevynuluje ho – v ostrém běhu prošlo sledované místní jméno zkomolené i s nasazeným promptem.

**Na slovník se proto nedá spolehnout naslepo: jména, na kterých záleží, si v hotovém přepisu ověř.** Projdi je a podívej se, jestli v textu opravdu stojí ve správném tvaru – nestačí, že byla v promptu. Sedí-li špatně soustavně, je na místě slovník přeskládat a nahrávku přepsat znovu; kolik toho složení slovníku rozhodne, drží [`internals.md`](internals.md).

**Doplň slovník o to, co jsi našel při čištění.** Když v přepisu narazíš na termín, který v `.transcript-glossary.md` chybí, dopiš ho tam dřív, než budeš psát shrnutí. Shrnutí pak stojí na stejném slovníku jako přepis.

**[`mishearings.md`](mishearings.md) je při čištění seznam míst, kde se vyplatí dívat pozorně** – ne seznam náhrad ke spuštění. Rozhoduje vždycky věta, ve které slovo stojí; u zkratek se správný tvar liší podle oboru.

**Časovaný přepis.** `<název>.srt` už existuje, vznikl při přepisu. Nech ho ležet vedle `<název>.md`, stejné jméno, jiná přípona. Rozlišení mluvčích ho **nenahrazuje** – `<název>.vtt` a `<název>.json` přibydou vedle něj.

SRT se vyrábí vždycky, protože z něj `transcribe.sh` počítá podíl přepsaného zvuku a `merge.py` bere text pro diarizaci. Když si ho uživatel nevybral, je to mezivýstup a smaže se v úklidu.

**Rozlišení mluvčích mění doslovný přepis na dialog.** Kapitoly a mezinadpisy zůstávají, uvnitř nich se místo odstavců střídají repliky:

```markdown
## Životní cyklus člena

**Tomáš:** Jde o to, že když někdo přijde do AK1, tak je to jasné.

**Jan:** A potom to krystalizuje podle toho, jak vypadají prostory.
```

Repliku bez přiřazeného mluvčího uveď bez jména, ne pod nejbližším mluvčím.

**Shrnutí.** Navrhni uživateli „Výstižný název“ celé nahrávky a **nech si ho odsouhlasit** (ať nemusí nic vymýšlet ani psát), pak zapiš `YYYYMMDD - Výstižný název.md` dle [Formátu souhrnného MD](#formát-souhrnného-md).

### 10. Úklid

Smaž mezivýstupy: všechny `<název>.txt`, `<název>.wav`, `<název>.16k.wav`, `<název>.diarization.json`, `<název>.16k.diarization.json`, `.speakers.json`, `whisper-progress.log` a `.transcript-glossary.md`. **U spojené schůzky s diarizací leží v adresáři `<název>.wav` i `<název>.16k.wav` zároveň** – první vyrobil `join.sh`, druhý `transcribe.sh`; smaž oba. Ponech zdrojové audio a to, co si uživatel vybral v kroku 4. **Nevybrané výstupy smaž** – když uživatel nechtěl SRT, `<název>.srt` po sobě ukliď, i když mezitím vznikl.

**Zdrojové části spojené schůzky zůstávají** – maže se jen to, co z nich vzniklo.

**Sáhl-li jsi po nápravě z kroku 7 nebo po řezu z kroku 1, ukliď i po nich:** části `<název>-1.*` a `<název>-2.*` ze `split.sh` a prázdné `<název>.txt` / `<název>.srt`, které zůstanou, když se běh po úsecích nepovede ani jednou. Úklid je jmenovitý, takže o souborech, které přibyly nápravou, sám od sebe neví.

**Než slovník smažeš, nabídni přenesení soustavných zkomolenin do [`mishearings.md`](mishearings.md)** – tedy těch, které rozpoznávač dělá u každého, kdo mluví o tomhle oboru, ne jednorázového přeslechu ani jména konkrétní firmy. Kritéria, co tam patří a co ne, drží ten soubor sám.

**Vypiš, co bys doplnil, a zapiš to teprve po odsouhlasení.** `mishearings.md` leží v `~/.claude`, tedy ve verzovaném repozitáři konfigurace, kdežto běh probíhá v adresáři s nahrávkou – zápis bez zeptání by tam po každém přepisu nechal necommitnutou změnu, kterou tam nikdo nečeká a kterou při zapnutém autocommitu posbírá klidně jiná session spolu s něčím nesouvisejícím. Odmítne-li to uživatel, nic nezapisuj a pokračuj; slovník se smaže tak jako tak.

Než slovník smažeš, **vypiš uživateli i termíny, které jsi nechal být** – ty, co modely dávaly konzistentně a vypadají jako interní žargon, a ty, kde je zvuk nesrozumitelný a tvar je tvůj odhad. Ať ví, co má ověřit. Zapiš je i **na konec doslovného přepisu** jako poznámku. Když si uživatel doslovný přepis nevybral, dej tu poznámku na konec shrnutí – nesmí zmizet jen proto, že vznikl jiný výstup.

---

## Průběžný stav – NEspouštěj automaticky

Opakované časovače zbytečně plýtvají kapacitou. Progress bar vypiš **jen když se uživatel zeptá**, jak to jde:

```bash
python3 <skill>/progress.py <workdir>/whisper-progress.log
```

Ukáže procenta, zpracované a celkové minuty, kolik zbývá, tempo (× realtime) a ETA.

**U běhu po úsecích ukazuje jen dokončené soubory, ne postup uvnitř nahrávky.** Whisper v každém úseku čísluje časy znovu od nuly, takže by se ukazatel na každé hranici vracel zpátky; `progress.py` proto postup uvnitř souboru raději nezapočítá, než aby hlásil nesmysl.

---

## Pravidla doslovného přepisu

Platí pro `<název>.md` každé nahrávky i pro sekci „Doslovný přepis“ v souhrnu. Připrav doslovný přepis v jazyce nahrávky:

- Uprav jen **stylistiku a slovosled** tam, kde je to potřeba, aby se text dal plynule a smysluplně číst.
- **Oprav pravopis a gramatiku** podle pravidel jazyka nahrávky. Rozpoznávač neumí i/y ve shodě přísudku s podmětem, plete si tvary, které znějí stejně, a sází interpunkci od oka. Mluvčí to neřekl špatně – špatně to zapsal model, takže to není zásah do jeho projevu, ale oprava chyby přepisu. Typicky: „mrtvoli“ místo **mrtvoly**, čárky ve vedlejších větách, velká písmena u vlastních jmen. **Které pravidlo použít, řekne jazyk zjištěný v kroku 1**, ne domněnka, že jde o češtinu. U češtiny platí `~/Dev/context/text/text.md`, sekce *Gramatika a pravopis*, a celý `~/Dev/context/text/typography.md`; u jiného jazyka jeho vlastní konvence – anglický text má anglické uvozovky a anglickou interpunkci, ne české.
- **Nespisovné tvary a hovorovou mluvu ale nech být.** „Bysme“, „vokno“, „dycky“ nebo „démoni“ místo demonstrátorů jsou to, jak lidé mluví, a do doslovného přepisu patří. Opravuje se chyba zápisu, ne mluvčí.
- Odstraň **výplňová slova** (hesitační výplně) a **opakovaná slova** / místa, kde se řečník zamotal při hledání formulace.
- **Odstraň halucinace ASR** – i s VAD se občas objeví nesmyslné opakující se řádky (dokola tatáž věta, „Titulky vytvořil …“). Takové smyčky celé smaž.
- Rozděl text do **ucelených kapitol** s výstižnými mezinadpisy (`##`).
- Každou kapitolu rozděl do **kratších odstavců** – žádné dlouhé bloky.
- Nosné pojmy a důležitá sdělení vyznač **tučně**.
- Výčty uveď jako **odrážkový/číslovaný seznam**, kde to dává smysl.
- **Oprava přeslechů:** podle tématu a kontextu najdi a oprav slova, kterým rozpoznávač rozuměl špatně – tak, jak jsou, nedávají smysl, ale pravděpodobně jde o zkomoleninu jiného slova, které by v daném kontextu smysl dávalo.
- **Vlastní jména a názvy:** stejně oprav jména a názvy zkomolené špatnou výslovností nebo cizím přízvukem. Slovník z kroku 3 je pro tuhle opravu závazný zdroj správných tvarů.
- **České jméno v cizojazyčné nahrávce piš česky.** Když v anglicky mluveném záznamu zazní české jméno, firma nebo místo, rozpoznávač ho přepíše foneticky tak, jak to vyslovil cizinec – „Novak“, „Yarda“, „Brno“ jako „Burno“, „Škoda“ jako „Skoda“. Vrať mu **původní český tvar i s diakritikou**, i když je zbytek věty anglicky. Platí to oběma směry a je to jediná oprava, kterou děláš i tam, kde přepsané slovo dává v cizím jazyce zdánlivě smysl.
- **Neopravuj to, čemu jen nerozumíš.** Když stejné podivné slovo dává model opakovaně a konzistentně, je to nejspíš interní žargon, ne přeslech. Nech ho být, případně se zeptej.
- U dialogu **nepřehazuj pořadí** myšlenek; kde je zřejmé, kdo mluví, můžeš mluvčí odlišit, ale nevymýšlej jména.
- **Mluvčího nehádej.** S diarizací ber nálepky z `<název>.json` a repliku, která tam mluvčího nemá, nech bez jména. Bez diarizace mluvčí rozlišuj jen tam, kde to plyne přímo z textu. Špatné přiřazení je horší než chyba ve slově – překlep čtenář pozná, „Tomáš slíbil, že to dodá“ ne.

## Formát souhrnného MD

**Celý souhrnný dokument piš v jazyce nahrávky**, který jsi zjistil v kroku 1 – včetně nadpisu, anotace a názvů sekcí. Anglicky mluvená schůzka nemá mít české shrnutí.

Soubor `YYYYMMDD - Výstižný název.md` má tuto strukturu:

1. **Hlavní nadpis (H1):** `Výstižný název`.
2. **Úvodní odstavec (anotace):** do jednoho odstavce základní charakteristika celé nahrávky – o co jde, jednotlivé strany a účastníci.
3. **`## Shrnutí`:** stručné, logické, strukturované shrnutí dle [Pravidel shrnutí](#pravidla-shrnutí).
4. **`## Doslovný přepis`:** doslovné přepisy všech nahrávek dle [Pravidel doslovného přepisu](#pravidla-doslovného-přepisu), za sebou; u každého je zřejmé, ze které nahrávky pochází. U schůzky spojené v kroku 1 je přepis **jeden souvislý** a nedělí se zpátky podle původních částí – ty už nejsou předěl v obsahu, ale jen stopa po tom, kde se zastavil diktafon. Tuhle sekci vynech, když si uživatel doslovný přepis nevybral.

**Body 1 až 3 jsou tvůj vlastní text**, ne přepis. Platí pro ně [Pravidla shrnutí](#pravidla-shrnutí), ne [Pravidla doslovného přepisu](#pravidla-doslovného-přepisu) – ta se vztahují jen na bod 4.

## Pravidla shrnutí

Platí pro sekci „Shrnutí“. Připrav stručné, logické, strukturované shrnutí celé nahrávky – důležitých témat, poznatků a klíčových informací:

- Využij **přehledné formátování** – mezinadpisy, odstavce, odrážky, **tučný** text pro důležité pojmy.
- **Nedodržuj chronologické pořadí**, ve kterém informace zazněly. Uspořádej vše do logických sekcí a skupin tak, aby to dávalo při čtení smysl.
- Pokud to není nezbytné pro kontext nebo pochopení, **neopakuj** jednu informaci na více místech.
- Na **úplném konci** přehledně shrň vzájemné **domluvy, vyplývající úkoly a další kroky**.
- **Relativní časové údaje převeď na konkrétní data podle data nahrávky.** „Do konce týdne“, „příští čtvrtek“ nebo „za čtrnáct dní“ se v seznamu úkolů čtou špatně, protože čtenář neví, odkdy se počítají. **Konkrétní datum, které v hovoru zaznělo, ale platí tak, jak zaznělo** – i když s tvým přepočtem nesedí. Rozpor mezi obojím je signál, že je špatně datum nahrávky, ne hovor; vrať se ke kroku 1 a ověř ho. **Datum, které nezaznělo a nedá se odvodit, nedoplňuj** – termín u úkolu vypadá stejně věrohodně, ať je spočítaný, nebo vymyšlený.
- **Když běžela diarizace, piš ke každému úkolu majitele.** Je to hlavní důvod, proč se rozlišení mluvčích vůbec zapíná: bez něj se dá napsat „dodat seznam“, s ním „**Tomáš** dodá seznam“. U rozhodnutí stejně tak uveď, kdo co navrhl a kdo souhlasil, když to z přepisu plyne. Kde mluvčí chybí nebo je nejistý, majitele **nedoplňuj odhadem** – radši úkol bez majitele než přisouzený špatnému člověku.
- **Jazykový standard platí i tady, a v plném rozsahu.** Shrnutí není doslovný přepis, ale tvůj vlastní souvislý text, takže se na něj pravidla z [Pravidel doslovného přepisu](#pravidla-doslovného-přepisu) nevztahují sama od sebe – drž je vědomě. U češtiny navíc platí **celý** `~/Dev/context/text/text.md`, ne jen *Gramatika a pravopis* jako u přepisu: i stavba textu, zakázané obraty a stylistika. `~/Dev/context/text/typography.md` platí v obou případech stejně. U jiného jazyka jeho vlastní konvence, protože souhrn se píše v jazyce nahrávky. Pozor hlavně na termíny přebrané z přepisu: chybu opravenou v přepisu snadno zopakuješ ve shrnutí, protože ho píšeš z téhož podkladu. Přesně takhle v ostrém běhu prošly „mrtvoli“ do souhrnného dokumentu, zatímco v přepisu už byly opravené.

(Základní charakteristika a účastníci jsou už v úvodním odstavci – viz [Formát souhrnného MD](#formát-souhrnného-md).)

---

## Technické detaily

Naměřené hodnoty, zamítnutá nastavení a vnitřní rozhodnutí drží
**[`internals.md`](internals.md)**. Sáhni tam, když měníš nastavení whisperu nebo
potřebuješ vědět, proč je nějaké číslo zrovna takové – při běžném běhu to číst
nemusíš.

## Soubory skillu

| Soubor | K čemu |
|---|---|
| `check-deps.sh` | kontrola závislostí, volitelně pro konkrétní model |
| `transcribe.sh` | vlastní přepis, řízený proměnnými prostředí; umí i běh po úsecích jako nápravu |
| `common.sh` | cesty k modelům a k VAD, konfigurace diarizace (venv, token, gated repozitáře, název modelu), počet vláken – sourcuje se |
| `rate.py` | odhad a kalibrace tempa (`get`, `eta`, `update`) |
| `progress.py` | progress bar nad logem běhu |
| `detect-lang.sh` | detekce jazyka ze tří vzorků, hlásí i dvojjazyčnost |
| `join.sh` | spojí části jedné schůzky do jedné nahrávky (16 kHz mono WAV) |
| `split.sh` | rozřízne dvojjazyčnou nahrávku na dvě části v zadaném čase |
| `diarize.sh` | volitelný druhý průchod – kdo kdy mluví |
| `diarize.py` | vlastní běh pyannote uvnitř venv |
| `merge.py` | spojí časy z whisperu s mluvčími, vyrobí `.json` a `.vtt` |
| `mishearings.md` | zkomoleniny, které whisper dělá soustavně; čte se v kroku 3, doplňuje v kroku 10 |
| `internals.md` | naměřené hodnoty a vnitřní rozhodnutí – při běhu se nečte |
| `README.md` | popis skillu pro člověka, který ho nezná |