google tts defaults!

This commit is contained in:
legop3
2026-06-21 16:44:32 -04:00
parent 9cf71e8df3
commit 49bd8acf7b
8 changed files with 67 additions and 28 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -78,7 +78,7 @@
<script defer src="https://analytics.otter.land/script.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land"></script>
<script defer src="https://analytics.otter.land/recorder.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land" data-sample-rate="0.15" data-mask-level="moderate" data-max-duration="300000"></script>
<title>Roomba Rover</title>
<script type="module" crossorigin src="/assets/index-Cp0GiTXH.js"></script>
<script type="module" crossorigin src="/assets/index-CZg2vwtM.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CflZqP0e.css">
</head>
<body>
+4 -1
View File
@@ -40,7 +40,10 @@ function createHandlers({ sendSystemMessage }) {
playTypingNote(roverId, TYPING_SEND_NOTE, socket?.id);
if (isPrivateClosedRoverId(message.roverId)) {
const forcedTts = ttsOptions || { speak: true, engine: 'flite' };
// Private-closed chat does not broadcast the text, so TTS is the only
// delivery path. Use the same Google speech default as normal chat when
// the sender did not provide explicit TTS settings.
const forcedTts = ttsOptions || { speak: true, engine: 'chromegtts' };
maybeSpeak(socket, message, forcedTts);
cb({ success: true, privateOnly: true });
return;
@@ -36,7 +36,11 @@ function normalizeTtsOptions(raw = {}) {
const speak = raw.speak !== false;
if (!speak) return null;
const rawEngine = typeof raw.engine === 'string' ? raw.engine.toLowerCase() : '';
const engine = rawEngine === 'espeak' ? 'espeak' : rawEngine === 'chromegtts' ? 'chromegtts' : 'flite';
// Chat payloads come from browsers and bridged command paths, so this is the
// chat-specific copy of the server TTS default. Unknown or missing engines
// become Google speech here instead of falling through to flite before the
// shared command service gets a chance to apply its own default.
const engine = rawEngine === 'espeak' ? 'espeak' : rawEngine === 'flite' ? 'flite' : 'chromegtts';
const voice = typeof raw.voice === 'string' ? raw.voice.trim() : undefined;
let pitch = Number.isFinite(raw.pitch) ? raw.pitch : undefined;
let speed = Number.isFinite(raw.speed) ? raw.speed : undefined;
+24 -3
View File
@@ -13,16 +13,37 @@ const pendingCommands = new Map(); // id -> { roverId }
const lastDriveActivity = new Map(); // roverId -> { ts, socketId, direction, speed, isAdmin }
const driveCooldowns = new Map(); // roverId -> blockedUntil
function normalizeOutboundCommandPayload(payload = {}) {
if (payload?.type !== 'tts') return payload;
const tts = payload.tts && typeof payload.tts === 'object' ? payload.tts : {};
const configuredEngine = typeof tts.engine === 'string' ? tts.engine.trim() : '';
if (configuredEngine) return payload;
// The server owns the default for commands it sends. Roverd still keeps its
// own local default for payloads that omit an engine from some other source,
// but normal server-issued TTS should prefer Google speech without requiring
// every caller to remember that policy.
return {
...payload,
tts: {
...tts,
engine: 'chromegtts',
},
};
}
function issueCommand(roverId, payload) {
const record = roverManager.rovers.get(roverId);
if (!record || !record.ws) {
throw new Error('Rover offline');
}
const id = uuidv4();
const message = { ...payload, id };
const normalizedPayload = normalizeOutboundCommandPayload(payload);
const message = { ...normalizedPayload, id };
record.ws.send(JSON.stringify(message));
pendingCommands.set(id, { roverId, ts: Date.now(), type: payload.type });
logger.info('Issued command', roverId, payload.type, id);
pendingCommands.set(id, { roverId, ts: Date.now(), type: normalizedPayload.type });
logger.info('Issued command', roverId, normalizedPayload.type, id);
return id;
}