Files
gnome-jarvis/daemon/transcript.js
T
snxraven e9040d110a
Rolling release / release (push) Successful in 6m40s
Updates
2026-09-12 07:22:47 -04:00

89 lines
2.4 KiB
JavaScript

export const MIN_UTTERANCE_CHARS = 3;
const SPOKEN_ACRONYMS = {
qvac: 'Quantum Verse Automatic Computer',
cpu: 'C P U',
gpu: 'G P U',
ram: 'R A M',
ssd: 'S S D',
hdd: 'H D D',
usb: 'U S B',
dns: 'D N S',
isp: 'I S P',
vpn: 'V P N',
ssh: 'S S H',
api: 'A P I',
url: 'U R L',
uri: 'U R I',
http: 'H T T P',
https: 'H T T P S',
html: 'H T M L',
json: 'J S O N',
xml: 'X M L',
os: 'O S',
ip: 'I P',
tts: 'T T S',
asr: 'A S R',
hud: 'heads up display',
llm: 'L L M',
cli: 'C L I',
gui: 'G U I',
ptt: 'P T T',
vad: 'V A D',
};
function spellAcronyms(text) {
return String(text || '').replace(/\b([A-Za-z]{2,6})\b/g, (word) => {
const spoken = SPOKEN_ACRONYMS[word.toLowerCase()];
return spoken || word;
});
}
function speakableAddresses(text) {
return String(text || '')
.replace(/\b(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\b/g, '$1 $2 $3 $4')
.replace(/https?:\/\//gi, '')
.replace(/\b([A-Za-z0-9-]+)\.(com|org|net|io|dev|local|lan)\b/gi, (_, host, tld) => `${host} dot ${tld}`)
.replace(/\//g, ' slash ')
.replace(/@/g, ' at ')
.replace(/_/g, ' ');
}
export function speakableForTts(text) {
return spellAcronyms(speakableAddresses(String(text || '')))
.replace(/[`]/g, "'")
.replace(/[<>]/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
export function isSpeakable(text) {
const value = String(text || '').trim();
if (!value || value === '[object Object]') return false;
if (/\[no speech detected\]|\[blank_audio\]/i.test(value)) return false;
if (/^\[[^\]]+\]$/.test(value)) return false;
return /[\p{L}\p{N}]/u.test(value);
}
export function isMeaningfulTranscript(text) {
const value = String(text || '').trim();
if (!isSpeakable(value)) return false;
return value.replace(/[^\p{L}\p{N}]/gu, '').length >= MIN_UTTERANCE_CHARS;
}
export class SentenceBuffer {
constructor({ onSentence } = {}) { this.onSentence = onSentence; this.pending = ''; }
push(text) {
this.pending += String(text || '');
const sentences = [];
let match;
while ((match = this.pending.match(/^(.+?[.!?](?:["')\]]+)?)(?:\s+|$)/s))) {
sentences.push(match[1].trim()); this.pending = this.pending.slice(match[0].length);
}
for (const sentence of sentences) this.onSentence?.(sentence);
return sentences;
}
flush() { const value = this.pending.trim(); this.pending = ''; if (value) this.onSentence?.(value); return value; }
clear() { this.pending = ''; }
}