"""Gradio web UI for IPA Translator.""" from typing import Optional import gradio as gr from core import Phonemlyze, AnalysisResult # ── Lazy singleton ───────────────────────────────────────────────────────────── _engine: Optional[Phonemlyze] = None WHISPER_SIZES = ["tiny", "base", "small", "medium", "large"] LANGUAGES = { "Arabic": "ar", "Czech": "cs", "Dutch": "nl", "English (UK)": "en-gb", "English (US)": "en-us", "French (Canadian)": "fr-ca", "French (Parisian)": "fr", "German": "de", "Greek": "el", "Hindi": "hi", "Hungarian": "hu", "Italian": "it", "Japanese": "ja", "Mandarin (Simplified)": "zh", "Mandarin (Traditional)": "zh-tw", "Portuguese (Brazilian)": "pt-br", "Russian": "ru", "Spanish (Castilian)": "es-es", "Spanish (Latin American)": "es-419", "Thai": "th", "Turkish": "tr", "Ukrainian": "uk", } def get_engine(whisper_size: str) -> Phonemlyze: global _engine if _engine is None: _engine = Phonemlyze(whisper_model=whisper_size) return _engine # ── Colour palette (dark-first) ─────────────────────────────────────────────── # Every custom HTML component uses these so the whole app is consistently dark. _C_BG = "#111827" # page / deepest background _C_CARD = "#1e2535" # card / IPA box background _C_RAISED = "#2d3748" # raised elements (keys, input bg, table header) _C_BORDER = "#4b5563" # borders / dividers _C_TEXT = "#f1f5f9" # primary text _C_TEXT2 = "#cbd5e1" # secondary text _C_MUTED = "#94a3b8" # muted / label text # Alignment status colours – muted dark backgrounds, bright foreground text STATUS_COLORS = { "match": ("#0a3320", "#6ee7b7"), # dark green / mint "replace": ("#4a2000", "#fbbf24"), # dark amber / gold "delete": ("#4a0e0e", "#fca5a5"), # dark red / rose "insert": ("#0e2744", "#93c5fd"), # dark blue / sky } # ── HTML rendering ───────────────────────────────────────────────────────────── STATUS_LABELS = { "match": "✓ match", "replace": "≠ substitution", "delete": "− missing", "insert": "+ extra", } # IPA reference: symbol → {desc, ex (examples), word (spoken on click)} # "ex" uses plain-English spelling hints so non-linguists can map the sound. IPA_REFERENCE = { # ── Stops ──────────────────────────────────────────────────────────────── "p": {"desc": "voiceless stop", "ex": '"p" as in pat, cap, happy', "word": "pat"}, "b": {"desc": "voiced stop", "ex": '"b" as in bat, cab, lab', "word": "bat"}, "t": {"desc": "voiceless stop", "ex": '"t" as in tap, cat, butter', "word": "tap"}, "d": {"desc": "voiced stop", "ex": '"d" as in dog, bed, ladder', "word": "dog"}, "k": {"desc": "voiceless stop", "ex": '"k/c" as in cat, back, kick', "word": "cat"}, "ɡ": {"desc": "voiced stop", "ex": '"g" as in go, bag, tiger', "word": "go"}, "g": {"desc": "voiced stop", "ex": '"g" as in go, bag, tiger', "word": "go"}, "ʔ": {"desc": "glottal stop", "ex": 'the catch in uh-oh, or "t" in Button (UK)',"word": "uh oh"}, # ── Affricates ─────────────────────────────────────────────────────────── "tʃ": {"desc": "voiceless affricate", "ex": '"ch" as in chip, catch, nature', "word": "chip"}, "dʒ": {"desc": "voiced affricate", "ex": '"j/g" as in jam, age, magic', "word": "jam"}, "ts": {"desc": "voiceless affricate", "ex": '"ts" as in cats, bits', "word": "cats"}, "dz": {"desc": "voiced affricate", "ex": '"ds/z" as in beds, adze', "word": "beds"}, # ── Fricatives ─────────────────────────────────────────────────────────── "f": {"desc": "voiceless fricative", "ex": '"f/ph" as in fat, leaf, phone', "word": "fat"}, "v": {"desc": "voiced fricative", "ex": '"v" as in vat, love, over', "word": "vat"}, "θ": {"desc": "voiceless fricative", "ex": '"th" as in thin, bath', "word": "thin"}, "ð": {"desc": "voiced fricative", "ex": '"th" as in the, this, father', "word": "this"}, "s": {"desc": "voiceless fricative", "ex": '"s" as in sit, bus, hiss', "word": "sit"}, "z": {"desc": "voiced fricative", "ex": '"z" as in zoo, buzz, lazy', "word": "zoo"}, "ʃ": {"desc": "voiceless fricative", "ex": '"sh" as in ship, cash, sugar', "word": "ship"}, "ʒ": {"desc": "voiced fricative", "ex": '"s/g" as in measure, vision, beige',"word": "measure"}, "h": {"desc": "voiceless fricative", "ex": '"h" as in hat, ahead, who', "word": "hat"}, "x": {"desc": "voiceless fricative", "ex": '"ch" as in loch (Scottish), Bach', "word": "loch"}, "ç": {"desc": "voiceless fricative", "ex": 'soft "ch" as in ich (German)', "word": "huge"}, # ── Nasals ─────────────────────────────────────────────────────────────── "m": {"desc": "nasal", "ex": '"m" as in mat, ham, summer', "word": "mat"}, "n": {"desc": "nasal", "ex": '"n" as in nap, ban, sunny', "word": "nap"}, "ŋ": {"desc": "nasal", "ex": '"ng" as in sing, ring, singer', "word": "singing"}, "ɲ": {"desc": "palatal nasal", "ex": '"ny/gn" as in canyon, lasagne', "word": "canyon"}, # ── Liquids & Approximants ─────────────────────────────────────────────── "l": {"desc": "lateral", "ex": '"l" as in lip, bell, silly', "word": "lip"}, "r": {"desc": "trill/tap", "ex": 'rolled "r" as in Spanish rosa', "word": "red"}, "ɹ": {"desc": "approximant", "ex": '"r" as in red, car, very (US/UK)', "word": "red"}, "ɾ": {"desc": "flap", "ex": 'quick "d/t" as in butter, ladder (US)', "word": "butter"}, "w": {"desc": "approximant", "ex": '"w" as in wet, twin, away', "word": "wet"}, "j": {"desc": "approximant", "ex": '"y" as in yes, you, beyond', "word": "yes"}, "ʍ": {"desc": "voiceless approximant","ex": 'breathy "wh" as in which (Scottish/Irish)', "word": "which"}, # ── Short / lax vowels ─────────────────────────────────────────────────── "ɪ": {"desc": "short vowel", "ex": '"i" as in sit, ship, big', "word": "sit"}, "ʊ": {"desc": "short vowel", "ex": '"oo" as in put, foot, could', "word": "foot"}, "ɛ": {"desc": "short vowel", "ex": '"e" as in bed, head, said', "word": "bed"}, "æ": {"desc": "short vowel", "ex": '"a" as in cat, bad, hand', "word": "cat"}, "ɒ": {"desc": "short vowel", "ex": '"o" as in pot, dog, not (UK)', "word": "pot"}, "ʌ": {"desc": "short vowel", "ex": '"u" as in cup, luck, blood', "word": "cup"}, "ə": {"desc": "schwa (unstressed)", "ex": 'weak vowel: about, sofa, banana', "word": "about"}, "ɐ": {"desc": "open-mid central", "ex": 'short "a/u" as in cut, about (some accents)',"word": "cut"}, # ── Long vowels ────────────────────────────────────────────────────────── "iː": {"desc": "long vowel", "ex": '"ee" as in see, feet, key', "word": "see"}, "i": {"desc": "close front vowel", "ex": '"ee" as in see, happy, coffee', "word": "see"}, "uː": {"desc": "long vowel", "ex": '"oo" as in too, blue, food', "word": "too"}, "u": {"desc": "close back vowel", "ex": '"oo" as in too, blue, food', "word": "too"}, "ɑː": {"desc": "long vowel", "ex": '"ah" as in car, father, palm', "word": "father"}, "ɑ": {"desc": "open back vowel", "ex": '"ah" as in father, spa', "word": "father"}, "ɔː": {"desc": "long vowel", "ex": '"aw" as in saw, call, thought', "word": "saw"}, "ɔ": {"desc": "open-mid back vowel", "ex": '"aw/o" as in saw, law', "word": "saw"}, "ɜː": {"desc": "long vowel", "ex": '"ur" as in bird, word, turn', "word": "bird"}, "ɜ": {"desc": "open-mid central", "ex": '"ur" as in bird, word', "word": "bird"}, "aː": {"desc": "long open vowel", "ex": '"ah" as in car, father', "word": "car"}, "a": {"desc": "open front vowel", "ex": '"a" as in father, spa', "word": "father"}, "e": {"desc": "mid front vowel", "ex": '"ay/e" as in day, face, they', "word": "day"}, "o": {"desc": "mid back vowel", "ex": '"oh" as in go, home, note', "word": "go"}, "ø": {"desc": "front rounded vowel", "ex": '"eu" as in feu (French), schön (German)', "word": "fur"}, "y": {"desc": "close front rounded", "ex": '"ü" as in lune (French), über (German)', "word": "few"}, "ʉ": {"desc": "close central vowel", "ex": 'between "ee" and "oo", e.g. goose (Australian)', "word": "goose"}, # ── R-coloured vowels ──────────────────────────────────────────────────── "ɚ": {"desc": "r-coloured schwa", "ex": '"er" as in butter, better (US)', "word": "butter"}, "ɝ": {"desc": "r-coloured vowel", "ex": '"ur" as in bird, word (US)', "word": "bird"}, "ɻ": {"desc": "retroflex approximant","ex": '"r" sound made with tongue curled back (some US)', "word": "red"}, # ── Diphthongs ─────────────────────────────────────────────────────────── "eɪ": {"desc": "diphthong", "ex": '"ay" as in day, face, take', "word": "day"}, "aɪ": {"desc": "diphthong", "ex": '"i" as in fly, time, high', "word": "fly"}, "ɔɪ": {"desc": "diphthong", "ex": '"oy" as in boy, toy, coin', "word": "boy"}, "aʊ": {"desc": "diphthong", "ex": '"ow" as in now, out, mouse', "word": "now"}, "oʊ": {"desc": "diphthong", "ex": '"oh" as in go, home, know', "word": "go"}, "əʊ": {"desc": "diphthong", "ex": '"oh" as in go, home, know (UK)', "word": "go"}, "ɪə": {"desc": "diphthong", "ex": '"ear" as in ear, here, near', "word": "ear"}, "ʊə": {"desc": "diphthong", "ex": '"oor" as in tour, poor (UK)', "word": "tour"}, "eə": {"desc": "diphthong", "ex": '"air" as in hair, care, there (UK)',"word": "hair"}, } # Pure-CSS tooltip + inline onclick (no