Automatic Speech Recognition
Transformers
Safetensors
English
asr_model
feature-extraction
asr
speech-recognition
speech-to-text
audio
speech-llm
word-timestamps
speaker-diarization
qwen
granite-speech
custom_code
Instructions to use mazesmazes/tiny-audio with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use mazesmazes/tiny-audio with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("automatic-speech-recognition", model="mazesmazes/tiny-audio", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("mazesmazes/tiny-audio", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 5,091 Bytes
26ce2ed | 1 2 3 4 5 6 7 8 9 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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | """Transcript text cleanup: collapse the repetition loops a decoder can fall into.
A language-model decoder that loses the audio sometimes repeats its last
character, word or phrase until it hits the token limit. These functions trim
such a trailing run back to one copy; ASRPipeline applies them to every output.
`truncate_runaway_loop` also catches a loop that starts mid-transcript and
drifts ("It's It's It it's It's"), so it never forms an exact trailing run.
"""
import re
MIN_REPEATS = 3
LOOSE_MIN_REPEATS = 6
TRAILING_CHAR_RE = re.compile(rf"(.)\1{{{MIN_REPEATS - 1},}}$")
TRAILING_WORD_RE = re.compile(rf"\b(\w+)(?:\s+\1){{{MIN_REPEATS - 1},}}\s*$", re.IGNORECASE)
NON_WORD_RE = re.compile(r"\W+")
# A 1-4 word unit repeated this many times in a row, after which at most this
# share of the words are distinct: the decoder lost the audio and never came
# back. Measured on the Open ASR leaderboard runs of 2026-10-16/17: URGENT
# -0.97 WER (13.12 -> 12.11 on an independent rerun), and no set worse in
# either run. Cutting at every 6x run regardless of what follows cost up to
# +0.05 (Monsoon, GigaSpeech): "No, no, no, no, no, no, no, sir, which..." is
# real speech that recovers.
RUNAWAY_MIN_REPEATS = 6
RUNAWAY_MAX_UNIT = 4
RUNAWAY_MAX_DISTINCT = 0.5
def truncate_repetitions(text: str) -> str:
"""Truncate repeated words/phrases/characters at end of text.
Detects patterns like:
- Repeated words: "the the the the" -> "the"
- Repeated phrases: "i am sorry i am sorry i am sorry" -> "i am sorry"
- Repeated characters: "444444" -> "4"
Words match ignoring case. A run of `LOOSE_MIN_REPEATS` also matches
ignoring punctuation, since the model punctuates inside a loop ("Yeah Yeah
Yeah. Yeah. Yeah,"); shorter punctuated runs are real speech ("No, no,
no,"), and collapsing those cost 40 errors over 47 rows of the served eval.
Args:
text: Input text to process
Returns:
Text with trailing repetitions removed
"""
if not text:
return text
text = truncate_runaway_loop(text)
text = TRAILING_CHAR_RE.sub(r"\1", text)
while TRAILING_WORD_RE.search(text):
text = TRAILING_WORD_RE.sub(r"\1", text)
# 3. Truncate repeated phrases (2-20 words) at end
# e.g., "i am sorry i am sorry i am sorry" -> "i am sorry"
words = text.split()
if len(words) < MIN_REPEATS * 2:
return text
# Cheap pre-check: trailing window must contain duplicates for any phrase repeat
# to be possible. set(window) == window means all unique → no repetition.
window = words[-MIN_REPEATS * 2 :]
if len(set(window)) == len(window):
return truncate_punctuated_loop(text)
for phrase_len in range(2, min(21, len(words) // MIN_REPEATS + 1)):
phrase_escaped = re.escape(" ".join(words[-phrase_len:]))
phrase_pattern = re.compile(
rf"(^|.*?\s)({phrase_escaped})(?:\s+{phrase_escaped}){{{MIN_REPEATS - 1},}}\s*$",
re.IGNORECASE,
)
match = phrase_pattern.match(text)
if match:
text = (match.group(1) + match.group(2)).strip()
break
return truncate_punctuated_loop(text)
def truncate_punctuated_loop(text: str) -> str:
"""Collapse a trailing 1-20 word phrase run `LOOSE_MIN_REPEATS`+ times, punctuation ignored."""
words = text.split()
keys = [NON_WORD_RE.sub("", w).lower() for w in words]
end = len(words)
# Shortest phrase first, so "Yeah Yeah. Yeah," stops at "Yeah".
for n in range(1, min(21, end // LOOSE_MIN_REPEATS + 1)):
phrase = keys[end - n : end]
reps = 1
while end - (reps + 1) * n >= 0 and keys[end - (reps + 1) * n : end - reps * n] == phrase:
reps += 1
if reps >= LOOSE_MIN_REPEATS:
return " ".join(words[: end - (reps - 1) * n])
return text
def truncate_runaway_loop(text: str) -> str:
"""Cut at a loop the decoder never leaves, keeping the first copy of its unit.
Finds the first 1-`RUNAWAY_MAX_UNIT` word unit repeated
`RUNAWAY_MIN_REPEATS`+ times in a row (case and punctuation ignored). It
cuts there only when the rest of the transcript, from that run on, has at
most `RUNAWAY_MAX_DISTINCT` distinct words per word: a loop that drifts
("It's It's It it's It's ...") rather than speech that moves on.
"""
words = text.split()
keys = [NON_WORD_RE.sub("", w).lower() for w in words]
for start in range(len(keys)):
for size in range(1, RUNAWAY_MAX_UNIT + 1):
unit = keys[start : start + size]
if len(unit) < size or not all(unit):
break
reps = 1
while keys[start + reps * size : start + (reps + 1) * size] == unit:
reps += 1
if reps < RUNAWAY_MIN_REPEATS:
continue
rest = keys[start:]
if len(set(rest)) / len(rest) > RUNAWAY_MAX_DISTINCT:
return text # the transcript recovers after the first run
return " ".join(words[: start + size])
return text
|