export interface DictionaryEntry { from: string; to: string; } export interface DictationSettings { spokenPunctuation: boolean; removeFillerWords: boolean; dictionary: DictionaryEntry[]; } const SPOKEN_PUNCTUATION: Record = { comma: ',', period: '.', 'full stop': '.', 'question mark': '?', 'exclamation mark': '!', 'exclamation point': '!', 'new line': '\n', 'new paragraph': '\n\n', colon: ':', semicolon: ';', 'open quote': '"', 'close quote': '"', hyphen: '-', dash: '-', }; const FILLER_WORDS = ['um', 'uh', 'erm', 'you know', 'like,', 'i mean,']; export const DEFAULT_DICTATION_SETTINGS: DictationSettings = { spokenPunctuation: true, removeFillerWords: false, dictionary: [ { from: 'neura vault', to: 'NeuraVault' }, { from: 'open ai', to: 'OpenAI' }, ], }; function applySpokenPunctuation(text: string): string { let out = text; for (const [phrase, symbol] of Object.entries(SPOKEN_PUNCTUATION)) { const re = new RegExp(`\\s*\\b${phrase}\\b\\s*`, 'gi'); out = out.replace(re, symbol === '\n' || symbol === '\n\n' ? symbol : `${symbol} `); } return out.replace(/ +([.,!?;:])/g, '$1').replace(/[ \t]+/g, ' '); } function removeFillers(text: string): string { let out = text; for (const filler of FILLER_WORDS) { const re = new RegExp(`\\b${filler.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'gi'); out = out.replace(re, ''); } return out.replace(/[ \t]+/g, ' ').trim(); } function applyDictionary(text: string, dictionary: DictionaryEntry[]): string { let out = text; for (const { from, to } of dictionary) { if (!from.trim()) continue; const re = new RegExp(`\\b${from.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'gi'); out = out.replace(re, to); } return out; } /** Full pipeline applied to each finalized speech segment, in the order dedicated * dictation tools apply them: custom vocabulary first, then voice commands, then cleanup. */ export function processSpeechSegment(raw: string, settings: DictationSettings): string { let text = raw; text = applyDictionary(text, settings.dictionary); if (settings.spokenPunctuation) text = applySpokenPunctuation(text); if (settings.removeFillerWords) text = removeFillers(text); // Capitalize first letter of the segment for readability text = text.replace(/^\s*([a-z])/, (m) => m.toUpperCase()); return text.trim(); } const STORAGE_KEY = 'neuravault:dictation-settings'; export function loadDictationSettings(): DictationSettings { try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return DEFAULT_DICTATION_SETTINGS; const parsed = JSON.parse(raw); return { ...DEFAULT_DICTATION_SETTINGS, ...parsed }; } catch { return DEFAULT_DICTATION_SETTINGS; } } export function saveDictationSettings(settings: DictationSettings) { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); } catch { /* storage unavailable */ } }