diff --git a/Jenkinsfile b/Jenkinsfile index 985363986..38e05bb00 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -12,7 +12,7 @@ pipeline { environment { AR_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/06-11-26-0' DE_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/10-23-24-0' - EN_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/06-04-26-3' + EN_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/06-11-26-1' ES_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/09-25-24-0' ES_EN_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/08-30-24-0' HI_EN_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/06-04-26-4' diff --git a/evalution_dataset_itn_kannada.txt b/evalution_dataset_itn_kannada.txt new file mode 100644 index 000000000..b3283efbf --- /dev/null +++ b/evalution_dataset_itn_kannada.txt @@ -0,0 +1,1400 @@ +CARDINAL ೪ ಷಟ್ಕಗಳು ೧೪ ಚೌಕಗಳು ನಾಲ್ಕು ಷಟ್ಕಗಳು ಹದಿನಾಲ್ಕು ಚೌಕಗಳು + +CARDINAL ೬ ಓಟ ಗಳಿಸಿದ ಆರು ಓಟ ಗಳಿಸಿದ + +CARDINAL ೩ ಗೋಲು ಹೊಡೆದ ಮೂರು ಗೋಲು ಹೊಡೆದ + +CARDINAL ೯ ಷಟ್ಕಗಳು ಒಂಬತ್ತು ಷಟ್ಕಗಳು + +CARDINAL ೫ ಚೌಕಗಳು ಐದು ಚೌಕಗಳು + +CARDINAL ೨ ಷಟ್ಕಗಳು ೧೨ ಓಟ ಎರಡು ಷಟ್ಕಗಳು ಹನ್ನೆರಡು ಓಟ + +CARDINAL ೯ ಅಂಕಗಳು ಒಂಬತ್ತು ಅಂಕಗಳು + +CARDINAL ೪ ಮೃತ ೧೮ ಗಾಯಗೊಂಡ ನಾಲ್ಕು ಮೃತ ಹದಿನೆಂಟು ಗಾಯಗೊಂಡ + +CARDINAL ೫ ಗೋಲು ಹೊಡೆದ ಐದು ಗೋಲು ಹೊಡೆದ + +CARDINAL ೩ ಬ್ಯಾಟ್ಸ್ಮನ್ ೧೨ ಆಟಗಾರ ಮೂರು ಬ್ಯಾಟ್ಸ್ಮನ್ ಹನ್ನೆರಡು ಆಟಗಾರ + +CARDINAL ೧ ಓವರ್ ೧೩ ಓಟ ಒಂದು ಓವರ್ ಹದಿಮೂರು ಓಟ + +CARDINAL ೩ ಓವರ್ ಮೂರು ಓವರ್ + +CARDINAL ೫ ಗೋಲು ಐದು ಗೋಲು + +CARDINAL ೩ ಸೇಬು ಮೂರು ಸೇಬು + +CARDINAL ೭ ಬಾಳೆಹಣ್ಣು ಏಳು ಬಾಳೆಹಣ್ಣು + +CARDINAL ೩ ಸೋಲು ೧೨ ಗೆಲುವು ಮೂರು ಸೋಲು ಹನ್ನೆರಡು ಗೆಲುವು + +CARDINAL ೫ ಸೋಲು ೧ ಡ್ರಾ ೧೭ ಗೆಲುವು ಐದು ಸೋಲು ಒಂದು ಡ್ರಾ ಹದಿನೇಳು ಗೆಲುವು + +CARDINAL ೮ ಪಂದ್ಯ ಡ್ರಾ ಎಂಟು ಪಂದ್ಯ ಡ್ರಾ + +CARDINAL ೪ ಚೌಕಗಳು ನಾಲ್ಕು ಚೌಕಗಳು + +CARDINAL ೮ ಷಟ್ಕಗಳು ೨ ಔಟ್ ಎಂಟು ಷಟ್ಕಗಳು ಎರಡು ಔಟ್ + +CARDINAL ೬ ಆಟಗಾರ ಔಟ್ ಆರು ಆಟಗಾರ ಔಟ್ + +CARDINAL ೪ ಓಟ ೩ ಚೌಕಗಳು ನಾಲ್ಕು ಓಟ ಮೂರು ಚೌಕಗಳು + +CARDINAL ಒನ್‌ಪ್ಲಸ್ ೮ ಪ್ರೊ ಒನ್‌ಪ್ಲಸ್ ಎಂಟು ಪ್ರೊ + +CARDINAL ೫ ಚಾರ್ಜರ್ ಐದು ಚಾರ್ಜರ್ + +CARDINAL ೪ ಓವರ್‌ನಲ್ಲಿ ೧೭ ಓಟ ನಾಲ್ಕು ಓವರ್‌ನಲ್ಲಿ ಹದಿನೇಳು ಓಟ + +CARDINAL ೫ ಚಾಕೊಲೇಟ್‌ಗಳು ೯ ಟಾಫಿಗಳು ಐದು ಚಾಕೊಲೇಟ್‌ಗಳು ಒಂಬತ್ತು ಟಾಫಿಗಳು + +CARDINAL ೬ ಬ್ಯಾಟ್ಸ್‌ಮನ್ ೨ ಬೌಲರ್ ಆರು ಬ್ಯಾಟ್ಸ್‌ಮನ್ ಎರಡು ಬೌಲರ್ + +CARDINAL ೧ ವಿಕೆಟ್ ಕೀಪರ್ ಒಂದು ವಿಕೆಟ್ ಕೀಪರ್ + +CARDINAL ೮ ಕ್ಯಾಚ್ ಔಟ್ ಎಂಟು ಕ್ಯಾಚ್ ಔಟ್ + +CARDINAL ೫ ವಿಕೆಟ್‌ಗೆ ೧೦ ಓಟ ಐದು ವಿಕೆಟ್‌ಗೆ ಹತ್ತು ಓಟ + +CARDINAL ೭ ಗೆಲುವು ೨ ಡ್ರಾ ಏಳು ಗೆಲುವು ಎರಡು ಡ್ರಾ + +CARDINAL ೨ ಚೌಕಗಳು ಎರಡು ಚೌಕಗಳು + +CARDINAL ೬ ಓಟ ೫ ವಿಕೆಟ್ ಆರು ಓಟ ಐದು ವಿಕೆಟ್ + +CARDINAL ೭ ಚೆಂಡು ೧೧ ಓಟ ಏಳು ಚೆಂಡು ಹನ್ನೊಂದು ಓಟ + +CARDINAL ೬ ಚಾಕೊಲೇಟ್ ೪ ಟಾಫಿ ಆರು ಚಾಕೊಲೇಟ್ ನಾಲ್ಕು ಟಾಫಿ + +CARDINAL ೮ ಕಂಚು ೨ ಚಿನ್ನ ಎಂಟು ಕಂಚು ಎರಡು ಚಿನ್ನ + +CARDINAL ೧ ಚಿನ್ನದ ಪದಕ ಒಂದು ಚಿನ್ನದ ಪದಕ + +CARDINAL ೩ ಓಟ ಮೂರು ಓಟ + +CARDINAL ೫ ಓವರ್‌ ಐದು ಓವರ್‌ + +CARDINAL ೬ ಚೆಂಡು ಆರು ಚೆಂಡು + +CARDINAL ೩ ಇನ್ನಿಂಗ್ಸ್ ಮೂರು ಇನ್ನಿಂಗ್ಸ್ + +CARDINAL ಶ್ಲೋಕ ೭ ಪಾಠ ೧೫ ಶ್ಲೋಕ ಏಳು ಪಾಠ ಹದಿನೈದು + +CARDINAL ಪಾಠ ಸಂಖ್ಯೆ ೨ ಪದ್ಯ ೪ ಪಾಠ ಸಂಖ್ಯೆ ಎರಡು ಪದ್ಯ ನಾಲ್ಕು + +CARDINAL ಪುಟ ಸಂಖ್ಯೆ ೮ ಪ್ಯಾರಾಗ್ರಾಫ್ ೬ ಪುಟ ಸಂಖ್ಯೆ ಎಂಟು ಪ್ಯಾರಾಗ್ರಾಫ್ ಆರು + +CARDINAL ೨ ಚೆಂಡು ೪ ಓಟ ಎರಡು ಚೆಂಡು ನಾಲ್ಕು ಓಟ + +CARDINAL ೬ ವಿಕೆಟ್ ಆರು ವಿಕೆಟ್ + +CARDINAL ೨ ಅಂಕಗಳು ೫ ಗೋಲು ಎರಡು ಅಂಕಗಳು ಐದು ಗೋಲು + +CARDINAL ಪಾಠ ೧೦ ಶ್ಲೋಕ ೨ ಪಾಠ ಹತ್ತು ಶ್ಲೋಕ ಎರಡು + +CARDINAL ಅಧ್ಯಾಯ ೫ ದೃಶ್ಯ ೬ ಅಧ್ಯಾಯ ಐದು ದೃಶ್ಯ ಆರು + +CARDINAL ೬ ಪ್ರಶ್ನೆ ೫ ತಪ್ಪು ಆರು ಪ್ರಶ್ನೆ ಐದು ತಪ್ಪು + +CARDINAL ೩ ಗುಲಾಬಿ ೪ ಮಲ್ಲಿಗೆ ೨ ಚೆಂಡುಹೂವು ಮೂರು ಗುಲಾಬಿ ನಾಲ್ಕು ಮಲ್ಲಿಗೆ ಎರಡು ಚೆಂಡುಹೂವು + +CARDINAL ೨ ಉಚಿತ ಹೊಡೆತ ೧ ಅಮಾನ್ಯ ಎಸೆತ ಎರಡು ಉಚಿತ ಹೊಡೆತ ಒಂದು ಅಮಾನ್ಯ ಎಸೆತ + +CARDINAL ೩ ದೂರವಾಣಿ ೧ ಚಾರ್ಜರ್ ಮೂರು ದೂರವಾಣಿ ಒಂದು ಚಾರ್ಜರ್ + +CARDINAL ೬ ಡ್ರಾ ೭ ಸೋಲು ೯ ಗೆಲುವು ಆರು ಡ್ರಾ ಏಳು ಸೋಲು ಒಂಬತ್ತು ಗೆಲುವು + +CARDINAL ೪ ಕಾರು ೨ ಬೈಕ್ ನಾಲ್ಕು ಕಾರು ಎರಡು ಬೈಕ್ + +CARDINAL ೧ ಬುಟ್ಟಿ ೮ ಹಣ್ಣು ಒಂದು ಬುಟ್ಟಿ ಎಂಟು ಹಣ್ಣು + +CARDINAL ೩ ಸಾಲು ೮ ಜನ ಮೂರು ಸಾಲು ಎಂಟು ಜನ + +CARDINAL ೧೦ ಪೆನ್ಸಿಲ್ ೨ ಪೆನ್ ಹತ್ತು ಪೆನ್ಸಿಲ್ ಎರಡು ಪೆನ್ + +CARDINAL ೫ ಬಿಲ್ಡಿಂಗ್ ಐದು ಬಿಲ್ಡಿಂಗ್ + +CARDINAL ೬ ಮಕ್ಕಳು ಆರು ಮಕ್ಕಳು + +CARDINAL ಪ್ಯಾರಾಗ್ರಾಫ್ ೧೩ ಸಾಲು ೪ ಪ್ಯಾರಾಗ್ರಾಫ್ ಹದಿಮೂರು ಸಾಲು ನಾಲ್ಕು + +CARDINAL ೩ ಚಿನ್ನ ೪ ಬೆಳ್ಳಿ ಮೂರು ಚಿನ್ನ ನಾಲ್ಕು ಬೆಳ್ಳಿ + +CARDINAL ೫ ಗುಂಡಿಗಳು ಐದು ಗುಂಡಿಗಳು + +CARDINAL ೮ ಬಸ್ತಿ ಎಂಟು ಬಸ್ತಿ + +CARDINAL ೩ ಲ್ಯಾಪ್‌ಟಾಪ್ ಮೂರು ಲ್ಯಾಪ್‌ಟಾಪ್ + +CARDINAL ೧ ಷಟ್ಕಗಳು ೨ ಚೌಕಗಳು ಒಂದು ಷಟ್ಕಗಳು ಎರಡು ಚೌಕಗಳು + +CARDINAL ೫ ಬಸ್ ಐದು ಬಸ್ + +CARDINAL ೨ ಟ್ರಕ್ ಎರಡು ಟ್ರಕ್ + +CARDINAL ೩ ಗಾಡಿ ಮೂರು ಗಾಡಿ + +CARDINAL ೬ ಶಾರ್ಕ್ ೩೦ ಹೂಡಿಕೆದಾರರು ಆರು ಶಾರ್ಕ್ ಮೂವತ್ತು ಹೂಡಿಕೆದಾರರು + +CARDINAL ೨ ಸಚಿವರು ೫೦ ಸಮಸ್ಯೆಗಳು ಎರಡು ಸಚಿವರು ಐವತ್ತು ಸಮಸ್ಯೆಗಳು + +CARDINAL ೬ ಬೌಲರ್ ಆರು ಬೌಲರ್ + +CARDINAL ಶ್ಲೋಕ ೩ ಪಾಠ ೧ ಶ್ಲೋಕ ಮೂರು ಪಾಠ ಒಂದು + +CARDINAL ಸಾಲು ೬ ಪ್ಯಾರಾಗ್ರಾಫ್ ೯ ಸಾಲು ಆರು ಪ್ಯಾರಾಗ್ರಾಫ್ ಒಂಬತ್ತು + +CARDINAL ಪುಸ್ತಕ ೧ ಪಾಠ ೮ ಪುಸ್ತಕ ಒಂದು ಪಾಠ ಎಂಟು + +CARDINAL ಸಣ್ಣ ಕಥೆ ಸಂಖ್ಯೆ ೨ ಸಾಲು ೬ ಸಣ್ಣ ಕಥೆ ಸಂಖ್ಯೆ ಎರಡು ಸಾಲು ಆರು + +CARDINAL ಖೈದಿ ಸಂಖ್ಯೆ ೪ ಖೈದಿ ಸಂಖ್ಯೆ ನಾಲ್ಕು + +CARDINAL ಪುಟ ಸಂಖ್ಯೆ ೧೦ ಸಾಲು ೨ ಪುಟ ಸಂಖ್ಯೆ ಹತ್ತು ಸಾಲು ಎರಡು + +CARDINAL ೪ ಡಾಕ್ಟರ್ ನಾಲ್ಕು ಡಾಕ್ಟರ್ + +CARDINAL ೨ ಚೆಂಡು ೩ ಓಟ ಎರಡು ಚೆಂಡು ಮೂರು ಓಟ + +CARDINAL ಅಂಕಗಳು ೨ ಗೋಲು ೪ ಅಂಕಗಳು ಎರಡು ಗೋಲು ನಾಲ್ಕು + +CARDINAL ಪಾಠ ಸಂಖ್ಯೆ ೪ ಪಾಠ ಸಂಖ್ಯೆ ನಾಲ್ಕು + +CARDINAL ೮ ಓವರ್ ಎಂಟು ಓವರ್ + +CARDINAL ೭ ಓಟ ೨ ಓವರ್ ಏಳು ಓಟ ಎರಡು ಓವರ್ + +CARDINAL ೪ ಚೆಂಡು ೮ ಓಟ ನಾಲ್ಕು ಚೆಂಡು ಎಂಟು ಓಟ + +CARDINAL ೩ ಬಾಟಲಿ ೫ ಗ್ಲಾಸ್ ಮೂರು ಬಾಟಲಿ ಐದು ಗ್ಲಾಸ್ + +CARDINAL ೬ ಓಟ ಆರು ಓಟ + +CARDINAL ೬ ಗೋಲು ಆರು ಗೋಲು + +CARDINAL ೧೦ ಅಂಕಗಳು ೩ ಗೋಲು ಹತ್ತು ಅಂಕಗಳು ಮೂರು ಗೋಲು + +CARDINAL ೧೪ ಷಟ್ಕಗಳು ೩ ಚೌಕಗಳು ಹದಿನಾಲ್ಕು ಷಟ್ಕಗಳು ಮೂರು ಚೌಕಗಳು + +CARDINAL ೬ ಸೇಬು ೩ ಬಾಳೆಹಣ್ಣು ಆರು ಸೇಬು ಮೂರು ಬಾಳೆಹಣ್ಣು + +CARDINAL ೩ ಪಂದ್ಯ ಡ್ರಾ ಮೂರು ಪಂದ್ಯ ಡ್ರಾ + +CARDINAL ೬ ಪಂದ್ಯ ಸೋತರು ಆರು ಪಂದ್ಯ ಸೋತರು + +CARDINAL ೯ ಪಂದ್ಯ ಗೆದ್ದರು ಒಂಬತ್ತು ಪಂದ್ಯ ಗೆದ್ದರು + +CARDINAL ಶ್ಲೋಕ ೬ ಪಾಠ ೯ ಶ್ಲೋಕ ಆರು ಪಾಠ ಒಂಬತ್ತು + +CARDINAL ಪದ ೪ ಸಾಲು ಸಂಖ್ಯೆ ೩ ಪದ ನಾಲ್ಕು ಸಾಲು ಸಂಖ್ಯೆ ಮೂರು + +CARDINAL ಪಾಠ ೧೦ ಪುಟ ೪ ಪಾಠ ಹತ್ತು ಪುಟ ನಾಲ್ಕು + +CARDINAL ೫ ಕಾರು ೨ ಮೋಟಾರ್‌ಸೈಕಲ್ ಐದು ಕಾರು ಎರಡು ಮೋಟಾರ್‌ಸೈಕಲ್ + +CARDINAL ೭ ಅಂಕಗಳು ೨ ಗೋಲು ಏಳು ಅಂಕಗಳು ಎರಡು ಗೋಲು + +CARDINAL ೪ ರಾತ್ರಿ ೩ ದಿನ ನಾಲ್ಕು ರಾತ್ರಿ ಮೂರು ದಿನ + +CARDINAL ೧ ಏಸ್ ೧ ರಾಣಿ ೫ ಕಾರ್ಡ್‌ಗಳು ಒಂದು ಏಸ್ ಒಂದು ರಾಣಿ ಐದು ಕಾರ್ಡ್‌ಗಳು + +CARDINAL ಸಾಲು ೨ ಪ್ಯಾರಾಗ್ರಾಫ್ ೧ ಸಾಲು ಎರಡು ಪ್ಯಾರಾಗ್ರಾಫ್ ಒಂದು + +CARDINAL ೫ ಜೋಡಿ ಬೂಟುಗಳು ಐದು ಜೋಡಿ ಬೂಟುಗಳು + +CARDINAL ೧೦ ಓವರ್‌ನಲ್ಲಿ ೯ ಓಟ ಹತ್ತು ಓವರ್‌ನಲ್ಲಿ ಒಂಬತ್ತು ಓಟ + +CARDINAL ೮ ಓಟ ಎಂಟು ಓಟ + +CARDINAL ೪ ಷಟ್ಕಗಳು ೧ ಚೌಕ ನಾಲ್ಕು ಷಟ್ಕಗಳು ಒಂದು ಚೌಕ + +CARDINAL ಪುಟ ಸಂಖ್ಯೆ ೯ ರ ಸಾಲು ೪ ಪುಟ ಸಂಖ್ಯೆ ಒಂಬತ್ತು ರ ಸಾಲು ನಾಲ್ಕು + +CARDINAL ಪಾರಾ ೧೦ ರ ರುಕು ೩ ಪಾರಾ ಹತ್ತು ರ ರುಕು ಮೂರು + +CARDINAL ಆಯತ್ ೪ ರುಕು ೬ ಆಯತ್ ನಾಲ್ಕು ರುಕು ಆರು + +CARDINAL ಪಾರಾ ೯ ರುಕು ೬ ಪಾರಾ ಒಂಬತ್ತು ರುಕು ಆರು + +CARDINAL ೮ ಪ್ಯಾಂಟ್‌ ೯ ಅಂಗಿ ಎಂಟು ಪ್ಯಾಂಟ್‌ ಒಂಬತ್ತು ಅಂಗಿ + +CARDINAL ೪ ರೊಟ್ಟಿ ೨ ಪಲ್ಯ ನಾಲ್ಕು ರೊಟ್ಟಿ ಎರಡು ಪಲ್ಯ + +CARDINAL ೩ ಪಂದ್ಯ ೪ ಗೆಲುವು ಮೂರು ಪಂದ್ಯ ನಾಲ್ಕು ಗೆಲುವು + +CARDINAL ೪ ಸೋಲು ೩ ಗೆಲುವು ೧ ಡ್ರಾ ನಾಲ್ಕು ಸೋಲು ಮೂರು ಗೆಲುವು ಒಂದು ಡ್ರಾ + +CARDINAL ಚಿತ್ರ ೧೯ ಪಾಠ ೨ ಚಿತ್ರ ಹತ್ತೊಂಬತ್ತು ಪಾಠ ಎರಡು + +CARDINAL ಪಾಠ ೧ ಪುಟ ೧೨೨ ಪಾಠ ಒಂದು ಪುಟ ನೂರ ಇಪ್ಪತ್ತೆರಡು + +CARDINAL ಪಾಠ ೩ ಸಾಲು ೬ ಪಾಠ ಮೂರು ಸಾಲು ಆರು + +CARDINAL ಶ್ಲೋಕ ೧೦ ಪುಟ ೩ ಶ್ಲೋಕ ಹತ್ತು ಪುಟ ಮೂರು + +CARDINAL ೬ ಅಂಕಗಳು ೩ ಗೋಲು ಆರು ಅಂಕಗಳು ಮೂರು ಗೋಲು + +CARDINAL ೨ ಟೆಸ್ಟ್ ಪಂದ್ಯ ೬ ಒನ್ ಡೇ ಎರಡು ಟೆಸ್ಟ್ ಪಂದ್ಯ ಆರು ಒನ್ ಡೇ + +CARDINAL ೨ ಓವರ್‌ನಲ್ಲಿ ೭ ಓಟ ಎರಡು ಓವರ್‌ನಲ್ಲಿ ಏಳು ಓಟ + +CARDINAL ೮ ಓವರ್‌ನಲ್ಲಿ ೪೫ ಓಟ ಎಂಟು ಓವರ್‌ನಲ್ಲಿ ನಲವತ್ತೈದು ಓಟ + +CARDINAL ೯ ಓವರ್‌ನಲ್ಲಿ ೬೦ ಓಟ ಒಂಬತ್ತು ಓವರ್‌ನಲ್ಲಿ ಅರವತ್ತು ಓಟ + +CARDINAL ೫ ಪಂದ್ಯ ೪ ಗೆಲುವು ಐದು ಪಂದ್ಯ ನಾಲ್ಕು ಗೆಲುವು + +CARDINAL ೨ ಗೆಲುವು ೪ ಸೋಲು ೫ ಡ್ರಾ ಎರಡು ಗೆಲುವು ನಾಲ್ಕು ಸೋಲು ಐದು ಡ್ರಾ + +CARDINAL ಶ್ಲೋಕ ೯ ಪುಟ ೭ ಶ್ಲೋಕ ಒಂಬತ್ತು ಪುಟ ಏಳು + +CARDINAL ಪಾಠ ೨ ಪುಟ ೬೬ ಪಾಠ ಎರಡು ಪುಟ ಅರವತ್ತಾರು + +CARDINAL ರೇಖಾಚಿತ್ರ ೨ ಪುಟ ಸಂಖ್ಯೆ ೧೩ ರೇಖಾಚಿತ್ರ ಎರಡು ಪುಟ ಸಂಖ್ಯೆ ಹದಿಮೂರು + +CARDINAL ಚಿತ್ರ ಸಂಖ್ಯೆ ೮ ಪಾಠ ೪ ಚಿತ್ರ ಸಂಖ್ಯೆ ಎಂಟು ಪಾಠ ನಾಲ್ಕು + +CARDINAL ಪುಟ ಸಂಖ್ಯೆ ೧೦ ಪಾಠ ೩ ಪುಟ ಸಂಖ್ಯೆ ಹತ್ತು ಪಾಠ ಮೂರು + +CARDINAL ರುಕು ೩ ಆಯತ್ ೮ ರುಕು ಮೂರು ಆಯತ್ ಎಂಟು + +CARDINAL ರುಕು ೪ ಆಯತ್ ೬ ರ ಸಾಲು ೩೩ ರುಕು ನಾಲ್ಕು ಆಯತ್ ಆರು ರ ಸಾಲು ಮೂವತ್ತಮೂರು + +CARDINAL ಪಾರಾ ೨ ರುಕು ೭ ರ ಸಾಲು ೧೫ ಪಾರಾ ಎರಡು ರುಕು ಏಳು ರ ಸಾಲು ಹದಿನೈದು + +CARDINAL ೩೦ ಪಾರೆ ರ ಸಾಲು ೮ ಮೂವತ್ತು ಪಾರೆ ರ ಸಾಲು ಎಂಟು + +CARDINAL ೪ ಷಟ್ಕಗಳು ೧೨ ಚೌಕಗಳು ನಾಲ್ಕು ಷಟ್ಕಗಳು ಹನ್ನೆರಡು ಚೌಕಗಳು + +CARDINAL 5 ಅಂಕಗಳು 7 ಗೋಲು ಐದು ಅಂಕಗಳು ಏಳು ಗೋಲು + +CARDINAL ಆವೃತ್ತಿ ೨ ಪೀಳಿಗೆ ೪ ಆವೃತ್ತಿ ಎರಡು ಪೀಳಿಗೆ ನಾಲ್ಕು + +CARDINAL ೮ ಇಟ್ಟಿಗೆ ೩೨ ಕಲ್ಲು ಎಂಟು ಇಟ್ಟಿಗೆ ಮೂವತ್ತೆರಡು ಕಲ್ಲು + +CARDINAL ೯ ಓವರ್‌ನಲ್ಲಿ ೧೫ ಓಟ ಒಂಬತ್ತು ಓವರ್‌ನಲ್ಲಿ ಹದಿನೈದು ಓಟ + +CARDINAL ೪ ವಿಕೆಟ್ ೧೧೩ ಓಟ ನಾಲ್ಕು ವಿಕೆಟ್ ನೂರ ಹದಿಮೂರು ಓಟ + +CARDINAL ೭ ವಿಕೆಟ್ ೨೧೧ ಓಟ ಏಳು ವಿಕೆಟ್ ಇನ್ನೂರ ಹನ್ನೊಂದು ಓಟ + +CARDINAL ೪ ಷಟ್ಕಗಳು ೫ ಚೌಕಗಳು ೪೪ ಓಟ ನಾಲ್ಕು ಷಟ್ಕಗಳು ಐದು ಚೌಕಗಳು ನಲವತ್ತನಾಲ್ಕು ಓಟ + +CARDINAL ರುಕು ೮ ಸಾಲು ೧೦ ರುಕು ಎಂಟು ಸಾಲು ಹತ್ತು + +CARDINAL ಪಾಠ ೯ ಪಂಕ್ತಿ ೧೩ ಪಾಠ ಒಂಬತ್ತು ಪಂಕ್ತಿ ಹದಿಮೂರು + +CARDINAL ಭಾಗ ೧೦ ಪಂಕ್ತಿ ೬ ಶ್ಲೋಕ ೨ ಭಾಗ ಹತ್ತು ಪಂಕ್ತಿ ಆರು ಶ್ಲೋಕ ಎರಡು + +CARDINAL ಭಾಗ ೧೨ ಶ್ಲೋಕ ೩ ಪಂಕ್ತಿ ೧೭ ಭಾಗ ಹನ್ನೆರಡು ಶ್ಲೋಕ ಮೂರು ಪಂಕ್ತಿ ಹದಿನೇಳು + +CARDINAL ೭ ಓವರ್ ಏಳು ಓವರ್ + +CARDINAL ೬ ಚೌಕಗಳು ಆರು ಚೌಕಗಳು + +CARDINAL ೩ ಒನ್ ಡೇ ೫ ಟೆಸ್ಟ್ ಪಂದ್ಯ ಮೂರು ಒನ್ ಡೇ ಐದು ಟೆಸ್ಟ್ ಪಂದ್ಯ + +CARDINAL ೭ ಆಟಗಾರ ೨ ಗಾಯಾಳು ಏಳು ಆಟಗಾರ ಎರಡು ಗಾಯಾಳು + +CARDINAL ಆವೃತ್ತಿ ೩ ಪೀಳಿಗೆ ೧೦ ಆವೃತ್ತಿ ಮೂರು ಪೀಳಿಗೆ ಹತ್ತು + +CARDINAL ರುಕು ೧೪ ಪಾರಾ ೮ ರುಕು ಹದಿನಾಲ್ಕು ಪಾರಾ ಎಂಟು + +CARDINAL ಶ್ಲೋಕ ೮ ಪಾಠ ೬ ಶ್ಲೋಕ ಎಂಟು ಪಾಠ ಆರು + +CARDINAL ಉಪನ್ಯಾಸ ೩ ವರ್ಗ ೮ ಉಪನ್ಯಾಸ ಮೂರು ವರ್ಗ ಎಂಟು + +CARDINAL ವರ್ಗ ೧೦ ವಿಭಾಗ ೨ ವರ್ಗ ಹತ್ತು ವಿಭಾಗ ಎರಡು + +CARDINAL ೩ ಡ್ರಾ ೨ ಸೋಲು ಮೂರು ಡ್ರಾ ಎರಡು ಸೋಲು + +CARDINAL ಶ್ಲೋಕ ೩ ಪಾಠ ೧೧ ಶ್ಲೋಕ ಮೂರು ಪಾಠ ಹನ್ನೊಂದು + +CARDINAL ಸಾಲು ೬ ಪಾಠ ೧೦ ಸಾಲು ಆರು ಪಾಠ ಹತ್ತು + +CARDINAL ರುಕು ೨ ಪಾರಾ ೧೫ ರುಕು ಎರಡು ಪಾರಾ ಹದಿನೈದು + +CARDINAL ೪ ಷಟ್ಕಗಳು ೫ ಚೆಂಡು ನಾಲ್ಕು ಷಟ್ಕಗಳು ಐದು ಚೆಂಡು + +CARDINAL ೨ ಚೆಂಡು ೧ ಓಟ ಎರಡು ಚೆಂಡು ಒಂದು ಓಟ + +CARDINAL ಸಾಲು ೮ ಚಾಪ್ಟರ್ ೧೯ ಸಾಲು ಎಂಟು ಚಾಪ್ಟರ್ ಹತ್ತೊಂಬತ್ತು + +CARDINAL ಪುಟ ೧೦ ಪ್ಯಾರಾಗ್ರಾಫ್ ೨ ಪುಟ ಹತ್ತು ಪ್ಯಾರಾಗ್ರಾಫ್ ಎರಡು + +CARDINAL ೯ ಓವರ್‌ನಲ್ಲಿ ೧೭ ಓಟ ಒಂಬತ್ತು ಓವರ್‌ನಲ್ಲಿ ಹದಿನೇಳು ಓಟ + +CARDINAL ೪ ಚೆಂಡಿನಲ್ಲಿ ೬ ಓಟ ನಾಲ್ಕು ಚೆಂಡಿನಲ್ಲಿ ಆರು ಓಟ + +CARDINAL ೧೭ ಚೆಂಡಿನಲ್ಲಿ ೧೦ ಓಟ ಹದಿನೇಳು ಚೆಂಡಿನಲ್ಲಿ ಹತ್ತು ಓಟ + +CARDINAL ೫ ಓವರ್ ೬೬ ಓಟ ಐದು ಓವರ್ ಅರವತ್ತಾರು ಓಟ + +CARDINAL ೮ ಅಂಕಗಳು ೯ ಗೋಲು ಎಂಟು ಅಂಕಗಳು ಒಂಬತ್ತು ಗೋಲು + +CARDINAL ೫ ಸೀಬೆಹಣ್ಣು ಐದು ಸೀಬೆಹಣ್ಣು + +CARDINAL ೬ ರುಕು ೭ ಪಾರಾ ಆರು ರುಕು ಏಳು ಪಾರಾ + +CARDINAL ಶ್ಲೋಕ ೮ ಪದ ೯ ಶ್ಲೋಕ ಎಂಟು ಪದ ಒಂಬತ್ತು + +CARDINAL ೭ ಓವರ್‌ನಲ್ಲಿ ೨೧ ಓಟ ಏಳು ಓವರ್‌ನಲ್ಲಿ ಇಪ್ಪತ್ತೊಂದು ಓಟ + +CARDINAL ೧ ಓವರ್‌ನಲ್ಲಿ ೩ ಓಟ ಒಂದು ಓವರ್‌ನಲ್ಲಿ ಮೂರು ಓಟ + +CARDINAL ೭ ಷಟ್ಕಗಳು ೫ ಚೌಕಗಳು ಏಳು ಷಟ್ಕಗಳು ಐದು ಚೌಕಗಳು + +CARDINAL ೩ ಶ್ಲೋಕ ಮೂರು ಶ್ಲೋಕ + +CARDINAL ೬ ಪುಟ ಆರು ಪುಟ + +CARDINAL ೫ ಷಟ್ಕಗಳು ಐದು ಷಟ್ಕಗಳು + +CARDINAL ೩ ಬಾಟಲಿ ೧೦ ಗ್ಲಾಸ್ ಮೂರು ಬಾಟಲಿ ಹತ್ತು ಗ್ಲಾಸ್ + +CARDINAL ೩ ಪಂದ್ಯ ಮೂರು ಪಂದ್ಯ + +CARDINAL ೬ ಪಂದ್ಯ ೪ ಡ್ರಾ ಆರು ಪಂದ್ಯ ನಾಲ್ಕು ಡ್ರಾ + +CARDINAL ೨ ಚೆಂಡುದಲ್ಲಿ ೩ ಓಟ ಎರಡು ಚೆಂಡುದಲ್ಲಿ ಮೂರು ಓಟ + +CARDINAL ೩ ಅಂಕಗಳು ೪ ಗೋಲು ಮೂರು ಅಂಕಗಳು ನಾಲ್ಕು ಗೋಲು + +CARDINAL ಆಯತ್ ೪ ಸಾಲು ೯ ಆಯತ್ ನಾಲ್ಕು ಸಾಲು ಒಂಬತ್ತು + +CARDINAL ಪಾರಾ ೪ ರುಕು ೧೦ ಸಾಲು ೧೭ ಪಾರಾ ನಾಲ್ಕು ರುಕು ಹತ್ತು ಸಾಲು ಹದಿನೇಳು + +CARDINAL ಪಾರಾ ೬ ರುಕು ೨೫ ಸಾಲು ೨೦ ಪಾರಾ ಆರು ರುಕು ಇಪ್ಪತ್ತೈದು ಸಾಲು ಇಪ್ಪತ್ತು + +CARDINAL ಪಾಠ ೩ ದೋಹಾ ೪ ಸಾಲು ೨ ಪಾಠ ಮೂರು ದೋಹಾ ನಾಲ್ಕು ಸಾಲು ಎರಡು + +CARDINAL ಸಾಲು ೮ ಪದ ೬ ಸಾಲು ಎಂಟು ಪದ ಆರು + +CARDINAL ನಿಬಂಧನೆ ೧೦ ಪ್ಯಾರಾಗ್ರಾಫ್ ೨ ನಿಬಂಧನೆ ಹತ್ತು ಪ್ಯಾರಾಗ್ರಾಫ್ ಎರಡು + +CARDINAL ೭ ಸ್ವರ ಏಳು ಸ್ವರ + +CARDINAL ಹಾಡು ೪ ಕೋರಸ್ ೨ ಹಾಡು ನಾಲ್ಕು ಕೋರಸ್ ಎರಡು + +CARDINAL ಮುದ್ರೆ ಸಂಖ್ಯೆ ೯ ಸಾಲು ೮ ಮುದ್ರೆ ಸಂಖ್ಯೆ ಒಂಬತ್ತು ಸಾಲು ಎಂಟು + +CARDINAL ಆಯತ್ ೧೦ ಸಾಲು ೧೮ ಆಯತ್ ಹತ್ತು ಸಾಲು ಹದಿನೆಂಟು + +CARDINAL ೬ ಓವರ್ ೨೦ ಓಟ ಆರು ಓವರ್ ಇಪ್ಪತ್ತು ಓಟ + +CARDINAL ೮೦ ಓಟ ೩ ವಿಕೆಟ್ ಎಂಬತ್ತು ಓಟ ಮೂರು ವಿಕೆಟ್ + +CARDINAL ೪ ಸ್ಪಿನ್ನರ್ ೩ ಬ್ಯಾಟ್ಸ್ಮನ್ ೧ ವಿಕೆಟ್ ಕೀಪರ್ ನಾಲ್ಕು ಸ್ಪಿನ್ನರ್ ಮೂರು ಬ್ಯಾಟ್ಸ್ಮನ್ ಒಂದು ವಿಕೆಟ್ ಕೀಪರ್ + +CARDINAL ೧ ಗೋಲ್ ಕೀಪರ್ ೬ ಪ್ಲೇಯರ್ ಒಂದು ಗೋಲ್ ಕೀಪರ್ ಆರು ಪ್ಲೇಯರ್ + +CARDINAL ಪಾಠ ೧೮ ಪದ ೫ ಪಾಠ ಹದಿನೆಂಟು ಪದ ಐದು + +CARDINAL ದೋಹಾ ೬ ಸಾಲು ೯ ದೋಹಾ ಆರು ಸಾಲು ಒಂಬತ್ತು + +CARDINAL ಚಿತ್ರ ೬ ಪುಟ ೮೦ ಚಿತ್ರ ಆರು ಪುಟ ಎಂಬತ್ತು + +CARDINAL ೨ ಡ್ರಾ ೩ ಗೆಲುವು ಎರಡು ಡ್ರಾ ಮೂರು ಗೆಲುವು + +CARDINAL ೪ ಮೌಖಿಕ ಪರೀಕ್ಷೆ ೩ ಪರೀಕ್ಷೆ ನಾಲ್ಕು ಮೌಖಿಕ ಪರೀಕ್ಷೆ ಮೂರು ಪರೀಕ್ಷೆ + +CARDINAL ೪ ಪರೀಕ್ಷೆ ೬ ಅಧಿವೇಶನ ನಾಲ್ಕು ಪರೀಕ್ಷೆ ಆರು ಅಧಿವೇಶನ + +CARDINAL ೩ ತಟ್ಟೆ ೪ ಬಟ್ಟಲು ೨ ಚಮಚ ಮೂರು ತಟ್ಟೆ ನಾಲ್ಕು ಬಟ್ಟಲು ಎರಡು ಚಮಚ + +CARDINAL ೪ ಡ್ರಾ ೫ ಗೆಲುವು ನಾಲ್ಕು ಡ್ರಾ ಐದು ಗೆಲುವು + +CARDINAL ೮ ಷಟ್ಕಗಳು ೧೪ ಚೌಕಗಳು ಎಂಟು ಷಟ್ಕಗಳು ಹದಿನಾಲ್ಕು ಚೌಕಗಳು + +CARDINAL ೫ ಓವರ್ ೪ ವಿಕೆಟ್ ಐದು ಓವರ್ ನಾಲ್ಕು ವಿಕೆಟ್ + +CARDINAL ೩ ಓಟ ೨ ವಿಕೆಟ್ ಮೂರು ಓಟ ಎರಡು ವಿಕೆಟ್ + +CARDINAL ೬ ಓವರ್ ೪ ಓಟ ಆರು ಓವರ್ ನಾಲ್ಕು ಓಟ + +CARDINAL ೪ ಪರೀಕ್ಷೆ ಪಂದ್ಯ ೧ ಒನ್ ಡೇ ನಾಲ್ಕು ಪರೀಕ್ಷೆ ಪಂದ್ಯ ಒಂದು ಒನ್ ಡೇ + +CARDINAL ೨ ಅಂಕಗಳು ೧೨ ಗೋಲು ಎರಡು ಅಂಕಗಳು ಹನ್ನೆರಡು ಗೋಲು + +CARDINAL ೭ ಚಮಚ ಮುರಿದವು ಏಳು ಚಮಚ ಮುರಿದವು + +CARDINAL ೧೦ ರಲ್ಲಿ ೬ ಅಂಕ ಹತ್ತು ರಲ್ಲಿ ಆರು ಅಂಕ + +CARDINAL ಪಾಠ ೨ ರ ಪುಟ ಸಂಖ್ಯೆ ೧೨ ಪಾಠ ಎರಡು ರ ಪುಟ ಸಂಖ್ಯೆ ಹನ್ನೆರಡು + +CARDINAL ೧ ಓವರ್‌ನಲ್ಲಿ ೬ ಚೆಂಡು ಒಂದು ಓವರ್‌ನಲ್ಲಿ ಆರು ಚೆಂಡು + +CARDINAL ೭ ಶಾಟ್ ಸರಿಯಾಗಿ ತಗುಲಿದವು ಏಳು ಶಾಟ್ ಸರಿಯಾಗಿ ತಗುಲಿದವು + +CARDINAL ಭಾರತಕ್ಕೆ ೪ ಅಂಕ ಮುನ್ನಡೆ ಭಾರತಕ್ಕೆ ನಾಲ್ಕು ಅಂಕ ಮುನ್ನಡೆ + +CARDINAL ಶತಕಕ್ಕೆ ೩ ಓಟ ಬಾಕಿ ಶತಕಕ್ಕೆ ಮೂರು ಓಟ ಬಾಕಿ + +CARDINAL ೧ ಸೋತ ೨ ಡ್ರಾ ಒಂದು ಸೋತ ಎರಡು ಡ್ರಾ + +CARDINAL ಅರ್ಜೆಂಟಿನಾ ೨ ಅಂಕ ಹಿಂದೆ ಅರ್ಜೆಂಟಿನಾ ಎರಡು ಅಂಕ ಹಿಂದೆ + +CARDINAL ೨ ಗೋಲು ಆಯಿತು ಎರಡು ಗೋಲು ಆಯಿತು + +CARDINAL ೮ ಹೆಚ್ಚುವರಿ ಓಟ ಎಂಟು ಹೆಚ್ಚುವರಿ ಓಟ + +CARDINAL ೪ ಅಗಲ ಎಸೆತ ನಾಲ್ಕು ಅಗಲ ಎಸೆತ + +CARDINAL ತರಗತಿ ೯ ತರಗತಿ ಒಂಬತ್ತು + +CARDINAL ತರಗತಿ ೫ ತರಗತಿ ಐದು + +CARDINAL ೯ ಭಾಗ ಒಂಬತ್ತು ಭಾಗ + +CARDINAL ತರಗತಿ ೪ ಪಾಠ ೩ ತರಗತಿ ನಾಲ್ಕು ಪಾಠ ಮೂರು + +CARDINAL ಪಾಠ ೯ ಪಾಠ ಒಂಬತ್ತು + +CARDINAL ಪುಟ ಸಂಖ್ಯೆ ೮ ಪುಟ ಸಂಖ್ಯೆ ಎಂಟು + +CARDINAL ೪ ಬಾಟಲಿ ನಾಲ್ಕು ಬಾಟಲಿ + +CARDINAL ೧೦೦ ರಲ್ಲಿ ೪ ಅಂಕ ನೂರು ರಲ್ಲಿ ನಾಲ್ಕು ಅಂಕ + +CARDINAL ೮ ಅಂಕ ಎಂಟು ಅಂಕ + +CARDINAL ಕನ್ನಡಕದ ಅಂಕ ೨ ಕನ್ನಡಕದ ಅಂಕ ಎರಡು + +CARDINAL ೭ ಚಪ್ಪಲಿ ಏಳು ಚಪ್ಪಲಿ + +CARDINAL ೫ ಬೂಟು ಐದು ಬೂಟು + +CARDINAL ೨ ಸ್ಯಾಂಡಲ್ ಎರಡು ಸ್ಯಾಂಡಲ್ + +CARDINAL ೭ ಆಟ ಗೆದ್ದ ಏಳು ಆಟ ಗೆದ್ದ + +CARDINAL ೬ ಮುಚ್ಚಳ ಆರು ಮುಚ್ಚಳ + +CARDINAL ೧೦೦೦ ರ ೨ ನೋಟು ಒಂದು ಸಾವಿರ ರ ಎರಡು ನೋಟು + +CARDINAL ೧೯ ರಲ್ಲಿ ೩ ಗ್ಲಾಸ್ ಹತ್ತೊಂಬತ್ತು ರಲ್ಲಿ ಮೂರು ಗ್ಲಾಸ್ + +CARDINAL ಪುಟ ೧೯೯ ಪಾಠ ೬ ಪುಟ ನೂರ ತೊಂಬತ್ತೊಂಬತ್ತು ಪಾಠ ಆರು + +CARDINAL ೮ ಪಾರೆ ಎಂಟು ಪಾರೆ + +CARDINAL ಭಾಗ ೫ ಪಾಠ ೧೯ ಭಾಗ ಐದು ಪಾಠ ಹತ್ತೊಂಬತ್ತು + +CARDINAL ೮೦ ಓಟ ೬ ವಿಕೆಟ್ ಎಂಬತ್ತು ಓಟ ಆರು ವಿಕೆಟ್ + +CARDINAL ೯ ಹೆಚ್ಚುವರಿ ಓಟ ಒಂಬತ್ತು ಹೆಚ್ಚುವರಿ ಓಟ + +CARDINAL ೧೧ ಚೆಂಡು ೮ ಓಟ ಹನ್ನೊಂದು ಚೆಂಡು ಎಂಟು ಓಟ + +CARDINAL ೨ ಹಳದಿ ೮ ಕೆಂಪು ಕಾರ್ಡ್ ಎರಡು ಹಳದಿ ಎಂಟು ಕೆಂಪು ಕಾರ್ಡ್ + +CARDINAL ಅಧ್ಯಾಯ ೧೨ ಶ್ಲೋಕ ೮ ಅಧ್ಯಾಯ ಹನ್ನೆರಡು ಶ್ಲೋಕ ಎಂಟು + +CARDINAL ಪುಟ ೮೮ ಅಧ್ಯಾಯ ೭ ಪುಟ ಎಂಬತ್ತೆಂಟು ಅಧ್ಯಾಯ ಏಳು + +CARDINAL ೧೦೦ ಓಟ ೫ ವಿಕೆಟ್ ನೂರು ಓಟ ಐದು ವಿಕೆಟ್ + +CARDINAL ೮ ಗೋಲಿನಿಂದ ಗೆಲುವು ಎಂಟು ಗೋಲಿನಿಂದ ಗೆಲುವು + +CARDINAL ೩ ಚಕ್ರ ವಾಹನ ಮೂರು ಚಕ್ರ ವಾಹನ + +CARDINAL ಅಧ್ಯಾಯ ೧೯ ಭಾಗ ೪ ಅಧ್ಯಾಯ ಹತ್ತೊಂಬತ್ತು ಭಾಗ ನಾಲ್ಕು + +CARDINAL ೧೧ ತಿಂಗಳು ೮ ದಿನ ಹನ್ನೊಂದು ತಿಂಗಳು ಎಂಟು ದಿನ + +CARDINAL ೯ ದಿನ ೧೨ ಗಂಟೆ ಒಂಬತ್ತು ದಿನ ಹನ್ನೆರಡು ಗಂಟೆ + +CARDINAL ೪ ಕಟ್ಟು ೧೩ ಕಾರ್ಡ್ ನಾಲ್ಕು ಕಟ್ಟು ಹದಿಮೂರು ಕಾರ್ಡ್ + +CARDINAL ೭ ಪಂದ್ಯ ೧೨ ವಿಕೆಟ್ ಏಳು ಪಂದ್ಯ ಹನ್ನೆರಡು ವಿಕೆಟ್ + +CARDINAL ೧ ವ್ಯಕ್ತಿ ಒಂದು ವ್ಯಕ್ತಿ + +CARDINAL ೨ ಮಹಿಳೆಯರು ಎರಡು ಮಹಿಳೆಯರು + +CARDINAL ೩ ಮಕ್ಕಳು ಮೂರು ಮಕ್ಕಳು + +CARDINAL ೪ ಪುಸ್ತಕಗಳು ನಾಲ್ಕು ಪುಸ್ತಕಗಳು + +CARDINAL ೫ ಕೊಠಡಿಗಳು ಐದು ಕೊಠಡಿಗಳು + +CARDINAL ೬ ಮನೆಗಳು ಆರು ಮನೆಗಳು + +CARDINAL ೭ ಪುಟಗಳು ಏಳು ಪುಟಗಳು + +CARDINAL ೮ ನಾಣ್ಯಗಳು ಎಂಟು ನಾಣ್ಯಗಳು + +CARDINAL ೯ ಡಬ್ಬಿಗಳು ಒಂಬತ್ತು ಡಬ್ಬಿಗಳು + +CARDINAL ೧೦ ಕೆಲಸಗಳು ಹತ್ತು ಕೆಲಸಗಳು + +CARDINAL ೧೧ ಹಣ್ಣು ೨ ಹೂವು ಹನ್ನೊಂದು ಹಣ್ಣು ಎರಡು ಹೂವು + +CARDINAL ೩ ಹೂವು ಮೂರು ಹೂವು + +CARDINAL ೧೩ ಕುಂಡಿಗಳು ೪ ಗಿಡಗಳು ಹದಿಮೂರು ಕುಂಡಿಗಳು ನಾಲ್ಕು ಗಿಡಗಳು + +CARDINAL ೪ ಪಪ್ಪಾಯಿ ನಾಲ್ಕು ಪಪ್ಪಾಯಿ + +CARDINAL ೫ ಮಾವಿನಹಣ್ಣು ಐದು ಮಾವಿನಹಣ್ಣು + +CARDINAL ೬ ಬಾಳೆಹಣ್ಣು ಆರು ಬಾಳೆಹಣ್ಣು + +CARDINAL ೭ ದ್ರಾಕ್ಷಿ ಏಳು ದ್ರಾಕ್ಷಿ + +CARDINAL ೮ ಕಿತ್ತಳೆಹಣ್ಣು ಎಂಟು ಕಿತ್ತಳೆಹಣ್ಣು + +CARDINAL ೯ ಸೇಬು ಒಂಬತ್ತು ಸೇಬು + +CARDINAL ೧೦ ಚಿಕ್ಕು ಹತ್ತು ಚಿಕ್ಕು + +CARDINAL ೧ ಕಮಲ ಒಂದು ಕಮಲ + +CARDINAL ೨ ಕಲ್ಲುಗಳು ಎರಡು ಕಲ್ಲುಗಳು + +CARDINAL ೩ ಕುರ್ಚಿಗಳು ಮೂರು ಕುರ್ಚಿಗಳು + +CARDINAL ೪ ಬ್ಯಾಗ್ ನಾಲ್ಕು ಬ್ಯಾಗ್ + +CARDINAL ೫ ಫೋನ್ ಐದು ಫೋನ್ + +CARDINAL ೬ ಕೊಠಡಿಗಳು ಆರು ಕೊಠಡಿಗಳು + +CARDINAL ೭ ಮಹಿಳೆಯರು ಏಳು ಮಹಿಳೆಯರು + +CARDINAL ೮ ಪುಸ್ತಕಗಳು ಎಂಟು ಪುಸ್ತಕಗಳು + +CARDINAL ೯ ವಾಹನಗಳು ಒಂಬತ್ತು ವಾಹನಗಳು + +CARDINAL ೧೦ ನದಿಗಳು ಹತ್ತು ನದಿಗಳು + +CARDINAL ೩ ಎಮ್ಮೆಗಳು ಮೂರು ಎಮ್ಮೆಗಳು + +CARDINAL ೨ ಬೂಟುಗಳು ಎರಡು ಬೂಟುಗಳು + +CARDINAL ೩ ನಾಯಿಗಳು ಮೂರು ನಾಯಿಗಳು + +CARDINAL ೪ ಕುದುರೆಗಳು ನಾಲ್ಕು ಕುದುರೆಗಳು + +CARDINAL ೫ ಪುತ್ರರು ಐದು ಪುತ್ರರು + +CARDINAL ೬ ಕೋಳಿಗಳು ಆರು ಕೋಳಿಗಳು + +CARDINAL ೭ ಕತ್ತೆಗಳು ಏಳು ಕತ್ತೆಗಳು + +CARDINAL ೮ ಹುಡುಗಿಯರು ಎಂಟು ಹುಡುಗಿಯರು + +CARDINAL ೯ ಹುಡುಗರು ಒಂಬತ್ತು ಹುಡುಗರು + +CARDINAL ೧೦ ಪ್ರಶ್ನೆಗಳು ಹತ್ತು ಪ್ರಶ್ನೆಗಳು + +CARDINAL ೧ ಶರ್ಟ್ ಒಂದು ಶರ್ಟ್ + +CARDINAL ೨ ದೋಣಿಗಳು ಎರಡು ದೋಣಿಗಳು + +CARDINAL ೩ ಡಬ್ಬಿಗಳು ಮೂರು ಡಬ್ಬಿಗಳು + +CARDINAL ೪ ಮುಚ್ಚಳಗಳು ನಾಲ್ಕು ಮುಚ್ಚಳಗಳು + +CARDINAL ೫ ನೋಟ ಐದು ನೋಟ + +CARDINAL ೬ ನಾಣ್ಯ ಆರು ನಾಣ್ಯ + +CARDINAL ೭ ಗಾಯ ಏಳು ಗಾಯ + +CARDINAL ೮ ಬಣ್ಣ ಎಂಟು ಬಣ್ಣ + +CARDINAL ೯ ಜನ ಒಂಬತ್ತು ಜನ + +CARDINAL ೧೦ ದಿನ ಹತ್ತು ದಿನ + +CARDINAL ೫ ಮಾತು ಐದು ಮಾತು + +CARDINAL ೨ ಔಷಧಗಳು ಎರಡು ಔಷಧಗಳು + +CARDINAL ೩ ಗೂಡುಗಳು ಮೂರು ಗೂಡುಗಳು + +CARDINAL ೪ ಗೆಳತಿಯರು ನಾಲ್ಕು ಗೆಳತಿಯರು + +CARDINAL ೫ ಗಿಡಗಳು ಐದು ಗಿಡಗಳು + +CARDINAL ೬ ಪರದೆ ಆರು ಪರದೆ + +CARDINAL ೭ ಬೆಕ್ಕುಗಳು ಏಳು ಬೆಕ್ಕುಗಳು + +CARDINAL ೮ ಇಲಿಗಳು ಎಂಟು ಇಲಿಗಳು + +CARDINAL ೯ ಗಾಡಿಗಳು ಒಂಬತ್ತು ಗಾಡಿಗಳು + +CARDINAL ೧೦ ಕಣ್ಣುಗಳು ಹತ್ತು ಕಣ್ಣುಗಳು + +CARDINAL ೬ ಗೋಡೆಗಳು ಆರು ಗೋಡೆಗಳು + +CARDINAL ೨ ಗಡಿಯಾರಗಳು ಎರಡು ಗಡಿಯಾರಗಳು + +CARDINAL ೩ ಪಪ್ಪಾಯಿಗಳು ಮೂರು ಪಪ್ಪಾಯಿಗಳು + +CARDINAL ೪ ಸೈಕಲ್ಗಳು ನಾಲ್ಕು ಸೈಕಲ್ಗಳು + +CARDINAL ೫ ಕಿಟಕಿಗಳು ಐದು ಕಿಟಕಿಗಳು + +CARDINAL ೬ ಕೊಂಬೆಗಳು ಆರು ಕೊಂಬೆಗಳು + +CARDINAL ೭ ಗೊಂಬೆಗಳು ಏಳು ಗೊಂಬೆಗಳು + +CARDINAL ೮ ಕವಿತೆಗಳು ಎಂಟು ಕವಿತೆಗಳು + +CARDINAL ೯ ಕಥೆಗಳು ಒಂಬತ್ತು ಕಥೆಗಳು + +CARDINAL ೧೦ ಕಥೆಗಳು ಹತ್ತು ಕಥೆಗಳು + +CARDINAL ೭ ಮೊಗ್ಗುಗಳು ಏಳು ಮೊಗ್ಗುಗಳು + +CARDINAL ೨ ಕೋಳಿಗಳು ಎರಡು ಕೋಳಿಗಳು + +CARDINAL ೩ ಬೀದಿಗಳು ಮೂರು ಬೀದಿಗಳು + +CARDINAL ೪ ದಿನಾಂಕಗಳು ನಾಲ್ಕು ದಿನಾಂಕಗಳು + +CARDINAL ೫ ಉಪಕರಣ ಐದು ಉಪಕರಣ + +CARDINAL ೬ ಹುಡುಗಿಯರು ಆರು ಹುಡುಗಿಯರು + +CARDINAL ೭ ತಟ್ಟೆಗಳು ಏಳು ತಟ್ಟೆಗಳು + +CARDINAL ೮ ಸ್ತ್ರೀಯರು ಎಂಟು ಸ್ತ್ರೀಯರು + +CARDINAL ೯ ರಾತ್ರಿ ಒಂಬತ್ತು ರಾತ್ರಿ + +CARDINAL ೧೦ ತರಕಾರಿಗಳು ಹತ್ತು ತರಕಾರಿಗಳು + +CARDINAL ೮ ಮಕ್ಕಳು ಎಂಟು ಮಕ್ಕಳು + +CARDINAL ೨ ಟೋಪಿಗಳು ಎರಡು ಟೋಪಿಗಳು + +CARDINAL ೩ ಹುಡುಗಿಯರು ಮೂರು ಹುಡುಗಿಯರು + +CARDINAL ೪ ನದಿಗಳು ನಾಲ್ಕು ನದಿಗಳು + +CARDINAL ೫ ನಾರಿಯರು ಐದು ನಾರಿಯರು + +CARDINAL ೬ ಬಿಂದಿಗಳು ಆರು ಬಿಂದಿಗಳು + +CARDINAL ೭ ಡಬ್ಬಿಗಳು ಏಳು ಡಬ್ಬಿಗಳು + +CARDINAL ೯ ಗೊಂಬೆಗಳು ಒಂಬತ್ತು ಗೊಂಬೆಗಳು + +CARDINAL ೧೦ ಕಥೆಗಳು ಹತ್ತು ಕಥೆಗಳು + +CARDINAL ೯ ಪತ್ರಿಕೆಗಳು ಒಂಬತ್ತು ಪತ್ರಿಕೆಗಳು + +CARDINAL ೨ ಲತೆಗಳು ಎರಡು ಲತೆಗಳು + +CARDINAL ೩ ಕವಿತೆಗಳು ಮೂರು ಕವಿತೆಗಳು + +CARDINAL ೪ ಸರೋವರಗಳು ನಾಲ್ಕು ಸರೋವರಗಳು + +CARDINAL ೫ ಚಪ್ಪಲಿಗಳು ಐದು ಚಪ್ಪಲಿಗಳು + +CARDINAL ೬ ಹಸುಗಳು ಆರು ಹಸುಗಳು + +CARDINAL ೭ ರಸ್ತೆಗಳು ಏಳು ರಸ್ತೆಗಳು + +CARDINAL ೮ ಕಣ್ಣುಗಳು ಎಂಟು ಕಣ್ಣುಗಳು + +CARDINAL ೧೦ ಮಾತುಗಳು ಹತ್ತು ಮಾತುಗಳು + +CARDINAL ೧೦೧ ನೂರ ಒಂದು + +CARDINAL ೧೦೨ ನೂರ ಎರಡು + +CARDINAL ೧೦೩ ನೂರ ಮೂರು + +CARDINAL ೧೦೪ ನೂರ ನಾಲ್ಕು + +CARDINAL ೧೦೫ ನೂರ ಐದು + +CARDINAL ೧೦೬ ನೂರ ಆರು + +CARDINAL ೧೦೭ ನೂರ ಏಳು + +CARDINAL ೧೦೮ ನೂರ ಎಂಟು + +CARDINAL ೧೦೯ ನೂರ ಒಂಬತ್ತು + +CARDINAL ೧೧೦ ನೂರ ಹತ್ತು + +CARDINAL ೧೧೧ ನೂರ ಹನ್ನೊಂದು + +CARDINAL ೧೧೨ ನೂರ ಹನ್ನೆರಡು + +CARDINAL ೧೧೩ ನೂರ ಹದಿಮೂರು + +CARDINAL ೧೧೪ ನೂರ ಹದಿನಾಲ್ಕು + +CARDINAL ೧೧೫ ನೂರ ಹದಿನೈದು + +CARDINAL ೧೧೬ ನೂರ ಹದಿನಾರು + +CARDINAL ೮೧೭ ಎಂಟುನೂರ ಹದಿನೇಳು + +CARDINAL ೮೧೮ ಎಂಟುನೂರ ಹದಿನೆಂಟು + +CARDINAL ೮೧೯ ಎಂಟುನೂರ ಹತ್ತೊಂಬತ್ತು + +CARDINAL ೮೨೦ ಎಂಟುನೂರ ಇಪ್ಪತ್ತು + +CARDINAL ೮೨೧ ಎಂಟುನೂರ ಇಪ್ಪತ್ತೊಂದು + +CARDINAL ೮೨೨ ಎಂಟುನೂರ ಇಪ್ಪತ್ತೆರಡು + +CARDINAL ೮೨೩ ಎಂಟುನೂರ ಇಪ್ಪತ್ತಮೂರು + +CARDINAL ೮೨೪ ಎಂಟುನೂರ ಇಪ್ಪತ್ತನಾಲ್ಕು + +CARDINAL ೮೨೫ ಎಂಟುನೂರ ಇಪ್ಪತ್ತೈದು + +CARDINAL ೮೨೬ ಎಂಟುನೂರ ಇಪ್ಪತ್ತಾರು + +CARDINAL ೮೨೭ ಎಂಟುನೂರ ಇಪ್ಪತ್ತೇಳು + +CARDINAL ೮೨೮ ಎಂಟುನೂರ ಇಪ್ಪತ್ತೆಂಟು + +CARDINAL ೮೨೯ ಎಂಟುನೂರ ಇಪ್ಪತ್ತೊಂಬತ್ತು + +CARDINAL ೮೩೦ ಎಂಟುನೂರ ಮೂವತ್ತು + +CARDINAL ೮೩೧ ಎಂಟುನೂರ ಮೂವತ್ತೊಂದು + +CARDINAL ೮೩೨ ಎಂಟುನೂರ ಮೂವತ್ತೆರಡು + +CARDINAL ೮೩೩ ಎಂಟುನೂರ ಮೂವತ್ತಮೂರು + +CARDINAL ೮೩೪ ಎಂಟುನೂರ ಮೂವತ್ತನಾಲ್ಕು + +CARDINAL ೮೩೫ ಎಂಟುನೂರ ಮೂವತ್ತೈದು + +CARDINAL ೮೩೬ ಎಂಟುನೂರ ಮೂವತ್ತಾರು + +CARDINAL ೭೩೭ ಏಳುನೂರ ಮೂವತ್ತೇಳು + +CARDINAL ೭೩೮ ಏಳುನೂರ ಮೂವತ್ತೆಂಟು + +CARDINAL ೭೩೯ ಏಳುನೂರ ಮೂವತ್ತೊಂಬತ್ತು + +CARDINAL ೭೪೦ ಏಳುನೂರ ನಲವತ್ತು + +CARDINAL ೭೪೧ ಏಳುನೂರ ನಲವತ್ತೊಂದು + +CARDINAL ೭೪೨ ಏಳುನೂರ ನಲವತ್ತೆರಡು + +CARDINAL ೭೪೩ ಏಳುನೂರ ನಲವತ್ತಮೂರು + +CARDINAL ೭೪೪ ಏಳುನೂರ ನಲವತ್ತನಾಲ್ಕು + +CARDINAL ೭೪೫ ಏಳುನೂರ ನಲವತ್ತೈದು + +CARDINAL ೪೪೬ ನಾನೂರ ನಲವತ್ತಾರು + +CARDINAL ೪೪೭ ನಾನೂರ ನಲವತ್ತೇಳು + +CARDINAL ೪೪೮ ನಾನೂರ ನಲವತ್ತೆಂಟು + +CARDINAL ೪೪೯ ನಾನೂರ ನಲವತ್ತೊಂಬತ್ತು + +CARDINAL ೪೫೦ ನಾನೂರ ಐವತ್ತು + +CARDINAL ೪೬೧ ನಾನೂರ ಅರವತ್ತೊಂದು + +CARDINAL ೧೭೫ ನೂರ ಎಪ್ಪತ್ತೈದು + +CARDINAL ೧೮೧ ನೂರ ಎಂಬತ್ತೊಂದು + +CARDINAL ೧೯೦ ನೂರ ತೊಂಬತ್ತು + +CARDINAL ೧೯೯ ನೂರ ತೊಂಬತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೧ ಒಂದು ಸಾವಿರದ ಒಂದು + +CARDINAL ೧೦೦೨ ಒಂದು ಸಾವಿರದ ಎರಡು + +CARDINAL ೧೦೦೩ ಒಂದು ಸಾವಿರದ ಮೂರು + +CARDINAL ೧೦೦೪ ಒಂದು ಸಾವಿರದ ನಾಲ್ಕು + +CARDINAL ೧೦೦೫ ಒಂದು ಸಾವಿರದ ಐದು + +CARDINAL ೧೦೦೬ ಒಂದು ಸಾವಿರದ ಆರು + +CARDINAL ೧೦೦೭ ಒಂದು ಸಾವಿರದ ಏಳು + +CARDINAL ೧೦೦೮ ಒಂದು ಸಾವಿರದ ಎಂಟು + +CARDINAL ೧೦೦೯ ಒಂದು ಸಾವಿರದ ಒಂಬತ್ತು + +CARDINAL ೧೦೧೦ ಒಂದು ಸಾವಿರದ ಹತ್ತು + +CARDINAL ೧೦೧೧ ಒಂದು ಸಾವಿರದ ಹನ್ನೊಂದು + +CARDINAL ೧೦೧೨ ಒಂದು ಸಾವಿರದ ಹನ್ನೆರಡು + +CARDINAL ೧೦೧೩ ಒಂದು ಸಾವಿರದ ಹದಿಮೂರು + +CARDINAL ೧೦೧೪ ಒಂದು ಸಾವಿರದ ಹದಿನಾಲ್ಕು + +CARDINAL ೧೦೧೫ ಒಂದು ಸಾವಿರದ ಹದಿನೈದು + +CARDINAL ೧೦೧೬ ಒಂದು ಸಾವಿರದ ಹದಿನಾರು + +CARDINAL ೧೦೧೭ ಒಂದು ಸಾವಿರದ ಹದಿನೇಳು + +CARDINAL ೧೦೧೮ ಒಂದು ಸಾವಿರದ ಹದಿನೆಂಟು + +CARDINAL ೧೦೧೯ ಒಂದು ಸಾವಿರದ ಹತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೨೦ ಒಂದು ಸಾವಿರದ ಇಪ್ಪತ್ತು + +CARDINAL ೧೦೨೧ ಒಂದು ಸಾವಿರದ ಇಪ್ಪತ್ತೊಂದು + +CARDINAL ೧೦೨೨ ಒಂದು ಸಾವಿರದ ಇಪ್ಪತ್ತೆರಡು + +CARDINAL ೧೧೨೩ ಒಂದು ಸಾವಿರದ ನೂರ ಇಪ್ಪತ್ತಮೂರು + +CARDINAL ೧೪೨೪ ಒಂದು ಸಾವಿರದ ನಾನೂರ ಇಪ್ಪತ್ತನಾಲ್ಕು + +CARDINAL ೧೫೨೫ ಒಂದು ಸಾವಿರದ ಐನೂರ ಇಪ್ಪತ್ತೈದು + +CARDINAL ೧೩೨೬ ಒಂದು ಸಾವಿರದ ಮುನ್ನೂರ ಇಪ್ಪತ್ತಾರು + +CARDINAL ೧೪೨೭ ಒಂದು ಸಾವಿರದ ನಾನೂರ ಇಪ್ಪತ್ತೇಳು + +CARDINAL ೧೬೨೮ ಒಂದು ಸಾವಿರದ ಆರುನೂರ ಇಪ್ಪತ್ತೆಂಟು + +CARDINAL ೧೭೨೯ ಒಂದು ಸಾವಿರದ ಏಳುನೂರ ಇಪ್ಪತ್ತೊಂಬತ್ತು + +CARDINAL ೧೮೩೦ ಒಂದು ಸಾವಿರದ ಎಂಟುನೂರ ಮೂವತ್ತು + +CARDINAL ೧೧೩೧ ಒಂದು ಸಾವಿರದ ನೂರ ಮೂವತ್ತೊಂದು + +CARDINAL ೧೨೩೨ ಒಂದು ಸಾವಿರದ ಇನ್ನೂರ ಮೂವತ್ತೆರಡು + +CARDINAL ೧೩೩೩ ಒಂದು ಸಾವಿರದ ಮುನ್ನೂರ ಮೂವತ್ತಮೂರು + +CARDINAL ೧೪೩೪ ಒಂದು ಸಾವಿರದ ನಾನೂರ ಮೂವತ್ತನಾಲ್ಕು + +CARDINAL ೧೫೩೫ ಒಂದು ಸಾವಿರದ ಐನೂರ ಮೂವತ್ತೈದು + +CARDINAL ೧೬೩೬ ಒಂದು ಸಾವಿರದ ಆರುನೂರ ಮೂವತ್ತಾರು + +CARDINAL ೧೭೩೭ ಒಂದು ಸಾವಿರದ ಏಳುನೂರ ಮೂವತ್ತೇಳು + +CARDINAL ೧೮೩೮ ಒಂದು ಸಾವಿರದ ಎಂಟುನೂರ ಮೂವತ್ತೆಂಟು + +CARDINAL ೧೯೩೯ ಒಂದು ಸಾವಿರದ ಒಂಬೈನೂರ ಮೂವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೪೦ ಒಂದು ಸಾವಿರದ ನಲವತ್ತು + +CARDINAL ೧೦೪೧ ಒಂದು ಸಾವಿರದ ನಲವತ್ತೊಂದು + +CARDINAL ೧೦೪೨ ಒಂದು ಸಾವಿರದ ನಲವತ್ತೆರಡು + +CARDINAL ೧೦೪೩ ಒಂದು ಸಾವಿರದ ನಲವತ್ತಮೂರು + +CARDINAL ೧೦೪೪ ಒಂದು ಸಾವಿರದ ನಲವತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೪೫ ಒಂದು ಸಾವಿರದ ನಲವತ್ತೈದು + +CARDINAL ೧೦೪೬ ಒಂದು ಸಾವಿರದ ನಲವತ್ತಾರು + +CARDINAL ೧೦೪೭ ಒಂದು ಸಾವಿರದ ನಲವತ್ತೇಳು + +CARDINAL ೧೦೪೮ ಒಂದು ಸಾವಿರದ ನಲವತ್ತೆಂಟು + +CARDINAL ೧೦೪೯ ಒಂದು ಸಾವಿರದ ನಲವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೫೦ ಒಂದು ಸಾವಿರದ ಐವತ್ತು + +CARDINAL ೧೦೬೧ ಒಂದು ಸಾವಿರದ ಅರವತ್ತೊಂದು + +CARDINAL ೧೦೭೫ ಒಂದು ಸಾವಿರದ ಎಪ್ಪತ್ತೈದು + +CARDINAL ೧೦೮೧ ಒಂದು ಸಾವಿರದ ಎಂಬತ್ತೊಂದು + +CARDINAL ೧೦೯೦ ಒಂದು ಸಾವಿರದ ತೊಂಬತ್ತು + +CARDINAL ೧೦೯೯ ಒಂದು ಸಾವಿರದ ತೊಂಬತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೧ ಹತ್ತು ಸಾವಿರದ ಒಂದು + +CARDINAL ೧೦೦೦೨ ಹತ್ತು ಸಾವಿರದ ಎರಡು + +CARDINAL ೧೦೦೨೩ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತಮೂರು + +CARDINAL ೧೦೦೩೪ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತನಾಲ್ಕು + +CARDINAL ೧೧೩೦೫ ಹನ್ನೊಂದು ಸಾವಿರದ ಮುನ್ನೂರ ಐದು + +CARDINAL ೧೨೪೫೬ ಹನ್ನೆರಡು ಸಾವಿರದ ನಾನೂರ ಐವತ್ತಾರು + +CARDINAL ೧೩೦೪೭ ಹದಿಮೂರು ಸಾವಿರದ ನಲವತ್ತೇಳು + +CARDINAL ೧೦೦೦೮ ಹತ್ತು ಸಾವಿರದ ಎಂಟು + +CARDINAL ೧೦೦೦೯ ಹತ್ತು ಸಾವಿರದ ಒಂಬತ್ತು + +CARDINAL ೧೦೦೧೦ ಹತ್ತು ಸಾವಿರದ ಹತ್ತು + +CARDINAL ೧೦೦೧೧ ಹತ್ತು ಸಾವಿರದ ಹನ್ನೊಂದು + +CARDINAL ೧೦೦೧೨ ಹತ್ತು ಸಾವಿರದ ಹನ್ನೆರಡು + +CARDINAL ೧೦೦೧೩ ಹತ್ತು ಸಾವಿರದ ಹದಿಮೂರು + +CARDINAL ೧೦೦೧೪ ಹತ್ತು ಸಾವಿರದ ಹದಿನಾಲ್ಕು + +CARDINAL ೧೦೦೧೫ ಹತ್ತು ಸಾವಿರದ ಹದಿನೈದು + +CARDINAL ೧೦೦೧೬ ಹತ್ತು ಸಾವಿರದ ಹದಿನಾರು + +CARDINAL ೧೦೦೧೭ ಹತ್ತು ಸಾವಿರದ ಹದಿನೇಳು + +CARDINAL ೧೦೦೧೮ ಹತ್ತು ಸಾವಿರದ ಹದಿನೆಂಟು + +CARDINAL ೧೦೦೧೯ ಹತ್ತು ಸಾವಿರದ ಹತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೨೦ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತು + +CARDINAL ೧೦೦೨೧ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತೊಂದು + +CARDINAL ೧೦೦೨೨ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತೆರಡು + +CARDINAL ೧೦೦೨೩ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತಮೂರು + +CARDINAL ೧೦೦೨೪ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೨೫ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತೈದು + +CARDINAL ೧೦೦೨೬ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತಾರು + +CARDINAL ೧೦೦೨೭ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತೇಳು + +CARDINAL ೧೦೦೨೮ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತೆಂಟು + +CARDINAL ೧೦೦೨೯ ಹತ್ತು ಸಾವಿರದ ಇಪ್ಪತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೩೦ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತು + +CARDINAL ೧೦೦೩೧ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತೊಂದು + +CARDINAL ೧೦೦೩೨ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತೆರಡು + +CARDINAL ೧೦೦೩೩ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತಮೂರು + +CARDINAL ೧೦೦೩೪ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೩೫ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತೈದು + +CARDINAL ೧೦೦೩೬ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತಾರು + +CARDINAL ೧೦೦೩೭ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತೇಳು + +CARDINAL ೧೦೦೩೮ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತೆಂಟು + +CARDINAL ೧೦೦೩೯ ಹತ್ತು ಸಾವಿರದ ಮೂವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೪೦ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತು + +CARDINAL ೧೦೦೪೧ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತೊಂದು + +CARDINAL ೧೦೦೪೨ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತೆರಡು + +CARDINAL ೧೦೦೪೩ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತಮೂರು + +CARDINAL ೧೦೦೪೪ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೪೫ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತೈದು + +CARDINAL ೧೦೦೪೬ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತಾರು + +CARDINAL ೧೦೦೪೭ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತೇಳು + +CARDINAL ೧೦೦೪೮ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತೆಂಟು + +CARDINAL ೧೦೦೪೯ ಹತ್ತು ಸಾವಿರದ ನಲವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೫೦ ಹತ್ತು ಸಾವಿರದ ಐವತ್ತು + +CARDINAL ೧೦೦೬೧ ಹತ್ತು ಸಾವಿರದ ಅರವತ್ತೊಂದು + +CARDINAL ೧೦೦೭೫ ಹತ್ತು ಸಾವಿರದ ಎಪ್ಪತ್ತೈದು + +CARDINAL ೧೦೦೮೧ ಹತ್ತು ಸಾವಿರದ ಎಂಬತ್ತೊಂದು + +CARDINAL ೧೦೦೯೦ ಹತ್ತು ಸಾವಿರದ ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೯೯ ಹತ್ತು ಸಾವಿರದ ತೊಂಬತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೧ ಒಂದು ಲಕ್ಷದ ಒಂದು + +CARDINAL ೧೧೦೦೦೨ ಒಂದು ಲಕ್ಷದ ಹತ್ತು ಸಾವಿರದ ಎರಡು + +CARDINAL ೧೨೦೪೦೩ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತು ಸಾವಿರದ ನಾನೂರ ಮೂರು + +CARDINAL ೧೪೧೫೦೪ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತೊಂದು ಸಾವಿರದ ಐನೂರ ನಾಲ್ಕು + +CARDINAL ೧೫೧೫೧೫ ಒಂದು ಲಕ್ಷದ ಐವತ್ತೊಂದು ಸಾವಿರದ ಐನೂರ ಹದಿನೈದು + +CARDINAL ೧೦೦೦೦೬ ಒಂದು ಲಕ್ಷದ ಆರು + +CARDINAL ೧೦೦೦೦೭ ಒಂದು ಲಕ್ಷದ ಏಳು + +CARDINAL ೧೦೦೦೦೮ ಒಂದು ಲಕ್ಷದ ಎಂಟು + +CARDINAL ೧೦೦೦೦೯ ಒಂದು ಲಕ್ಷದ ಒಂಬತ್ತು + +CARDINAL ೧೦೦೦೧೦ ಒಂದು ಲಕ್ಷದ ಹತ್ತು + +CARDINAL ೧೦೦೦೧೧ ಒಂದು ಲಕ್ಷದ ಹನ್ನೊಂದು + +CARDINAL ೧೦೦೦೧೨ ಒಂದು ಲಕ್ಷದ ಹನ್ನೆರಡು + +CARDINAL ೧೦೦೦೧೩ ಒಂದು ಲಕ್ಷದ ಹದಿಮೂರು + +CARDINAL ೧೦೦೦೧೪ ಒಂದು ಲಕ್ಷದ ಹದಿನಾಲ್ಕು + +CARDINAL ೧೦೦೦೧೫ ಒಂದು ಲಕ್ಷದ ಹದಿನೈದು + +CARDINAL ೧೦೦೦೧೬ ಒಂದು ಲಕ್ಷದ ಹದಿನಾರು + +CARDINAL ೧೦೦೦೧೭ ಒಂದು ಲಕ್ಷದ ಹದಿನೇಳು + +CARDINAL ೧೦೦೦೧೮ ಒಂದು ಲಕ್ಷದ ಹದಿನೆಂಟು + +CARDINAL ೧೦೦೦೧೯ ಒಂದು ಲಕ್ಷದ ಹತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೨೦ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತು + +CARDINAL ೧೦೦೦೨೧ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತೊಂದು + +CARDINAL ೧೦೦೦೨೨ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತೆರಡು + +CARDINAL ೧೦೦೦೨೩ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತಮೂರು + +CARDINAL ೧೦೦೦೨೪ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೦೨೫ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತೈದು + +CARDINAL ೧೦೦೦೨೬ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತಾರು + +CARDINAL ೧೦೦೦೨೭ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತೇಳು + +CARDINAL ೧೦೦೦೨೮ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತೆಂಟು + +CARDINAL ೧೦೦೦೨೯ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೩೦ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತು + +CARDINAL ೧೦೦೦೩೧ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತೊಂದು + +CARDINAL ೧೦೦೦೩೨ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತೆರಡು + +CARDINAL ೧೦೦೦೩೩ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತಮೂರು + +CARDINAL ೧೦೦೦೩೪ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೦೩೫ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತೈದು + +CARDINAL ೧೦೦೦೩೬ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತಾರು + +CARDINAL ೧೦೦೦೩೭ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತೇಳು + +CARDINAL ೧೦೦೦೩೮ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತೆಂಟು + +CARDINAL ೧೦೦೦೩೯ ಒಂದು ಲಕ್ಷದ ಮೂವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೪೦ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತು + +CARDINAL ೧೦೦೦೪೧ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತೊಂದು + +CARDINAL ೧೦೦೦೪೨ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತೆರಡು + +CARDINAL ೧೦೦೦೪೩ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತಮೂರು + +CARDINAL ೧೦೦೦೪೪ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೦೪೫ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತೈದು + +CARDINAL ೧೦೦೦೪೬ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತಾರು + +CARDINAL ೧೦೦೦೪೭ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತೇಳು + +CARDINAL ೧೦೦೦೪೮ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತೆಂಟು + +CARDINAL ೧೦೦೦೪೯ ಒಂದು ಲಕ್ಷದ ನಲವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೫೦ ಒಂದು ಲಕ್ಷದ ಐವತ್ತು + +CARDINAL ೧೦೦೦೬೧ ಒಂದು ಲಕ್ಷದ ಅರವತ್ತೊಂದು + +CARDINAL ೧೦೦೦೭೫ ಒಂದು ಲಕ್ಷದ ಎಪ್ಪತ್ತೈದು + +CARDINAL ೧೦೦೦೮೧ ಒಂದು ಲಕ್ಷದ ಎಂಬತ್ತೊಂದು + +CARDINAL ೧೦೦೦೯೦ ಒಂದು ಲಕ್ಷದ ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೯೯ ಒಂದು ಲಕ್ಷದ ತೊಂಬತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೦೧ ಹತ್ತು ಲಕ್ಷದ ಒಂದು + +CARDINAL ೧೦೦೦೦೦೨ ಹತ್ತು ಲಕ್ಷದ ಎರಡು + +CARDINAL ೧೦೦೦೦೦೩ ಹತ್ತು ಲಕ್ಷದ ಮೂರು + +CARDINAL ೧೦೦೦೦೦೪ ಹತ್ತು ಲಕ್ಷದ ನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೦೫ ಹತ್ತು ಲಕ್ಷದ ಐದು + +CARDINAL ೧೦೦೦೦೦೬ ಹತ್ತು ಲಕ್ಷದ ಆರು + +CARDINAL ೧೦೦೦೦೦೭ ಹತ್ತು ಲಕ್ಷದ ಏಳು + +CARDINAL ೧೦೦೦೦೦೮ ಹತ್ತು ಲಕ್ಷದ ಎಂಟು + +CARDINAL ೧೦೦೦೦೦೯ ಹತ್ತು ಲಕ್ಷದ ಒಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೧೦ ಹತ್ತು ಲಕ್ಷದ ಹತ್ತು + +CARDINAL ೧೦೦೦೦೧೧ ಹತ್ತು ಲಕ್ಷದ ಹನ್ನೊಂದು + +CARDINAL ೧೦೦೦೦೧೨ ಹತ್ತು ಲಕ್ಷದ ಹನ್ನೆರಡು + +CARDINAL ೧೦೦೦೦೧೩ ಹತ್ತು ಲಕ್ಷದ ಹದಿಮೂರು + +CARDINAL ೧೦೦೦೦೧೪ ಹತ್ತು ಲಕ್ಷದ ಹದಿನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೧೫ ಹತ್ತು ಲಕ್ಷದ ಹದಿನೈದು + +CARDINAL ೧೦೦೦೦೧೬ ಹತ್ತು ಲಕ್ಷದ ಹದಿನಾರು + +CARDINAL ೧೦೦೦೦೧೭ ಹತ್ತು ಲಕ್ಷದ ಹದಿನೇಳು + +CARDINAL ೧೦೦೦೦೧೮ ಹತ್ತು ಲಕ್ಷದ ಹದಿನೆಂಟು + +CARDINAL ೧೦೦೦೦೧೯ ಹತ್ತು ಲಕ್ಷದ ಹತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೨೦ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತು + +CARDINAL ೧೦೦೦೦೨೧ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೨೨ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತೆರಡು + +CARDINAL ೧೦೦೦೦೨೩ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತಮೂರು + +CARDINAL ೧೦೦೦೦೨೪ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೨೫ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತೈದು + +CARDINAL ೧೦೦೦೦೨೬ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತಾರು + +CARDINAL ೧೦೦೦೦೨೭ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತೇಳು + +CARDINAL ೧೦೦೦೦೨೮ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತೆಂಟು + +CARDINAL ೧೦೦೦೦೨೯ ಹತ್ತು ಲಕ್ಷದ ಇಪ್ಪತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೩೦ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತು + +CARDINAL ೧೦೦೦೦೩೧ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೩೨ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತೆರಡು + +CARDINAL ೧೦೦೦೦೩೩ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತಮೂರು + +CARDINAL ೧೦೦೦೦೩೪ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೩೫ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತೈದು + +CARDINAL ೧೦೦೦೦೩೬ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತಾರು + +CARDINAL ೧೦೦೦೦೩೭ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತೇಳು + +CARDINAL ೧೦೦೦೦೩೮ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತೆಂಟು + +CARDINAL ೧೦೦೦೦೩೯ ಹತ್ತು ಲಕ್ಷದ ಮೂವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೪೦ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತು + +CARDINAL ೧೦೦೦೦೪೧ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೪೨ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತೆರಡು + +CARDINAL ೧೦೦೦೦೪೩ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತಮೂರು + +CARDINAL ೧೦೦೦೦೪೪ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೪೫ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತೈದು + +CARDINAL ೧೦೦೦೦೪೬ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತಾರು + +CARDINAL ೧೦೦೦೦೪೭ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತೇಳು + +CARDINAL ೧೦೦೦೦೪೮ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತೆಂಟು + +CARDINAL ೧೦೦೦೦೪೯ ಹತ್ತು ಲಕ್ಷದ ನಲವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೫೦ ಹತ್ತು ಲಕ್ಷದ ಐವತ್ತು + +CARDINAL ೧೦೦೦೦೬೧ ಹತ್ತು ಲಕ್ಷದ ಅರವತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೭೫ ಹತ್ತು ಲಕ್ಷದ ಎಪ್ಪತ್ತೈದು + +CARDINAL ೧೦೦೦೦೮೧ ಹತ್ತು ಲಕ್ಷದ ಎಂಬತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೯೦ ಹತ್ತು ಲಕ್ಷದ ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೯೯ ಹತ್ತು ಲಕ್ಷದ ತೊಂಬತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೦೦೧ ಒಂದು ಕೋಟಿಯ ಒಂದು + +CARDINAL ೧೦೦೦೦೦೦೨ ಒಂದು ಕೋಟಿಯ ಎರಡು + +CARDINAL ೧೦೦೦೦೦೦೩ ಒಂದು ಕೋಟಿಯ ಮೂರು + +CARDINAL ೧೦೦೦೦೦೦೪ ಒಂದು ಕೋಟಿಯ ನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೦೦೫ ಒಂದು ಕೋಟಿಯ ಐದು + +CARDINAL ೧೦೦೦೦೦೦೬ ಒಂದು ಕೋಟಿಯ ಆರು + +CARDINAL ೧೦೦೦೦೦೦೭ ಒಂದು ಕೋಟಿಯ ಏಳು + +CARDINAL ೧೦೦೦೦೦೦೮ ಒಂದು ಕೋಟಿಯ ಎಂಟು + +CARDINAL ೧೦೦೦೦೦೦೯ ಒಂದು ಕೋಟಿಯ ಒಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೦೧೦ ಒಂದು ಕೋಟಿಯ ಹತ್ತು + +CARDINAL ೧೦೦೦೦೦೧೧ ಒಂದು ಕೋಟಿಯ ಹನ್ನೊಂದು + +CARDINAL ೧೦೦೦೦೦೧೨ ಒಂದು ಕೋಟಿಯ ಹನ್ನೆರಡು + +CARDINAL ೧೦೦೦೦೦೧೩ ಒಂದು ಕೋಟಿಯ ಹದಿಮೂರು + +CARDINAL ೧೦೦೦೦೦೧೪ ಒಂದು ಕೋಟಿಯ ಹದಿನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೦೧೫ ಒಂದು ಕೋಟಿಯ ಹದಿನೈದು + +CARDINAL ೧೦೦೦೦೦೧೬ ಒಂದು ಕೋಟಿಯ ಹದಿನಾರು + +CARDINAL ೧೦೦೦೦೦೧೭ ಒಂದು ಕೋಟಿಯ ಹದಿನೇಳು + +CARDINAL ೧೦೦೦೦೦೧೮ ಒಂದು ಕೋಟಿಯ ಹದಿನೆಂಟು + +CARDINAL ೧೦೦೦೦೦೧೯ ಒಂದು ಕೋಟಿಯ ಹತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೦೨೦ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತು + +CARDINAL ೧೦೦೦೦೦೨೧ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೦೨೨ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತೆರಡು + +CARDINAL ೧೦೦೦೦೦೨೩ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತಮೂರು + +CARDINAL ೧೦೦೦೦೦೨೪ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೦೨೫ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತೈದು + +CARDINAL ೧೦೦೦೦೦೨೬ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತಾರು + +CARDINAL ೧೦೦೦೦೦೨೭ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತೇಳು + +CARDINAL ೧೦೦೦೦೦೨೮ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತೆಂಟು + +CARDINAL ೧೦೦೦೦೦೨೯ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೦೩೦ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತು + +CARDINAL ೧೦೦೦೦೦೩೧ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೦೩೨ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತೆರಡು + +CARDINAL ೧೦೦೦೦೦೩೩ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತಮೂರು + +CARDINAL ೧೦೦೦೦೦೩೪ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೦೩೫ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತೈದು + +CARDINAL ೧೦೦೦೦೦೩೬ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತಾರು + +CARDINAL ೧೦೦೦೦೦೩೭ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತೇಳು + +CARDINAL ೧೦೦೦೦೦೩೮ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತೆಂಟು + +CARDINAL ೧೦೦೦೦೦೩೯ ಒಂದು ಕೋಟಿಯ ಮೂವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೦೪೦ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತು + +CARDINAL ೧೦೦೦೦೦೪೧ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೦೪೨ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತೆರಡು + +CARDINAL ೧೦೦೦೦೦೪೩ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತಮೂರು + +CARDINAL ೧೦೦೦೦೦೪೪ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತನಾಲ್ಕು + +CARDINAL ೧೦೦೦೦೦೪೫ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತೈದು + +CARDINAL ೧೦೦೦೦೦೪೬ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತಾರು + +CARDINAL ೧೦೦೦೦೦೪೭ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತೇಳು + +CARDINAL ೧೦೦೦೦೦೪೮ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತೆಂಟು + +CARDINAL ೧೦೦೦೦೦೪೯ ಒಂದು ಕೋಟಿಯ ನಲವತ್ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೦೫೦ ಒಂದು ಕೋಟಿಯ ಐವತ್ತು + +CARDINAL ೧೦೦೦೦೦೬೧ ಒಂದು ಕೋಟಿಯ ಅರವತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೦೭೫ ಒಂದು ಕೋಟಿಯ ಎಪ್ಪತ್ತೈದು + +CARDINAL ೧೦೦೦೦೦೮೧ ಒಂದು ಕೋಟಿಯ ಎಂಬತ್ತೊಂದು + +CARDINAL ೧೦೦೦೦೦೯೦ ಒಂದು ಕೋಟಿಯ ತೊಂಬತ್ತು + +CARDINAL ೧೦೦೦೦೦೯೯ ಒಂದು ಕೋಟಿಯ ತೊಂಬತ್ತೊಂಬತ್ತು + +CARDINAL ೧೩೨೩ ಒಂದು ಸಾವಿರದ ಮುನ್ನೂರ ಇಪ್ಪತ್ತಮೂರು + +CARDINAL ೧೩೪೫ ಒಂದು ಸಾವಿರದ ಮುನ್ನೂರ ನಲವತ್ತೈದು + +CARDINAL ೧೩೪೫೬ ಹದಿಮೂರು ಸಾವಿರದ ನಾನೂರ ಐವತ್ತಾರು + +CARDINAL ೧೨೩೪೬ ಹನ್ನೆರಡು ಸಾವಿರದ ಮುನ್ನೂರ ನಲವತ್ತಾರು + +CARDINAL ೧೨೩೪೫೬ ಒಂದು ಲಕ್ಷದ ಇಪ್ಪತ್ತಮೂರು ಸಾವಿರದ ನಾನೂರ ಐವತ್ತಾರು + +CARDINAL ೮೭೨೯೮೭ ಎಂಟು ಲಕ್ಷದ ಎಪ್ಪತ್ತೆರಡು ಸಾವಿರದ ಒಂಬೈನೂರ ಎಂಬತ್ತೇಳು + +CARDINAL ೯೮೭೬೦೯ ಒಂಬತ್ತು ಲಕ್ಷದ ಎಂಬತ್ತೇಳು ಸಾವಿರದ ಆರುನೂರ ಒಂಬತ್ತು + +CARDINAL ೯೮೭೬೭೮೯ ತೊಂಬತ್ತೆಂಟು ಲಕ್ಷದ ಎಪ್ಪತ್ತಾರು ಸಾವಿರದ ಏಳುನೂರ ಎಂಬತ್ತೊಂಬತ್ತು + +CARDINAL ೨೩೪೫೫೬೭ ಇಪ್ಪತ್ತಮೂರು ಲಕ್ಷದ ನಲವತ್ತೈದು ಸಾವಿರದ ಐನೂರ ಅರವತ್ತೇಳು + +CARDINAL ೧೨೩೪೫೫೬೭ ಒಂದು ಕೋಟಿಯ ಇಪ್ಪತ್ತಮೂರು ಲಕ್ಷದ ನಲವತ್ತೈದು ಸಾವಿರದ ಐನೂರ ಅರವತ್ತೇಳು + +CARDINAL ೧೨೧೨೧೨೧೨೨ ಹನ್ನೆರಡು ಕೋಟಿಯ ಹನ್ನೆರಡು ಲಕ್ಷದ ಹನ್ನೆರಡು ಸಾವಿರದ ನೂರ ಇಪ್ಪತ್ತೆರಡು + +CARDINAL ೧೦೦೨೩೪೫೫೬೭ ನೂರು ಕೋಟಿಯ ಇಪ್ಪತ್ತಮೂರು ಲಕ್ಷದ ನಲವತ್ತೈದು ಸಾವಿರದ ಐನೂರ ಅರವತ್ತೇಳು + +CARDINAL ೧೧೨೨೩೪೫೫೬೭ ನೂರ ಹನ್ನೆರಡು ಕೋಟಿಯ ಇಪ್ಪತ್ತಮೂರು ಲಕ್ಷದ ನಲವತ್ತೈದು ಸಾವಿರದ ಐನೂರ ಅರವತ್ತೇಳು + +CARDINAL ೧೦೨೨೩೪೫೫೬೭ ನೂರ ಎರಡು ಕೋಟಿಯ ಇಪ್ಪತ್ತಮೂರು ಲಕ್ಷದ ನಲವತ್ತೈದು ಸಾವಿರದ ಐನೂರ ಅರವತ್ತೇಳು + +CARDINAL ೧೧೦೨೨೩೪೫೫೬೭ ಒಂದು ಸಾವಿರದ ನೂರ ಎರಡು ಕೋಟಿಯ ಇಪ್ಪತ್ತಮೂರು ಲಕ್ಷದ ನಲವತ್ತೈದು ಸಾವಿರದ ಐನೂರ ಅರವತ್ತೇಳು + +CARDINAL ೫೧೦೨೨೩೪೫೫೬೭ ಐದು ಸಾವಿರದ ನೂರ ಎರಡು ಕೋಟಿಯ ಇಪ್ಪತ್ತಮೂರು ಲಕ್ಷದ ನಲವತ್ತೈದು ಸಾವಿರದ ಐನೂರ ಅರವತ್ತೇಳು + \ No newline at end of file diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/__init__.py b/nemo_text_processing 2/inverse_text_normalization/kn/__init__.py new file mode 100644 index 000000000..b650cbece --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/__init__.py @@ -0,0 +1,17 @@ +# Copyright (c) 2024, 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. + +from nemo_text_processing.inverse_text_normalization.hi.taggers.tokenize_and_classify import ClassifyFst +from nemo_text_processing.inverse_text_normalization.hi.verbalizers.verbalize import VerbalizeFst +from nemo_text_processing.inverse_text_normalization.hi.verbalizers.verbalize_final import VerbalizeFinalFst diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/data/__init__.py b/nemo_text_processing 2/inverse_text_normalization/kn/data/__init__.py new file mode 100644 index 000000000..d9155f923 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/data/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2024, 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. diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/digit.tsv b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/digit.tsv new file mode 100644 index 000000000..6d9c5db59 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/digit.tsv @@ -0,0 +1,18 @@ +೧ ಒಂದು +೨ ಎರಡು +೩ ಮೂರು +೪ ನಾಲ್ಕು +೫ ಐದು +೬ ಆರು +೭ ಏಳು +೮ ಎಂಟು +೯ ಒಂಬತ್ತು +1 ಒಂದು +2 ಎರಡು +3 ಮೂರು +4 ನಾಲ್ಕು +5 ಐದು +6 ಆರು +7 ಏಳು +8 ಎಂಟು +9 ಒಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/hundred.tsv b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/hundred.tsv new file mode 100644 index 000000000..b3aff9b13 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/hundred.tsv @@ -0,0 +1,18 @@ +೧ ನೂರ +೨ ಇನ್ನೂರ +೩ ಮುನ್ನೂರ +೪ ನಾನೂರ +೫ ಐನೂರ +೬ ಆರುನೂರ +೭ ಏಳುನೂರ +೮ ಎಂಟುನೂರ +೯ ಒಂಬೈನೂರ +1 ನೂರ +2 ಇನ್ನೂರ +3 ಮುನ್ನೂರ +4 ನಾನೂರ +5 ಐನೂರ +6 ಆರುನೂರ +7 ಏಳುನೂರ +8 ಎಂಟುನೂರ +9 ಒಂಬೈನೂರ \ No newline at end of file diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/paune.tsv b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/paune.tsv new file mode 100644 index 000000000..4e9fb55d5 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/paune.tsv @@ -0,0 +1,98 @@ +೨ ಎರಡು +೩ ಮೂರು +೪ ನಾಲ್ಕು +೫ ಐದು +೬ ಆರು +೭ ಏಳು +೮ ಎಂಟು +೯ ಒಂಬತ್ತು +೧೦ ಹತ್ತು +೧೧ ಹನ್ನೊಂದು +೧೨ ಹನ್ನೆರಡು +೧೩ ಹದಿಮೂರು +೧೪ ಹದಿನಾಲ್ಕು +೧೫ ಹದಿನೈದು +೧೬ ಹದಿನಾರು +೧೭ ಹದಿನೇಳು +೧೮ ಹದಿನೆಂಟು +೧೯ ಹತ್ತೊಂಬತ್ತು +೨೦ ಇಪ್ಪತ್ತು +೨೧ ಇಪ್ಪತ್ತೊಂದು +೨೨ ಇಪ್ಪತ್ತೆರಡು +೨೩ ಇಪ್ಪತ್ತ್ಮೂರು +೨೪ ಇಪ್ಪತ್ತ್ನಾಲ್ಕು +೨೫ ಇಪ್ಪತ್ತೈದು +೨೬ ಇಪ್ಪತ್ತಾರು +೨೭ ಇಪ್ಪತ್ತೇಳು +೨೮ ಇಪ್ಪತ್ತೆಂಟು +೨೯ ಇಪ್ಪತ್ತೊಂಬತ್ತು +೩೦ ಮೂವತ್ತು +೩೧ ಮೂವತ್ತೊಂದು +೩೨ ಮೂವತ್ತೆರಡು +೩೩ ಮೂವತ್ತ್ಮೂರು +೩೪ ಮೂವತ್ತ್ನಾಲ್ಕು +೩೫ ಮೂವತ್ತೈದು +೩೬ ಮೂವತ್ತಾರು +೩೭ ಮೂವತ್ತೇಳು +೩೮ ಮೂವತ್ತೆಂಟು +೩೯ ಮೂವತ್ತೊಂಬತ್ತು +೪೦ ನಲವತ್ತು +೪೧ ನಲವತ್ತೊಂದು +೪೨ ನಲವತ್ತೆರಡು +೪೩ ನಲವತ್ತ್ಮೂರು +೪೪ ನಲವತ್ತ್ನಾಲ್ಕು +೪೫ ನಲವತ್ತೈದು +೪೬ ನಲವತ್ತಾರು +೪೭ ನಲವತ್ತೇಳು +೪೮ ನಲವತ್ತೆಂಟು +೪೯ ನಲವತ್ತೊಂಬತ್ತು +೫೦ ಐವತ್ತು +೫೧ ಐವತ್ತೊಂದು +೫೨ ಐವತ್ತೆರಡು +೫೩ ಐವತ್ತ್ಮೂರು +೫೪ ಐವತ್ತ್ನಾಲ್ಕು +೫೫ ಐವತ್ತೈದು +೫೬ ಐವತ್ತಾರು +೫೭ ಐವತ್ತೇಳು +೫೮ ಐವತ್ತೆಂಟು +೫೯ ಐವತ್ತೊಂಬತ್ತು +೬೦ ಅರವತ್ತು +೬೧ ಅರವತ್ತೊಂದು +೬೨ ಅರವತ್ತೆರಡು +೬೩ ಅರವತ್ತ್ಮೂರು +೬೪ ಅರವತ್ತ್ನಾಲ್ಕು +೬೫ ಅರವತ್ತೈದು +೬೬ ಅರವತ್ತಾರು +೬೭ ಅರವತ್ತೇಳು +೬೮ ಅರವತ್ತೆಂಟು +೬೯ ಅರವತ್ತೊಂಬತ್ತು +೭೦ ಎಪ್ಪತ್ತು +೭೧ ಎಪ್ಪತ್ತೊಂದು +೭೨ ಎಪ್ಪತ್ತೆರಡು +೭೩ ಎಪ್ಪತ್ತ್ಮೂರು +೭೪ ಎಪ್ಪತ್ತ್ನಾಲ್ಕು +೭೫ ಎಪ್ಪತ್ತೈದು +೭೬ ಎಪ್ಪತ್ತಾರು +೭೭ ಎಪ್ಪತ್ತೇಳು +೭೮ ಎಪ್ಪತ್ತೆಂಟು +೭೯ ಎಪ್ಪತ್ತೊಂಬತ್ತು +೮೦ ಎಂಬತ್ತು +೮೧ ಎಂಬತ್ತೊಂದು +೮೨ ಎಂಬತ್ತೆರಡು +೮೩ ಎಂಬತ್ತ್ಮೂರು +೮೪ ಎಂಬತ್ತ್ನಾಲ್ಕು +೮೫ ಎಂಬತ್ತೈದು +೮೬ ಎಂಬತ್ತಾರು +೮೭ ಎಂಬತ್ತೇಳು +೮೮ ಎಂಬತ್ತೆಂಟು +೮೯ ಎಂಬತ್ತೊಂಬತ್ತು +೯೦ ತೊಂಬತ್ತು +೯೧ ತೊಂಬತ್ತೊಂದು +೯೨ ತೊಂಬತ್ತೆರಡು +೯೩ ತೊಂಬತ್ತ್ಮೂರು +೯೪ ತೊಂಬತ್ತ್ನಾಲ್ಕು +೯೫ ತೊಂಬತ್ತೈದು +೯೬ ತೊಂಬತ್ತಾರು +೯೭ ತೊಂಬತ್ತೇಳು +೯೮ ತೊಂಬತ್ತೆಂಟು +೯೯ ತೊಂಬತ್ತೊಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/quantities.tsv b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/quantities.tsv new file mode 100644 index 000000000..db24a441d --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/quantities.tsv @@ -0,0 +1,3 @@ +ಸಾವಿರ ಸಾವಿರ +ಲಕ್ಷ ಲಕ್ಷ +ಕೋಟಿ ಕೋಟಿ \ No newline at end of file diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/teens_and_ties.tsv b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/teens_and_ties.tsv new file mode 100644 index 000000000..d7cc5a427 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/teens_and_ties.tsv @@ -0,0 +1,90 @@ +೧೦ ಹತ್ತು +೧೧ ಹನ್ನೊಂದು +೧೨ ಹನ್ನೆರಡು +೧೩ ಹದಿಮೂರು +೧೪ ಹದಿನಾಲ್ಕು +೧೫ ಹದಿನೈದು +೧೬ ಹದಿನಾರು +೧೭ ಹದಿನೇಳು +೧೮ ಹದಿನೆಂಟು +೧೯ ಹತ್ತೊಂಬತ್ತು +೨೦ ಇಪ್ಪತ್ತು +೨೧ ಇಪ್ಪತ್ತೊಂದು +೨೨ ಇಪ್ಪತ್ತೆರಡು +೨೩ ಇಪ್ಪತ್ತಮೂರು +೨೪ ಇಪ್ಪತ್ತನಾಲ್ಕು +೨೫ ಇಪ್ಪತ್ತೈದು +೨೬ ಇಪ್ಪತ್ತಾರು +೨೭ ಇಪ್ಪತ್ತೇಳು +೨೮ ಇಪ್ಪತ್ತೆಂಟು +೨೯ ಇಪ್ಪತ್ತೊಂಬತ್ತು +೩೦ ಮೂವತ್ತು +೩೧ ಮೂವತ್ತೊಂದು +೩೨ ಮೂವತ್ತೆರಡು +೩೩ ಮೂವತ್ತಮೂರು +೩೪ ಮೂವತ್ತನಾಲ್ಕು +೩೫ ಮೂವತ್ತೈದು +೩೬ ಮೂವತ್ತಾರು +೩೭ ಮೂವತ್ತೇಳು +೩೮ ಮೂವತ್ತೆಂಟು +೩೯ ಮೂವತ್ತೊಂಬತ್ತು +೪೦ ನಲವತ್ತು +೪೧ ನಲವತ್ತೊಂದು +೪೨ ನಲವತ್ತೆರಡು +೪೩ ನಲವತ್ತಮೂರು +೪೪ ನಲವತ್ತನಾಲ್ಕು +೪೫ ನಲವತ್ತೈದು +೪೬ ನಲವತ್ತಾರು +೪೭ ನಲವತ್ತೇಳು +೪೮ ನಲವತ್ತೆಂಟು +೪೯ ನಲವತ್ತೊಂಬತ್ತು +೫೦ ಐವತ್ತು +೫೧ ಐವತ್ತೊಂದು +೫೨ ಐವತ್ತೆರಡು +೫೩ ಐವತ್ತಮೂರು +೫೪ ಐವತ್ತನಾಲ್ಕು +೫೫ ಐವತ್ತೈದು +೫೬ ಐವತ್ತಾರು +೫೭ ಐವತ್ತೇಳು +೫೮ ಐವತ್ತೆಂಟು +೫೯ ಐವತ್ತೊಂಬತ್ತು +೬೦ ಅರವತ್ತು +೬೧ ಅರವತ್ತೊಂದು +೬೨ ಅರವತ್ತೆರಡು +೬೩ ಅರವತ್ತಮೂರು +೬೪ ಅರವತ್ತನಾಲ್ಕು +೬೫ ಅರವತ್ತೈದು +೬೬ ಅರವತ್ತಾರು +೬೭ ಅರವತ್ತೇಳು +೬೮ ಅರವತ್ತೆಂಟು +೬೯ ಅರವತ್ತೊಂಬತ್ತು +೭೦ ಎಪ್ಪತ್ತು +೭೧ ಎಪ್ಪತ್ತೊಂದು +೭೨ ಎಪ್ಪತ್ತೆರಡು +೭೩ ಎಪ್ಪತ್ತಮೂರು +೭೪ ಎಪ್ಪತ್ತನಾಲ್ಕು +೭೫ ಎಪ್ಪತ್ತೈದು +೭೬ ಎಪ್ಪತ್ತಾರು +೭೭ ಎಪ್ಪತ್ತೇಳು +೭೮ ಎಪ್ಪತ್ತೆಂಟು +೭೯ ಎಪ್ಪತ್ತೊಂಬತ್ತು +೮೦ ಎಂಬತ್ತು +೮೧ ಎಂಬತ್ತೊಂದು +೮೨ ಎಂಬತ್ತೆರಡು +೮೩ ಎಂಬತ್ತಮೂರು +೮೪ ಎಂಬತ್ತನಾಲ್ಕು +೮೫ ಎಂಬತ್ತೈದು +೮೬ ಎಂಬತ್ತಾರು +೮೭ ಎಂಬತ್ತೇಳು +೮೮ ಎಂಬತ್ತೆಂಟು +೮೯ ಎಂಬತ್ತೊಂಬತ್ತು +೯೦ ತೊಂಬತ್ತು +೯೧ ತೊಂಬತ್ತೊಂದು +೯೨ ತೊಂಬತ್ತೆರಡು +೯೩ ತೊಂಬತ್ತಮೂರು +೯೪ ತೊಂಬತ್ತನಾಲ್ಕು +೯೫ ತೊಂಬತ್ತೈದು +೯೬ ತೊಂಬತ್ತಾರು +೯೭ ತೊಂಬತ್ತೇಳು +೯೮ ತೊಂಬತ್ತೆಂಟು +೯೯ ತೊಂಬತ್ತೊಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/teens_and_ties_en.tsv b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/teens_and_ties_en.tsv new file mode 100644 index 000000000..1a4a6fbd8 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/teens_and_ties_en.tsv @@ -0,0 +1,90 @@ +10 ಹತ್ತು +11 ಹನ್ನೊಂದು +12 ಹನ್ನೆರಡು +13 ಹದಿಮೂರು +14 ಹದಿನಾಲ್ಕು +15 ಹದಿನೈದು +16 ಹದಿನಾರು +17 ಹದಿನೇಳು +18 ಹದಿನೆಂಟು +19 ಹತ್ತೊಂಬತ್ತು +20 ಇಪ್ಪತ್ತು +21 ಇಪ್ಪತ್ತೊಂದು +22 ಇಪ್ಪತ್ತೆರಡು +23 ಇಪ್ಪತ್ತಮೂರು +24 ಇಪ್ಪತ್ತನಾಲ್ಕು +25 ಇಪ್ಪತ್ತೈದು +26 ಇಪ್ಪತ್ತಾರು +27 ಇಪ್ಪತ್ತೇಳು +28 ಇಪ್ಪತ್ತೆಂಟು +29 ಇಪ್ಪತ್ತೊಂಬತ್ತು +30 ಮೂವತ್ತು +31 ಮೂವತ್ತೊಂದು +32 ಮೂವತ್ತೆರಡು +33 ಮೂವತ್ತಮೂರು +34 ಮೂವತ್ತನಾಲ್ಕು +35 ಮೂವತ್ತೈದು +36 ಮೂವತ್ತಾರು +37 ಮೂವತ್ತೇಳು +38 ಮೂವತ್ತೆಂಟು +39 ಮೂವತ್ತೊಂಬತ್ತು +40 ನಲವತ್ತು +41 ನಲವತ್ತೊಂದು +42 ನಲವತ್ತೆರಡು +43 ನಲವತ್ತಮೂರು +44 ನಲವತ್ತನಾಲ್ಕು +45 ನಲವತ್ತೈದು +46 ನಲವತ್ತಾರು +47 ನಲವತ್ತೇಳು +48 ನಲವತ್ತೆಂಟು +49 ನಲವತ್ತೊಂಬತ್ತು +50 ಐವತ್ತು +51 ಐವತ್ತೊಂದು +52 ಐವತ್ತೆರಡು +53 ಐವತ್ತಮೂರು +54 ಐವತ್ತನಾಲ್ಕು +55 ಐವತ್ತೈದು +56 ಐವತ್ತಾರು +57 ಐವತ್ತೇಳು +58 ಐವತ್ತೆಂಟು +59 ಐವತ್ತೊಂಬತ್ತು +60 ಅರವತ್ತು +61 ಅರವತ್ತೊಂದು +62 ಅರವತ್ತೆರಡು +63 ಅರವತ್ತಮೂರು +64 ಅರವತ್ತನಾಲ್ಕು +65 ಅರವತ್ತೈದು +66 ಅರವತ್ತಾರು +67 ಅರವತ್ತೇಳು +68 ಅರವತ್ತೆಂಟು +69 ಅರವತ್ತೊಂಬತ್ತು +70 ಎಪ್ಪತ್ತು +71 ಎಪ್ಪತ್ತೊಂದು +72 ಎಪ್ಪತ್ತೆರಡು +73 ಎಪ್ಪತ್ತಮೂರು +74 ಎಪ್ಪತ್ತನಾಲ್ಕು +75 ಎಪ್ಪತ್ತೈದು +76 ಎಪ್ಪತ್ತಾರು +77 ಎಪ್ಪತ್ತೇಳು +78 ಎಪ್ಪತ್ತೆಂಟು +79 ಎಪ್ಪತ್ತೊಂಬತ್ತು +80 ಎಂಬತ್ತು +81 ಎಂಬತ್ತೊಂದು +82 ಎಂಬತ್ತೆರಡು +83 ಎಂಬತ್ತಮೂರು +84 ಎಂಬತ್ತನಾಲ್ಕು +85 ಎಂಬತ್ತೈದು +86 ಎಂಬತ್ತಾರು +87 ಎಂಬತ್ತೇಳು +88 ಎಂಬತ್ತೆಂಟು +89 ಎಂಬತ್ತೊಂಬತ್ತು +90 ತೊಂಬತ್ತು +91 ತೊಂಬತ್ತೊಂದು +92 ತೊಂಬತ್ತೆರಡು +93 ತೊಂಬತ್ತಮೂರು +94 ತೊಂಬತ್ತನಾಲ್ಕು +95 ತೊಂಬತ್ತೈದು +96 ತೊಂಬತ್ತಾರು +97 ತೊಂಬತ್ತೇಳು +98 ತೊಂಬತ್ತೆಂಟು +99 ತೊಂಬತ್ತೊಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/thousands.tsv b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/thousands.tsv new file mode 100644 index 000000000..ac3f398a1 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/thousands.tsv @@ -0,0 +1,8 @@ +೧೦೦೦ ಸಾವಿರ +೧೦೦೦೦೦ ಲಕ್ಷ +೧೦೦೦೦೦೦೦ ಕೋಟಿ +೧೦೦೦೦೦೦೦೦೦ ಅರಬ್ +೧೦೦೦೦೦೦೦೦೦೦೦ ಖರಬ್ +೧೦೦೦೦೦೦೦೦೦೦೦೦೦ ನೀಲ +೧೦೦೦೦೦೦೦೦೦೦೦೦೦೦೦ ಪದ್ಮ +೧೦೦೦೦೦೦೦೦೦೦೦೦೦೦೦೦೦ ಶಂಖ \ No newline at end of file diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/zero.tsv b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/zero.tsv new file mode 100644 index 000000000..736d0cdad --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/data/numbers/zero.tsv @@ -0,0 +1,2 @@ +೦ ಸೊನ್ನೆ +0 ಸೊನ್ನೆ \ No newline at end of file diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/graph_utils.py b/nemo_text_processing 2/inverse_text_normalization/kn/graph_utils.py new file mode 100644 index 000000000..f04731a0a --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/graph_utils.py @@ -0,0 +1,204 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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 logging +import os +import string +from pathlib import Path +from typing import Dict + +import pynini +from pynini import Far +from pynini.examples import plurals +from pynini.export import export +from pynini.lib import byte, pynutil, utf8 + +from nemo_text_processing.inverse_text_normalization.hi.utils import get_abs_path, load_labels + +NEMO_CHAR = utf8.VALID_UTF8_CHAR + +graph_digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + +NEMO_KN_DIGIT = pynini.union("೦", "೧", "೨", "೩", "೪", "೫", "೬", "೭", "೮", "೯") + + +NEMO_HEX = pynini.union(*string.hexdigits).optimize() +NEMO_NON_BREAKING_SPACE = u"\u00a0" +NEMO_ZWNJ = u"\u200c" +NEMO_SPACE = " " +NEMO_WHITE_SPACE = pynini.union(" ", "\t", "\n", "\r", u"\u00a0").optimize() +NEMO_NOT_SPACE = pynini.difference(NEMO_CHAR, NEMO_WHITE_SPACE).optimize() +NEMO_NOT_QUOTE = pynini.difference(NEMO_CHAR, r'"').optimize() + +NEMO_PUNCT = pynini.union(*map(pynini.escape, string.punctuation)).optimize() +NEMO_GRAPH = pynini.union(NEMO_CHAR, NEMO_PUNCT).optimize() + +NEMO_SIGMA = pynini.closure(NEMO_CHAR) + +delete_space = pynutil.delete(pynini.closure(NEMO_WHITE_SPACE)) +delete_zero_or_one_space = pynutil.delete(pynini.closure(NEMO_WHITE_SPACE, 0, 1)) +insert_space = pynutil.insert(" ") +delete_extra_space = pynini.cross(pynini.closure(NEMO_WHITE_SPACE, 1), " ") +delete_preserve_order = pynini.closure( + pynutil.delete(" preserve_order: true") + | (pynutil.delete(" field_order: \"") + NEMO_NOT_QUOTE + pynutil.delete("\"")) +) + + +MIN_NEG_WEIGHT = -0.0001 +MIN_POS_WEIGHT = 0.0001 +INPUT_CASED = "cased" +INPUT_LOWER_CASED = "lower_cased" +MINUS = pynini.union("ऋणात्मक", "नकारात्मक").optimize() + + +def integer_to_devanagari(n: int) -> str: + return ''.join(DEVANAGARI_DIGIT[int(d)] for d in str(n)) + + +def generator_main(file_name: str, graphs: Dict[str, 'pynini.FstLike']): + """ + Exports graph as OpenFst finite state archive (FAR) file with given file name and rule name. + + Args: + file_name: exported file name + graphs: Mapping of a rule name and Pynini WFST graph to be exported + """ + exporter = export.Exporter(file_name) + for rule, graph in graphs.items(): + exporter[rule] = graph.optimize() + exporter.close() + logging.info(f'Created {file_name}') + + +def convert_space(fst) -> 'pynini.FstLike': + """ + Converts space to nonbreaking space. + Used only in tagger grammars for transducing token values within quotes, e.g. name: "hello kitty" + This is making transducer significantly slower, so only use when there could be potential spaces within quotes, otherwise leave it. + + Args: + fst: input fst + + Returns output fst where breaking spaces are converted to non breaking spaces + """ + return fst @ pynini.cdrewrite(pynini.cross(NEMO_SPACE, NEMO_NON_BREAKING_SPACE), "", "", NEMO_SIGMA) + + +def string_map_cased(input_file: str, input_case: str = INPUT_LOWER_CASED): + labels = load_labels(input_file) + + if input_case == INPUT_CASED: + additional_labels = [] + for written, spoken, *weight in labels: + written_capitalized = written[0].upper() + written[1:] + additional_labels.extend( + [ + [written_capitalized, spoken.capitalize()], # first letter capitalized + [ + written_capitalized, + spoken.upper().replace(" AND ", " and "), + ], # # add pairs with the all letters capitalized + ] + ) + + spoken_no_space = spoken.replace(" ", "") + # add abbreviations without spaces (both lower and upper case), i.e. "BMW" not "B M W" + if len(spoken) == (2 * len(spoken_no_space) - 1): + logging.debug(f"This is weight {weight}") + if len(weight) == 0: + additional_labels.extend( + [[written, spoken_no_space], [written_capitalized, spoken_no_space.upper()]] + ) + else: + additional_labels.extend( + [ + [written, spoken_no_space, weight[0]], + [written_capitalized, spoken_no_space.upper(), weight[0]], + ] + ) + labels += additional_labels + + whitelist = pynini.string_map(labels).invert().optimize() + return whitelist + + +class GraphFst: + """ + Base class for all grammar fsts. + + Args: + name: name of grammar class + kind: either 'classify' or 'verbalize' + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, name: str, kind: str, deterministic: bool = True): + self.name = name + self.kind = kind + self._fst = None + self.deterministic = deterministic + + self.far_path = Path(os.path.dirname(__file__) + '/grammars/' + kind + '/' + name + '.far') + if self.far_exist(): + self._fst = Far(self.far_path, mode="r", arc_type="standard", far_type="default").get_fst() + + def far_exist(self) -> bool: + """ + Returns true if FAR can be loaded + """ + return self.far_path.exists() + + @property + def fst(self) -> 'pynini.FstLike': + return self._fst + + @fst.setter + def fst(self, fst): + self._fst = fst + + def add_tokens(self, fst) -> 'pynini.FstLike': + """ + Wraps class name around to given fst + + Args: + fst: input fst + + Returns: + Fst: fst + """ + return pynutil.insert(f"{self.name} {{ ") + fst + pynutil.insert(" }") + + def delete_tokens(self, fst) -> 'pynini.FstLike': + """ + Deletes class name wrap around output of given fst + + Args: + fst: input fst + + Returns: + Fst: fst + """ + res = ( + pynutil.delete(f"{self.name}") + + delete_space + + pynutil.delete("{") + + delete_space + + fst + + delete_space + + pynutil.delete("}") + ) + return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/taggers/__init__.py b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/__init__.py new file mode 100644 index 000000000..d9155f923 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2024, 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. diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/taggers/cardinal.py b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/cardinal.py new file mode 100644 index 000000000..78e7b56a0 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/cardinal.py @@ -0,0 +1,181 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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 +# +# [apache.org](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.inverse_text_normalization.kn.graph_utils import ( + INPUT_CASED, + INPUT_LOWER_CASED, + MINUS, + NEMO_KN_DIGIT, + NEMO_SIGMA, + NEMO_SPACE, + GraphFst, + delete_space, +) +from nemo_text_processing.inverse_text_normalization.kn.utils import get_abs_path + + +class CardinalFst(GraphFst): + """ + Finite state transducer for classifying cardinals in Kannada + e.g. ಋಣ ಇಪ್ಪತ್ಮೂರು -> cardinal { integer: "೨೩" negative: "-" } + + Args: + input_case: accepting either "lower_cased" or "cased" input. + """ + + def __init__(self, input_case: str = INPUT_LOWER_CASED): + super().__init__(name="cardinal", kind="classify") + self.input_case = input_case + + # Load Kannada number mappings from TSV files + graph_zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")).invert() + graph_digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")).invert() + graph_teens_and_ties = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")).invert() + + self.graph_zero = graph_zero + self.graph_digit = graph_digit + self.graph_single_digit_with_zero = pynutil.insert("೦") + graph_digit + self.graph_teens_and_ties = graph_teens_and_ties + self.graph_two_digit = graph_teens_and_ties | (pynutil.insert("೦") + graph_digit) + + # Kannada unit words + graph_hundred = pynini.cross("ನೂರು", "") + delete_hundred = pynutil.delete("ನೂರು") | pynutil.delete("ನೂರ") + delete_thousand = pynutil.delete("ಸಾವಿರ") | pynutil.delete("ಸಾವಿರದ") + + # Hundreds component + graph_hundred_component = pynini.union(graph_digit + delete_space + graph_hundred, pynutil.insert("೦")) + graph_hundred_component += delete_space + graph_hundred_component += self.graph_two_digit | pynutil.insert("೦೦") + + graph_hundred_component_at_least_one_none_zero_digit = graph_hundred_component @ ( + pynini.closure(NEMO_KN_DIGIT) + (NEMO_KN_DIGIT - "೦") + pynini.closure(NEMO_KN_DIGIT) + ) + self.graph_hundred_component_at_least_one_none_zero_digit = ( + graph_hundred_component_at_least_one_none_zero_digit + ) + + # Transducer for patterns like "ಹನ್ನೊಂದು ನೂರು" -> 1100 + graph_hundred_as_thousand = pynini.union( + graph_teens_and_ties + delete_space + graph_hundred, pynutil.insert("೦") + ) + graph_hundred_as_thousand += delete_space + graph_hundred_as_thousand += self.graph_two_digit | pynutil.insert("೦೦") + + # Kannada fractional thousand patterns + # ಒಂದೂವರೆ ಸಾವಿರ (one and a half thousand) -> 1500 + graph_hundred_as_thousand |= pynutil.add_weight( + pynutil.delete("ಒಂದೂವರೆ") + + delete_space + + pynutil.insert("೧೫೦೦", weight=-0.1) + + delete_space + + delete_thousand, + -0.1, + ) + # ಎರಡೂವರೆ ಸಾವಿರ (two and a half thousand) -> 2500 + graph_hundred_as_thousand |= pynutil.add_weight( + pynutil.delete("ಎರಡೂವರೆ") + + delete_space + + pynutil.insert("೨೫೦೦", weight=-0.1) + + delete_space + + delete_thousand, + -0.1, + ) + + # Fractional hundreds + # ಒಂದೂವರೆ ನೂರು -> 150 + graph_in_hundreds = pynutil.add_weight( + pynutil.delete("ಒಂದೂವರೆ") + + delete_space + + pynutil.insert("೧೫೦", weight=-0.1) + + delete_space + + delete_hundred, + -0.1, + ) + # ಎರಡೂವರೆ ನೂರು -> 250 + graph_in_hundreds |= pynutil.add_weight( + pynutil.delete("ಎರಡೂವರೆ") + + delete_space + + pynutil.insert("೨೫೦", weight=-0.1) + + delete_space + + delete_hundred, + -0.1, + ) + + self.graph_hundreds = graph_hundred_component | graph_hundred_as_thousand | graph_in_hundreds + + graph_ties_component_at_least_one_none_zero_digit = self.graph_two_digit @ ( + pynini.closure(NEMO_KN_DIGIT) + pynini.closure(NEMO_KN_DIGIT) + ) + self.graph_ties_component_at_least_one_none_zero_digit = graph_ties_component_at_least_one_none_zero_digit + + # Indian numeric format for Kannada + # Structure: Crores, Lakhs, Thousands, Hundreds (max unit is crore) + graph_in_thousands = pynini.union( + self.graph_two_digit + delete_space + delete_thousand, + pynutil.insert("೦೦", weight=0.1), + ) + self.graph_thousands = graph_in_thousands + + graph_in_lakhs = pynini.union( + self.graph_two_digit + delete_space + pynutil.delete("ಲಕ್ಷ"), + pynutil.insert("೦೦", weight=0.1), + ) + + graph_in_crores = pynini.union( + self.graph_two_digit + delete_space + (pynutil.delete("ಕೋಟಿ") | pynutil.delete("crores")), + pynutil.insert("೦೦", weight=0.1), + ) + + # Build the full Indian number graph (crore is the highest unit) + graph_ind = graph_in_crores + delete_space + graph_in_lakhs + delete_space + graph_in_thousands + + # Standalone unit words + graph_no_prefix = pynutil.add_weight( + pynini.cross("ನೂರು", "೧೦೦") + | pynini.cross("ಸಾವಿರ", "೧೦೦೦") + | pynini.cross("ಲಕ್ಷ", "೧೦೦೦೦೦") + | pynini.cross("ಕೋಟಿ", "೧೦೦೦೦೦೦೦"), + 2, + ) + + graph = pynini.union(graph_ind + delete_space + self.graph_hundreds, graph_zero, graph_no_prefix) + + # Remove leading zeros + graph = graph @ pynini.union( + pynutil.delete(pynini.closure("೦")) + + pynini.difference(NEMO_KN_DIGIT, "೦") + + pynini.closure(NEMO_KN_DIGIT), + "೦", + ) + + # labels_exception = [pynini.string_file(get_abs_path("data/numbers/labels_exception.tsv"))] + # graph_exception = pynini.union(*labels_exception).optimize() + + self.graph_no_exception = graph + self.graph = graph # (pynini.project(graph, "input") - graph_exception.arcsort()) @ graph + + # Handle negative numbers (ಋಣ = negative in Kannada) + optional_minus_graph = pynini.closure( + pynutil.insert("negative: ") + pynini.cross(MINUS, "\"-\"") + NEMO_SPACE, 0, 1 + ) + + final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.graph + pynutil.insert("\"") + + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/taggers/punctuation.py b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/punctuation.py new file mode 100644 index 000000000..6ec7f6c2b --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/punctuation.py @@ -0,0 +1,36 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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.inverse_text_normalization.kn.graph_utils import GraphFst + + +class PunctuationFst(GraphFst): + """ + Finite state transducer for classifying punctuation + e.g. आ, -> tokens { name: "आ" } tokens { name: "," } + """ + + def __init__(self): + super().__init__(name="punctuation", kind="classify") + + s = "!#$%&\'()*+,-./:;<=>?@^_`{|}~" + punct = pynini.union(*s) + + graph = pynutil.insert("name: \"") + punct + pynutil.insert("\"") + + self.fst = graph.optimize() diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/taggers/tokenize_and_classify.py b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/tokenize_and_classify.py new file mode 100644 index 000000000..397b14762 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/tokenize_and_classify.py @@ -0,0 +1,125 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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 logging +import os + +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.inverse_text_normalization.kn.graph_utils import ( + GraphFst, + delete_extra_space, + delete_space, + generator_main, +) +from nemo_text_processing.inverse_text_normalization.kn.taggers.cardinal import CardinalFst + +# from nemo_text_processing.inverse_text_normalization.kn.taggers.date import DateFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.decimal import DecimalFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.fraction import FractionFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.measure import MeasureFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.money import MoneyFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.ordinal import OrdinalFst +from nemo_text_processing.inverse_text_normalization.kn.taggers.punctuation import PunctuationFst + +# from nemo_text_processing.inverse_text_normalization.kn.taggers.telephone import TelephoneFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.time import TimeFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.whitelist import WhiteListFst +from nemo_text_processing.inverse_text_normalization.kn.taggers.word import WordFst + + +class ClassifyFst(GraphFst): + """ + Final class that composes all other classification grammars. This class can process an entire sentence, that is lower cased. + For deployment, this grammar will be compiled and exported to OpenFst Finite State Archive (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + + Args: + input_case: accepting either "lower_cased" or "cased" input. + cache_dir: path to a dir with .far grammar file. Set to None to avoid using cache. + overwrite_cache: set to True to overwrite .far files + whitelist: path to a file with whitelist replacements + """ + + def __init__( + self, + cache_dir: str = None, + overwrite_cache: bool = False, + whitelist: str = None, + input_case: str = None, + ): + super().__init__(name="tokenize_and_classify", kind="classify") + + far_file = None + if cache_dir is not None and cache_dir != "None": + os.makedirs(cache_dir, exist_ok=True) + far_file = os.path.join(cache_dir, f"hi_itn.far") + if not overwrite_cache and far_file and os.path.exists(far_file): + self.fst = pynini.Far(far_file, mode="r")["tokenize_and_classify"] + logging.info(f"ClassifyFst.fst was restored from {far_file}.") + else: + logging.info(f"Creating ClassifyFst grammars.") + cardinal = CardinalFst() + cardinal_graph = cardinal.fst + + # ordinal = OrdinalFst(cardinal) + # ordinal_graph = ordinal.fst + # decimal = DecimalFst(cardinal) + # decimal_graph = decimal.fst + # fraction = FractionFst(cardinal) + # fraction_graph = fraction.fst + # date = DateFst(cardinal, ordinal) + # date_graph = date.fst + # time = TimeFst(cardinal) + # time_graph = time.fst + # measure = MeasureFst(cardinal, decimal) + # measure_graph = measure.fst + # money = MoneyFst(cardinal, decimal) + # money_graph = money.fst + # telephone = TelephoneFst(cardinal) + # telephone_graph = telephone.fst + punct_graph = PunctuationFst().fst + # whitelist_graph = WhiteListFst().fst + word_graph = WordFst().fst + + classify = ( + pynutil.add_weight(cardinal_graph, 1.1) + # | pynutil.add_weight(ordinal_graph, 1.1) + # | pynutil.add_weight(decimal_graph, 1.1) + # | pynutil.add_weight(fraction_graph, 1.1) + # | pynutil.add_weight(date_graph, 1.1) + # | pynutil.add_weight(time_graph, 1.1) + # | pynutil.add_weight(measure_graph, 1.1) + # | pynutil.add_weight(money_graph, 1.1) + # | pynutil.add_weight(telephone_graph, 1.1) + # | pynutil.add_weight(word_graph, 100) + # | pynutil.add_weight(whitelist_graph, 1.01) + ) + + punct = pynutil.insert("tokens { ") + pynutil.add_weight(punct_graph, weight=1.1) + pynutil.insert(" }") + token = pynutil.insert("tokens { ") + classify + pynutil.insert(" }") + token_plus_punct = ( + pynini.closure(punct + pynutil.insert(" ")) + token + pynini.closure(pynutil.insert(" ") + punct) + ) + + graph = token_plus_punct + pynini.closure(delete_extra_space + token_plus_punct) + graph = delete_space + graph + delete_space + + self.fst = graph.optimize() + + if far_file: + generator_main(far_file, {"tokenize_and_classify": self.fst}) + logging.info(f"ClassifyFst grammars are saved to {far_file}.") diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/taggers/word.py b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/word.py new file mode 100644 index 000000000..4de6c6fa8 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/taggers/word.py @@ -0,0 +1,31 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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.inverse_text_normalization.kn.graph_utils import NEMO_NOT_SPACE, GraphFst + + +class WordFst(GraphFst): + """ + Finite state transducer for classifying plain tokens, that do not belong to any special class. This can be considered as the default class. + e.g. नींद -> tokens { name: "नींद" } + """ + + def __init__(self): + super().__init__(name="word", kind="classify") + word = pynutil.insert("name: \"") + pynini.closure(NEMO_NOT_SPACE, 1) + pynutil.insert("\"") + self.fst = word.optimize() diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/utils.py b/nemo_text_processing 2/inverse_text_normalization/kn/utils.py new file mode 100644 index 000000000..8e3f62c3c --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/utils.py @@ -0,0 +1,63 @@ +# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. 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 csv +import logging +import os +import pynini + + +def get_abs_path(rel_path): + """ + Get absolute path + + Args: + rel_path: relative path to this file + + Returns absolute path + """ + abs_path = os.path.dirname(os.path.abspath(__file__)) + os.sep + rel_path + + if not os.path.exists(abs_path): + logging.warning(f'{abs_path} does not exist') + return abs_path + + +def load_labels(abs_path): + """ + loads relative path file as dictionary + + Args: + abs_path: absolute path + + Returns dictionary of mappings + """ + label_tsv = open(abs_path, encoding="utf-8") + labels = list(csv.reader(label_tsv, delimiter="\t")) + return labels + + +from pynini.lib import pynutil + + +def apply_fst(text, fst): + """Given a string input, returns the output string + produced by traversing the path with lowest weight. + If no valid path accepts input string, returns an + error. + """ + try: + print(pynini.shortestpath(text @ fst).string()) + except pynini.FstOpError: + print(f"Error: No valid output with given input: '{text}'") diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/__init__.py b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/__init__.py new file mode 100644 index 000000000..d9155f923 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2024, 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. diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/cardinal.py b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/cardinal.py new file mode 100644 index 000000000..20822af95 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/cardinal.py @@ -0,0 +1,23 @@ +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.inverse_text_normalization.kn.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space + + +class CardinalFst(GraphFst): + """ + Verbalizes the digits, e.g. cardinal { integer: "5" } -> 5 + """ + + def __init__(self): + super().__init__(name="cardinal", kind="verbalize") + graph = ( + pynutil.delete("integer:") + + delete_space + + pynutil.delete('"') + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete('"') + ) + + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/verbalize.py b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/verbalize.py new file mode 100644 index 000000000..e7afcbbcf --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/verbalize.py @@ -0,0 +1,68 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.kn.graph_utils import GraphFst +from nemo_text_processing.inverse_text_normalization.kn.verbalizers.cardinal import CardinalFst + +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.date import DateFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.decimal import DecimalFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.fraction import FractionFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.measure import MeasureFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.money import MoneyFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.ordinal import OrdinalFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.telephone import TelephoneFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.time import TimeFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.whitelist import WhiteListFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.word import WordFst + + +class VerbalizeFst(GraphFst): + """ + Composes other verbalizer grammars. + For deployment, this grammar will be compiled and exported to OpenFst Finite State Archive (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + """ + + def __init__(self): + super().__init__(name="verbalize", kind="verbalize") + cardinal = CardinalFst() + cardinal_graph = cardinal.fst + # ordinal = OrdinalFst() + # ordinal_graph = ordinal.fst + # decimal = DecimalFst() + # decimal_graph = decimal.fst + # fraction_graph = FractionFst().fst + # date_graph = DateFst(cardinal, ordinal).fst + # time_graph = TimeFst().fst + # measure_graph = MeasureFst(cardinal, decimal).fst + # money_graph = MoneyFst(cardinal, decimal).fst + # telephone_graph = TelephoneFst(cardinal).fst + # word_graph = WordFst().fst + # whitelist_graph = WhiteListFst().fst + + graph = ( + cardinal_graph + # | whitelist_graph + # | word_graph + # | ordinal_graph + # | decimal_graph + # | fraction_graph + # | date_graph + # | time_graph + # | measure_graph + # | money_graph + # | telephone_graph + ) + self.fst = graph diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/verbalize_final.py b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/verbalize_final.py new file mode 100644 index 000000000..2f0352a74 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/verbalize_final.py @@ -0,0 +1,45 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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.inverse_text_normalization.kn.graph_utils import GraphFst, delete_extra_space, delete_space +from nemo_text_processing.inverse_text_normalization.kn.verbalizers.verbalize import VerbalizeFst +from nemo_text_processing.inverse_text_normalization.kn.verbalizers.word import WordFst + + +class VerbalizeFinalFst(GraphFst): + """ + Finite state transducer that verbalizes an entire sentence, e.g. + tokens { name: "अब" } tokens { time { hours: "१२" minutes: "३०" } } tokens { name: "बज" } tokens { name: "गए" } tokens { name: "हैं" } -> अब १२:३० बज गए हैं + """ + + def __init__(self): + super().__init__(name="verbalize_final", kind="verbalize") + verbalize = VerbalizeFst().fst + word = WordFst().fst + types = verbalize | word + graph = ( + pynutil.delete("tokens") + + delete_space + + pynutil.delete("{") + + delete_space + + types + + delete_space + + pynutil.delete("}") + ) + graph = delete_space + pynini.closure(graph + delete_extra_space) + graph + delete_space + self.fst = graph diff --git a/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/word.py b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/word.py new file mode 100644 index 000000000..dd71360a6 --- /dev/null +++ b/nemo_text_processing 2/inverse_text_normalization/kn/verbalizers/word.py @@ -0,0 +1,39 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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.inverse_text_normalization.kn.graph_utils import ( + NEMO_CHAR, + NEMO_SIGMA, + GraphFst, + delete_space, +) + + +class WordFst(GraphFst): + """ + Finite state transducer for verbalizing plain tokens + e.g. tokens { name: "नींद" } -> नींद + """ + + def __init__(self): + super().__init__(name="word", kind="verbalize") + chars = pynini.closure(NEMO_CHAR - " ", 1) + char = pynutil.delete("name:") + delete_space + pynutil.delete("\"") + chars + pynutil.delete("\"") + graph = char @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) + + self.fst = graph.optimize() diff --git a/nemo_text_processing/inverse_text_normalization/inverse_normalize.py b/nemo_text_processing/inverse_text_normalization/inverse_normalize.py index 9a6fcc64c..83b2e3272 100644 --- a/nemo_text_processing/inverse_text_normalization/inverse_normalize.py +++ b/nemo_text_processing/inverse_text_normalization/inverse_normalize.py @@ -146,6 +146,11 @@ def __init__( from nemo_text_processing.inverse_text_normalization.ko.verbalizers.verbalize_final import ( VerbalizeFinalFst, ) + elif lang == 'kn': # Kannada + from nemo_text_processing.inverse_text_normalization.kn.taggers.tokenize_and_classify import ClassifyFst + from nemo_text_processing.inverse_text_normalization.kn.verbalizers.verbalize_final import ( + VerbalizeFinalFst, + ) else: raise NotImplementedError(f"Language {lang} has not been supported yet.") @@ -211,6 +216,7 @@ def parse_args(): 'mr', 'ja', 'ko', + 'kn', ], default="en", type=str, diff --git a/nemo_text_processing/inverse_text_normalization/kn/__init__.py b/nemo_text_processing/inverse_text_normalization/kn/__init__.py new file mode 100644 index 000000000..4aea4c281 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/__init__.py @@ -0,0 +1,17 @@ +# 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. + +from nemo_text_processing.inverse_text_normalization.hi.taggers.tokenize_and_classify import ClassifyFst +from nemo_text_processing.inverse_text_normalization.hi.verbalizers.verbalize import VerbalizeFst +from nemo_text_processing.inverse_text_normalization.hi.verbalizers.verbalize_final import VerbalizeFinalFst diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/__init__.py b/nemo_text_processing/inverse_text_normalization/kn/data/__init__.py new file mode 100644 index 000000000..d9155f923 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2024, 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. diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/numbers/digit.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/digit.tsv new file mode 100644 index 000000000..6d9c5db59 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/digit.tsv @@ -0,0 +1,18 @@ +೧ ಒಂದು +೨ ಎರಡು +೩ ಮೂರು +೪ ನಾಲ್ಕು +೫ ಐದು +೬ ಆರು +೭ ಏಳು +೮ ಎಂಟು +೯ ಒಂಬತ್ತು +1 ಒಂದು +2 ಎರಡು +3 ಮೂರು +4 ನಾಲ್ಕು +5 ಐದು +6 ಆರು +7 ಏಳು +8 ಎಂಟು +9 ಒಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/numbers/hundred.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/hundred.tsv new file mode 100644 index 000000000..b3aff9b13 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/hundred.tsv @@ -0,0 +1,18 @@ +೧ ನೂರ +೨ ಇನ್ನೂರ +೩ ಮುನ್ನೂರ +೪ ನಾನೂರ +೫ ಐನೂರ +೬ ಆರುನೂರ +೭ ಏಳುನೂರ +೮ ಎಂಟುನೂರ +೯ ಒಂಬೈನೂರ +1 ನೂರ +2 ಇನ್ನೂರ +3 ಮುನ್ನೂರ +4 ನಾನೂರ +5 ಐನೂರ +6 ಆರುನೂರ +7 ಏಳುನೂರ +8 ಎಂಟುನೂರ +9 ಒಂಬೈನೂರ \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/numbers/labels_exception.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/labels_exception.tsv new file mode 100644 index 000000000..b41ffcc8b --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/labels_exception.tsv @@ -0,0 +1,4 @@ +ಶೂನ್ಯ +ಒಂದು +ಎರಡು +ಮೂರು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/numbers/paune.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/paune.tsv new file mode 100644 index 000000000..4e9fb55d5 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/paune.tsv @@ -0,0 +1,98 @@ +೨ ಎರಡು +೩ ಮೂರು +೪ ನಾಲ್ಕು +೫ ಐದು +೬ ಆರು +೭ ಏಳು +೮ ಎಂಟು +೯ ಒಂಬತ್ತು +೧೦ ಹತ್ತು +೧೧ ಹನ್ನೊಂದು +೧೨ ಹನ್ನೆರಡು +೧೩ ಹದಿಮೂರು +೧೪ ಹದಿನಾಲ್ಕು +೧೫ ಹದಿನೈದು +೧೬ ಹದಿನಾರು +೧೭ ಹದಿನೇಳು +೧೮ ಹದಿನೆಂಟು +೧೯ ಹತ್ತೊಂಬತ್ತು +೨೦ ಇಪ್ಪತ್ತು +೨೧ ಇಪ್ಪತ್ತೊಂದು +೨೨ ಇಪ್ಪತ್ತೆರಡು +೨೩ ಇಪ್ಪತ್ತ್ಮೂರು +೨೪ ಇಪ್ಪತ್ತ್ನಾಲ್ಕು +೨೫ ಇಪ್ಪತ್ತೈದು +೨೬ ಇಪ್ಪತ್ತಾರು +೨೭ ಇಪ್ಪತ್ತೇಳು +೨೮ ಇಪ್ಪತ್ತೆಂಟು +೨೯ ಇಪ್ಪತ್ತೊಂಬತ್ತು +೩೦ ಮೂವತ್ತು +೩೧ ಮೂವತ್ತೊಂದು +೩೨ ಮೂವತ್ತೆರಡು +೩೩ ಮೂವತ್ತ್ಮೂರು +೩೪ ಮೂವತ್ತ್ನಾಲ್ಕು +೩೫ ಮೂವತ್ತೈದು +೩೬ ಮೂವತ್ತಾರು +೩೭ ಮೂವತ್ತೇಳು +೩೮ ಮೂವತ್ತೆಂಟು +೩೯ ಮೂವತ್ತೊಂಬತ್ತು +೪೦ ನಲವತ್ತು +೪೧ ನಲವತ್ತೊಂದು +೪೨ ನಲವತ್ತೆರಡು +೪೩ ನಲವತ್ತ್ಮೂರು +೪೪ ನಲವತ್ತ್ನಾಲ್ಕು +೪೫ ನಲವತ್ತೈದು +೪೬ ನಲವತ್ತಾರು +೪೭ ನಲವತ್ತೇಳು +೪೮ ನಲವತ್ತೆಂಟು +೪೯ ನಲವತ್ತೊಂಬತ್ತು +೫೦ ಐವತ್ತು +೫೧ ಐವತ್ತೊಂದು +೫೨ ಐವತ್ತೆರಡು +೫೩ ಐವತ್ತ್ಮೂರು +೫೪ ಐವತ್ತ್ನಾಲ್ಕು +೫೫ ಐವತ್ತೈದು +೫೬ ಐವತ್ತಾರು +೫೭ ಐವತ್ತೇಳು +೫೮ ಐವತ್ತೆಂಟು +೫೯ ಐವತ್ತೊಂಬತ್ತು +೬೦ ಅರವತ್ತು +೬೧ ಅರವತ್ತೊಂದು +೬೨ ಅರವತ್ತೆರಡು +೬೩ ಅರವತ್ತ್ಮೂರು +೬೪ ಅರವತ್ತ್ನಾಲ್ಕು +೬೫ ಅರವತ್ತೈದು +೬೬ ಅರವತ್ತಾರು +೬೭ ಅರವತ್ತೇಳು +೬೮ ಅರವತ್ತೆಂಟು +೬೯ ಅರವತ್ತೊಂಬತ್ತು +೭೦ ಎಪ್ಪತ್ತು +೭೧ ಎಪ್ಪತ್ತೊಂದು +೭೨ ಎಪ್ಪತ್ತೆರಡು +೭೩ ಎಪ್ಪತ್ತ್ಮೂರು +೭೪ ಎಪ್ಪತ್ತ್ನಾಲ್ಕು +೭೫ ಎಪ್ಪತ್ತೈದು +೭೬ ಎಪ್ಪತ್ತಾರು +೭೭ ಎಪ್ಪತ್ತೇಳು +೭೮ ಎಪ್ಪತ್ತೆಂಟು +೭೯ ಎಪ್ಪತ್ತೊಂಬತ್ತು +೮೦ ಎಂಬತ್ತು +೮೧ ಎಂಬತ್ತೊಂದು +೮೨ ಎಂಬತ್ತೆರಡು +೮೩ ಎಂಬತ್ತ್ಮೂರು +೮೪ ಎಂಬತ್ತ್ನಾಲ್ಕು +೮೫ ಎಂಬತ್ತೈದು +೮೬ ಎಂಬತ್ತಾರು +೮೭ ಎಂಬತ್ತೇಳು +೮೮ ಎಂಬತ್ತೆಂಟು +೮೯ ಎಂಬತ್ತೊಂಬತ್ತು +೯೦ ತೊಂಬತ್ತು +೯೧ ತೊಂಬತ್ತೊಂದು +೯೨ ತೊಂಬತ್ತೆರಡು +೯೩ ತೊಂಬತ್ತ್ಮೂರು +೯೪ ತೊಂಬತ್ತ್ನಾಲ್ಕು +೯೫ ತೊಂಬತ್ತೈದು +೯೬ ತೊಂಬತ್ತಾರು +೯೭ ತೊಂಬತ್ತೇಳು +೯೮ ತೊಂಬತ್ತೆಂಟು +೯೯ ತೊಂಬತ್ತೊಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/numbers/quantities.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/quantities.tsv new file mode 100644 index 000000000..db24a441d --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/quantities.tsv @@ -0,0 +1,3 @@ +ಸಾವಿರ ಸಾವಿರ +ಲಕ್ಷ ಲಕ್ಷ +ಕೋಟಿ ಕೋಟಿ \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/numbers/teens_and_ties.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/teens_and_ties.tsv new file mode 100644 index 000000000..d7cc5a427 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/teens_and_ties.tsv @@ -0,0 +1,90 @@ +೧೦ ಹತ್ತು +೧೧ ಹನ್ನೊಂದು +೧೨ ಹನ್ನೆರಡು +೧೩ ಹದಿಮೂರು +೧೪ ಹದಿನಾಲ್ಕು +೧೫ ಹದಿನೈದು +೧೬ ಹದಿನಾರು +೧೭ ಹದಿನೇಳು +೧೮ ಹದಿನೆಂಟು +೧೯ ಹತ್ತೊಂಬತ್ತು +೨೦ ಇಪ್ಪತ್ತು +೨೧ ಇಪ್ಪತ್ತೊಂದು +೨೨ ಇಪ್ಪತ್ತೆರಡು +೨೩ ಇಪ್ಪತ್ತಮೂರು +೨೪ ಇಪ್ಪತ್ತನಾಲ್ಕು +೨೫ ಇಪ್ಪತ್ತೈದು +೨೬ ಇಪ್ಪತ್ತಾರು +೨೭ ಇಪ್ಪತ್ತೇಳು +೨೮ ಇಪ್ಪತ್ತೆಂಟು +೨೯ ಇಪ್ಪತ್ತೊಂಬತ್ತು +೩೦ ಮೂವತ್ತು +೩೧ ಮೂವತ್ತೊಂದು +೩೨ ಮೂವತ್ತೆರಡು +೩೩ ಮೂವತ್ತಮೂರು +೩೪ ಮೂವತ್ತನಾಲ್ಕು +೩೫ ಮೂವತ್ತೈದು +೩೬ ಮೂವತ್ತಾರು +೩೭ ಮೂವತ್ತೇಳು +೩೮ ಮೂವತ್ತೆಂಟು +೩೯ ಮೂವತ್ತೊಂಬತ್ತು +೪೦ ನಲವತ್ತು +೪೧ ನಲವತ್ತೊಂದು +೪೨ ನಲವತ್ತೆರಡು +೪೩ ನಲವತ್ತಮೂರು +೪೪ ನಲವತ್ತನಾಲ್ಕು +೪೫ ನಲವತ್ತೈದು +೪೬ ನಲವತ್ತಾರು +೪೭ ನಲವತ್ತೇಳು +೪೮ ನಲವತ್ತೆಂಟು +೪೯ ನಲವತ್ತೊಂಬತ್ತು +೫೦ ಐವತ್ತು +೫೧ ಐವತ್ತೊಂದು +೫೨ ಐವತ್ತೆರಡು +೫೩ ಐವತ್ತಮೂರು +೫೪ ಐವತ್ತನಾಲ್ಕು +೫೫ ಐವತ್ತೈದು +೫೬ ಐವತ್ತಾರು +೫೭ ಐವತ್ತೇಳು +೫೮ ಐವತ್ತೆಂಟು +೫೯ ಐವತ್ತೊಂಬತ್ತು +೬೦ ಅರವತ್ತು +೬೧ ಅರವತ್ತೊಂದು +೬೨ ಅರವತ್ತೆರಡು +೬೩ ಅರವತ್ತಮೂರು +೬೪ ಅರವತ್ತನಾಲ್ಕು +೬೫ ಅರವತ್ತೈದು +೬೬ ಅರವತ್ತಾರು +೬೭ ಅರವತ್ತೇಳು +೬೮ ಅರವತ್ತೆಂಟು +೬೯ ಅರವತ್ತೊಂಬತ್ತು +೭೦ ಎಪ್ಪತ್ತು +೭೧ ಎಪ್ಪತ್ತೊಂದು +೭೨ ಎಪ್ಪತ್ತೆರಡು +೭೩ ಎಪ್ಪತ್ತಮೂರು +೭೪ ಎಪ್ಪತ್ತನಾಲ್ಕು +೭೫ ಎಪ್ಪತ್ತೈದು +೭೬ ಎಪ್ಪತ್ತಾರು +೭೭ ಎಪ್ಪತ್ತೇಳು +೭೮ ಎಪ್ಪತ್ತೆಂಟು +೭೯ ಎಪ್ಪತ್ತೊಂಬತ್ತು +೮೦ ಎಂಬತ್ತು +೮೧ ಎಂಬತ್ತೊಂದು +೮೨ ಎಂಬತ್ತೆರಡು +೮೩ ಎಂಬತ್ತಮೂರು +೮೪ ಎಂಬತ್ತನಾಲ್ಕು +೮೫ ಎಂಬತ್ತೈದು +೮೬ ಎಂಬತ್ತಾರು +೮೭ ಎಂಬತ್ತೇಳು +೮೮ ಎಂಬತ್ತೆಂಟು +೮೯ ಎಂಬತ್ತೊಂಬತ್ತು +೯೦ ತೊಂಬತ್ತು +೯೧ ತೊಂಬತ್ತೊಂದು +೯೨ ತೊಂಬತ್ತೆರಡು +೯೩ ತೊಂಬತ್ತಮೂರು +೯೪ ತೊಂಬತ್ತನಾಲ್ಕು +೯೫ ತೊಂಬತ್ತೈದು +೯೬ ತೊಂಬತ್ತಾರು +೯೭ ತೊಂಬತ್ತೇಳು +೯೮ ತೊಂಬತ್ತೆಂಟು +೯೯ ತೊಂಬತ್ತೊಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/numbers/teens_and_ties_en.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/teens_and_ties_en.tsv new file mode 100644 index 000000000..1a4a6fbd8 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/teens_and_ties_en.tsv @@ -0,0 +1,90 @@ +10 ಹತ್ತು +11 ಹನ್ನೊಂದು +12 ಹನ್ನೆರಡು +13 ಹದಿಮೂರು +14 ಹದಿನಾಲ್ಕು +15 ಹದಿನೈದು +16 ಹದಿನಾರು +17 ಹದಿನೇಳು +18 ಹದಿನೆಂಟು +19 ಹತ್ತೊಂಬತ್ತು +20 ಇಪ್ಪತ್ತು +21 ಇಪ್ಪತ್ತೊಂದು +22 ಇಪ್ಪತ್ತೆರಡು +23 ಇಪ್ಪತ್ತಮೂರು +24 ಇಪ್ಪತ್ತನಾಲ್ಕು +25 ಇಪ್ಪತ್ತೈದು +26 ಇಪ್ಪತ್ತಾರು +27 ಇಪ್ಪತ್ತೇಳು +28 ಇಪ್ಪತ್ತೆಂಟು +29 ಇಪ್ಪತ್ತೊಂಬತ್ತು +30 ಮೂವತ್ತು +31 ಮೂವತ್ತೊಂದು +32 ಮೂವತ್ತೆರಡು +33 ಮೂವತ್ತಮೂರು +34 ಮೂವತ್ತನಾಲ್ಕು +35 ಮೂವತ್ತೈದು +36 ಮೂವತ್ತಾರು +37 ಮೂವತ್ತೇಳು +38 ಮೂವತ್ತೆಂಟು +39 ಮೂವತ್ತೊಂಬತ್ತು +40 ನಲವತ್ತು +41 ನಲವತ್ತೊಂದು +42 ನಲವತ್ತೆರಡು +43 ನಲವತ್ತಮೂರು +44 ನಲವತ್ತನಾಲ್ಕು +45 ನಲವತ್ತೈದು +46 ನಲವತ್ತಾರು +47 ನಲವತ್ತೇಳು +48 ನಲವತ್ತೆಂಟು +49 ನಲವತ್ತೊಂಬತ್ತು +50 ಐವತ್ತು +51 ಐವತ್ತೊಂದು +52 ಐವತ್ತೆರಡು +53 ಐವತ್ತಮೂರು +54 ಐವತ್ತನಾಲ್ಕು +55 ಐವತ್ತೈದು +56 ಐವತ್ತಾರು +57 ಐವತ್ತೇಳು +58 ಐವತ್ತೆಂಟು +59 ಐವತ್ತೊಂಬತ್ತು +60 ಅರವತ್ತು +61 ಅರವತ್ತೊಂದು +62 ಅರವತ್ತೆರಡು +63 ಅರವತ್ತಮೂರು +64 ಅರವತ್ತನಾಲ್ಕು +65 ಅರವತ್ತೈದು +66 ಅರವತ್ತಾರು +67 ಅರವತ್ತೇಳು +68 ಅರವತ್ತೆಂಟು +69 ಅರವತ್ತೊಂಬತ್ತು +70 ಎಪ್ಪತ್ತು +71 ಎಪ್ಪತ್ತೊಂದು +72 ಎಪ್ಪತ್ತೆರಡು +73 ಎಪ್ಪತ್ತಮೂರು +74 ಎಪ್ಪತ್ತನಾಲ್ಕು +75 ಎಪ್ಪತ್ತೈದು +76 ಎಪ್ಪತ್ತಾರು +77 ಎಪ್ಪತ್ತೇಳು +78 ಎಪ್ಪತ್ತೆಂಟು +79 ಎಪ್ಪತ್ತೊಂಬತ್ತು +80 ಎಂಬತ್ತು +81 ಎಂಬತ್ತೊಂದು +82 ಎಂಬತ್ತೆರಡು +83 ಎಂಬತ್ತಮೂರು +84 ಎಂಬತ್ತನಾಲ್ಕು +85 ಎಂಬತ್ತೈದು +86 ಎಂಬತ್ತಾರು +87 ಎಂಬತ್ತೇಳು +88 ಎಂಬತ್ತೆಂಟು +89 ಎಂಬತ್ತೊಂಬತ್ತು +90 ತೊಂಬತ್ತು +91 ತೊಂಬತ್ತೊಂದು +92 ತೊಂಬತ್ತೆರಡು +93 ತೊಂಬತ್ತಮೂರು +94 ತೊಂಬತ್ತನಾಲ್ಕು +95 ತೊಂಬತ್ತೈದು +96 ತೊಂಬತ್ತಾರು +97 ತೊಂಬತ್ತೇಳು +98 ತೊಂಬತ್ತೆಂಟು +99 ತೊಂಬತ್ತೊಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/numbers/thousands.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/thousands.tsv new file mode 100644 index 000000000..589fa437f --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/thousands.tsv @@ -0,0 +1,3 @@ +೧೦೦೦ ಸಾವಿರ +೧೦೦೦೦೦ ಲಕ್ಷ +೧೦೦೦೦೦೦೦ ಕೋಟಿ \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/numbers/zero.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/zero.tsv new file mode 100644 index 000000000..736d0cdad --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/numbers/zero.tsv @@ -0,0 +1,2 @@ +೦ ಸೊನ್ನೆ +0 ಸೊನ್ನೆ \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/__init__.py b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/digit.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/digit.tsv new file mode 100644 index 000000000..92043c7d8 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/digit.tsv @@ -0,0 +1,6 @@ +ಮೊದಲನೆಯದು ಒಂದು +ಎರಡನೆಯದು ಎರಡು +ಮೂರನೆಯದು ಮೂರು +ನಾಲ್ಕನೆಯದು ನಾಲ್ಕು +ಐದನೆಯದು ಐದು +ಆರನೆಯದು ಆರು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/digit_fem.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/digit_fem.tsv new file mode 100644 index 000000000..259059e79 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/digit_fem.tsv @@ -0,0 +1,6 @@ +ಒಂದನೇ ಒಂದು +ಎರಡನೇ ಎರಡು +ಮೂರನೇ ಮೂರು +ನಾಲ್ಕನೇ ನಾಲ್ಕು +ಐದನೇ ಐದು +ಆರನೇ ಆರು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/hundred_digit.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/hundred_digit.tsv new file mode 100644 index 000000000..05415861f --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/hundred_digit.tsv @@ -0,0 +1,12 @@ +ಒಂದನೇ ಒಂದು +ಎರಡನೇ ಎರಡು +ಮೂರನೇ ಮೂರು +ನಾಲ್ಕನೇ ನಾಲ್ಕು +ಐದನೇ ಐದು +ಆರನೇ ಆರು +ಒಂದನೇ ಒಂದು +ಎರಡನೇ ಎರಡು +ಮೂರನೇ ಮೂರು +ನಾಲ್ಕನೇ ನಾಲ್ಕು +ಐದನೇ ಐದು +ಆರನೇ ಆರು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/hundred_digit_fem b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/hundred_digit_fem new file mode 100644 index 000000000..480b13d60 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/hundred_digit_fem @@ -0,0 +1,12 @@ +ಒಂದನೆಯ ಒಂದು +ಎರಡನೆಯ ಎರಡು +ಮೂರನೆಯ ಮೂರು +ನಾಲ್ಕನೆಯ ನಾಲ್ಕು +ಐದನೆಯ ಐದು +ಆರನೆಯ ಆರು +ಒಂದನೇ ಒಂದು +ಎರಡನೇ ಎರಡು +ಮೂರನೇ ಮೂರು +ನಾಲ್ಕನೇ ನಾಲ್ಕು +ಐದನೇ ಐದು +ಆರನೇ ಆರು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/morph_features.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/morph_features.tsv new file mode 100644 index 000000000..2f565e25b --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/morph_features.tsv @@ -0,0 +1 @@ +ನೇ diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/suffix.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/suffix.tsv new file mode 100644 index 000000000..e5f52d61b --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/suffix.tsv @@ -0,0 +1 @@ +ನೇ \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/suffix_fem.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/suffix_fem.tsv new file mode 100644 index 000000000..13c5d632d --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/suffix_fem.tsv @@ -0,0 +1 @@ +ನೆಯ diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/teens_and_ties.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/teens_and_ties.tsv new file mode 100644 index 000000000..aabdc5664 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/teens_and_ties.tsv @@ -0,0 +1 @@ +ತೊಂಬತ್ತನೇ ತೊಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/teens_and_ties_fem.tsv b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/teens_and_ties_fem.tsv new file mode 100644 index 000000000..7b5e819c7 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/data/ordinals/teens_and_ties_fem.tsv @@ -0,0 +1 @@ +ತೊಂಬತ್ತನೆಯ ತೊಂಬತ್ತು \ No newline at end of file diff --git a/nemo_text_processing/inverse_text_normalization/kn/graph_utils.py b/nemo_text_processing/inverse_text_normalization/kn/graph_utils.py new file mode 100644 index 000000000..640b65179 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/graph_utils.py @@ -0,0 +1,204 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# Copyright 2013 and onwards Google, Inc. +# +# 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 logging +import os +import string +from pathlib import Path +from typing import Dict + +import pynini +from pynini import Far +from pynini.examples import plurals +from pynini.export import export +from pynini.lib import byte, pynutil, utf8 + +from nemo_text_processing.inverse_text_normalization.kn.utils import get_abs_path, load_labels + +NEMO_CHAR = utf8.VALID_UTF8_CHAR + +graph_digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + +NEMO_KN_DIGIT = pynini.union("೦", "೧", "೨", "೩", "೪", "೫", "೬", "೭", "೮", "೯") + + +NEMO_HEX = pynini.union(*string.hexdigits).optimize() +NEMO_NON_BREAKING_SPACE = u"\u00a0" +NEMO_ZWNJ = u"\u200c" +NEMO_SPACE = " " +NEMO_WHITE_SPACE = pynini.union(" ", "\t", "\n", "\r", u"\u00a0").optimize() +NEMO_NOT_SPACE = pynini.difference(NEMO_CHAR, NEMO_WHITE_SPACE).optimize() +NEMO_NOT_QUOTE = pynini.difference(NEMO_CHAR, r'"').optimize() + +NEMO_PUNCT = pynini.union(*map(pynini.escape, string.punctuation)).optimize() +NEMO_GRAPH = pynini.union(NEMO_CHAR, NEMO_PUNCT).optimize() + +NEMO_SIGMA = pynini.closure(NEMO_CHAR) + +delete_space = pynutil.delete(pynini.closure(NEMO_WHITE_SPACE)) +delete_zero_or_one_space = pynutil.delete(pynini.closure(NEMO_WHITE_SPACE, 0, 1)) +insert_space = pynutil.insert(" ") +delete_extra_space = pynini.cross(pynini.closure(NEMO_WHITE_SPACE, 1), " ") +delete_preserve_order = pynini.closure( + pynutil.delete(" preserve_order: true") + | (pynutil.delete(" field_order: \"") + NEMO_NOT_QUOTE + pynutil.delete("\"")) +) + + +MIN_NEG_WEIGHT = -0.0001 +MIN_POS_WEIGHT = 0.0001 +INPUT_CASED = "cased" +INPUT_LOWER_CASED = "lower_cased" +MINUS = pynini.union("ऋणात्मक", "नकारात्मक").optimize() + + +def integer_to_devanagari(n: int) -> str: + return ''.join(DEVANAGARI_DIGIT[int(d)] for d in str(n)) + + +def generator_main(file_name: str, graphs: Dict[str, 'pynini.FstLike']): + """ + Exports graph as OpenFst finite state archive (FAR) file with given file name and rule name. + + Args: + file_name: exported file name + graphs: Mapping of a rule name and Pynini WFST graph to be exported + """ + exporter = export.Exporter(file_name) + for rule, graph in graphs.items(): + exporter[rule] = graph.optimize() + exporter.close() + logging.info(f'Created {file_name}') + + +def convert_space(fst) -> 'pynini.FstLike': + """ + Converts space to nonbreaking space. + Used only in tagger grammars for transducing token values within quotes, e.g. name: "hello kitty" + This is making transducer significantly slower, so only use when there could be potential spaces within quotes, otherwise leave it. + + Args: + fst: input fst + + Returns output fst where breaking spaces are converted to non breaking spaces + """ + return fst @ pynini.cdrewrite(pynini.cross(NEMO_SPACE, NEMO_NON_BREAKING_SPACE), "", "", NEMO_SIGMA) + + +def string_map_cased(input_file: str, input_case: str = INPUT_LOWER_CASED): + labels = load_labels(input_file) + + if input_case == INPUT_CASED: + additional_labels = [] + for written, spoken, *weight in labels: + written_capitalized = written[0].upper() + written[1:] + additional_labels.extend( + [ + [written_capitalized, spoken.capitalize()], # first letter capitalized + [ + written_capitalized, + spoken.upper().replace(" AND ", " and "), + ], # # add pairs with the all letters capitalized + ] + ) + + spoken_no_space = spoken.replace(" ", "") + # add abbreviations without spaces (both lower and upper case), i.e. "BMW" not "B M W" + if len(spoken) == (2 * len(spoken_no_space) - 1): + logging.debug(f"This is weight {weight}") + if len(weight) == 0: + additional_labels.extend( + [[written, spoken_no_space], [written_capitalized, spoken_no_space.upper()]] + ) + else: + additional_labels.extend( + [ + [written, spoken_no_space, weight[0]], + [written_capitalized, spoken_no_space.upper(), weight[0]], + ] + ) + labels += additional_labels + + whitelist = pynini.string_map(labels).invert().optimize() + return whitelist + + +class GraphFst: + """ + Base class for all grammar fsts. + + Args: + name: name of grammar class + kind: either 'classify' or 'verbalize' + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, name: str, kind: str, deterministic: bool = True): + self.name = name + self.kind = kind + self._fst = None + self.deterministic = deterministic + + self.far_path = Path(os.path.dirname(__file__) + '/grammars/' + kind + '/' + name + '.far') + if self.far_exist(): + self._fst = Far(self.far_path, mode="r", arc_type="standard", far_type="default").get_fst() + + def far_exist(self) -> bool: + """ + Returns true if FAR can be loaded + """ + return self.far_path.exists() + + @property + def fst(self) -> 'pynini.FstLike': + return self._fst + + @fst.setter + def fst(self, fst): + self._fst = fst + + def add_tokens(self, fst) -> 'pynini.FstLike': + """ + Wraps class name around to given fst + + Args: + fst: input fst + + Returns: + Fst: fst + """ + return pynutil.insert(f"{self.name} {{ ") + fst + pynutil.insert(" }") + + def delete_tokens(self, fst) -> 'pynini.FstLike': + """ + Deletes class name wrap around output of given fst + + Args: + fst: input fst + + Returns: + Fst: fst + """ + res = ( + pynutil.delete(f"{self.name}") + + delete_space + + pynutil.delete("{") + + delete_space + + fst + + delete_space + + pynutil.delete("}") + ) + return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) diff --git a/nemo_text_processing/inverse_text_normalization/kn/taggers/__init__.py b/nemo_text_processing/inverse_text_normalization/kn/taggers/__init__.py new file mode 100644 index 000000000..4fc25d0d3 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/taggers/__init__.py @@ -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. diff --git a/nemo_text_processing/inverse_text_normalization/kn/taggers/cardinal.py b/nemo_text_processing/inverse_text_normalization/kn/taggers/cardinal.py new file mode 100644 index 000000000..588b1b5f2 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/taggers/cardinal.py @@ -0,0 +1,167 @@ +# 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.inverse_text_normalization.kn.graph_utils import ( + INPUT_CASED, + INPUT_LOWER_CASED, + MINUS, + NEMO_KN_DIGIT, + NEMO_SIGMA, + NEMO_SPACE, + GraphFst, + delete_space, +) +from nemo_text_processing.inverse_text_normalization.kn.utils import get_abs_path + + +class CardinalFst(GraphFst): + + def __init__(self, input_case: str = INPUT_LOWER_CASED): + super().__init__(name="cardinal", kind="classify") + self.input_case = input_case + + # Base dictionaries + graph_zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")).invert() + graph_digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")).invert() + graph_teens_and_ties = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")).invert() + + self.graph_zero = graph_zero + self.graph_digit = graph_digit + self.graph_teens_and_ties = graph_teens_and_ties + + # Support native orthographic word variations + graph_additional_words = pynini.cross("ಇಪ್ಪತ್ತ್ಮೂರು", "೨೩") | pynini.cross("ಎಂಭತ್ತೊಂಬತ್ತು", "೮೯") + + graph_fractions = pynini.cross("ಕಾಲು", "೨೫") | pynini.cross("ಅರ್ಧ", "೫೦") | pynini.cross("ವರೆ", "೫೦") + + self.graph_two_digit = graph_teens_and_ties | graph_additional_words | (pynutil.insert("೦") + graph_digit) + self.graph_digit_or_pair = self.graph_two_digit | graph_digit + + # Base denormalization keywords + delete_hundred = pynutil.delete("ನೂರು") | pynutil.delete("ನೂರ") + delete_thousand = pynutil.delete("ಸಾವಿರ") | pynutil.delete("ಸಾವಿರದ") + delete_lakh = pynutil.delete("ಲಕ್ಷ") | pynutil.delete("ಲಕ್ಷದ") + delete_crore = pynutil.delete("ಕೋಟಿ") | pynutil.delete("ಕೋಟಿಯ") | pynutil.delete("crores") + + # Exceptional absolute phrases + graph_exceptional_comp = ( + pynini.cross("ನೂರಐವತ್ತು", "೧೫೦") + | pynini.cross("ಏಳೂವರೆ", "೭೫") + | pynini.cross("ಎರಡೂವರೆ", "೨೫") + | pynini.cross("ಹದಿನಾರೂವರೆ", "೧೬೫") + | pynini.cross("ಐನೂರು", "೫೦೦") + | pynini.cross("ಇನ್ನೂರ", "೨೦೦") + | pynini.cross("ಇನ್ನೂರು", "೨೦೦") + ) + + optional_space = pynini.closure(delete_space, 0, 1) + + # 1. Hundreds & Units Combinator + graph_hundred_prefix = (self.graph_digit_or_pair | pynutil.insert("೧")) + delete_space + delete_hundred + graph_hundred_component = pynini.union( + graph_hundred_prefix + optional_space + (self.graph_two_digit | pynutil.insert("೦೦")), + (pynini.cross("ಐನೂರ", "೫") | pynini.cross("ಇನ್ನೂರ", "೨")) + optional_space + self.graph_two_digit, + pynini.cross("ಐನೂರು", "೫೦೦"), + pynini.cross("ಇನ್ನೂರು", "೨೦೦"), + pynutil.insert("೦") + self.graph_two_digit, + pynutil.insert("೦೦೦"), + ) + + # 2. Thousands Place + graph_in_thousands = pynini.union( + self.graph_digit_or_pair + delete_space + delete_thousand, pynutil.insert("೦೦", weight=0.1) + ) + + # 3. Lakhs Place + graph_in_lakhs = pynini.union( + self.graph_digit_or_pair + delete_space + delete_lakh, pynutil.insert("೦೦", weight=0.1) + ) + + # 4. Crores Place + graph_in_crores = pynini.union( + self.graph_digit_or_pair + delete_space + delete_crore, pynutil.insert("೦೦", weight=0.1) + ) + + # Indian Number system structural layout + graph_ind = ( + graph_in_crores + + optional_space + + graph_in_lakhs + + optional_space + + graph_in_thousands + + optional_space + + graph_hundred_component + ) + + # Standalone scale keywords + graph_no_prefix = pynutil.add_weight( + pynini.cross("ನೂರು", "೧೦೦") + | pynini.cross("ಸಾವಿರ", "೧೦೦೦") + | pynini.cross("ಲಕ್ಷ", "೧೦೦೦೦೦") + | pynini.cross("ಕೋಟಿ", "೧೦೦೦೦೦೦೦"), + 2.0, + ) + + # Specialized component rules for distinct fraction terms + graph_fraction_idioms = pynini.union( + pynini.cross("ಏಳೂವರೆ ನೂರು", "೭೫೦"), + pynini.cross("ಏಳೂವರೆ ಸಾವಿರ", "೭೫೦೦"), + pynini.cross("ಏಳು ಕಾಲು ಸಾವಿರ", "೭೨೫೦"), + pynini.cross("ಎರಡೂವರೆ ನೂರು", "೨೫೦"), + pynini.cross("ಹದಿನಾರೂವರೆ ನೂರು", "೧೬೫೦"), + pynini.cross("ಹದಿನಾರು ಕಾಲು ನೂರು", "೧೬೨೫"), + ) + + # Raw fallback sequence matching digits precisely + graph_raw_digits = pynini.closure(NEMO_KN_DIGIT, 1) + + # Standard processing grammar + core_number_graph = pynini.union( + graph_ind, + graph_zero, + graph_no_prefix, + graph_fraction_idioms, + pynutil.add_weight(graph_exceptional_comp + pynutil.insert("೦"), 0.5), + pynutil.add_weight(self.graph_digit_or_pair, 1.5), + pynutil.add_weight(graph_fractions, 1.5), + pynutil.add_weight(graph_raw_digits, 20.0), + ) + + # Clean up leading zeros cleanly + core_number_graph = core_number_graph @ pynini.union( + pynutil.delete(pynini.closure("೦")) + + pynini.difference(NEMO_KN_DIGIT, "೦") + + pynini.closure(NEMO_KN_DIGIT), + "೦", + ) + + # Process standard exceptions + labels_exception = [pynini.string_file(get_abs_path("data/numbers/labels_exception.tsv"))] + graph_exception = pynini.union(*labels_exception).optimize() + + self.graph_no_exception = core_number_graph + self.graph = (pynini.project(core_number_graph, "input") - graph_exception.arcsort()) @ core_number_graph + + optional_minus_graph = pynini.closure( + pynutil.insert("negative: ") + pynini.cross(MINUS, "\"-\"") + NEMO_SPACE, 0, 1 + ) + + final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.graph + pynutil.insert("\"") + + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/nemo_text_processing/inverse_text_normalization/kn/taggers/ordinal.py b/nemo_text_processing/inverse_text_normalization/kn/taggers/ordinal.py new file mode 100644 index 000000000..429ce2f95 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/taggers/ordinal.py @@ -0,0 +1,84 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); + +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.inverse_text_normalization.kn.graph_utils import ( + NEMO_CHAR, + NEMO_KN_DIGIT, + NEMO_SIGMA, + GraphFst, +) +from nemo_text_processing.inverse_text_normalization.kn.utils import get_abs_path + + +class OrdinalFst(GraphFst): + """ + Finite state transducer for classifying ordinal + + e.g. ಹದಿಮೂರನೇ -> ordinal { integer: "13" } + + Args: + cardinal: CardinalFst + """ + + def __init__(self, cardinal: GraphFst): + super().__init__(name="ordinal", kind="classify") + + cardinal_graph = cardinal.graph_no_exception + + graph_digit = pynini.string_file(get_abs_path("data/ordinals/digit.tsv")) + graph_teens = pynini.string_file(get_abs_path("data/ordinals/teens_and_ties.tsv")) + graph_digit_hundred = pynini.string_file(get_abs_path("data/ordinals/hundred_digit.tsv")) + + graph = pynini.closure(NEMO_CHAR) + pynini.union( + graph_digit, + graph_teens, + graph_digit_hundred, + pynini.cross("ನೇ", "ನೇ"), + pynini.cross("ನೆಯ", "ನೆಯ"), + pynini.cross("ನೆಯದು", "ನೆಯದು"), + ) + + graph_fem_digit = pynini.string_file(get_abs_path("data/ordinals/digit_fem.tsv")) + graph_fem_teens = pynini.string_file(get_abs_path("data/ordinals/teens_and_ties_fem.tsv")) + graph_digit_hundred_fem = pynini.string_file(get_abs_path("data/ordinals/hundred_digit_fem.tsv")) + + graph_fem = pynini.closure(NEMO_CHAR) + pynini.union( + graph_fem_digit, + graph_fem_teens, + graph_digit_hundred_fem, + pynini.cross("ನೆಯ", "ನೆಯ"), + pynini.cross("ನೆಯದು", "ನೆಯದು"), + ) + + graph = pynini.compose( + graph | graph_fem, + ( + cardinal_graph + + pynini.union( + pynini.cross("ನೇ", "ನೇ"), + pynini.cross("ನೆಯ", "ನೆಯ"), + pynini.cross("ನೆಯದು", "ನೆಯದು"), + ) + ), + ).optimize() + + morph_features_graph = pynini.string_file(get_abs_path("data/ordinals/morph_features.tsv")) + + morpho_graph = pynutil.insert("\" morphosyntactic_features: \"") + morph_features_graph + pynutil.insert("\"") + + rule = pynini.cdrewrite( + morpho_graph, + pynini.closure(NEMO_KN_DIGIT), + pynini.union("[EOS]", " "), + NEMO_SIGMA, + ) + + final_graph = pynutil.insert("integer: \"") + graph @ rule + + self.final_graph = self.add_tokens(final_graph) + self.fst = self.final_graph.optimize() diff --git a/nemo_text_processing/inverse_text_normalization/kn/taggers/punctuation.py b/nemo_text_processing/inverse_text_normalization/kn/taggers/punctuation.py new file mode 100644 index 000000000..a9111b944 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/taggers/punctuation.py @@ -0,0 +1,36 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# Copyright 2026 and onwards Google, Inc. +# +# 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.inverse_text_normalization.kn.graph_utils import GraphFst + + +class PunctuationFst(GraphFst): + """ + Finite state transducer for classifying punctuation + e.g. आ, -> tokens { name: "आ" } tokens { name: "," } + """ + + def __init__(self): + super().__init__(name="punctuation", kind="classify") + + s = "!#$%&\'()*+,-./:;<=>?@^_`{|}~" + punct = pynini.union(*s) + + graph = pynutil.insert("name: \"") + punct + pynutil.insert("\"") + + self.fst = graph.optimize() diff --git a/nemo_text_processing/inverse_text_normalization/kn/taggers/tokenize_and_classify.py b/nemo_text_processing/inverse_text_normalization/kn/taggers/tokenize_and_classify.py new file mode 100644 index 000000000..ccb2c1c3d --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/taggers/tokenize_and_classify.py @@ -0,0 +1,125 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# Copyright 2026 and onwards Google, Inc. +# +# 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 logging +import os + +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.inverse_text_normalization.kn.graph_utils import ( + GraphFst, + delete_extra_space, + delete_space, + generator_main, +) +from nemo_text_processing.inverse_text_normalization.kn.taggers.cardinal import CardinalFst + +# from nemo_text_processing.inverse_text_normalization.kn.taggers.date import DateFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.decimal import DecimalFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.fraction import FractionFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.measure import MeasureFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.money import MoneyFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.ordinal import OrdinalFst +from nemo_text_processing.inverse_text_normalization.kn.taggers.punctuation import PunctuationFst + +# from nemo_text_processing.inverse_text_normalization.kn.taggers.telephone import TelephoneFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.time import TimeFst +# from nemo_text_processing.inverse_text_normalization.kn.taggers.whitelist import WhiteListFst +from nemo_text_processing.inverse_text_normalization.kn.taggers.word import WordFst + + +class ClassifyFst(GraphFst): + """ + Final class that composes all other classification grammars. This class can process an entire sentence, that is lower cased. + For deployment, this grammar will be compiled and exported to OpenFst Finite State Archive (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + + Args: + input_case: accepting either "lower_cased" or "cased" input. + cache_dir: path to a dir with .far grammar file. Set to None to avoid using cache. + overwrite_cache: set to True to overwrite .far files + whitelist: path to a file with whitelist replacements + """ + + def __init__( + self, + cache_dir: str = None, + overwrite_cache: bool = False, + whitelist: str = None, + input_case: str = None, + ): + super().__init__(name="tokenize_and_classify", kind="classify") + + far_file = None + if cache_dir is not None and cache_dir != "None": + os.makedirs(cache_dir, exist_ok=True) + far_file = os.path.join(cache_dir, f"hi_itn.far") + if not overwrite_cache and far_file and os.path.exists(far_file): + self.fst = pynini.Far(far_file, mode="r")["tokenize_and_classify"] + logging.info(f"ClassifyFst.fst was restored from {far_file}.") + else: + logging.info(f"Creating ClassifyFst grammars.") + cardinal = CardinalFst() + cardinal_graph = cardinal.fst + + # ordinal = OrdinalFst(cardinal) + # ordinal_graph = ordinal.fst + # decimal = DecimalFst(cardinal) + # decimal_graph = decimal.fst + # fraction = FractionFst(cardinal) + # fraction_graph = fraction.fst + # date = DateFst(cardinal, ordinal) + # date_graph = date.fst + # time = TimeFst(cardinal) + # time_graph = time.fst + # measure = MeasureFst(cardinal, decimal) + # measure_graph = measure.fst + # money = MoneyFst(cardinal, decimal) + # money_graph = money.fst + # telephone = TelephoneFst(cardinal) + # telephone_graph = telephone.fst + punct_graph = PunctuationFst().fst + # whitelist_graph = WhiteListFst().fst + word_graph = WordFst().fst + + classify = ( + pynutil.add_weight(cardinal_graph, 1.1) + # | pynutil.add_weight(ordinal_graph, 1.1) + # | pynutil.add_weight(decimal_graph, 1.1) + # | pynutil.add_weight(fraction_graph, 1.1) + # | pynutil.add_weight(date_graph, 1.1) + # | pynutil.add_weight(time_graph, 1.1) + # | pynutil.add_weight(measure_graph, 1.1) + # | pynutil.add_weight(money_graph, 1.1) + # | pynutil.add_weight(telephone_graph, 1.1) + | pynutil.add_weight(word_graph, 100) + # | pynutil.add_weight(whitelist_graph, 1.01) + ) + + punct = pynutil.insert("tokens { ") + pynutil.add_weight(punct_graph, weight=1.1) + pynutil.insert(" }") + token = pynutil.insert("tokens { ") + classify + pynutil.insert(" }") + token_plus_punct = ( + pynini.closure(punct + pynutil.insert(" ")) + token + pynini.closure(pynutil.insert(" ") + punct) + ) + + graph = token_plus_punct + pynini.closure(delete_extra_space + token_plus_punct) + graph = delete_space + graph + delete_space + + self.fst = graph.optimize() + + if far_file: + generator_main(far_file, {"tokenize_and_classify": self.fst}) + logging.info(f"ClassifyFst grammars are saved to {far_file}.") diff --git a/nemo_text_processing/inverse_text_normalization/kn/taggers/word.py b/nemo_text_processing/inverse_text_normalization/kn/taggers/word.py new file mode 100644 index 000000000..4de6c6fa8 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/taggers/word.py @@ -0,0 +1,31 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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.inverse_text_normalization.kn.graph_utils import NEMO_NOT_SPACE, GraphFst + + +class WordFst(GraphFst): + """ + Finite state transducer for classifying plain tokens, that do not belong to any special class. This can be considered as the default class. + e.g. नींद -> tokens { name: "नींद" } + """ + + def __init__(self): + super().__init__(name="word", kind="classify") + word = pynutil.insert("name: \"") + pynini.closure(NEMO_NOT_SPACE, 1) + pynutil.insert("\"") + self.fst = word.optimize() diff --git a/nemo_text_processing/inverse_text_normalization/kn/utils.py b/nemo_text_processing/inverse_text_normalization/kn/utils.py new file mode 100644 index 000000000..5830b50d0 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/utils.py @@ -0,0 +1,63 @@ +# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. 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 csv +import logging +import os +import pynini + + +def get_abs_path(rel_path): + """ + Get absolute path + + Args: + rel_path: relative path to this file + + Returns absolute path + """ + abs_path = os.path.dirname(os.path.abspath(__file__)) + os.sep + rel_path + + if not os.path.exists(abs_path): + logging.warning(f'{abs_path} does not exist') + return abs_path + + +def load_labels(abs_path): + """ + loads relative path file as dictionary + + Args: + abs_path: absolute path + + Returns dictionary of mappings + """ + label_tsv = open(abs_path, encoding="utf-8") + labels = list(csv.reader(label_tsv, delimiter="\t")) + return labels + + +from pynini.lib import pynutil + + +def apply_fst(text, fst): + """Given a string input, returns the output string + produced by traversing the path with lowest weight. + If no valid path accepts input string, returns an + error. + """ + try: + print(pynini.shortestpath(text @ fst).string()) + except pynini.FstOpError: + print(f"Error: No valid output with given input: '{text}'") diff --git a/nemo_text_processing/inverse_text_normalization/kn/verbalizers/__init__.py b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/__init__.py new file mode 100644 index 000000000..4fc25d0d3 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/__init__.py @@ -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. diff --git a/nemo_text_processing/inverse_text_normalization/kn/verbalizers/cardinal.py b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/cardinal.py new file mode 100644 index 000000000..2f0e66227 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/cardinal.py @@ -0,0 +1,45 @@ +# 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.inverse_text_normalization.kn.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space + + +class CardinalFst(GraphFst): + + def __init__(self): + super().__init__(name="cardinal", kind="verbalize") + optional_sign = pynini.closure( + pynutil.delete("negative:") + + delete_space + + pynutil.delete("\"") + + NEMO_NOT_QUOTE + + pynutil.delete("\"") + + delete_space, + 0, + 1, + ) + graph = ( + pynutil.delete("integer:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + self.numbers = graph + graph = optional_sign + graph + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/nemo_text_processing/inverse_text_normalization/kn/verbalizers/ordinal.py b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/ordinal.py new file mode 100644 index 000000000..7a95c3b0d --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/ordinal.py @@ -0,0 +1,50 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2024 and onwards Google, Inc. +# +# 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.inverse_text_normalization.kn.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space + + +class OrdinalFst(GraphFst): + """ + Finite state transducer for verbalizing ordinal, e.g. + + ordinal { integer: "೧೩" } -> ೧೩ನೇ + """ + + def __init__(self): + super().__init__(name="ordinal", kind="verbalize") + + graph = ( + pynutil.delete("integer:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + + delete_space + + pynutil.delete("morphosyntactic_features:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + + self.numbers = graph + graph = graph.optimize() + + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/nemo_text_processing/inverse_text_normalization/kn/verbalizers/verbalize.py b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/verbalize.py new file mode 100644 index 000000000..f7a6d2938 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/verbalize.py @@ -0,0 +1,68 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# Copyright 2026 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.kn.graph_utils import GraphFst +from nemo_text_processing.inverse_text_normalization.kn.verbalizers.cardinal import CardinalFst + +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.date import DateFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.decimal import DecimalFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.fraction import FractionFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.measure import MeasureFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.money import MoneyFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.ordinal import OrdinalFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.telephone import TelephoneFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.time import TimeFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.whitelist import WhiteListFst +# from nemo_text_processing.inverse_text_normalization.kn.verbalizers.word import WordFst + + +class VerbalizeFst(GraphFst): + """ + Composes other verbalizer grammars. + For deployment, this grammar will be compiled and exported to OpenFst Finite State Archive (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + """ + + def __init__(self): + super().__init__(name="verbalize", kind="verbalize") + cardinal = CardinalFst() + cardinal_graph = cardinal.fst + # ordinal = OrdinalFst() + # ordinal_graph = ordinal.fst + # decimal = DecimalFst() + # decimal_graph = decimal.fst + # fraction_graph = FractionFst().fst + # date_graph = DateFst(cardinal, ordinal).fst + # time_graph = TimeFst().fst + # measure_graph = MeasureFst(cardinal, decimal).fst + # money_graph = MoneyFst(cardinal, decimal).fst + # telephone_graph = TelephoneFst(cardinal).fst + # word_graph = WordFst().fst + # whitelist_graph = WhiteListFst().fst + + graph = ( + cardinal_graph + # | whitelist_graph + # | word_graph + # | ordinal_graph + # | decimal_graph + # | fraction_graph + # | date_graph + # | time_graph + # | measure_graph + # | money_graph + # | telephone_graph + ) + self.fst = graph diff --git a/nemo_text_processing/inverse_text_normalization/kn/verbalizers/verbalize_final.py b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/verbalize_final.py new file mode 100644 index 000000000..d63449cea --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/verbalize_final.py @@ -0,0 +1,45 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# Copyright 2026 and onwards Google, Inc. +# +# 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.inverse_text_normalization.kn.graph_utils import GraphFst, delete_extra_space, delete_space +from nemo_text_processing.inverse_text_normalization.kn.verbalizers.verbalize import VerbalizeFst +from nemo_text_processing.inverse_text_normalization.kn.verbalizers.word import WordFst + + +class VerbalizeFinalFst(GraphFst): + """ + Finite state transducer that verbalizes an entire sentence, e.g. + tokens { name: "अब" } tokens { time { hours: "१२" minutes: "३०" } } tokens { name: "बज" } tokens { name: "गए" } tokens { name: "हैं" } -> अब १२:३० बज गए हैं + """ + + def __init__(self): + super().__init__(name="verbalize_final", kind="verbalize") + verbalize = VerbalizeFst().fst + word = WordFst().fst + types = verbalize | word + graph = ( + pynutil.delete("tokens") + + delete_space + + pynutil.delete("{") + + delete_space + + types + + delete_space + + pynutil.delete("}") + ) + graph = delete_space + pynini.closure(graph + delete_extra_space) + graph + delete_space + self.fst = graph diff --git a/nemo_text_processing/inverse_text_normalization/kn/verbalizers/word.py b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/word.py new file mode 100644 index 000000000..3be65d597 --- /dev/null +++ b/nemo_text_processing/inverse_text_normalization/kn/verbalizers/word.py @@ -0,0 +1,39 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# Copyright 2026 and onwards Google, Inc. +# +# 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.inverse_text_normalization.kn.graph_utils import ( + NEMO_CHAR, + NEMO_SIGMA, + GraphFst, + delete_space, +) + + +class WordFst(GraphFst): + """ + Finite state transducer for verbalizing plain tokens + e.g. tokens { name: "नींद" } -> नींद + """ + + def __init__(self): + super().__init__(name="word", kind="verbalize") + chars = pynini.closure(NEMO_CHAR - " ", 1) + char = pynutil.delete("name:") + delete_space + pynutil.delete("\"") + chars + pynutil.delete("\"") + graph = char @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) + + self.fst = graph.optimize() diff --git a/nemo_text_processing/text_normalization/en/taggers/serial.py b/nemo_text_processing/text_normalization/en/taggers/serial.py index f650c8ff3..4a5d6bb9d 100644 --- a/nemo_text_processing/text_normalization/en/taggers/serial.py +++ b/nemo_text_processing/text_normalization/en/taggers/serial.py @@ -18,6 +18,8 @@ from pynini.lib import pynutil from nemo_text_processing.text_normalization.en.graph_utils import ( + MIN_NEG_WEIGHT, + MIN_POS_WEIGHT, NEMO_ALPHA, NEMO_DIGIT, NEMO_NOT_SPACE, @@ -28,16 +30,65 @@ from nemo_text_processing.text_normalization.en.utils import get_abs_path, load_labels +def _leading_zero_graph(cardinal: GraphFst) -> "pynini.FstLike": + return pynini.compose(pynini.accep("0") + pynini.closure(NEMO_DIGIT), cardinal.single_digits_graph).optimize() + + +def _build_serial_graph( + num_graph: "pynini.FstLike", + delimiter: "pynini.FstLike", + alphas: "pynini.FstLike", + ordinal: GraphFst, +) -> "pynini.FstLike": + letter_num = alphas + delimiter + num_graph + num_letter = pynini.closure(num_graph + delimiter, 1) + alphas + next_alpha_or_num = pynini.closure(delimiter + (alphas | num_graph)) + next_alpha_or_num |= pynini.closure( + delimiter + + num_graph + + plurals._priority_union(pynini.accep(" "), pynutil.insert(" "), NEMO_SIGMA).optimize() + + alphas + ) + + serial_graph = letter_num + next_alpha_or_num + serial_graph |= num_letter + next_alpha_or_num + serial_graph |= num_graph + delimiter + num_graph + delimiter + num_graph + pynini.closure(delimiter + num_graph) + + symbols = [x[0] for x in load_labels(get_abs_path("data/whitelist/symbol.tsv"))] + symbols = pynini.union(*symbols) + serial_graph |= pynini.compose(NEMO_SIGMA + symbols + NEMO_SIGMA, num_graph + delimiter + num_graph) + + serial_graph = pynini.compose( + pynini.difference(NEMO_SIGMA, pynini.project(ordinal.graph, "input")), serial_graph + ).optimize() + + serial_graph = pynutil.add_weight(serial_graph, MIN_POS_WEIGHT) + serial_graph |= ( + pynini.closure(NEMO_NOT_SPACE, 1) + (pynini.cross("^2", " squared") | pynini.cross("^3", " cubed")).optimize() + ) + + serial_graph = ( + pynini.closure((serial_graph | num_graph | alphas) + delimiter) + + serial_graph + + pynini.closure(delimiter + (serial_graph | num_graph | alphas)) + ) + return serial_graph.optimize() + + class SerialFst(GraphFst): """ - This class is a composite class of two other class instances + Finite state transducer for classifying serial numbers without conventional delimiters. + + Digit normalization within letter-digit tokens follows: + 1. 1-2 digits, or single digits followed by zeros -> cardinal + 2. 3 digits not ending in 00, or 4+ digits -> single-digit reading + 3. Digit-only tokens separated by ``/`` -> cardinal per segment (5+ digits stay single-digit) Args: - time: composed tagger and verbalizer - date: composed tagger and verbalizer - cardinal: tagger + cardinal: cardinal tagger + ordinal: ordinal tagger (used to exclude ordinal readings) deterministic: if True will provide a single transduction option, - for False multiple transduction are generated (used for audio-based normalization) + for False multiple transduction are generated (used for audio-based normalization) lm: whether to use for hybrid LM """ @@ -48,31 +99,56 @@ def __init__(self, cardinal: GraphFst, ordinal: GraphFst, deterministic: bool = Finite state transducer for classifying serial (handles only cases without delimiters, values with delimiters are handled by default). The serial is a combination of digits, letters and dashes, e.g.: - c325b -> tokens { cardinal { integer: "c three two five b" } } + "H800" -> tokens { name: "H eight hundred" } + "a320b" -> tokens { name: "a three two zero b" } + "12/345/67890" -> tokens { name: "twelve/three hundred forty five/six seven eight nine zero" } + """ if deterministic: - num_graph = pynini.compose(NEMO_DIGIT ** (6, ...), cardinal.single_digits_graph).optimize() - num_graph |= pynini.compose(NEMO_DIGIT ** (1, 5), cardinal.graph).optimize() - # to handle numbers starting with zero - num_graph |= pynini.compose( - pynini.accep("0") + pynini.closure(NEMO_DIGIT), cardinal.single_digits_graph + num_graph_pure = ( + pynini.compose(NEMO_DIGIT ** (1, 3), cardinal.graph) + | pynini.compose(NEMO_DIGIT ** (4, ...), cardinal.single_digits_graph) + | _leading_zero_graph(cardinal) + ).optimize() + + num_graph_alnum = ( + pynini.compose(NEMO_DIGIT, cardinal.graph) + | pynini.compose(NEMO_DIGIT**2, cardinal.graph) + | pynutil.add_weight( + pynini.compose(NEMO_DIGIT + pynini.closure("0", 1), cardinal.graph), MIN_NEG_WEIGHT + ) + | pynini.compose( + pynini.difference(NEMO_DIGIT**3, NEMO_DIGIT + NEMO_DIGIT + "00"), cardinal.single_digits_graph + ) + | pynini.compose(NEMO_DIGIT ** (4, ...), cardinal.single_digits_graph) + | _leading_zero_graph(cardinal) + ).optimize() + + num_graph_slash = ( + pynini.compose(NEMO_DIGIT ** (1, 4), cardinal.graph) + | pynini.compose(NEMO_DIGIT ** (5, ...), cardinal.single_digits_graph) + | _leading_zero_graph(cardinal) ).optimize() + else: - num_graph = cardinal.final_graph + num_graph_pure = cardinal.final_graph + num_graph_alnum = cardinal.final_graph + num_graph_slash = cardinal.final_graph # TODO: "#" doesn't work from the file symbols_graph = pynini.string_file(get_abs_path("data/whitelist/symbol.tsv")).optimize() | pynini.cross( "#", "hash" ) - num_graph |= symbols_graph + num_graph_pure |= symbols_graph + num_graph_alnum |= symbols_graph if not self.deterministic and not lm: - num_graph |= cardinal.single_digits_graph - num_graph |= pynini.compose(num_graph, NEMO_SIGMA + pynutil.delete("hundred ") + NEMO_SIGMA) - # also allow double digits to be pronounced as integer in serial number - num_graph |= pynutil.add_weight( - NEMO_DIGIT**2 @ cardinal.graph_hundred_component_at_least_one_none_zero_digit, weight=0.0001 + num_graph_pure |= cardinal.single_digits_graph + num_graph_pure |= pynini.compose(num_graph_pure, NEMO_SIGMA + pynutil.delete("hundred ") + NEMO_SIGMA) + num_graph_pure |= pynutil.add_weight( + NEMO_DIGIT**2 @ cardinal.graph_hundred_component_at_least_one_none_zero_digit, weight=MIN_POS_WEIGHT ) + num_graph_alnum = num_graph_pure # add space between letter and digit/symbol symbols = [x[0] for x in load_labels(get_abs_path("data/whitelist/symbol.tsv"))] @@ -90,44 +166,21 @@ def __init__(self, cardinal: GraphFst, ordinal: GraphFst, deterministic: bool = delimiter |= pynini.cross("-", " dash ") | pynini.cross("/", " slash ") alphas = pynini.closure(NEMO_ALPHA, 1) - letter_num = alphas + delimiter + num_graph - num_letter = pynini.closure(num_graph + delimiter, 1) + alphas - next_alpha_or_num = pynini.closure(delimiter + (alphas | num_graph)) - next_alpha_or_num |= pynini.closure( - delimiter - + num_graph - + plurals._priority_union(pynini.accep(" "), pynutil.insert(" "), NEMO_SIGMA).optimize() - + alphas - ) - - serial_graph = letter_num + next_alpha_or_num - serial_graph |= num_letter + next_alpha_or_num - # numbers only with 2+ delimiters - serial_graph |= ( - num_graph + delimiter + num_graph + delimiter + num_graph + pynini.closure(delimiter + num_graph) - ) - # 2+ symbols - serial_graph |= pynini.compose(NEMO_SIGMA + symbols + NEMO_SIGMA, num_graph + delimiter + num_graph) - - # exclude ordinal numbers from serial options - serial_graph = pynini.compose( - pynini.difference(NEMO_SIGMA, pynini.project(ordinal.graph, "input")), serial_graph - ).optimize() - serial_graph = pynutil.add_weight(serial_graph, 0.0001) - serial_graph |= ( - pynini.closure(NEMO_NOT_SPACE, 1) - + (pynini.cross("^2", " squared") | pynini.cross("^3", " cubed")).optimize() - ) + serial_graph = _build_serial_graph(num_graph_pure, delimiter, alphas, ordinal) + serial_graph_alnum = _build_serial_graph(num_graph_alnum, delimiter, alphas, ordinal) - # at least one serial graph with alpha numeric value and optional additional serial/num/alpha values - serial_graph = ( - pynini.closure((serial_graph | num_graph | alphas) + delimiter) - + serial_graph - + pynini.closure(delimiter + (serial_graph | num_graph | alphas)) + # Rule 3: tokens that contain only digits and slashes (e.g. 31/31/100, 123/261788/2021). + slash_digit_token = ( + pynini.closure(NEMO_DIGIT, 1) + pynini.accep("/") + pynini.closure(NEMO_DIGIT | pynini.accep("/"), 0) ) + slash_serial = pynini.compose( + slash_digit_token, + pynini.closure(num_graph_slash + pynini.accep("/"), 1) + num_graph_slash, + ).optimize() + serial_graph |= pynutil.add_weight(slash_serial, MIN_NEG_WEIGHT) - serial_graph |= pynini.compose(graph_with_space, serial_graph.optimize()).optimize() + serial_graph |= pynini.compose(graph_with_space, serial_graph_alnum.optimize()).optimize() serial_graph = pynini.compose(pynini.closure(NEMO_NOT_SPACE, 2), serial_graph).optimize() # this is not to verbolize "/" as "slash" in cases like "import/export" diff --git a/nemo_text_processing/text_normalization/normalize.py b/nemo_text_processing/text_normalization/normalize.py index d8ebf2f4d..7f3cef10e 100644 --- a/nemo_text_processing/text_normalization/normalize.py +++ b/nemo_text_processing/text_normalization/normalize.py @@ -190,7 +190,6 @@ def __init__( from nemo_text_processing.text_normalization.pt.verbalizers.verbalize_final import VerbalizeFinalFst elif lang == 'ko': from nemo_text_processing.text_normalization.ko.taggers.tokenize_and_classify import ClassifyFst - from nemo_text_processing.text_normalization.ko.verbalizers.verbalize_final import VerbalizeFinalFst else: raise NotImplementedError(f"Language {lang} has not been supported yet.") diff --git a/tests/nemo_text_processing/en/data_text_normalization/test_cases_ordinal.txt b/tests/nemo_text_processing/en/data_text_normalization/test_cases_ordinal.txt index 2e1b5ec7e..d4f073525 100644 --- a/tests/nemo_text_processing/en/data_text_normalization/test_cases_ordinal.txt +++ b/tests/nemo_text_processing/en/data_text_normalization/test_cases_ordinal.txt @@ -24,4 +24,4 @@ 21th~twenty one th 121st~one hundred twenty first 111th~one hundred eleventh -111st~one hundred eleven st \ No newline at end of file +111st~one one one st \ No newline at end of file diff --git a/tests/nemo_text_processing/en/data_text_normalization/test_cases_serial.txt b/tests/nemo_text_processing/en/data_text_normalization/test_cases_serial.txt index f0a6e0a3f..f142ceb7e 100644 --- a/tests/nemo_text_processing/en/data_text_normalization/test_cases_serial.txt +++ b/tests/nemo_text_processing/en/data_text_normalization/test_cases_serial.txt @@ -29,3 +29,5 @@ a 4-kilogram bag~a four-kilogram bag 100-car~one hundred-car 123/261788/2021~one hundred twenty three/two six one seven eight eight/two thousand twenty one 2*8~two asterisk eight +my pnr is t2000~my pnr is t two thousand +your otp is ab9453~your otp is ab nine four five three \ No newline at end of file diff --git a/tests/nemo_text_processing/kn/__init__.py b/tests/nemo_text_processing/kn/__init__.py new file mode 100644 index 000000000..4fc25d0d3 --- /dev/null +++ b/tests/nemo_text_processing/kn/__init__.py @@ -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. diff --git a/tests/nemo_text_processing/kn/data_inverse_text_normalization/test_cases_cardinal.txt b/tests/nemo_text_processing/kn/data_inverse_text_normalization/test_cases_cardinal.txt new file mode 100644 index 000000000..2f3194f1c --- /dev/null +++ b/tests/nemo_text_processing/kn/data_inverse_text_normalization/test_cases_cardinal.txt @@ -0,0 +1,59 @@ +ನಾಲ್ಕು ಷಟ್ಕಗಳು~೪ ಷಟ್ಕಗಳು +ಆರು ಆಟಗಾರರು ಔಟ್~೬ ಆಟಗಾರರು ಔಟ್ +ವನ್ಪ್ಲಸ್ ಎಂಟು ಪ್ರೊ~ವನ್ಪ್ಲಸ್ ೮ ಪ್ರೊ +ಐದು ಚಾರ್ಜರ್~೫ ಚಾರ್ಜರ್ +ನಾಲ್ಕು ಓವರ್‌ನಲ್ಲಿ ಹದಿನೇಳು ರನ್~೪ ಓವರ್‌ನಲ್ಲಿ ೧೭ ರನ್ +ಐದು ಚಾಕೊಲೇಟ್‌ಗಳು ಒಂಬತ್ತು ಟಾಫಿಗಳು~೫ ಚಾಕೊಲೇಟ್‌ಗಳು ೯ ಟಾಫಿಗಳು +ಹತ್ತು ಸಾವಿರದ ತೊಂಬತ್ತೊಂಬತ್ತು~೧೦೦೯೯ +ಒಂದು ಲಕ್ಷದ ಒಂದು~೧೦೦೦೦೧ +ಒಂದು ನೂರು~೧೦೦ +ಮೂರು ನೂರು ಒಂಬತ್ತು~೩೦೯ +ಏಳು ನೂರು ತೊಂಬತ್ತೆಂಟು~೭೯೮ +ನಾಲ್ಕು ಚೌಕೆ~೪ ಚೌಕೆ +ಒನ್‌ಪ್ಲಸ್ ಎಂಟು ಪ್ರೊ~ಒನ್‌ಪ್ಲಸ್ ೮ ಪ್ರೊ +ಐದು ಚಾರ್ಜರ್‌ಗಳು~೫ ಚಾರ್ಜರ್‌ಗಳು +ನಾಲ್ಕು ಓವರ್‌ಗಳಲ್ಲಿ ಹದಿನೇಳು ರನ್‌ಗಳು~೪ ಓವರ್‌ಗಳಲ್ಲಿ ೧೭ ರನ್‌ಗಳು +ನೂರು~೧೦೦ +ಐದು ಸಾವಿರ~೫೦೦೦ +ಎಂಟು ಸಾವಿರದ ನಾಲ್ಕು~೮೦೦೪ +ಒಂಬತ್ತು ಸಾವಿರದ ಹದಿನಾರು~೯೦೧೬ +ಹತ್ತೊಂಬತ್ತು ನೂರು ಹನ್ನೆರಡು~೧೯೧೨ +ಎರಡು ಸಾವಿರ ಎರಡು ನೂರು ಇಪ್ಪತ್ತೆರಡು~೨೨೨೨ +ಹದಿನಾಲ್ಕು ಸಾವಿರ~೧೪೦೦೦ +ಹದಿನೆಂಟು ಸಾವಿರದ ಆರು~೧೮೦೦೬ +ಇಪ್ಪತ್ತಾರು ಸಾವಿರದ ಇಪ್ಪತ್ತೊಂದು~೨೬೦೨೧ +ತೊಂಬತ್ತಾರು ಸಾವಿರದ ಎಂಟು ನೂರು ಹನ್ನೊಂದು~೯೬೮೧೧ +ನಾಲ್ಕು ಲಕ್ಷ~೪೦೦೦೦೦ +ಎರಡು ಲಕ್ಷದ ಎರಡು~೨೦೦೦೦೨ +ಏಳು ಲಕ್ಷದ ಇಪ್ಪತ್ತು~೭೦೦೦೨೦ +ಒಂಬತ್ತು ಲಕ್ಷದ ಮೂರು ನೂರು ಇಪ್ಪತ್ತೊಂದು~೯೦೦೩೨೧ +ಎಂಟು ಲಕ್ಷದ ಐದು ಸಾವಿರದ ಮೂರು ನೂರು ಇಪ್ಪತ್ತೊಂದು~೮೦೫೩೨೧ +ಇಪ್ಪತ್ತ್ಮೂರು ಲಕ್ಷ~೨೩೦೦೦೦೦ +ಹದಿನೈದು ಲಕ್ಷದ ಒಂದು~೧೫೦೦೦೦೧ +ಇಪ್ಪತ್ತೇಳು ಲಕ್ಷದ ಎಂಟು ನೂರು ಇಪ್ಪತ್ತು~೨೭೦೦೮೨೦ +ತೊಂಬತ್ತೊಂದು ಲಕ್ಷದ ಮೂವತ್ತೊಂದು ಸಾವಿರ ಎಂಟು ನೂರು ಇಪ್ಪತ್ತೊಂಬತ್ತು~೯೧೩೧೮೨೯ +ಮೂರು ಕೋಟಿ~೩೦೦೦೦೦೦೦ +ಒಂದು ಕೋಟಿ ಒಂದು~೧೦೦೦೦೦೦೧ +ಏಳು ಕೋಟಿ ಹದಿಮೂರು~೭೦೦೦೦೦೧೩ +ನಾಲ್ಕು ಕೋಟಿ ಒಂಬತ್ತು ನೂರು ಹನ್ನೊಂದು~೪೦೦೦೦೯೧೧ +ಆರು ಕೋಟಿ ಐದು ಸಾವಿರ ಒಂಬತ್ತು ನೂರು ಹನ್ನೊಂದು~೬೦೦೦೫೯೧೧ +ಆರು ಕೋಟಿ ಇಪ್ಪತ್ತೈದು ಸಾವಿರ ಒಂಬತ್ತು ನೂರು ಹನ್ನೊಂದು~೬೦೦೨೫೯೧೧ +ಮೂರು ಕೋಟಿ ಒಂದು ಲಕ್ಷ ಇಪ್ಪತ್ತೈದು ಸಾವಿರ ಒಂಬತ್ತು ನೂರು ಹನ್ನೊಂದು~೩೦೧೨೫೯೧೧ +ಎರಡು ಕೋಟಿ ಹದಿನೇಳು ಲಕ್ಷ ಇಪ್ಪತ್ತೈದು ಸಾವಿರ ಒಂಬತ್ತು ನೂರು ಹನ್ನೊಂದು~೨೧೭೨೫೯೧೧ +ಮೂವತ್ತು ಕೋಟಿ~೩೦೦೦೦೦೦೦೦ +ತೊಂಬತ್ತೆಂಟು ಲಕ್ಷ ಎಪ್ಪತ್ತಾರು ಸಾವಿರ ಏಳು ನೂರು ಎಂಬತ್ತೊಂಬತ್ತು~೯೮೭೬೭೮೯ +ಇಪ್ಪತ್ತಮೂರು ಲಕ್ಷ ನಲವತ್ತೈದು ಸಾವಿರ ಐದು ನೂರು ಅರವತ್ತೇಳು~೨೩೪೫೫೬೭ +ಒಂದು ಕೋಟಿ ಇಪ್ಪತ್ತಮೂರು ಲಕ್ಷ ನಲವತ್ತೈದು ಸಾವಿರ ಐದು ನೂರು ಅರವತ್ತೇಳು~೧೨೩೪೫೫೬೭ +ಒಂದು ಕೋಟಿ ಇಪ್ಪತ್ತೊಂದು ಲಕ್ಷ ಇಪ್ಪತ್ತೊಂದು ಸಾವಿರ ಎರಡು ನೂರು ಹನ್ನೆರಡು~೧೨೧೨೧೨೧೨ +ಏಳೂವರೆ ನೂರು~೭೫೦ +ಏಳೂವರೆ ಸಾವಿರ~೭೫೦೦ +ಏಳು ಕಾಲು ಸಾವಿರ~೭೨೫೦ +ನೂರಐವತ್ತು~೧೫೦ +ಎರಡೂವರೆ ನೂರು~೨೫೦ +ಹದಿನಾರೂವರೆ ನೂರು~೧೬೫೦ +ಹದಿನಾರು ಕಾಲು ನೂರು~೧೬೨೫ +ಏಳುನೂರ ಇಪ್ಪತ್ತೈದು~೭೨೫ +ಏಳುನೂರು ಐವತ್ತು~೭೫೦ +ಏಳು ಸಾವಿರದ ಐನೂರು~೭೫೦೦ +ಏಳು ಸಾವಿರದ ಇನ್ನೂರ ಐವತ್ತು~೭೨೫೦ +ಒಂದು ನೂರ ಐವತ್ತು~೧೫೦ \ No newline at end of file diff --git a/tests/nemo_text_processing/kn/data_inverse_text_normalization/test_cases_ordinal.txt b/tests/nemo_text_processing/kn/data_inverse_text_normalization/test_cases_ordinal.txt new file mode 100644 index 000000000..d3d70ab53 --- /dev/null +++ b/tests/nemo_text_processing/kn/data_inverse_text_normalization/test_cases_ordinal.txt @@ -0,0 +1,13 @@ +ಸಾವಿರ ಒಂದನೆಯ~೧೦೦೧ನೆಯ +ನೂರನೇ~೧೦೦ನೇ +ನೂರ ಒಂದನೇ~೧೦೧ನೇ +ಹತ್ತನೇ~೧೦ನೇ +ಹತ್ತನೆಯ~೧೦ನೆಯ +ಹತ್ತನೇ~೧೦ನೇ +ನೂರ ಹತ್ತೊಂಬತ್ತನೇ~೧೧೯ನೇ +ನೂರ ಹತ್ತೊಂಬತ್ತನೆಯ~೧೧೯ನೆಯ +ನೂರ ಹತ್ತೊಂಬತ್ತನೇ~೧೧೯ನೇ +ಒಂಬೈನೂರ ಇಪ್ಪತ್ತಾರನೆಯ~೯೮೨೬ನೆಯ +ತೊಂಬತ್ತೆಂಟನೆಯ~೯೮ನೆಯ +ತೊಂಬತ್ತೊಂಬತ್ತನೇ~೯೯ನೇ +ಆರುನೂರ ನಲವತ್ತನೆಯ~೬೪೦ನೆಯ \ No newline at end of file diff --git a/tests/nemo_text_processing/kn/test_cardinal.py b/tests/nemo_text_processing/kn/test_cardinal.py new file mode 100644 index 000000000..90e598ffe --- /dev/null +++ b/tests/nemo_text_processing/kn/test_cardinal.py @@ -0,0 +1,42 @@ +# 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.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer + +from ..utils import CACHE_DIR, parse_test_case_file + + +class TestCardinal: + normalizer = Normalizer( + input_case='cased', lang='kn', cache_dir=CACHE_DIR, overwrite_cache=False, post_process=False + ) + inverse_normalizer = InverseNormalizer(lang='kn', cache_dir=CACHE_DIR, overwrite_cache=False) + + @parameterized.expand(parse_test_case_file('kn/data_text_normalization/test_cases_cardinal.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.strip() == expected.strip() + + @parameterized.expand(parse_test_case_file('kn/data_inverse_text_normalization/test_cases_cardinal.txt')) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected diff --git a/tests/nemo_text_processing/kn/test_ordinal.py b/tests/nemo_text_processing/kn/test_ordinal.py new file mode 100644 index 000000000..d46dab846 --- /dev/null +++ b/tests/nemo_text_processing/kn/test_ordinal.py @@ -0,0 +1,43 @@ +# Copyright (c) 2024, 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.inverse_text_normalization.inverse_normalize import InverseNormalizer +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 + ) + inverse_normalizer = InverseNormalizer(lang='kn', cache_dir=CACHE_DIR, overwrite_cache=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.strip() == expected.strip() + + @parameterized.expand(parse_test_case_file('kn/data_inverse_text_normalization/test_cases_ordinal.txt')) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected