summaryrefslogtreecommitdiff
path: root/src/actions/prosody.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/actions/prosody.ts')
-rw-r--r--src/actions/prosody.ts104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/actions/prosody.ts b/src/actions/prosody.ts
new file mode 100644
index 0000000..9ec5dd2
--- /dev/null
+++ b/src/actions/prosody.ts
@@ -0,0 +1,104 @@
+"use server";
+
+import pdb from "@/lib/db/prosodydb";
+import { WordData } from "@/zoom/logic/types";
+
+export async function getOnsets(onset: string) {
+ const data = pdb.fetchOnsets(onset);
+ return data;
+}
+// Helper to extract tone from prosody - assuming prosody is an array of objects like [{tone: number}, ...]
+const getTonesFromProsody = (prosody: any): number[] | null => {
+ if (Array.isArray(prosody) && prosody.length > 0) {
+ return prosody.map((p) => p.tone).filter((t) => typeof t === "number");
+ }
+ return null;
+};
+
+export async function fetchWordsByToneAndSyllables(
+ syllableCount: number,
+ tones: (number | null)[], // Array of tones, one for each syllable. null means any tone.
+): Promise<WordData | null> {
+ if (syllableCount !== tones.length) {
+ console.error("Syllable count and tones array length mismatch");
+ return null;
+ }
+
+ const queryParams: (string | number)[] = ["th", syllableCount, syllableCount]; // lang, syllables (for WHERE), syllables (for json_array_length)
+ let toneConditions = "";
+
+ const toneClauses: string[] = [];
+ tones.forEach((tone, index) => {
+ if (tone !== null && typeof tone === "number") {
+ // Assumes SQLite's json_extract function is available and prosody is like: [{"tone": 1}, {"tone": 3}, ...]
+ // Path for first syllable's tone: '$[0].tone'
+ toneClauses.push(`json_extract(prosody, '$[${index}].tone') = ?`);
+ queryParams.push(tone);
+ }
+ });
+
+ if (toneClauses.length > 0) {
+ toneConditions = `AND ${toneClauses.join(" AND ")}`;
+ }
+
+ const queryString = `
+ SELECT id, spelling, prosody, syllables, lang, type, frequency, confidence, ipa,
+ (SELECT
+ json_group_array(json_object(
+ 'pos', pos,
+ 'senses', s.senses,
+ 'forms', forms,
+ 'etymology', etymology,
+ 'related', related)
+ ) FROM senses s WHERE s.parent_id = expressions.id
+ ) as senses_array
+ FROM expressions
+ WHERE lang = ?
+ AND syllables = ?
+ AND type = 'word'
+ AND json_valid(prosody)
+ AND json_array_length(prosody) = ? -- Ensures prosody array has correct number of elements
+ ${toneConditions}
+ ORDER BY RANDOM() -- Get a random word matching criteria
+ LIMIT 1
+ `;
+
+ try {
+ const query = db.db.query(queryString);
+ const row = query.get(...queryParams) as any;
+
+ if (!row) return null;
+
+ // Map to WordData (simplified, similar to initial fetch in tones.tsx or db.fetchWordBySpelling)
+ // This mapping might need to be more robust depending on actual WordData requirements.
+ const word: WordData = {
+ id: row.id,
+ spelling: row.spelling,
+ prosody: JSON.parse(row.prosody),
+ syllables: row.syllables,
+ lang: row.lang,
+ type: row.type,
+ frequency: row.frequency,
+ confidence: row.confidence,
+ ipa: row.ipa ? JSON.parse(row.ipa) : [],
+ // Senses parsing is simplified here. Adjust if full sense data is needed.
+ senses: row.senses_array
+ ? JSON.parse(row.senses_array).map((s: any) => ({
+ pos: s.pos,
+ senses:
+ typeof s.senses === "string" ? JSON.parse(s.senses) : s.senses,
+ forms: typeof s.forms === "string" ? JSON.parse(s.forms) : s.forms,
+ etymology: s.etymology,
+ related:
+ typeof s.related === "string" ? JSON.parse(s.related) : s.related,
+ }))
+ : [],
+ };
+ return word;
+ } catch (error) {
+ console.error("Error fetching word by tone and syllables:", error);
+ console.error("Query:", queryString);
+ console.error("Params:", queryParams);
+ return null;
+ }
+}