Skip to main content

Polish Whisper Normalizer

CI PyPI Python License Docs

Polish port of OpenAI Whisper normalizers — keeps ąćęłńóśźż, normalizes numbers/time/currency/dates with Morfeusz2 declensions.

🇬🇧 English | 🇵🇱 Polski


English

Features

Area Example Normalized
Diacritics Żółć! żółć (kept) / zolc with remove_diacritics=True
Cardinal / ordinal sto dwadzieścia trzy, dwudziestu pięciu, pierwszego → 1. 123, 25, 1.
Time piąta trzydzieści, wpół do ósmej, o piątej, piąta rano, od piątej do szóstej 5:30, 7:30, o 5:00, 5:00 rano, od 5:00 do 6:00
Time with minut dziesięć minut po piątej, za dwadzieścia minut ósma 5:10, 7:40
Fractions jedna trzecia, trzy czwarte 1/3, 3/4 (keeps /, idempotent)
Half pół litra, półtora, dwa i pół 0.5 litra, 1.5, 2.5
Currency pięć złotych, €10, pięć złotówek 5 zł, 10 €, 5 zł
Percent pięć procentów 5%
Ordinal multipliers tysiąc dziewięćsetny 1900.
Dates 5 maja05.05 · piątego maja05.05 · piątego maja 202605.05.2026 · piątego maja roku dwa tysiące dwudziestego szóstego05.05.2026 DD.MM / DD.MM.YYYY zero-padded, conditional (maja alone stays maja, avoids Maja5)
Geographic guard na północ stays, jest północjest 0:00 no false 0:00 for north

