summaryrefslogtreecommitdiff
path: root/src/lib/db/thaiseed.ts
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-06-02 23:05:36 +0700
committerpolwex <polwex@sortug.com>2025-06-02 23:05:36 +0700
commit904b34de8f7748b7954d88784369b9cae6fa92fb (patch)
tree53bb5cb3377ae40d8bfa44087a0c712edd6c9d02 /src/lib/db/thaiseed.ts
parenta03c92dc82ad527d7da6bbaa3c43000e2e5f0e69 (diff)
all me here should merge
Diffstat (limited to 'src/lib/db/thaiseed.ts')
-rw-r--r--src/lib/db/thaiseed.ts184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/lib/db/thaiseed.ts b/src/lib/db/thaiseed.ts
new file mode 100644
index 0000000..687f0f3
--- /dev/null
+++ b/src/lib/db/thaiseed.ts
@@ -0,0 +1,184 @@
+import Database from "bun:sqlite";
+import {
+ analyzeTHWord,
+ deconstructSyllable,
+ segmentateThai,
+ type SorSyl,
+ type ThaiNLPRes,
+ sorSyl,
+ getThaiFreq,
+} from "../calls/nlp";
+import pdb from "./prosodydb";
+import { cleanIpa } from "../utils";
+import { handleFile } from "./utils";
+import { Tone } from "../types/phonetics";
+
+async function readDump(lang: string) {
+ await pdb.init();
+ pdb.addLanguage("th", "thai");
+ let count = 0;
+ const langdb = new Database(
+ `/home/y/code/prosody/resources/wiktionary/${lang}.db`,
+ );
+ let langrows: any = langdb.query("SELECT data FROM langs");
+ // langrows = langrows.slice(10);
+ for (const langrow of langrows) {
+ count++;
+ console.log(count);
+ // if (count <= 10000) continue;
+ // if (count > 30) break;
+ const j = JSON.parse(langrow.data);
+ const word = j.word.trim();
+ if (!word) continue;
+ if (word.includes("ๆ")) await handleWord(word, j);
+ else {
+ const split = word.split(" ");
+ if (split.length > 1) await handleIdiom(word);
+ else await handleWord(word, j);
+ }
+ }
+}
+
+async function handleWord(word: string, j: any) {
+ // TODO add categories but add a tag to see what classifying scheme we're using
+ //
+ const sounds = j.sounds || [];
+ const hasIpa = sounds.find((s: any) => "ipa" in s);
+ if (!hasIpa) return;
+ const freq = await getThaiFreq(word);
+ const wordId = pdb.addWord(word, "th", freq, null);
+ const analyzed = await analyzeTHWord(word);
+ // console.log(analyzed);
+ for (let snd of sounds) if ("ipa" in snd) handleIpa(wordId, j, snd, analyzed);
+}
+async function handleIpa(
+ wordId: number | bigint,
+ j: any,
+ snd: any,
+ analyzed: ThaiNLPRes,
+) {
+ const tags = JSON.stringify(snd.tags) || null;
+ // console.log("handleipa", analyzed.syllables.length);
+ // console.log(analyzed);
+ const wikiIpa = cleanIpa(snd.ipa);
+ const nlpIpa = cleanIpa(analyzed.ipa);
+ const ipa = wikiIpa || nlpIpa;
+ const wikiIpaSplit = wikiIpa.split(".");
+ const nlpIpaSplit = nlpIpa.split(".");
+ if (wikiIpaSplit.length !== nlpIpaSplit.length) {
+ console.log("ipa mismatch");
+ console.log(wikiIpa);
+ console.log(nlpIpa);
+ // return;
+ }
+ if (analyzed.syllables.length !== wikiIpaSplit.length) {
+ console.log("syllable analysis mismatch", j.word);
+ console.log({ syls: analyzed.syllables, ipa: wikiIpaSplit });
+ // console.dir(j, { depth: null });
+ return;
+ }
+ pdb.addPronunciation(wordId, ipa, analyzed.syllables.length, tags, null);
+
+ for (let i = 0; i < analyzed.syllables.length; i++) {
+ const spelling = analyzed.syllables[i]!;
+ const ipa = wikiIpaSplit[i]!;
+ try {
+ await handleSyllable(spelling, ipa, wordId, i);
+ } catch (e) {
+ console.error("syl error", j.word, j.sounds);
+ console.error({ spelling, ipa, wikiIpaSplit });
+ console.error(e);
+ }
+ }
+}
+const thaiTones: Record<string, string> = {
+ "˧": "mid",
+ "˨˩": "low",
+ "˥˩": "falling",
+ "˦˥": "high",
+ "˩˩˦": "rising",
+};
+const thaiToneNums: Record<string, number> = {
+ "˧": 33,
+ "˨˩": 21,
+ "˥˩": 41,
+ "˦˥": 45,
+ "˩˩˦": 214,
+};
+function parseTone(ipa: string, spelling: string): Tone {
+ try {
+ const name = thaiTones[ipa]!;
+ const numbers = thaiToneNums[ipa]!;
+ return { letters: ipa, name, numbers };
+ } catch (e) {
+ console.error("wrong tones!!", { s: spelling, ipa });
+ throw new Error("");
+ }
+}
+async function handleSyllable(
+ spelling: string,
+ ipa: string,
+ wordId: number | bigint,
+ idx: number,
+) {
+ const sorsyl = await sorSyl(spelling, "th", ipa);
+ if (sorsyl.syls.length !== 1) throw new Error("wtf sorsyl!");
+ const syl = sorsyl.syls[0]!;
+ const tone = syl.tone ? parseTone(syl.tone, spelling) : null;
+ try {
+ pdb.addSyllable(
+ wordId,
+ idx + 1,
+ "th",
+ syl.ipa,
+ syl.long,
+ spelling,
+ { spelling: syl.onset, ipa: syl.onset },
+ { spelling: syl.medial, ipa: syl.medial },
+ { spelling: syl.nucleus, ipa: syl.nucleus },
+ { spelling: syl.coda, ipa: syl.coda },
+ { spelling: syl.rhyme, ipa: syl.rhyme },
+ tone,
+ null,
+ );
+ } catch (e) {
+ // console.log("well fuck", syl);
+ // console.error(e);
+ console.log();
+ }
+}
+async function handleIdiom(idiom: string) {
+ pdb.addIdiom(idiom, "th");
+ // TODO later set idiom_words once all words are populated
+ // console.log();
+}
+// ช้า ๆ
+// งก ๆ
+// หงก ๆ
+
+async function getFrequency() {
+ const files = [
+ "/home/y/code/prosody/resources/langdata/thai/data/1yin_freq.csv",
+ "/home/y/code/prosody/resources/langdata/thai/data/2yin_freq.csv",
+ "/home/y/code/prosody/resources/langdata/thai/data/3yin_freq.csv",
+ "/home/y/code/prosody/resources/langdata/thai/data/4yin_freq.csv",
+ "/home/y/code/prosody/resources/langdata/thai/data/5yin_freq.csv",
+ "/home/y/code/prosody/resources/langdata/thai/data/6yin_freq.csv",
+ ];
+ const freqMap = new Map<number, string>();
+ for (const file of files) {
+ await handleFile(file, (line, idx) => {
+ const [spelling, IPA, tone, length, frequency, ...rest] = line.split(",");
+ freqMap.set(Number(frequency!), spelling!);
+ });
+ }
+ const orderedMap = new Map<string, number>();
+ const keys = Array.from(freqMap.keys()).sort();
+ for (let i = 0; i < keys.length; i++) {
+ const val = freqMap.get(keys[i]!)!;
+ orderedMap.set(val, i + 1);
+ }
+ return orderedMap;
+}
+
+readDump("th");