-
Notifications
You must be signed in to change notification settings - Fork 185
Kannada TN - Created Ordinal Semiotic Class #493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: staging/kannada_tn_v1
Are you sure you want to change the base?
Changes from all commits
e0795ad
aaec4ef
af25078
e262e57
c6b8fe5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| ು | ||
| ಿ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| 1ನೇ ಮೊದಲನೆಯ | ||
| ೧ನೇ ಮೊದಲನೆಯ | ||
| ೦ನೇ ಸೊನ್ನೆಯ | ||
| 0ನೇ ಸೊನ್ನೆಯ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| ನೆ ನೆಯ | ||
| ನೇ ನೆಯ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| # Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import pynini | ||
| from pynini.lib import pynutil | ||
|
|
||
| from nemo_text_processing.text_normalization.kn.graph_utils import NEMO_SIGMA, GraphFst | ||
| from nemo_text_processing.text_normalization.kn.taggers.cardinal import CardinalFst | ||
| from nemo_text_processing.text_normalization.kn.utils import get_abs_path | ||
|
|
||
|
|
||
| class OrdinalFst(GraphFst): | ||
| """ | ||
| Finite state transducer for classifying Kannada ordinals, e.g. | ||
| ೧೦ನೇ -> ordinal { integer: "ಹತ್ತನೆಯ" } | ||
| 12ನೇ -> ordinal { integer: "ಹನ್ನೆರಡನೆಯ" } | ||
|
|
||
| Args: | ||
| deterministic: if True will provide a single transduction option, | ||
| for False multiple transduction are generated (used for audio-based normalization) | ||
| """ | ||
|
|
||
| def __init__(self, cardinal: CardinalFst, deterministic: bool = True): | ||
| super().__init__(name="ordinal", kind="classify", deterministic=deterministic) | ||
|
|
||
| exceptions = pynini.string_file(get_abs_path("data/ordinals/exceptions.tsv")) | ||
| endings = pynini.string_file(get_abs_path("data/ordinals/ending.tsv")) | ||
| kn_suffixes = pynini.string_file(get_abs_path("data/ordinals/kn_suffixes.tsv")) | ||
|
|
||
| drop_cardinal_ending = pynini.cdrewrite(pynutil.delete(endings), "", "[EOS]", NEMO_SIGMA).optimize() | ||
|
|
||
| kn_ordinal_graph = cardinal.final_graph @ drop_cardinal_ending + kn_suffixes | ||
|
|
||
| exception_inputs = pynini.project(exceptions, "input").optimize() | ||
| ordinal_input = pynini.project(kn_ordinal_graph, "input").optimize() | ||
| ordinal_inputs = pynini.difference(ordinal_input, exception_inputs).optimize() | ||
|
|
||
| ordinal_graph = (ordinal_inputs @ kn_ordinal_graph).optimize() | ||
|
|
||
| graph = pynini.union(exceptions, ordinal_graph).optimize() | ||
|
|
||
| final_graph = pynutil.insert('integer: "') + graph + pynutil.insert('"') | ||
| self.fst = self.add_tokens(final_graph).optimize() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import pynini | ||
| from pynini.lib import pynutil | ||
|
|
||
| from nemo_text_processing.text_normalization.kn.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space | ||
|
|
||
|
|
||
| class OrdinalFst(GraphFst): | ||
| """ | ||
| Finite state transducer for verbalizing Kannada ordinals, e.g. | ||
| ordinal { integer: "ಮೊದಲನೆಯ" } -> ಮೊದಲನೆಯ | ||
| ordinal { integer: "ಹತ್ತನೆಯ" } -> ಹತ್ತನೆಯ | ||
|
|
||
| Args: | ||
| deterministic: if True will provide a single transduction option, | ||
| for False multiple transduction are generated (used for audio-based normalization) | ||
| """ | ||
|
|
||
| def __init__(self, deterministic: bool = True): | ||
| super().__init__(name="ordinal", kind="verbalize", deterministic=deterministic) | ||
|
|
||
| integer_value = delete_space + pynutil.delete("\"") + pynini.closure(NEMO_NOT_QUOTE, 1) + pynutil.delete("\"") | ||
| graph = pynutil.delete("integer:") + integer_value | ||
| delete_tokens = self.delete_tokens(graph) | ||
| self.fst = delete_tokens.optimize() |
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,71 @@ | ||||||||||||
| ೧ನೇ~ಮೊದಲನೆಯ | ||||||||||||
| ೨ನೇ~ಎರಡನೆಯ | ||||||||||||
| 2ನೇ~ಎರಡನೆಯ | ||||||||||||
| ೩ನೇ~ಮೂರನೆಯ | ||||||||||||
| ೪ನೇ~ನಾಲ್ಕನೆಯ | ||||||||||||
| ೫ನೇ~ಐದನೆಯ | ||||||||||||
| 5ನೇ~ಐದನೆಯ | ||||||||||||
| ೬ನೇ~ಆರನೆಯ | ||||||||||||
| ೭ನೇ~ಏಳನೆಯ | ||||||||||||
| 7ನೇ~ಏಳನೆಯ | ||||||||||||
| ೮ನೇ~ಎಂಟನೆಯ | ||||||||||||
| ೯ನೇ~ಒಂಬತ್ತನೆಯ | ||||||||||||
| ೧೦ನೇ~ಹತ್ತನೆಯ | ||||||||||||
| ೧೨ನೇ~ಹನ್ನೆರಡನೆಯ | ||||||||||||
| 12ನೇ~ಹನ್ನೆರಡನೆಯ | ||||||||||||
| ೧೪ನೇ~ಹದಿನಾಲ್ಕನೆಯ | ||||||||||||
| 15ನೇ~ಹದಿನೈದನೆಯ | ||||||||||||
| ೧೬ನೇ~ಹದಿನಾರನೆಯ | ||||||||||||
| ೧೭ನೇ~ಹದಿನೇಳನೆಯ | ||||||||||||
| ೧೮ನೇ~ಹದಿನೆಂಟನೆಯ | ||||||||||||
| ೧೯ನೇ~ಹತ್ತೊಂಬತ್ತನೆಯ | ||||||||||||
| 19ನೇ~ಹತ್ತೊಂಬತ್ತನೆಯ | ||||||||||||
| ೨೦ನೇ~ಇಪ್ಪತ್ತನೆಯ | ||||||||||||
| ೨೧ನೇ~ಇಪ್ಪತ್ತೊಂದನೆಯ | ||||||||||||
| ೨೫ನೇ~ಇಪ್ಪತ್ತೈದನೆಯ | ||||||||||||
| ೨೭ನೇ~ಇಪ್ಪತ್ತೇಳನೆಯ | ||||||||||||
| ೩೦ನೇ~ಮೂವತ್ತನೆಯ | ||||||||||||
| ೩೩ನೇ~ಮೂವತ್ತಮೂರನೆಯ | ||||||||||||
| ೪೦ನೇ~ನಲವತ್ತನೆಯ | ||||||||||||
| ೪೫ನೇ~ನಲವತ್ತೈದನೆಯ | ||||||||||||
| ೫೦ನೇ~ಐವತ್ತನೆಯ | ||||||||||||
| ೫೬ನೇ~ಐವತ್ತಾರನೆಯ | ||||||||||||
| ೬೦ನೇ~ಅರವತ್ತನೆಯ | ||||||||||||
| ೬೭ನೇ~ಅರವತ್ತೇಳನೆಯ | ||||||||||||
| 67ನೇ~ಅರವತ್ತೇಳನೆಯ | ||||||||||||
| ೭೫ನೇ~ಎಪ್ಪತ್ತೈದನೆಯ | ||||||||||||
| ೮೦ನೇ~ಎಂಬತ್ತನೆಯ | ||||||||||||
| ೮೮ನೇ~ಎಂಬತ್ತೆಂಟನೆಯ | ||||||||||||
| ೯೧ನೇ~ತೊಂಬತ್ತೊಂದನೆಯ | ||||||||||||
| ೯೯ನೇ~ತೊಂಬತ್ತೊಂಬತ್ತನೆಯ | ||||||||||||
| ೧೦೦ನೇ~ನೂರನೆಯ | ||||||||||||
| 100899823000ನೇ~ಹತ್ತು ಸಾವಿರದ ಎಂಬತ್ತೊಂಬತ್ತು ಕೋಟಿಯ ತೊಂಬತ್ತೆಂಟು ಲಕ್ಷದ ಇಪ್ಪತ್ತಮೂರು ಸಾವಿರನೆಯ | ||||||||||||
| ೧೦೧ನೇ~ನೂರ ಒಂದನೆಯ | ||||||||||||
| ೧೧೧ನೇ~ನೂರ ಹನ್ನೊಂದನೆಯ | ||||||||||||
| ೧೨೫ನೇ~ನೂರ ಇಪ್ಪತ್ತೈದನೆಯ | ||||||||||||
| ೧೫೩ನೇ~ನೂರ ಐವತ್ತಮೂರನೆಯ | ||||||||||||
| ೨೦೦ನೇ~ಇನ್ನೂರನೆಯ | ||||||||||||
| ೨೧೯ನೇ~ಇನ್ನೂರ ಹತ್ತೊಂಬತ್ತನೆಯ | ||||||||||||
| ೨೪೦ನೇ~ಇನ್ನೂರ ನಲವತ್ತನೆಯ | ||||||||||||
| ೩೨೯ನೇ~ಮುನ್ನೂರ ಇಪ್ಪತ್ತೊಂಬತ್ತನೆಯ | ||||||||||||
| ೩೬೫ನೇ~ಮುನ್ನೂರ ಅರವತ್ತೈದನೆಯ | ||||||||||||
| ೪೫೫ನೇ~ನಾನೂರ ಐವತ್ತೈದನೆಯ | ||||||||||||
| ೫೫೫ನೇ~ಐನೂರ ಐವತ್ತೈದನೆಯ | ||||||||||||
| ೬೪೦ನೇ~ಆರುನೂರ ನಲವತ್ತನೆಯ | ||||||||||||
| ೮೯೦ನೇ~ಎಂಟುನೂರ ತೊಂಬತ್ತನೆಯ | ||||||||||||
| ೧೦೦೧ನೇ~ಒಂದು ಸಾವಿರದ ಒಂದನೆಯ | ||||||||||||
| ೧೦೯೧ನೇ~ಒಂದು ಸಾವಿರದ ತೊಂಬತ್ತೊಂದನೆಯ | ||||||||||||
| ೧೭೮೨ನೆ~ಒಂದು ಸಾವಿರದ ಏಳುನೂರ ಎಂಬತ್ತೆರಡನೆಯ | ||||||||||||
| ೧೮೯೦ನೇ~ಒಂದು ಸಾವಿರದ ಎಂಟುನೂರ ತೊಂಬತ್ತನೆಯ | ||||||||||||
| ೧೯೮೧ನೇ~ಒಂದು ಸಾವಿರದ ಒಂಬೈನೂರ ಎಂಬತ್ತೊಂದನೆಯ | ||||||||||||
| ೯೮೨೬ನೇ~ಒಂಬತ್ತು ಸಾವಿರದ ಎಂಟುನೂರ ಇಪ್ಪತ್ತಾರನೆಯ | ||||||||||||
| 6789876ನೆ~ಅರವತ್ತೇಳು ಲಕ್ಷದ ಎಂಬತ್ತೊಂಬತ್ತು ಸಾವಿರದ ಎಂಟುನೂರ ಎಪ್ಪತ್ತಾರನೆಯ | ||||||||||||
| 10000000000000ನೆ~ಹತ್ತು ಲಕ್ಷ ಕೋಟನೆಯ | ||||||||||||
| 10000001ನೇ~ಒಂದು ಕೋಟಿಯ ಒಂದನೆಯ | ||||||||||||
| 1000ನೇ~ಒಂದು ಸಾವಿರನೆಯ | ||||||||||||
| ೭೦೦೦೦೦ನೇ~ಏಳು ಲಕ್ಷನೆಯ | ||||||||||||
| ಈ ಮಗುವಿನ ಶೈಕ್ಷಣಿಕ ಫಲಿತಾಂಶವು ಯಾವಾಗಲೂ ಇಡೀ ತರಗತಿಯಲ್ಲಿ ೧ನೇ ಸ್ಥಾನದಲ್ಲಿದೆ.~ಈ ಮಗುವಿನ ಶೈಕ್ಷಣಿಕ ಫಲಿತಾಂಶವು ಯಾವಾಗಲೂ ಇಡೀ ತರಗತಿಯಲ್ಲಿ ಮೊದಲನೆಯ ಸ್ಥಾನದಲ್ಲಿದೆ. | ||||||||||||
| ಈ ಸಾಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಎಣಿಸಿದಾಗ 5ನೇ ರಾಘವೇಂದ್ರ.~ಈ ಸಾಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಎಣಿಸಿದಾಗ ಐದನೆಯ ರಾಘವೇಂದ್ರ. | ||||||||||||
| ಅಭಿನಂದನೆಗಳು! ನೀವು ನಮ್ಮ ಅಂಗಡಿಯ ೧೦೧ನೇ ಗ್ರಾಹಕರಾಗಿದ್ದೀರಿ.~ಅಭಿನಂದನೆಗಳು! ನೀವು ನಮ್ಮ ಅಂಗಡಿಯ ನೂರ ಒಂದನೆಯ ಗ್ರಾಹಕರಾಗಿದ್ದೀರಿ. | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should-fix · verified 81 cases with both scripts, tier boundaries, a 12-digit number and two full sentences — this is 1. Nothing covers the 15/16 reading boundary.
Suggested change
I've left 2. Nothing covers malformed English suffixes, which is why
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added the missing boundary cases to the test file, including 15ನೇ, 16ನೇ using the Kannada convention consistently. |
||||||||||||
| ಈ ಪಟ್ಟಿಯ ಆರಂಭದಿಂದ ೧೦೦ನೇ ವ್ಯಕ್ತಿಯವರೆಗೆ ಇರುವ ಎಲ್ಲರೂ ನಿಮ್ಮ ಗುರಿ ಗ್ರಾಹಕರು.~ಈ ಪಟ್ಟಿಯ ಆರಂಭದಿಂದ ನೂರನೆಯ ವ್ಯಕ್ತಿಯವರೆಗೆ ಇರುವ ಎಲ್ಲರೂ ನಿಮ್ಮ ಗುರಿ ಗ್ರಾಹಕರು. | ||||||||||||
| 0ನೇ~ಸೊನ್ನೆಯ | ||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import pytest | ||
| from parameterized import parameterized | ||
|
|
||
| from nemo_text_processing.text_normalization.normalize import Normalizer | ||
|
|
||
| from ..utils import CACHE_DIR, parse_test_case_file | ||
|
|
||
|
|
||
| class TestOrdinal: | ||
| normalizer = Normalizer( | ||
| input_case='cased', lang='kn', cache_dir=CACHE_DIR, overwrite_cache=False, post_process=False | ||
| ) | ||
|
|
||
| @parameterized.expand(parse_test_case_file('kn/data_text_normalization/test_cases_ordinal.txt')) | ||
| @pytest.mark.run_only_on('CPU') | ||
| @pytest.mark.unit | ||
| def test_norm(self, test_input, expected): | ||
| pred = self.normalizer.normalize(test_input, verbose=False) | ||
| assert pred == expected |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optional · verified + linguistic-claim
Nice use of
cdrewriteto strip the cardinal's final vowel before the suffix — and the two entriesare well chosen:
ುcovers the digits/teens/ties andಿcovers the threescale_suffixes.tsvrowsending that way (ಕೋಟಿ). I checked and every cardinal in
data/numbers/ends in one of the two.Except zero:
ಸೊನ್ನೆends inೆ, which isn't here, so nothing gets stripped:Whether that even matters is your call — "zeroth" is a marginal thing to write, and rejecting
0ನೇoutright (so it falls through to
word) may well be better than normalizing it. But right now itproduces output, and I'd rather flag that it's unreviewed than let it through silently. If ಸೊನ್ನೆನೆಯ
isn't the form a Kannada reader expects, either add
ೆhere or exclude zero from the ordinal inputset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added 0ನೇ and ೦ನೇ as exceptions in exceptions.tsv with the output ಸೊನ್ನೆಯ, since zero does not follow the existing last-vowel stripping pattern.