{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from phonemizer import phonemize\n",
    "\n",
    "phonemes = phonemize(text, language='en-us', backend='espeak')\n",
    "print(phonemes)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import nltk\n",
    "nltk.download('averaged_perceptron_tagger_eng')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from g2p_en import G2p\n",
    "g2p = G2p()\n",
    "print(g2p(\"banana\"))\n",
    "\n",
    "text = \"Pronunciation respelling systems for English have been developed primarily for use in dictionaries.\"\n",
    "text = \"\"\"\n",
    "I ain't sayin' that I always sleep alone\n",
    "I ain't sayin' that I ain't met no one else\n",
    "Done a little bit of midnight movin' on\n",
    "And I ain't sayin' when I do that it don't help\n",
    "Leave with someone, I don't know her name\n",
    "Pull her real close, but I leave some space\n",
    "And I could forget you, girl, for good\n",
    "Even though I should\n",
    "\"\"\"\n",
    "\n",
    "symbols = g2p(text)\n",
    "symbols = [symbol.strip(\"0\").strip(\"1\").strip(\"2\") for symbol in symbols]\n",
    "print(symbols)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "import re\n",
    "from g2p_en import G2p\n",
    "\n",
    "# ARPAbet → dictionary-style respelling map\n",
    "ARPABET_TO_RESPELLING = {\n",
    "  \"AA\": \"ah\",     # father\n",
    "  \"AE\": \"a\",      # cat\n",
    "  \"AH\": \"uh\",     # about\n",
    "  \"AO\": \"aw\",     # caught\n",
    "  \"AW\": \"ow\",     # now\n",
    "  \"AY\": \"eye\",    # my\n",
    "  \"B\": \"b\",\n",
    "  \"CH\": \"ch\",\n",
    "  \"D\": \"d\",\n",
    "  \"DH\": \"th\",     # this\n",
    "  \"EH\": \"eh\",     # bed\n",
    "  \"ER\": \"ur\",     # bird\n",
    "  \"EY\": \"ay\",     # say\n",
    "  \"F\": \"f\",\n",
    "  \"G\": \"g\",\n",
    "  \"HH\": \"h\",\n",
    "  \"IH\": \"i\",      # bit\n",
    "  \"IY\": \"ee\",     # seat\n",
    "  \"JH\": \"j\",      # jam\n",
    "  \"K\": \"k\",\n",
    "  \"L\": \"l\",\n",
    "  \"M\": \"m\",\n",
    "  \"N\": \"n\",\n",
    "  \"NG\": \"ng\",\n",
    "  \"OW\": \"oh\",     # go\n",
    "  \"OY\": \"oy\",     # boy\n",
    "  \"P\": \"p\",\n",
    "  \"R\": \"r\",\n",
    "  \"S\": \"s\",\n",
    "  \"SH\": \"sh\",\n",
    "  \"T\": \"t\",\n",
    "  \"TH\": \"th\",     # thin\n",
    "  \"UH\": \"oo\",     # book (best guess for most readers)\n",
    "  \"UW\": \"oo\",     # food\n",
    "  \"V\": \"v\",\n",
    "  \"W\": \"w\",\n",
    "  \"Y\": \"y\",\n",
    "  \"Z\": \"z\",\n",
    "  \"ZH\": \"zh\"      # genre — if confusing, could use \"zher\"\n",
    "}\n",
    "\n",
    "COMMON_MISPRONOUNCED_RESPELLINGS = {\n",
    "  # Foods & Ingredients\n",
    "  \"acai\": \"ahsighee\",\n",
    "  \"quinoa\": \"keenwah\",\n",
    "  \"gnocchi\": \"nyokee\",\n",
    "  \"bruschetta\": \"broosketta\",\n",
    "  \"jalapeno\": \"halapainyo\",\n",
    "  \"croissant\": \"cwahsahnt\",\n",
    "  \"tortilla\": \"torteeya\",\n",
    "  \"hors d'oeuvre\": \"orderv\",\n",
    "  \"pho\": \"fuh\",\n",
    "  \"gyro\": \"yeeroh\",\n",
    "  \"paella\": \"pah-ehya\",  # consider \"pahaya\"\n",
    "\n",
    "  # Foreign loanwords (general)\n",
    "  \"rendezvous\": \"rahndayvoo\",\n",
    "  \"faux\": \"foe\",\n",
    "  \"bourgeois\": \"boorzhwah\",\n",
    "  \"genre\": \"zhahnruh\",\n",
    "  \"liaison\": \"leeayzon\",\n",
    "  \"debacle\": \"daybahkul\",\n",
    "  \"ennui\": \"onwee\",\n",
    "  \"niche\": \"neesh\",\n",
    "  \"coup\": \"koo\",\n",
    "  \"déjà vu\": \"dayzhahvoo\",\n",
    "  \"au revoir\": \"oh ruhvwah\",\n",
    "  \"carte blanche\": \"cart blawnsh\",\n",
    "  \"fiancé\": \"feeahnsay\",\n",
    "  \"résumé\": \"rezuhmay\",\n",
    "\n",
    "  # Place names\n",
    "  \"worcestershire\": \"wustersheer\",\n",
    "  \"gloucester\": \"gloster\",\n",
    "  \"leicester\": \"lester\",\n",
    "  \"edinburgh\": \"edinburrah\",\n",
    "  \"new orleans\": \"nawlins\",\n",
    "  \"thames\": \"tems\",\n",
    "  \"cairo\": \"kairo\",\n",
    "  \"dover\": \"dohver\",\n",
    "  \"reykjavik\": \"raykyaveek\",\n",
    "  \"melbourne\": \"melbun\",\n",
    "\n",
    "  # People & brands\n",
    "  \"nike\": \"nikey\",\n",
    "  \"adidas\": \"ahdeedas\",\n",
    "  \"colonel\": \"kernel\",\n",
    "  \"hermes\": \"airmez\",\n",
    "  \"versace\": \"versahchee\",\n",
    "  \"mozart\": \"mohzart\",\n",
    "  \"goethe\": \"gurtuh\",\n",
    "  \"chloe\": \"kloh-ee\",\n",
    "  \"saoirse\": \"seer-shuh\",\n",
    "  \"aoife\": \"ee-fuh\",\n",
    "  \"siobhan\": \"shivawn\",\n",
    "  \"rachel\": \"raychel\",\n",
    "\n",
    "  # Silent letters\n",
    "  \"bologna\": \"baloney\",\n",
    "  \"debris\": \"duhbree\",\n",
    "  \"salmon\": \"samon\",\n",
    "  \"solder\": \"sodder\",\n",
    "  \"aisle\": \"ile\",\n",
    "  \"island\": \"iland\",\n",
    "  \"plumber\": \"plummer\",\n",
    "  \"subtle\": \"suttle\",\n",
    "  \"receipt\": \"reseet\",\n",
    "  \"honest\": \"onest\",\n",
    "  \"heir\": \"air\",\n",
    "  \"gnome\": \"nome\",\n",
    "  \"knife\": \"nife\",\n",
    "\n",
    "  # Other weird ones\n",
    "  \"segue\": \"segway\",\n",
    "  \"epitome\": \"uhpituhmee\",\n",
    "  \"victuals\": \"vittles\",\n",
    "  \"cache\": \"cash\",\n",
    "  \"nausea\": \"nawzhuh\",\n",
    "  \"gesture\": \"jeshchur\",\n",
    "  \"nuclear\": \"nookyular\",\n",
    "  \"pecan\": \"puhkahn\",  # regional variant\n",
    "  \"affluent\": \"aflooent\",\n",
    "  \"et cetera\": \"etseteruh\",\n",
    "  \"often\": \"offen\",  # silent 't' variant\n",
    "  \"almond\": \"ahmuhnd\",  # regional\n",
    "  \"clothes\": \"cloze\",\n",
    "  \"wolf\": \"woof\",\n",
    "  \"jewelry\": \"joolree\",\n",
    "  \"Wednesday\": \"wensday\",\n",
    "  \"February\": \"febyuary\",\n",
    "  \"library\": \"librerry\",\n",
    "  \"espresso\": \"espresso\",  # commonly mispronounced \"expresso\"\n",
    "  \"pronunciation\": \"pruhnunseeayshun\",\n",
    "\n",
    "  # mroe \n",
    "  \"anemone\": \"uhnemonee\",\n",
    "  \"asterisk\": \"asterisk\",  # often mispronounced as \"asterix\"\n",
    "  \"balloon\": \"baloon\",\n",
    "  \"banal\": \"buhnahl\",  # or \"baynul\", varies\n",
    "  \"baroque\": \"buhroke\",\n",
    "  \"beignet\": \"benyay\",\n",
    "  \"biopic\": \"biopic\",  # often misread as \"bio-pick\", but \"bye-oh-pick\"\n",
    "  \"celtic\": \"keltic\",  # for sports teams\n",
    "  \"chassis\": \"chassee\",\n",
    "  \"chiaroscuro\": \"keeahroskuro\",\n",
    "  \"coup de grâce\": \"koo duh grahss\",\n",
    "  \"dais\": \"dayis\",\n",
    "  \"demesne\": \"demeen\",\n",
    "  \"duodenum\": \"dooahdeenum\",  # varies\n",
    "  \"echelon\": \"eshuhlon\",\n",
    "  \"eider\": \"ider\",\n",
    "  \"ensign\": \"ensun\",\n",
    "  \"eschew\": \"eshchoo\",\n",
    "  \"facetious\": \"fuhsee shus\",\n",
    "  \"forte\": \"fortay\",  # debated but common usage\n",
    "  \"gaffe\": \"gaf\",\n",
    "  \"gif\": \"jif\",  # controversial but relevant\n",
    "  \"grotesque\": \"grotessk\",\n",
    "  \"guillotine\": \"geeuhteen\",\n",
    "  \"halcyon\": \"halseeun\",\n",
    "  \"harass\": \"huh rass\",\n",
    "  \"hegemony\": \"hehjuhmonee\",\n",
    "  \"hirsute\": \"hersoot\",\n",
    "  \"hyperbole\": \"hyperbuhlee\",\n",
    "  \"indict\": \"indite\",\n",
    "  \"inquiry\": \"inquiree\",\n",
    "  \"leisure\": \"leezhur\",\n",
    "  \"lingerie\": \"lahnzhuray\",\n",
    "  \"macabre\": \"muhkahbruh\",\n",
    "  \"mauve\": \"moav\",\n",
    "  \"melee\": \"maylay\",\n",
    "  \"minutiae\": \"minoosheeay\",\n",
    "  \"mischief\": \"misschif\",\n",
    "  \"moi\": \"mwah\",\n",
    "  \"nauseous\": \"nawshus\",\n",
    "  \"neither\": \"nee ther\",\n",
    "  \"omen\": \"ohmen\",\n",
    "  \"onomatopoeia\": \"onuhmatuhpeeuh\",\n",
    "  \"paradigm\": \"paradime\",\n",
    "  \"phlegm\": \"flem\",\n",
    "  \"precocious\": \"pruhcoshus\",\n",
    "  \"prescient\": \"preshunt\",\n",
    "  \"prologue\": \"prolawg\",\n",
    "  \"pseudonym\": \"soodunim\",\n",
    "  \"ptarmigan\": \"tarmigan\",\n",
    "  \"queue\": \"kyoo\",\n",
    "  \"rapport\": \"rapor\",\n",
    "  \"reconnaissance\": \"rekonuhsuns\",\n",
    "  \"reprise\": \"reprize\",\n",
    "  \"reveille\": \"revuhlee\",\n",
    "  \"rhetoric\": \"retuhric\",\n",
    "  \"risqué\": \"riskay\",\n",
    "  \"rout\": \"rowt\",\n",
    "  \"sacrosanct\": \"sackrosankt\",\n",
    "  \"sangfroid\": \"sangfwah\",\n",
    "  \"schematic\": \"skeematic\",\n",
    "  \"schism\": \"sizm\",\n",
    "  \"sergeant\": \"sarjunt\",\n",
    "  \"sinew\": \"sinyoo\",\n",
    "  \"soiree\": \"swahray\",\n",
    "  \"sovereign\": \"sovrun\",\n",
    "  \"subtlety\": \"suttultee\",\n",
    "  \"syrup\": \"sirup\",\n",
    "  \"taut\": \"tawt\",\n",
    "  \"timbre\": \"tambr\",\n",
    "  \"tome\": \"tohm\",\n",
    "  \"treatise\": \"tretis\",\n",
    "  \"viscous\": \"viskus\",\n",
    "  \"vogue\": \"vohg\",\n",
    "  \"yacht\": \"yot\",\n",
    "  \"zealot\": \"zellut\"\n",
    "}\n",
    "\n",
    "\n",
    "g2p = G2p()\n",
    "\n",
    "\n",
    "#def strip_stress(phoneme):\n",
    "#    return re.sub(r'\\d', '', phoneme)\n",
    "\n",
    "def strip_stress(phoneme):\n",
    "    return phoneme.strip(\"0\").strip(\"1\").strip(\"2\")\n",
    "\n",
    "def phonemes_to_respelling(phonemes):\n",
    "    #stripped = [strip_stress(p) for p in phonemes if p.isalpha()]\n",
    "    #print(stripped)\n",
    "    stripped = [strip_stress(p) for p in phonemes]\n",
    "    return ''.join(ARPABET_TO_RESPELLING.get(p, '') for p in stripped)\n",
    "\n",
    "def respell_random_words_in_text(text, N=3):\n",
    "    text = text.replace(\"'\", \"\")\n",
    "    # Tokenize words and punctuation separately\n",
    "    words = re.findall(r'\\b\\w+\\b|\\W+', text)\n",
    "    word_indices = [i for i, w in enumerate(words) if re.match(r'\\b\\w+\\b', w)]\n",
    "    selected_indices = random.sample(word_indices, min(N, len(word_indices)))\n",
    "\n",
    "    for i in selected_indices:\n",
    "        word = words[i]\n",
    "        # Check if the word is in our common mispronounced words dictionary\n",
    "        if word.lower() in COMMON_MISPRONOUNCED_RESPELLINGS:\n",
    "            respelling = COMMON_MISPRONOUNCED_RESPELLINGS[word.lower()]\n",
    "            print(f\"{word} (from dictionary): {respelling}\")\n",
    "        else:\n",
    "            # If not in dictionary, use phoneme-based respelling\n",
    "            phonemes = g2p(word)\n",
    "            respelling = phonemes_to_respelling(phonemes)\n",
    "            print(word, phonemes, respelling)\n",
    "        \n",
    "        if respelling:\n",
    "            words[i] = respelling\n",
    "\n",
    "    return ''.join(words)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "text = \"\"\"\n",
    "colonel quinoa gnocchi Worcestershire mischievous niche rendezvous salmon affluent debris cache epitome segue bologna victuals acai chai solder pecan schedule\n",
    "\"\"\"\n",
    "\n",
    "text = \"\"\"\n",
    "I never let my heart go all the way\n",
    "Every time I try, I just hit the brakes\n",
    "And there's always a couple tryna take your place\n",
    "But I never fall in love, baby, just in case\n",
    "You wake up wantin' me out of the blue\n",
    "You lay down needin' what I used to do\n",
    "Yeah, every now and then, I go get a taste\n",
    "But I never fall in love, baby, just in case\n",
    "Just in case\n",
    "\"\"\"\n",
    "\n",
    "respelled_text = respell_random_words_in_text(text, N=10)\n",
    "print(respelled_text)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# lets' write a function that takes a full text string\n",
    "# we will then split this into words (by spaces and newlines)\n",
    "# then we will apply g2p to a subset of random words (N)\n",
    "# then we will map the symbols to the respellings \n",
    "# then we will re-insert them into the text at the same positions\n",
    "# we will then return the full respelled text\n",
    "\n",
    "def respell_text(text, N=10):\n",
    "    words = text.split(\" \")\n",
    "    random_words = random.sample(words, N)\n",
    "    random_words = [word for word in random_words if word != \"\"]\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string_respell = \"\"\n",
    "for symbol in symbols:\n",
    "    if symbol in rapabet_to_respell:\n",
    "        string_respell += rapabet_to_respell[symbol]\n",
    "    else:\n",
    "        string_respell += symbol\n",
    "print(string_respell)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "\n",
    "ipa_to_respell = json.load(open(\"/home/christian/code/christian/metadata/phonemes/ipa_mappings_extended.json\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "ipa_to_wikipedia = {\n",
    "    \"tʃ\": \"ch\",\n",
    "    \"ɡ\": \"gh\",\n",
    "    \"h\": \"h\",\n",
    "    \"hw\": \"wh\",\n",
    "    \"dʒ\": \"j\",\n",
    "    \"k\": \"k\",\n",
    "    \"x\": \"kh\",\n",
    "    \"ŋ\": \"ng\",\n",
    "    \"s\": \"s\",\n",
    "    \"ʃ\": \"sh\",\n",
    "    \"θ\": \"th\",\n",
    "    \"ð\": \"dh\",\n",
    "    \"j\": \"y\",\n",
    "    \"ʒ\": \"zh\",\n",
    "    \"æ\": \"a\",\n",
    "    \"eɪ\": \"ay\",\n",
    "    \"ɛər\": \"air\",\n",
    "    \"ɑː\": \"ah\",\n",
    "    \"ɑːr\": \"ar\",\n",
    "    \"ɛ\t\": \"e\",\n",
    "    \"iː\t\": \"ee\",\n",
    "    \"ɪər\": \"eer\",\n",
    "    \"ɪ\": \"i\",\n",
    "    \"aɪ\": \"y\",\n",
    "    \"ɒ\": \"o\",\n",
    "    \"oʊ\": \"oh\",\n",
    "    \"ɔː\": \"aw\",\n",
    "    \"ɔːr\": \"or\",\n",
    "    \"ɔɪ\": \"oy\",\n",
    "    \"ʊ\": \"uu\",\n",
    "    \"ʊər\": \"oor\",\n",
    "    \"uː\": \"oo\",\n",
    "    \"aʊ\t\" : \"ow\",\n",
    "    \"ʌ\" : \"u\",\n",
    "    \"ɜːr\" : \"ur\",\n",
    "    \"ə\" : \"ə\",\n",
    "    \"ər\" : \"ər\",\n",
    "    \"juː\" : \"ew\",\n",
    "}\n",
    "\n",
    "rapabet_to_respell = {\n",
    "  \"AA\": \"ah\",\n",
    "  \"AE\": \"a\",\n",
    "  \"AH\": \"uh\",\n",
    "  \"AO\": \"aw\",\n",
    "  \"AW\": \"ow\",\n",
    "  \"AY\": \"eye\",\n",
    "  \"B\": \"b\",\n",
    "  \"CH\": \"ch\",\n",
    "  \"D\": \"d\",\n",
    "  \"DH\": \"th\",\n",
    "  \"EH\": \"eh\",\n",
    "  \"ER\": \"er\",\n",
    "  \"EY\": \"ay\",\n",
    "  \"F\": \"f\",\n",
    "  \"G\": \"g\",\n",
    "  \"HH\": \"h\",\n",
    "  \"IH\": \"ih\",\n",
    "  \"IY\": \"ee\",\n",
    "  \"JH\": \"j\",\n",
    "  \"K\": \"k\",\n",
    "  \"L\": \"l\",\n",
    "  \"M\": \"m\",\n",
    "  \"N\": \"n\",\n",
    "  \"NG\": \"ng\",\n",
    "  \"OW\": \"oh\",\n",
    "  \"OY\": \"oy\",\n",
    "  \"P\": \"p\",\n",
    "  \"R\": \"r\",\n",
    "  \"S\": \"s\",\n",
    "  \"SH\": \"sh\",\n",
    "  \"T\": \"t\",\n",
    "  \"TH\": \"th\",\n",
    "  \"UH\": \"oo\",\n",
    "  \"UW\": \"oo\",\n",
    "  \"V\": \"v\",\n",
    "  \"W\": \"w\",\n",
    "  \"Y\": \"y\",\n",
    "  \"Z\": \"z\",\n",
    "  \"ZH\": \"zh\"\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# convert phonemes to respell\n",
    "respell = \"\"\n",
    "for char, phoneme in zip(text, phonemes):\n",
    "    if phoneme in ipa_to_wikipedia:\n",
    "        respell += ipa_to_wikipedia[phoneme]\n",
    "    else:\n",
    "        respell += char\n",
    "\n",
    "# join to a string\n",
    "string_respell = \"\".join(respell)\n",
    "print(string_respell)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for phoneme in phonemes:\n",
    "    print(phoneme)\n",
    "    # check if phoneme is in ipa_to_respell\n",
    "    if phoneme in ipa_to_wikipedia:\n",
    "        print(ipa_to_wikipedia[phoneme])\n",
    "    else:\n",
    "        print(\"not found\")\n",
    "    print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "suno_env",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
