voice updates and databasing

This commit is contained in:
legop3
2026-06-09 15:01:11 -04:00
parent de34f1b0a2
commit 2d0e883c97
4 changed files with 32 additions and 10 deletions
+15 -1
View File
@@ -2,9 +2,23 @@
"codes": { "codes": {
"r001": { "r001": {
"type": "rover", "type": "rover",
"entityId": "Freaky", "entityId": "freaky",
"label": "Freaky" "label": "Freaky"
}, },
"r002": {
"type": "rover",
"entityId": "walle",
"label": "WALL-E"
},
"r003": {
"type": "rover",
"entityId": "bweeble",
"label": "Bweeble"
},
"o001": { "o001": {
"type": "object", "type": "object",
"entityId": "woodblock", "entityId": "woodblock",
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -11,7 +11,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Roomba Rover" /> <meta name="apple-mobile-web-app-title" content="Roomba Rover" />
<title>Roomba Rover</title> <title>Roomba Rover</title>
<script type="module" crossorigin src="/assets/index-BhQJmAe_.js"></script> <script type="module" crossorigin src="/assets/index-DNxiEuzr.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Djpv3bOo.css"> <link rel="stylesheet" crossorigin href="/assets/index-Djpv3bOo.css">
</head> </head>
<body> <body>
@@ -5,23 +5,31 @@ import { useEffect, useRef } from 'react';
const SPEECH_START_TIMEOUT_MS = 1500; const SPEECH_START_TIMEOUT_MS = 1500;
const SPEECH_RETRY_DELAY_MS = 700; const SPEECH_RETRY_DELAY_MS = 700;
const PREFERRED_VOICE_PATTERN = /female|samantha|victoria|zira|karen|moira|serena|ava|susan|hazel|google uk english female/i; const PREFERRED_VOICE_PATTERN = /female|samantha|victoria|allison|zira|karen|moira|serena|ava|susan|hazel|google (us|uk) english/i;
const NOVELTY_VOICE_PATTERN = /whisper|bubbles|bells|boing|bad news|bahh|cellos|deranged|good news|hysterical|pipe organ|trinoids|zarvox/i;
function isNoveltyVoice(voice) {
return NOVELTY_VOICE_PATTERN.test(String(voice?.name || ''));
}
function pickScannerVoice(synth) { function pickScannerVoice(synth) {
const voices = typeof synth?.getVoices === 'function' ? synth.getVoices() : []; const voices = typeof synth?.getVoices === 'function' ? synth.getVoices() : [];
if (!voices.length) return null; if (!voices.length) return null;
const englishVoices = voices.filter((voice) => String(voice?.lang || '').toLowerCase().startsWith('en')); const usableVoices = voices.filter((voice) => !isNoveltyVoice(voice));
const defaultVoice = usableVoices.find((voice) => voice?.default) || null;
const englishVoices = usableVoices.filter((voice) => String(voice?.lang || '').toLowerCase().startsWith('en'));
// Browser voice lists vary by operating system and installed speech packs, so // Browser voice lists vary by operating system and installed speech packs, so
// this is intentionally a preference rather than a requirement. A recognized // this is intentionally a preference rather than a requirement. A recognized
// female-sounding English voice is best for the scanner speaker, but any // female-sounding English voice is best for the scanner speaker, but any
// English voice is better than failing to speak, and the browser default is // normal/default voice is better than accidentally choosing a novelty voice
// the final fallback. // like Whisper just because it appears early in the browser's voice list.
return ( return (
englishVoices.find((voice) => PREFERRED_VOICE_PATTERN.test(String(voice?.name || ''))) || englishVoices.find((voice) => PREFERRED_VOICE_PATTERN.test(String(voice?.name || ''))) ||
voices.find((voice) => PREFERRED_VOICE_PATTERN.test(String(voice?.name || ''))) || usableVoices.find((voice) => PREFERRED_VOICE_PATTERN.test(String(voice?.name || ''))) ||
defaultVoice ||
englishVoices[0] || englishVoices[0] ||
voices[0] || usableVoices[0] ||
null null
); );
} }
@@ -77,7 +85,7 @@ export default function useScannerSpeech(scan) {
utterance.voice = preferredVoice; utterance.voice = preferredVoice;
utterance.lang = preferredVoice.lang; utterance.lang = preferredVoice.lang;
} }
utterance.rate = 0.92; utterance.rate = 1;
utterance.pitch = 1; utterance.pitch = 1;
utterance.volume = 1; utterance.volume = 1;
utterance.onstart = () => { utterance.onstart = () => {