dyslexic-engine / phonemes.py
Wayfinder6's picture
Upload folder using huggingface_hub
e96bf82 verified
Raw
History Blame Contribute Delete
7.36 kB
"""
The 44 Phonemes of English — mapped to simple readable pronunciations.
Source: DSF Literacy Resources / Dyslexia Reading Well
Each entry maps spelling patterns to their simple phonetic output.
We use everyday letter combinations that anyone can read — NOT IPA.
The IPA versions are only used in Version 4 (the punchline).
This is the core engine. The LLM enhances it. This never fails.
"""
# Consonant sounds → simple readable spelling
# Format: { "spelling_pattern": "simple_sound" }
# Ordered longest-first so we match digraphs before single letters
CONSONANT_SPELLINGS = {
# Digraphs and multi-letter first
"tch": "ch",
"dge": "j",
"ght": "t",
"ck": "k",
"ph": "f",
"gh": "f", # as in laugh (context-dependent, but common)
"gn": "n", # as in gnat
"kn": "n", # as in knight
"pn": "n", # as in pneumonia
"ps": "s", # as in psychology
"wr": "r", # as in wrong
"rh": "r", # as in rhyme
"mb": "m", # as in climb (final)
"mn": "m", # as in autumn
"lm": "m", # as in palm
"ng": "ng",
"nk": "nk",
"qu": "kw",
"sh": "sh",
"ch": "ch",
"th": "th",
"wh": "w",
"bb": "b",
"dd": "d",
"ff": "f",
"gg": "g",
"ll": "l",
"mm": "m",
"nn": "n",
"pp": "p",
"rr": "r",
"ss": "s",
"tt": "t",
"zz": "z",
# Singles
"b": "b",
"c": "k", # default, overridden by soft c rule
"d": "d",
"f": "f",
"g": "g", # default, overridden by soft g rule
"h": "h",
"j": "j",
"k": "k",
"l": "l",
"m": "m",
"n": "n",
"p": "p",
"r": "r",
"s": "s",
"t": "t",
"v": "v",
"w": "w",
"x": "ks",
"y": "y",
"z": "z",
}
# Vowel sounds — short vowels
# These are the basic sounds, mapped from common spellings
SHORT_VOWELS = {
"a": "a", # cat
"e": "e", # egg
"i": "i", # igloo
"o": "o", # orange
"u": "u", # mug
}
# Long vowels — common spelling patterns → simple pronunciation
LONG_VOWEL_PATTERNS = {
# Long A (say, cake, rain)
"ai": "ay",
"ay": "ay",
"a_e": "ay", # magic e pattern
"eigh": "ay",
"ey": "ay",
"ei": "ay",
# Long E (bee, meat, key)
"ee": "ee",
"ea": "ee",
"ie": "ee", # as in brief
"ey": "ee",
"ei": "ee",
# Long I (kite, fly, night)
"igh": "eye",
"ie": "eye", # as in pie
"i_e": "eye", # magic e
"y": "eye", # as in fly (end of word)
"uy": "eye",
# Long O (boat, bone, low)
"oa": "oh",
"o_e": "oh", # magic e
"ow": "oh", # as in low
"oe": "oh",
"ough": "oh", # as in though
# Long U (moon, blue, screw)
"oo": "oo",
"ew": "oo",
"ue": "oo",
"u_e": "oo", # magic e
"ough": "oo", # as in through
}
# R-controlled vowels
R_CONTROLLED = {
"air": "air",
"are": "air",
"ear": "eer", # as in ear (but also "air" as in pear — context)
"eer": "eer",
"ere": "eer",
"ar": "ar",
"or": "or",
"ore": "or",
"oor": "or",
"oar": "or",
"our": "or",
"ir": "er",
"er": "er",
"ur": "er",
}
# Schwa — the lazy vowel, most common sound in English
# Almost any vowel letter can make the schwa in unstressed syllables
SCHWA_NOTE = "uh" # the 'uh' sound in 'about', 'taken', 'pencil'
# Diphthongs
DIPHTHONGS = {
"oi": "oy",
"oy": "oy",
"ow": "ow", # as in cow
"ou": "ow", # as in shout
}
# ---- The full simple pronunciation map ----
# This maps the most common English spelling patterns to
# how they actually SOUND using everyday letters.
# Ordered longest pattern first for greedy matching.
PRONUNCIATION_MAP = [
# Multi-letter patterns (check these first)
("tion", "shun"),
("sion", "zhun"),
("ture", "cher"),
("sure", "zher"),
("ous", "us"),
("ight", "yte"),
("ough", "oh"),
("ough", "uff"),
("augh", "awf"),
("ould", "ood"),
("ough", "oo"),
("eigh", "ay"),
("tch", "ch"),
("dge", "j"),
("kn", "n"),
("wr", "r"),
("gn", "n"),
("ph", "f"),
("gh", ""), # often silent: through, night
("ck", "k"),
("ng", "ng"),
("nk", "nk"),
("qu", "kw"),
("sh", "sh"),
("ch", "ch"),
("th", "th"),
("wh", "w"),
("oo", "oo"),
("ee", "ee"),
("ea", "ee"),
("ai", "ay"),
("ay", "ay"),
("oa", "oh"),
("ow", "oh"),
("oi", "oy"),
("oy", "oy"),
("ou", "ow"),
("ew", "oo"),
("ue", "oo"),
("ie", "ee"),
("ar", "ar"),
("or", "or"),
("er", "er"),
("ir", "er"),
("ur", "er"),
]
# IPA equivalents — for Version 4 (the unreadable punchline)
IPA_MAP = [
("tion", "\u0283\u0259n"),
("sion", "\u0292\u0259n"),
("ture", "t\u0283\u0259\u0279"),
("ight", "a\u026At"),
("ough", "\u0254\u02D0"),
("eigh", "e\u026A"),
("tch", "t\u0283"),
("dge", "d\u0292"),
("kn", "n"),
("wr", "\u0279"),
("gn", "n"),
("ph", "f"),
("gh", ""),
("ck", "k"),
("ng", "\u014B"),
("nk", "\u014Bk"),
("qu", "kw"),
("sh", "\u0283"),
("ch", "t\u0283"),
("th", "\u03B8"),
("wh", "w"),
("oo", "u\u02D0"),
("ee", "i\u02D0"),
("ea", "i\u02D0"),
("ai", "e\u026A"),
("ay", "e\u026A"),
("oa", "\u0259\u028A"),
("ow", "\u0259\u028A"),
("oi", "\u0254\u026A"),
("oy", "\u0254\u026A"),
("ou", "a\u028A"),
("ew", "ju\u02D0"),
("ue", "u\u02D0"),
("ie", "i\u02D0"),
("ar", "\u0251\u02D0\u0279"),
("or", "\u0254\u02D0\u0279"),
("er", "\u025C\u02D0\u0279"),
("ir", "\u025C\u02D0\u0279"),
("ur", "\u025C\u02D0\u0279"),
("a", "\u00E6"),
("e", "\u025B"),
("i", "\u026A"),
("o", "\u0252"),
("u", "\u028C"),
("b", "b"),
("c", "k"),
("d", "d"),
("f", "f"),
("g", "\u0261"),
("h", "h"),
("j", "d\u0292"),
("k", "k"),
("l", "l"),
("m", "m"),
("n", "n"),
("p", "p"),
("r", "\u0279"),
("s", "s"),
("t", "t"),
("v", "v"),
("w", "w"),
("x", "ks"),
("y", "j"),
("z", "z"),
]
def word_to_ipa(word):
"""Convert a word to IPA-like transcription (deliberately unreadable)."""
result = ""
w = word.lower()
i = 0
while i < len(w):
matched = False
# Try longest patterns first
for pattern, ipa in IPA_MAP:
plen = len(pattern)
if w[i:i+plen] == pattern:
result += ipa
i += plen
matched = True
break
if not matched:
result += w[i]
i += 1
return result
def text_to_ipa(text):
"""Convert full text to IPA transcription."""
import re
words = text.split()
ipa_words = []
for word in words:
# Preserve punctuation
prefix = ""
suffix = ""
core = word
while core and not core[0].isalnum():
prefix += core[0]
core = core[1:]
while core and not core[-1].isalnum():
suffix = core[-1] + suffix
core = core[:-1]
if core:
ipa_words.append(f"{prefix}{word_to_ipa(core)}{suffix}")
else:
ipa_words.append(word)
return "/\u200B" + " ".join(ipa_words) + "\u200B/"