diff --git a/Plugin/unraid/include/ai_repair.php b/Plugin/unraid/include/ai_repair.php index c8887ac..e3e18a1 100644 --- a/Plugin/unraid/include/ai_repair.php +++ b/Plugin/unraid/include/ai_repair.php @@ -915,6 +915,47 @@ function vv_ai_phrase_lookup(string $term, int $minSeen = 3): ?array { return vv_ai_phrase_aliases($minSeen)[strtolower(trim($term))] ?? null; } +// ── Spellings ──────────────────────────────────────────────────────────────────────────────── +// The operator types quickly and knows it: "haversync" for "have rsync", "as it to the list" for +// "add it". Recorded when the meaning was obvious in context, so the next occurrence is read +// rather than puzzled over. +// +// Promoted on first sighting, unlike a term alias, and the difference is deliberate. A term alias +// decides what gets written to conf, so it has to be earned by repetition. A spelling decides how +// a sentence is read, costs a misreading at worst, and is rarely made identically three times — +// requiring repetition would mean never learning any of them. +// +// Recorded only when the intent was actually clear. A guess written down here is worse than +// leaving it out, because it will be applied silently every time afterwards. +function vv_ai_spelling_record(string $said, string $typo, string $meant): bool { + $typo = strtolower(trim($typo)); + $meant = trim($meant); + if ($typo === '' || $meant === '' || strcasecmp($typo, $meant) === 0) return false; + return vv_ai_phrase_record($said, $typo, $meant, 'spelling'); +} + +// What the operator most likely meant by a word, or null. Last writing wins, so a correction to +// an earlier reading simply supersedes it. +function vv_ai_spelling_lookup(string $word): ?string { + $word = strtolower(trim($word)); + $hit = null; + foreach (vv_ai_phrase_all() as $r) { + if (($r['kind'] ?? '') !== 'spelling' || ($r['outcome'] ?? '') === 'rejected') continue; + if (($r['term'] ?? '') === $word) $hit = (string)$r['target']; + } + return $hit; +} + +function vv_ai_spellings(): array { + $out = []; + foreach (vv_ai_phrase_all() as $r) { + if (($r['kind'] ?? '') !== 'spelling' || ($r['outcome'] ?? '') === 'rejected') continue; + $out[(string)$r['term']] = (string)$r['target']; + } + ksort($out); + return $out; +} + // Terms that have been corrected and have not yet earned promotion — what the assistant is still // getting wrong, and the thing worth reading when asking why it keeps mistaking something. function vv_ai_phrase_unsettled(): array {