Download python/sherpa_punct_sdk/postprocess.py from AXERA-TECH/punc-ct-transformer: direct link, hf CLI and curl.
- Browser
- Download file 3.09 kB
-
https://huggingface.co/AXERA-TECH/punc-ct-transformer/resolve/main/python/sherpa_punct_sdk/postprocess.py
- Command line
-
hf download hf://AXERA-TECH/punc-ct-transformer/python/sherpa_punct_sdk/postprocess.py
-
curl -L -o postprocess.py https://huggingface.co/AXERA-TECH/punc-ct-transformer/resolve/main/python/sherpa_punct_sdk/postprocess.py
3.09 kB
| # Sherpa Onnx Punctuation Postprocessor | |
| # | |
| # Converts model logits output to punctuation-annotated text. | |
| # 6 classes: <unk>(0), _(1), ,(2), 。(3), ?(4), 、(5) | |
| import numpy as np | |
| from typing import List | |
| PUNCT_CLASSES = [0, 1, 2, 3, 4, 5] | |
| PUNCT_MARKS = ["", "", ",", "。", "?", "、"] | |
| IGNORE_ID = 1 # underscore class = no punctuation | |
| def decode_punctuation( | |
| logits: np.ndarray, | |
| token_ids: List[int], | |
| id2token: List[str], | |
| original_length: int, | |
| dot_id: int = 3, | |
| comma_id: int = 2, | |
| quest_id: int = 4, | |
| pause_id: int = 5, | |
| ) -> str: | |
| """Decode the model output to punctuation-annotated text. | |
| Args: | |
| logits: (1, 64, 6) float32 array from model | |
| token_ids: list of original (unpadded) token IDs | |
| id2token: vocab list mapping ID → token string | |
| original_length: length before padding (<= 64) | |
| dot_id, comma_id, quest_id, pause_id: class IDs for punctuation | |
| Returns: | |
| Annotated text string with punctuation inserted | |
| """ | |
| # Take only valid portion | |
| if original_length > logits.shape[1]: | |
| original_length = logits.shape[1] | |
| if original_length > len(token_ids): | |
| original_length = len(token_ids) | |
| logits = logits[0, :original_length, :] | |
| ids = token_ids[:original_length] | |
| # Argmax over classes | |
| out = np.argmax(logits, axis=-1).tolist() | |
| # Segment with sentence-boundary heuristics | |
| # (simplified from original sherpa code) | |
| max_len = 200 | |
| segment_size = 20 | |
| num_segments = (len(ids) + segment_size - 1) // segment_size | |
| punctuations = [] | |
| last = -1 | |
| for i in range(num_segments): | |
| this_start = i * segment_size | |
| this_end = min(this_start + segment_size, len(ids)) | |
| if last != -1: | |
| this_start = last | |
| seg_out = out[this_start:this_end] | |
| dot_index = -1 | |
| comma_index = -1 | |
| for k in range(len(seg_out) - 1, 1, -1): | |
| if seg_out[k] in (dot_id, quest_id): | |
| dot_index = k | |
| break | |
| if comma_index == -1 and seg_out[k] == comma_id: | |
| comma_index = k | |
| if dot_index == -1 and len(ids) >= max_len and comma_index != -1: | |
| dot_index = comma_index | |
| seg_out[dot_index] = dot_id | |
| if dot_index == -1: | |
| if last == -1: | |
| last = this_start | |
| if i == num_segments - 1: | |
| dot_index = len(seg_out) - 1 | |
| else: | |
| last = this_start + dot_index + 1 | |
| if dot_index != -1: | |
| punctuations += seg_out[: dot_index + 1] | |
| # Build output | |
| ans = [] | |
| for j, p in enumerate(punctuations): | |
| if j >= len(ids): | |
| break | |
| t = id2token[ids[j]] if ids[j] < len(id2token) else "<unk>" | |
| # Insert space before ASCII tokens | |
| if ans and len(ans[-1][0].encode()) == 1 and len(t[0].encode()) == 1: | |
| ans.append(" ") | |
| ans.append(t) | |
| if p != IGNORE_ID and p < len(PUNCT_MARKS) and PUNCT_MARKS[p]: | |
| ans.append(PUNCT_MARKS[p]) | |
| return "".join(ans) | |