Spaces:
Running
on
Zero
Running
on
Zero
import os | |
import subprocess | |
subprocess.run(['apt-get', 'update']) | |
subprocess.run(['apt-get', 'install', '-y', 'build-essential', 'gawk', 'libasound2-dev', 'libpulse-dev', 'autoconf', 'automake', 'libtool']) | |
subprocess.run(['wget', 'https://github.com/espeak-ng/espeak-ng/archive/refs/tags/1.52.0.tar.gz']) | |
subprocess.run(['tar', 'xf', '1.52.0.tar.gz']) | |
cwd = 'espeak-ng-1.52.0' | |
subprocess.run(['./autogen.sh'], cwd=cwd) | |
subprocess.run(['./configure'], cwd=cwd) | |
subprocess.run(['make'], cwd=cwd) | |
subprocess.run(['make', 'install'], cwd=cwd) | |
del cwd | |
env = os.environ.copy() | |
env['LD_PRELOAD'] = '/usr/local/lib/libespeak-ng.so.1' | |
subprocess.run(['espeak-ng', '--version'], env=env) | |
from phonemizer.backend.espeak.wrapper import EspeakWrapper | |
EspeakWrapper.set_library('/usr/local/lib/libespeak-ng.so.1') | |
import spaces | |
def greet(n): | |
return f"Hello {zero + n} Tensor" | |
from misaki import en, espeak | |
import gradio as gr | |
import pprint | |
import time | |
fbs = [espeak.EspeakFallback(british=british) for british in (False, True)] | |
g2p = [[en.G2P(trf=trf, british=british, fallback=fbs[british]) for british in (False, True)] for trf in (False, True)] | |
def predict(text, use_spacy_transformer, british): | |
start = time.time() | |
ps, tokens = g2p[use_spacy_transformer][british](text) | |
debug = [] | |
for word in tokens: | |
if isinstance(word, list): | |
debug.append([]) | |
for t in word: | |
debug[-1].append(t.debug_all()) | |
else: | |
debug.append(word.debug_all()) | |
trace = pprint.pformat(debug) | |
elapsed_cpu_time = time.time() - start | |
return ps, len(ps), trace, elapsed_cpu_time | |
with gr.Blocks() as app: | |
gr.Markdown(''' | |
Misaki is an experimental G2P engine designed to power future versions of Kokoro models. | |
This English-only preview is primarily intended for researchers and linguists. It may be deeply uninteresting to most people. | |
''', container=True) | |
gr.Interface(fn=predict, inputs=[gr.Text(), gr.Checkbox(), gr.Checkbox()], | |
outputs=[gr.Text(label='phonemes'), gr.Number(label='token_count <= 510 fits in Kokoro context length'), gr.Text(label='trace'), gr.Number(label='elapsed_cpu_time')]) | |
gr.Markdown(''' | |
### Examples | |
```md | |
American: [Misaki](/misˈɑki/) is an experimental G2P engine designed to power future versions of [Kokoro](/kˈOkəɹO/) models. | |
British: [Misaki](/misˈɑːki/) is an experimental G2P engine designed to power future versions of [Kokoro](/kˈQkəɹQ/) models. | |
But I am the Chosen One. But I [am](+1) the Chosen [One](-1). But I [am](+2) the Chosen [One](-2). | |
1002. [1002](#a#). [1002](#an#). [1002](#a&#). 2025. 2,025. $45.67 billion trillion. | |
``` | |
''', container=True) | |
gr.Markdown(''' | |
### Token-Level Trace | |
```py | |
# 1. Text. Can be useful for aligning text to phonemes, e.g. highlighting text during audio playback. | |
# 2. Tag. See a full list of tags from spaCy: | |
# https://github.com/explosion/spaCy/blob/master/spacy/glossary.py | |
# 3. Whitespace. Whether or not a token has trailing whitespace (string => bool for this demo). | |
whitespace = True if whitespace else False | |
# 4. Phonemes. For this demo, the question mark means UNK, the ninja emoji means empty string. | |
phonemes = '❓' if phonemes is None else ('🥷' if phonemes == '' else phonemes) | |
# 5. Rating. Star rating for the estimated quality of this token's phonemes. | |
ratings = dict( | |
user_override = '💎(5/5)', | |
gold = '🏆(4/5)', | |
silver = '🥈(3/5)', | |
bronze = '🥉(2/5)', | |
unk = '❓(UNK)', | |
) | |
``` | |
''', container=True) | |
gr.Markdown(''' | |
### Notes | |
- For English, Misaki uses a gold dictionary with 80k words and a similarly sized silver dictionary. | |
- There are separate dictionaries for American & British English. | |
- Users can override the dictionary and/or individual tokens with custom pronunciations. | |
- `espeak-ng` is used as the fallback for OOD words, and the token is rated "bronze" in this case. | |
- Raw token objects are returned, with phonemes aligned at the per-token level. | |
- UNKs are easy to detect when `token.phonemes is None`. | |
- The entire implementation of Misaki (English) is <1000 lines of Python, excluding dictionary files. | |
- POS disambiguation should be live, e.g. to wound someone vs wound up. | |
- use_spacy_transformer should deliver more reliable POS tags. | |
- Non-POS-based disambiguation, like graph axes vs throwing axes, is still a TODO. | |
''', container=True) | |
with gr.Blocks() as info: | |
gr.Markdown(''' | |
# Misaki English Phonemes | |
For English, Misaki currently uses 49 total phonemes. Of these, 41 are shared by both Americans and Brits, 4 are American-only, and 4 are British-only. | |
Disclaimer: Author is an ML researcher, not a linguist, and may have butchered or reappropriated the traditional meaning of some symbols. These symbols are intended as input tokens for neural networks to yield optimal performance. | |
### 🤝 Shared (41) | |
**Stress Marks (2)** | |
- `ˈ`: Primary stress, visually looks similar to an apostrophe. | |
- `ˌ`: Secondary stress. | |
**IPA Consonants (22)** | |
- `bdfhjklmnpstvwz`: 15 alpha consonants taken from IPA. They mostly sound as you'd expect, but `j` actually represents the "y" sound, like `yes => jˈɛs`. | |
- `ɡ`: Hard "g" sound, like `get => ɡɛt`. Visually looks like the lowercase letter g, but its actually `U+0261`. | |
- `ŋ`: The "ng" sound, like `sung => sˈʌŋ`. | |
- `ɹ`: Upside-down r is just an "r" sound, like `red => ɹˈɛd`. | |
- `ʃ`: The "sh" sound, like `shin => ʃˈɪn`. | |
- `ʒ`: The "zh" sound, like `Asia => ˈAʒə`. | |
- `ð`: Soft "th" sound, like `than => ðən`. | |
- `θ`: Hard "th" sound, like `thin => θˈɪn`. | |
**Consonant Clusters (2)** | |
- `ʤ`: A "j" or "dg" sound, merges `dʒ`, like `jump => ʤˈʌmp` or `lunge => lˈʌnʤ`. | |
- `ʧ`: The "ch" sound, merges `tʃ`, like `chump => ʧˈʌmp` or `lunch => lˈʌnʧ`. | |
**IPA Vowels (10)** | |
- `ə`: The schwa is a common, unstressed vowel sound, like `a 🍌 => ə 🍌`. | |
- `i`: As in `easy => ˈizi`. | |
- `u`: As in `flu => flˈu`. | |
- `ɑ`: As in `spa => spˈɑ`. | |
- `ɔ`: As in `all => ˈɔl`. | |
- `ɛ`: As in `hair => hˈɛɹ` or `bed => bˈɛd`. Possibly dubious, because those vowel sounds do not sound similar to my ear. | |
- `ɜ`: As in `her => hɜɹ`. Easy to confuse with `ɛ` above. | |
- `ɪ`: As in `brick => bɹˈɪk`. | |
- `ʊ`: As in `wood => wˈʊd`. | |
- `ʌ`: As in `sun => sˈʌn`. | |
**Dipthong Vowels (4)** | |
- `A`: The "eh" vowel sound, like `hey => hˈA`. Expands to `eɪ` in IPA. | |
- `I`: The "eye" vowel sound, like `high => hˈI`. Expands to `aɪ` in IPA. | |
- `W`: The "ow" vowel sound, like `how => hˌW`. Expands to `aʊ` in IPA. | |
- `Y`: The "oy" vowel sound, like `soy => sˈY`. Expands to `ɔɪ` in IPA. | |
**Custom Vowel (1)** | |
- `ᵊ`: Small schwa, muted version of `ə`, like `pixel => pˈɪksᵊl`. I made this one up, so I'm not entirely sure if it's correct. | |
### 🇺🇸 American-only (4) | |
**Vowels (3)** | |
- `æ`: The vowel sound at the start of `ash => ˈæʃ`. | |
- `O`: Capital letter representing the American "oh" vowel sound. Expands to `oʊ` in IPA. | |
- `ᵻ`: A sound somewhere in between `ə` and `ɪ`, often used in certain -s suffixes like `boxes => bˈɑksᵻz`. | |
**Consonant (1)** | |
- `ɾ`: A sound somewhere in between `t` and `d`, like `butter => bˈʌɾəɹ`. | |
### 🇬🇧 British-only (4) | |
**Vowels (3)** | |
- `a`: The vowel sound at the start of `ash => ˈaʃ`. | |
- `Q`: Capital letter representing the British "oh" vowel sound. Expands to `əʊ` in IPA. | |
- `ɒ`: The sound at the start of `on => ˌɒn`. Easy to confuse with `ɑ`, which is a shared phoneme. | |
**Other (1)** | |
- `ː`: Vowel extender, visually looks similar to a colon. Possibly dubious, because Americans extend vowels too, but the gold US dictionary somehow lacks these. Often used by the Brits instead of `ɹ`: Americans say `or => ɔɹ`, but Brits say `or => ɔː`. | |
### ♻️ Misaki to espeak | |
```py | |
def to_espeak(ps): | |
# Optionally, you can add a tie character in between the 2 replacement characters. | |
ps = ps.replace('ʤ', 'dʒ').replace('ʧ', 'tʃ') | |
ps = ps.replace('A', 'eɪ').replace('I', 'aɪ').replace('Y', 'ɔɪ') | |
ps = ps.replace('O', 'oʊ').replace('Q', 'əʊ').replace('W', 'aʊ') | |
return ps.replace('ᵊ', 'ə') | |
``` | |
''') | |
demo = gr.TabbedInterface( | |
[app, info], | |
['🔥 Misaki English', 'ℹ️ Phonemes'], | |
) | |
demo.launch() |