Metadata-Version: 2.4
Name: stress-uk
Version: 0.1.1
Summary: Розставляє наголоси (U+0301) в українському тексті - char-level BiLSTM + контекстний резолвер омографів
Author: stress-uk contributors
License: MIT
Project-URL: Homepage, https://github.com/MykhailoMS/stress-uk
Keywords: ukrainian,nlp,stress,accent,g2p,tts
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Text Processing :: Linguistic
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: torch>=2.0
Requires-Dist: huggingface_hub>=0.20
Requires-Dist: numpy
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# stress-uk

Розставляє наголоси в українському тексті символом **U+0301** (combining
acute accent), напр. `рука` → `рука́`. Гібрид: char-level нейромережа
(BiLSTM) для самого слова + rule-based шар для слів, де наголос залежить
від ЗНАЧЕННЯ в контексті (омографи, напр. за́мок-фортеця проти
замо́к-механізм).

## Встановлення

```bash
pip install stress-uk
```

Вага моделі (~9.5MB) НЕ входить у пакет — підвантажується автоматично з
HuggingFace Hub при першому використанні й кешується locally
(`~/.cache/huggingface/`), повторні запуски вже offline.

## Використання

```python
from stress_uk import stressify_text, stressify

print(stressify_text("Привіт, як справи?"))
# Приві́т, я́к спра́ви?

print(stressify("електрифікація"))
# електрифіка́ція
```

Для ансамблю кількох чекпоінтів або власної моделі:

```python
from stress_uk import Stressifier

s = Stressifier(checkpoint_paths=["шлях/до/мого_чекпоінта.pt"])
print(s.stressify_text("Текст."))
```

Розстановка наголосу в омографах залежить від слів навколо (±8 слів, без
перетину пунктуації, ближчі слова важать більше) — словник сенсів і
контекстних тригерів у `stress_uk/heteronyms.py` можна редагувати/
розширювати напряму, формат самоописний
(`HETERONYMS: dict[слово, tuple[Sense, ...]]`).

## Тренування власної моделі

```bash
pip install stress-uk
python -m stress_uk.train --epochs 2          # демо на маленькій вибірці, що йде з пакетом
```

Формат даних — JSONL, один приклад на рядок:
```json
{"word": "рука", "stress": [0, 0, 0, 1]}
```
де `word` — слово малими буквами без наголосу, `stress` — бінарна маска
тієї самої довжини (1 на позиції наголошеної букви). За замовчуванням
використовується невелика ілюстративна вибірка з пакета (НЕ повний
навчальний набір) — передай `--data-dir шлях/до/своїх/даних` зі своїми
`train.jsonl`/`val.jsonl`/`vocab.json`/`word_patterns.json` того самого
формату (`word_patterns.json` потрібен лише для лагідної оцінки під час
тренування: `{слово: {"best": [...], "all": [[...]]}}`).

Звичайний прогін ділить дані на train/val і зупиняється сам через early
stopping, чекпоінт зберігається в `./models/`. Для фінального
прод-чекпоінта (тренування на train+val разом, без held-out оцінки) —
`--full-data --epochs N`, де `N` — номер найкращої епохи звичайного
прогону.

## Розробка/публікація

Якщо клонував репозиторій (не просто `pip install`):

```bash
cd release
pip install -e .
```

Інструкції з публікації нової версії моделі на HuggingFace Hub і пакета
на PyPI — `scripts/PUBLISHING.md`.

## Вимоги

`torch` + `huggingface_hub` (CPU достатньо — інференс на слово займає
частки мілісекунди, тренування на CPU теж практично, бо модель невелика).

## Історія розробки (коротко)

Базова модель — символьний (character-level) bidirectional LSTM:
embedding → 2-шаровий BiLSTM → лінійний шар, що для кожної букви слова
передбачає "ця буква наголошена чи ні" (multi-label, не softmax —
природно підтримує рідкі слова з кількома наголосами, зокрема дефісні
композити). Навчена на великому корпусі акцентованих українських
словоформ із кількох лексикографічних джерел, об'єднаних і узгоджених
між собою (конфліктні випадки — або очевидна друкарська помилка
джерела, яку виправляли голосуванням, або справжня граматична
омонімія, яку свідомо НЕ форсували до єдиної відповіді, а лишали
моделі вчити обидва варіанти з емпіричного розподілу).

Окремо — rule-based шар для омографів (слів, де те саме написання має
різний наголос залежно від значення): словник із кількох сотень
ручно/LLM-курованих записів, кожен запис — наголошені варіанти +
контекстні слова-тригери. Резолвер шукає тригери в ±8 словах навколо
цілі (з розривом контексту по будь-якій пунктуації) і зважує кандидатів
за відстанню (ближче слово — сильніший доказ), а не просто рахує
бінарний "матч/не матч".

Якість систематично перевірялась проти опублікованого незалежного
бенчмарку (Senyk et al., "Context-Aware Lexical Stress Prediction and
Phonemization for Ukrainian TTS Systems", UNLP 2025) — це дозволило
порівняти результат із кількома іншими опублікованими підходами на
тому самому тестовому наборі речень, а не лише на власних тестах.
Кілька раундів цільової діагностики (які саме слова й чому помиляються
на цьому бенчмарку, а не "сліпе" розширення словника) підняли
Macro-F1 на омографах із ~34% до ~49%, а також виявили і виправили
системний баг у підрахунку голосів між джерелами навчальних даних
(рідкісна граматична колізія могла переважити частотою формальних
словоформ значно частотніше в реальному вжитку слово). Фінальний
результат — найкращий за всіма п'ятьма метриками порівняння серед
усіх перевірених систем (включно з гібридними).
