feat(voice): per-account choice between Whisper and the browser; STT_ALLOW_BROWSER
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m40s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m40s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
55112b940c
commit
a927a94a95
21 files changed
+288
-15
No files matched your search
@@ -3,6 +3,8 @@
|
||||
// server record with MediaRecorder, the own Whisper server turns it into text after stopping
|
||||
// browser the browser's speech recognition (Chrome, Edge, Safari; text appears while speaking)
|
||||
// off no voice input
|
||||
// With a Whisper server everyone may pick the browser instead (account setting), unless the server
|
||||
// forbids it (STT_ALLOW_BROWSER=false).
|
||||
import { api } from './api';
|
||||
import type { VoiceMode } from './types';
|
||||
|
||||
@@ -15,6 +17,33 @@ export interface VoiceConfig {
|
||||
|
||||
let configPromise: Promise<VoiceConfig> | null = null;
|
||||
let loadedConfig: VoiceConfig | null = null;
|
||||
let serverMode: VoiceMode | undefined;
|
||||
let browserAllowed = true;
|
||||
let preference: '' | 'browser' = '';
|
||||
|
||||
/** Fired when the effective mode changes (the account setting was loaded or changed). */
|
||||
export const VOICE_CONFIG_EVENT = 'mindsift:voice-config';
|
||||
|
||||
function applyPreference(mode: VoiceMode | undefined): VoiceMode | undefined {
|
||||
return mode === 'server' && browserAllowed && preference === 'browser' ? 'browser' : mode;
|
||||
}
|
||||
|
||||
/** The account's choice ('' = Whisper server, 'browser'); set when the user is loaded or changes it. */
|
||||
export function setVoicePreference(next: '' | 'browser' | undefined): void {
|
||||
const value = next === 'browser' ? 'browser' : '';
|
||||
if (value === preference) return;
|
||||
preference = value;
|
||||
if (loadedConfig) {
|
||||
loadedConfig = { ...loadedConfig, mode: effectiveMode(applyPreference(serverMode)) };
|
||||
configPromise = Promise.resolve(loadedConfig);
|
||||
}
|
||||
if (typeof window !== 'undefined') window.dispatchEvent(new CustomEvent(VOICE_CONFIG_EVENT));
|
||||
}
|
||||
|
||||
/** Whether the account may choose between the Whisper server and the browser. */
|
||||
export function voiceChoiceAvailable(): boolean {
|
||||
return serverMode === 'server' && browserAllowed;
|
||||
}
|
||||
|
||||
export function browserRecognition(): any {
|
||||
if (typeof window === 'undefined') return null;
|
||||
@@ -38,7 +67,9 @@ export function loadVoiceConfig(): Promise<VoiceConfig> {
|
||||
configPromise = api
|
||||
.getAuthStatus()
|
||||
.then((st) => {
|
||||
loadedConfig = { mode: effectiveMode(st.voice?.mode), maxSeconds: st.voice?.maxSeconds || 600 };
|
||||
serverMode = st.voice?.mode;
|
||||
browserAllowed = st.voice?.browserAllowed !== false;
|
||||
loadedConfig = { mode: effectiveMode(applyPreference(serverMode)), maxSeconds: st.voice?.maxSeconds || 600 };
|
||||
return loadedConfig;
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -58,6 +89,9 @@ export function currentVoiceConfig(): VoiceConfig {
|
||||
export function resetVoiceConfig(): void {
|
||||
configPromise = null;
|
||||
loadedConfig = null;
|
||||
serverMode = undefined;
|
||||
browserAllowed = true;
|
||||
preference = '';
|
||||
}
|
||||
|
||||
// Containers in order of preference; Safari only records MP4/AAC
|
||||
|
||||
Reference in new issue
Block a user