sinlib 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sinlib-0.3.0 → sinlib-0.3.2}/PKG-INFO +3 -4
- {sinlib-0.3.0 → sinlib-0.3.2}/README.md +2 -3
- {sinlib-0.3.0 → sinlib-0.3.2}/pyproject.toml +1 -1
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/__init__.py +1 -1
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/encoder.py +19 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/seq2seq_decoder.py +5 -1
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/spellcheck.py +32 -17
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_charbert_backend.py +4 -3
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/api/spellcheck.mdx +46 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/guides/spellcheck.mdx +55 -2
- {sinlib-0.3.0 → sinlib-0.3.2}/.github/workflows/python-publish.yml +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/.github/workflows/test.yml +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/.gitignore +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/.readthedocs.yaml +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/LICENSE +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/requirements-dev.txt +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/requirements.txt +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/__init__.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/alignment.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/backend.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/char_encoder.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/char_tokenization.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/config.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/embeddings.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/hi_module.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/charbert/modeling.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/encoding.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/romanize.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/subword.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/tokenizer.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/transliterate.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/__init__.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/chars.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/dataset_utils.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/model_utils.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/models/__init__.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/models/akshara_ngram.json +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/models/akshara_vocab.json +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/models/bigru_detector.pt +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/models/transliterator-checkpoint.pth +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/models/transliterator_model.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/preprocessing.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/src/sinlib/utils/visualize.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_combined_detector.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_phase3_enhancements.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_romanizer.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_spellcheck.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_tokenizer.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_tokenizer_batch.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_tokenizer_bos.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_tokenizer_special_tokens.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_transliterator.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/tests/test_visualize.py +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/.gitignore +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/.vscode/extensions.json +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/.vscode/launch.json +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/README.md +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/astro.config.mjs +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/package-lock.json +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/package.json +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/public/favicon.svg +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/assets/houston.webp +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/assets/logo-dark.png +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/assets/logo-light.png +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/api/encoding.mdx +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/api/preprocessing.mdx +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/api/romanizer.mdx +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/api/tokenizer.mdx +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/api/visualization.mdx +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/examples/tokenization.md +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/examples/typo-correction.md +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/examples/visualization.md +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/guides/tokenization.mdx +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content/docs/index.mdx +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/content.config.ts +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/src/styles/custom.css +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/website/tsconfig.json +0 -0
- {sinlib-0.3.0 → sinlib-0.3.2}/welcome.png +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sinlib
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Sinhala NLP Toolkit
|
|
5
5
|
Project-URL: Code, https://github.com/Ransaka/sinlib
|
|
6
6
|
Project-URL: Docs, https://sinlib.readthedocs.io
|
|
@@ -147,9 +147,8 @@ Notes:
|
|
|
147
147
|
|
|
148
148
|
- **Default behavior is unchanged** — without `neural_backend` the detector is
|
|
149
149
|
purely statistical and requires no torch.
|
|
150
|
-
-
|
|
151
|
-
|
|
152
|
-
(hallucination guard).
|
|
150
|
+
- A neural candidate is accepted only if it scores no worse than the input
|
|
151
|
+
(hallucination guard), so already-clean text is never degraded.
|
|
153
152
|
- If the checkpoint cannot be downloaded, the detector degrades gracefully to
|
|
154
153
|
statistical-only correction with a warning.
|
|
155
154
|
|
|
@@ -100,9 +100,8 @@ Notes:
|
|
|
100
100
|
|
|
101
101
|
- **Default behavior is unchanged** — without `neural_backend` the detector is
|
|
102
102
|
purely statistical and requires no torch.
|
|
103
|
-
-
|
|
104
|
-
|
|
105
|
-
(hallucination guard).
|
|
103
|
+
- A neural candidate is accepted only if it scores no worse than the input
|
|
104
|
+
(hallucination guard), so already-clean text is never degraded.
|
|
106
105
|
- If the checkpoint cannot be downloaded, the detector degrades gracefully to
|
|
107
106
|
statistical-only correction with a warning.
|
|
108
107
|
|
|
@@ -120,6 +120,25 @@ class SinhalaCharBERTEncoder(nn.Module):
|
|
|
120
120
|
all_char_hidden_states: List[torch.Tensor] = []
|
|
121
121
|
all_attentions: List[torch.Tensor] = []
|
|
122
122
|
|
|
123
|
+
# Normalize the attention mask to the 4-D extended additive format
|
|
124
|
+
# (batch, 1, 1, seq_len) expected by transformers' attention
|
|
125
|
+
# implementations. Newer versions of transformers (>= 4.56) index the
|
|
126
|
+
# mask as attention_mask[:, :, :, :key_len] and crash with
|
|
127
|
+
# "too many indices for tensor of dimension 2" if a 2-D padding mask
|
|
128
|
+
# is passed straight through.
|
|
129
|
+
if attention_mask is not None and attention_mask.dim() != 4:
|
|
130
|
+
if attention_mask.dim() == 2:
|
|
131
|
+
mask = attention_mask[:, None, None, :]
|
|
132
|
+
elif attention_mask.dim() == 3:
|
|
133
|
+
mask = attention_mask[:, None, :, :]
|
|
134
|
+
else:
|
|
135
|
+
raise ValueError(
|
|
136
|
+
f"Unsupported attention_mask dims: {attention_mask.dim()}"
|
|
137
|
+
)
|
|
138
|
+
# Convert 1/0 padding mask to an additive mask (0 keep, -inf drop)
|
|
139
|
+
dtype = token_hidden_states.dtype
|
|
140
|
+
attention_mask = (1.0 - mask.to(dtype)) * torch.finfo(dtype).min
|
|
141
|
+
|
|
123
142
|
curr_token = token_hidden_states
|
|
124
143
|
curr_char = char_hidden_states
|
|
125
144
|
|
|
@@ -78,7 +78,11 @@ class SinhalaCharBERTDecoderLayer(nn.Module):
|
|
|
78
78
|
key=hidden_states,
|
|
79
79
|
value=hidden_states,
|
|
80
80
|
attn_mask=causal_mask,
|
|
81
|
-
need_weights=
|
|
81
|
+
# need_weights=True forces the math code path of
|
|
82
|
+
# nn.MultiheadAttention; the fused fast path has shown
|
|
83
|
+
# device-dependent failures with 2-D float causal masks
|
|
84
|
+
# on some CUDA builds.
|
|
85
|
+
need_weights=True,
|
|
82
86
|
)
|
|
83
87
|
hidden_states = self.self_attn_layer_norm(residual + self.dropout(attn_out))
|
|
84
88
|
|
|
@@ -4,6 +4,7 @@ import math
|
|
|
4
4
|
import warnings
|
|
5
5
|
import json
|
|
6
6
|
import re
|
|
7
|
+
import traceback
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from difflib import get_close_matches, SequenceMatcher
|
|
9
10
|
from typing import Dict, List, Optional, Set, Tuple
|
|
@@ -663,22 +664,19 @@ class TypoDetector:
|
|
|
663
664
|
|
|
664
665
|
def _try_neural_sentence(self, text: str) -> Optional[str]:
|
|
665
666
|
"""
|
|
666
|
-
Runs the CharBERT seq2seq neural pass over a sentence
|
|
667
|
-
|
|
668
|
-
|
|
667
|
+
Runs the CharBERT seq2seq neural pass over a sentence and returns the
|
|
668
|
+
neural correction if it passes the acceptance guard, otherwise None.
|
|
669
|
+
|
|
670
|
+
The model runs on every non-empty sentence: real-word typos
|
|
671
|
+
(e.g. sibilant confusion) and word split/fusion artifacts consist of
|
|
672
|
+
perfectly valid dictionary words and cannot be detected by any cheap
|
|
673
|
+
statistical heuristic. The acceptance guard — the neural output must
|
|
674
|
+
score no worse than the input — is what protects already-clean text
|
|
675
|
+
from spurious "corrections".
|
|
669
676
|
"""
|
|
670
677
|
if not text or not text.strip() or not self.has_charbert:
|
|
671
678
|
return None
|
|
672
679
|
|
|
673
|
-
# Trigger gate: structural noise or any out-of-dictionary word
|
|
674
|
-
words = [self._extract_punctuation(t)[1] for t in text.split()]
|
|
675
|
-
trigger = CharBERTBackend.has_structural_noise(text) or any(
|
|
676
|
-
w and (w not in self._dictionary and normalize_sinhala(w) not in self._dictionary)
|
|
677
|
-
for w in words
|
|
678
|
-
)
|
|
679
|
-
if not trigger:
|
|
680
|
-
return None
|
|
681
|
-
|
|
682
680
|
if text in self._neural_sentence_cache:
|
|
683
681
|
return self._neural_sentence_cache[text]
|
|
684
682
|
|
|
@@ -687,8 +685,13 @@ class TypoDetector:
|
|
|
687
685
|
candidate = self._charbert.correct_sentence(
|
|
688
686
|
text, num_beams=self._backend_num_beams
|
|
689
687
|
).strip()
|
|
690
|
-
except Exception
|
|
691
|
-
|
|
688
|
+
except Exception:
|
|
689
|
+
# Include the traceback: identical warnings are deduplicated by the
|
|
690
|
+
# warnings module, so a short message would hide repeated failures.
|
|
691
|
+
warnings.warn(
|
|
692
|
+
"CharBERT neural correction failed:\n" + traceback.format_exc(),
|
|
693
|
+
RuntimeWarning,
|
|
694
|
+
)
|
|
692
695
|
|
|
693
696
|
result: Optional[str] = None
|
|
694
697
|
if candidate and candidate != text:
|
|
@@ -934,8 +937,19 @@ class TypoDetector:
|
|
|
934
937
|
using Phonological Trie search, BiGRU Seq2Seq, and Stupid Backoff LM.
|
|
935
938
|
"""
|
|
936
939
|
self._ensure_loaded()
|
|
940
|
+
|
|
941
|
+
# Neural-first pass (seq2seq / hybrid modes): when structural noise or
|
|
942
|
+
# out-of-dictionary words are present, run the CharBERT model on the
|
|
943
|
+
# RAW input BEFORE the statistical word loop, so that word-level
|
|
944
|
+
# replacements cannot corrupt the sentence the model conditions on.
|
|
945
|
+
neural_done: Optional[str] = None
|
|
946
|
+
if self.neural_backend in ("seq2seq", "hybrid"):
|
|
947
|
+
neural_done = self._try_neural_sentence(text)
|
|
948
|
+
|
|
949
|
+
work_text = neural_done if neural_done is not None else text
|
|
950
|
+
|
|
937
951
|
corrected: List[str] = []
|
|
938
|
-
raw_tokens =
|
|
952
|
+
raw_tokens = work_text.split() if isinstance(work_text, str) else [str(work_text)]
|
|
939
953
|
parsed_tokens = [self._extract_punctuation(t) for t in raw_tokens]
|
|
940
954
|
words = [p[1] for p in parsed_tokens]
|
|
941
955
|
n_words = len(words)
|
|
@@ -979,8 +993,9 @@ class TypoDetector:
|
|
|
979
993
|
|
|
980
994
|
result_text = " ".join(corrected)
|
|
981
995
|
|
|
982
|
-
#
|
|
983
|
-
|
|
996
|
+
# Fallback neural pass (seq2seq / hybrid modes): only when the
|
|
997
|
+
# neural-first pass did not already handle this sentence.
|
|
998
|
+
if self.neural_backend in ("seq2seq", "hybrid") and neural_done is None:
|
|
984
999
|
neural_sentence = self._try_neural_sentence(result_text)
|
|
985
1000
|
if neural_sentence is not None:
|
|
986
1001
|
result_text = neural_sentence
|
|
@@ -142,11 +142,12 @@ def test_neural_pass_applies_correction(neural_detector):
|
|
|
142
142
|
assert result == "මම ගෙදර යන්න ඕනේ"
|
|
143
143
|
|
|
144
144
|
|
|
145
|
-
def
|
|
146
|
-
#
|
|
145
|
+
def test_clean_in_dictionary_sentence_unchanged(neural_detector):
|
|
146
|
+
# Clean sentence: the model is consulted, but its (unchanged) output is
|
|
147
|
+
# rejected by the acceptance guard, so the text is returned as-is.
|
|
147
148
|
result = neural_detector("ගෙදර පොත")
|
|
148
149
|
backend = FakeCharBERTBackend.instances[0]
|
|
149
|
-
assert len(backend.sentence_calls) ==
|
|
150
|
+
assert len(backend.sentence_calls) == 1
|
|
150
151
|
assert result == "ගෙදර පොත"
|
|
151
152
|
|
|
152
153
|
|
|
@@ -47,6 +47,31 @@ Main spell checking and correction class. Detects typos using Akshara Trigram sc
|
|
|
47
47
|
<td><span class="param-type">bool</span><span class="param-badge badge-optional">Optional</span></td>
|
|
48
48
|
<td>If True, defers downloading/loading weights until first call.</td>
|
|
49
49
|
</tr>
|
|
50
|
+
<tr>
|
|
51
|
+
<td><span class="param-name">neural_backend</span></td>
|
|
52
|
+
<td><span class="param-type">str | None</span><span class="param-badge badge-optional">Optional</span></td>
|
|
53
|
+
<td>Optional CharBERT neural correction mode: <code>None</code>, <code>"denoise"</code>, <code>"seq2seq"</code>, or <code>"hybrid"</code>. Default <code>None</code> (statistical only).</td>
|
|
54
|
+
</tr>
|
|
55
|
+
<tr>
|
|
56
|
+
<td><span class="param-name">backend_model</span></td>
|
|
57
|
+
<td><span class="param-type">str</span><span class="param-badge badge-optional">Optional</span></td>
|
|
58
|
+
<td>HF Hub repo id or local checkpoint directory for the CharBERT model. Default <code>"Ransaka/sinhala-charbert-seq2seq"</code>.</td>
|
|
59
|
+
</tr>
|
|
60
|
+
<tr>
|
|
61
|
+
<td><span class="param-name">backend_device</span></td>
|
|
62
|
+
<td><span class="param-type">str | None</span><span class="param-badge badge-optional">Optional</span></td>
|
|
63
|
+
<td>Torch device (cuda > mps > cpu by default).</td>
|
|
64
|
+
</tr>
|
|
65
|
+
<tr>
|
|
66
|
+
<td><span class="param-name">backend_revision</span></td>
|
|
67
|
+
<td><span class="param-type">str | None</span><span class="param-badge badge-optional">Optional</span></td>
|
|
68
|
+
<td>Pin a specific HF Hub revision of the CharBERT checkpoint.</td>
|
|
69
|
+
</tr>
|
|
70
|
+
<tr>
|
|
71
|
+
<td><span class="param-name">backend_num_beams</span></td>
|
|
72
|
+
<td><span class="param-type">int</span><span class="param-badge badge-optional">Optional</span></td>
|
|
73
|
+
<td>Beam width for seq2seq generation. Default <code>4</code>.</td>
|
|
74
|
+
</tr>
|
|
50
75
|
</tbody>
|
|
51
76
|
</table>
|
|
52
77
|
|
|
@@ -187,5 +212,26 @@ prob = detector.word_ngram_probability("සිංහල")
|
|
|
187
212
|
# ~3.2e-05 (higher is more common)
|
|
188
213
|
```
|
|
189
214
|
|
|
215
|
+
#### Neural Correction (CharBERT, optional)
|
|
216
|
+
```python
|
|
217
|
+
# pip install "sinlib[charbert]"
|
|
218
|
+
detector = TypoDetector(neural_backend="hybrid")
|
|
219
|
+
|
|
220
|
+
detector("මම ගෙදර යන්ඩ ඕනේ")
|
|
221
|
+
# 'මම ගෙදර යන්න ඕනේ' (dialectal morphology)
|
|
222
|
+
|
|
223
|
+
detector("මම gedara යන්න ඕනේ")
|
|
224
|
+
# 'මම ගෙදර යන්න ඕනේ' (Singlish code-mixing)
|
|
225
|
+
|
|
226
|
+
detector("ක්රීඩාව")
|
|
227
|
+
# 'ක්රීඩාව' (ZWJ-damaged ligature)
|
|
228
|
+
|
|
229
|
+
# Point at a local checkpoint instead of the Hub
|
|
230
|
+
detector = TypoDetector(
|
|
231
|
+
neural_backend="seq2seq",
|
|
232
|
+
backend_model="/path/to/checkpoint",
|
|
233
|
+
)
|
|
234
|
+
```
|
|
235
|
+
|
|
190
236
|
</div>
|
|
191
237
|
</div>
|
|
@@ -101,9 +101,62 @@ words = detector.get_dictionary() # set[str]
|
|
|
101
101
|
probs = detector.get_ngram_probs() # dict
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
## Neural typo correction (optional, CharBERT)
|
|
105
|
+
|
|
106
|
+
Version 0.3.0 adds an optional neural backend backed by **Sinhala-CharBERT** —
|
|
107
|
+
a dual-channel (subword + phonological akshara) seq2seq model. It handles noise
|
|
108
|
+
classes the statistical pipeline cannot fix: Singlish transliteration,
|
|
109
|
+
dialectal morphology (`යන්ඩ` → `යන්න`), ZWJ-damaged ligatures
|
|
110
|
+
(`ක්රීඩාව` → `ක්රීඩාව`), split/fused words, and Unicode decomposition errors.
|
|
111
|
+
|
|
112
|
+
Install the optional dependency and pick a backend mode:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from sinlib import TypoDetector
|
|
116
|
+
|
|
117
|
+
# "denoise" - bounded word-level neural fix when dictionary suggestions fail
|
|
118
|
+
# "seq2seq" - open-vocabulary sentence-level fix when structural noise is detected
|
|
119
|
+
# "hybrid" - both, in cascade (recommended)
|
|
120
|
+
detector = TypoDetector(neural_backend="hybrid")
|
|
121
|
+
|
|
122
|
+
detector("මම ගෙදර යන්ඩ ඕනේ")
|
|
123
|
+
# 'මම ගෙදර යන්න ඕනේ'
|
|
124
|
+
|
|
125
|
+
detector("මම gedara යන්න ඕනේ")
|
|
126
|
+
# 'මම ගෙදර යන්න ඕනේ'
|
|
127
|
+
|
|
128
|
+
detector("ක්රීඩාව")
|
|
129
|
+
# 'ක්රීඩාව'
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Constructor keywords
|
|
133
|
+
|
|
134
|
+
| Keyword | Default | Description |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| `neural_backend` | `None` | `None`, `"denoise"`, `"seq2seq"`, or `"hybrid"` |
|
|
137
|
+
| `backend_model` | `Ransaka/sinhala-charbert-seq2seq` | HF Hub repo id or a local checkpoint directory containing `pytorch_model.bin` + `char_vocab.json` |
|
|
138
|
+
| `backend_device` | auto (cuda > mps > cpu) | Torch device for the model |
|
|
139
|
+
| `backend_revision` | `None` | Pin a specific HF Hub revision |
|
|
140
|
+
| `backend_num_beams` | `4` | Beam width for seq2seq generation |
|
|
141
|
+
|
|
142
|
+
### How the gates work
|
|
143
|
+
|
|
144
|
+
- Without `neural_backend`, behaviour is unchanged and purely statistical — no
|
|
145
|
+
torch required.
|
|
146
|
+
- In `"seq2seq"` / `"hybrid"` modes, the model runs on every sentence: real-word
|
|
147
|
+
typos (e.g. sibilant confusion) and word split/fusion artifacts consist of
|
|
148
|
+
valid dictionary words, so no cheap heuristic can pre-detect them. On GPU the
|
|
149
|
+
beam search pass takes well under a second per sentence.
|
|
150
|
+
- A neural candidate is accepted only if it is no noisier than the input
|
|
151
|
+
(hallucination guard), so clean text is never "corrected" into garbage.
|
|
152
|
+
- If the checkpoint cannot be downloaded, the detector degrades gracefully to
|
|
153
|
+
statistical-only correction with a warning.
|
|
154
|
+
|
|
104
155
|
## Limitations
|
|
105
156
|
|
|
106
|
-
-
|
|
157
|
+
- Statistical correction is word-by-word; the model has no sentence context
|
|
158
|
+
(the optional neural backend does operate on full sentences).
|
|
107
159
|
- Only the top suggestion replaces a typo — alternatives available via `suggest_correction()`.
|
|
108
160
|
- The dictionary covers general Sinhala vocabulary; domain-specific or neologistic words may be flagged.
|
|
109
|
-
- Romanised Sinhala (Singlish)
|
|
161
|
+
- Romanised Sinhala (Singlish) and structural noise are only handled by the
|
|
162
|
+
optional CharBERT backend described above.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|