Pipeline: lower → brackets/parens → time → decimal ,.remove_symbols(keep=".:/%$€£¢+-")numbersmonths (conditional)dates→ cleanup. Configurable viaPolishTextNormalizer(date_format=...)`.

Installation

uv sync                 # dev + morfeusz2
uv pip install -e .     # editable
# or from PyPI (once published)
uv pip install polish-whisper-normalizer

Requires Python ≥3.10, regex, more-itertools, morfeusz2.

Usage

from polish_whisper_normalizer import PolishTextNormalizer, BasicTextNormalizer

n = PolishTextNormalizer()
n("Było piętnaście po piątej, minus dziesięć stopni.")
# → "było 5:15 -10 stopni"

n("Spotkanie dwudziestego pierwszego maja o piętnastej trzydzieści.")
# → "spotkanie 21.05 o 15:30"   # was "21. 5" before 05.05 fix

n("piątego maja roku dwa tysiące dwudziestego szóstego")
# → "05.05.2026"   # uniform, no trailing "r"

n("5 maja")  # digit day works too
# → "05.05"

n("pięć złotówek, pięć procentów, pół litra, jedna trzecia")
# → "5 zł 5% 0.5 litra 1/3"

# custom date format
PolishTextNormalizer(date_format="%Y-%m-%d")("piątego maja 2026")
# → "2026-05-05"
PolishTextNormalizer(date_format="{day}/{month}/{year}")("piątego maja 2026")
# → "5/5/2026"

# diacritics
BasicTextNormalizer()("Żółć!")  # → "żółć"
BasicTextNormalizer(remove_diacritics=True)("Żółć!")  # → "zolc"

# jiwer WER (words→digits, dates, time normalized before WER)
# pip install polish-whisper-normalizer[jiwer]
import jiwer
from polish_whisper_normalizer.jiwer import wer, PolishTransform, polish_transform
wer("piątego maja 2026", "05.05.2026")  # → 0.0  (raw jiwer.wer → 1.0)
jiwer.wer("piątego maja 2026", "05.05.2026",
          reference_transform=polish_transform,
          hypothesis_transform=polish_transform)  # → 0.0
# custom date_format
wer("piątego maja 2026", "2026-05-05", date_format="%Y-%m-%d")  # → 0.0

Jiwer — WER with Polish normalization

uv pip install "polish-whisper-normalizer[jiwer]"
# or
uv sync --extra jiwer

Without normalization jiwer.wer penalizes piątego maja 2026 vs 05.05.2026 as 100 % error. With PolishTransform they match:

import jiwer
from polish_whisper_normalizer.jiwer import wer, PolishTransform, polish_transform

# helper (recommended) — normalizes both sides with PolishTextNormalizer
wer("piątego maja 2026", "05.05.2026")  # → 0.0
wer("o piątej", "o 5:00")  # → 0.0
wer("pięć złotówek", "5 zł")  # → 0.0

# raw jiwer would be 1.0
jiwer.wer("piątego maja 2026", "05.05.2026")  # → 1.0

# via jiwer transforms (for pipelines)
jiwer.wer("piątego maja 2026", "05.05.2026",
          reference_transform=polish_transform,
          hypothesis_transform=polish_transform)  # → 0.0

# custom date_format is forwarded
wer("piątego maja 2026", "2026-05-05", date_format="%Y-%m-%d")  # → 0.0

# manual Compose
tr = jiwer.Compose([PolishTransform(date_format="%Y-%m-%d"), jiwer.RemoveMultipleSpaces(), jiwer.Strip(), jiwer.ReduceToListOfListOfWords()])
jiwer.wer("piątego maja 2026", "2026-05-05",
          reference_transform=tr, hypothesis_transform=tr)  # → 0.0

PolishTransform wraps PolishTextNormalizer (date_format kwarg supported) and returns str; polish_transform is the ready Compose ending with ReduceToListOfListOfWords required by jiwer.wer.

Components
from polish_whisper_normalizer import PolishNumberNormalizer, PolishTimeNormalizer, PolishLemmatizer

PolishNumberNormalizer()("dwudziestu pięciu złotych")  # → "25 zł"
PolishTimeNormalizer()("wpół do ósmej")  # → "7:30"
PolishLemmatizer().analyse("dwudziestu")  # → [("dwadzieścia","num")]
Class Description
PolishTextNormalizer(date_format="{day:02d}.{month:02d}.{year}") Full pipeline, date_format supports str.format ({day}, {month}, {year}) and strftime (%d.%m.%Y)
PolishNumberNormalizer Words → digits, currency/percent/decimals/signs/ordinals
PolishTimeNormalizer Spoken time → HH:MM, guards o 5. stronie vs o 5:00, na północ vs 0:00
PolishLemmatizer Morfeusz2 wrapper
BasicTextNormalizer Whisper basic but diacritics-aware

API Docs

Full API: neonfeline.github.io/polish-whisper-normalizer (mkdocs serve locally).

Development

uv sync --group dev
uv run pytest -q          # 486 tests
uv run mypy src           # strict, py.typed
uv run ruff check src tests && uv run ruff format --check src tests
uv build
mkdocs serve
  • py.typed + mypy --strict (warn_unused_ignores=false)
  • ruff + pre-commit + GitHub Actions (ci.yml: lint → mypy → pytest --cov → build)
  • Validated on BIGOS v2 + PELCRA (2397 samples, ~5 % number words)

License

MIT — see LICENSE (inherits Whisper MIT for basic.py).


Polski

Funkcje

Obszar Przykład Po normalizacji
Znaki diakrytyczne Żółć! żółć (zachowane)
Liczebniki sto dwadzieścia trzy, pierwszego 123, 1.
Czas piąta trzydzieści, o piątej, od piątej do szóstej 5:30, o 5:00, od 5:00 do 6:00
Daty 5 maja05.05 · piątego maja 202605.05.2026 DD.MM / DD.MM.RRRR, warunkowo (maja samo → maja)
Waluta / procent / ułamki pięć złotówek, procentów, 1/3, pół litra 5 zł, 5%, 1/3, 0.5 litra

Potok: lower → czas → liczby → miesiące (warunkowo) → daty.

Instalacja i użycie (PL)

uv sync
from polish_whisper_normalizer import PolishTextNormalizer
n = PolishTextNormalizer()  # date_format="{day:02d}.{month:02d}.{year}" domyślnie

n("piątego maja roku dwa tysiące dwudziestego szóstego")
# → "05.05.2026"  # jednolicie, bez "r"

n("5 maja")  # też działa
# → "05.05"

# własny format daty
PolishTextNormalizer(date_format="%Y-%m-%d")("piątego maja 2026")
# → "2026-05-05"

maja jako imię Maja zostaje maja (nie 5), na północ nie staje się 0:00.

Jiwer — WER po polsku

uv pip install "polish-whisper-normalizer[jiwer]"
from polish_whisper_normalizer.jiwer import wer
wer("piątego maja 2026", "05.05.2026")  # → 0.0  (bez normalizacji 1.0)
wer("o piątej", "o 5:00")  # → 0.0

Rozwój / testy

Jak wyżej — uv run pytest, mypy, ruff, mkdocs serve.


Made for BIGOS / Whisper WER — PRs welcome!

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

polish_whisper_normalizer-0.1.1.tar.gz (14.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

polish_whisper_normalizer-0.1.1-py3-none-any.whl (16.2 kB view details)

Uploaded Python 3

File details

Details for the file polish_whisper_normalizer-0.1.1.tar.gz.

File metadata

File hashes

Hashes for polish_whisper_normalizer-0.1.1.tar.gz
Algorithm Hash digest
SHA256 4804091a7dfd26fb04bcc3d47305938a5f007203b4b3a31b8b6658be4aab2a21
MD5 1d12084eb0eff2d40d0e3d05ce267c23
BLAKE2b-256 d7378fdd5fbf13c32d109ac89d4b8824d5435e7211eb74f4d04172884aa5dc6d

See more details on using hashes here.

Provenance

The following attestation bundles were made for polish_whisper_normalizer-0.1.1.tar.gz:

Publisher: publish.yml on NeonFeline/polish-whisper-normalizer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file polish_whisper_normalizer-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for polish_whisper_normalizer-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b484b99285b2bc773dac02369f915466dc293322a375c16c6d75f2392a60b06c
MD5 e0e6023e9801a0b1c4338cfe221751c6
BLAKE2b-256 adc93995cb2c944be39a278d1d5ebf06e5ae2c96b9a69694b5833e7dfd39447b

See more details on using hashes here.

Provenance

The following attestation bundles were made for polish_whisper_normalizer-0.1.1-py3-none-any.whl:

Publisher: publish.yml on NeonFeline/polish-whisper-normalizer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.12

2 files

0.1.11

2 files

0.1.9

2 files

0.1.4

2 files

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page