feat(stt): add server-side STT provider via OpenAI-compatible Whisper endpoint (#860)
Co-authored-by: Alexander Busse <alex@ableph.net>
This commit is contained in:
committed by
GitHub
co-authored by
Alexander Busse
parent
75a10ea66c
commit
3746d99a85
@@ -477,6 +477,15 @@ interface ConfigStore {
|
||||
browserVoice: string;
|
||||
openaiVoice: string;
|
||||
openaiApiKey: string;
|
||||
openaiCompatibleUrl: string;
|
||||
openaiCompatibleVoice: string;
|
||||
// STT (speech-to-text) settings
|
||||
sttProvider: 'browser' | 'server';
|
||||
sttServerUrl: string;
|
||||
sttModel: string;
|
||||
sttLanguage: string;
|
||||
sttSilenceThresholdDb: number;
|
||||
sttSilenceHoldMs: number;
|
||||
showMessageTTSButtons: boolean;
|
||||
voiceModeEnabled: boolean;
|
||||
// Summarization settings
|
||||
@@ -491,6 +500,14 @@ interface ConfigStore {
|
||||
setBrowserVoice: (voice: string) => void;
|
||||
setOpenaiVoice: (voice: string) => void;
|
||||
setOpenaiApiKey: (apiKey: string) => void;
|
||||
setOpenaiCompatibleUrl: (url: string) => void;
|
||||
setOpenaiCompatibleVoice: (voice: string) => void;
|
||||
setSttProvider: (provider: 'browser' | 'server') => void;
|
||||
setSttServerUrl: (url: string) => void;
|
||||
setSttModel: (model: string) => void;
|
||||
setSttLanguage: (lang: string) => void;
|
||||
setSttSilenceThresholdDb: (db: number) => void;
|
||||
setSttSilenceHoldMs: (ms: number) => void;
|
||||
setShowMessageTTSButtons: (show: boolean) => void;
|
||||
setVoiceModeEnabled: (enabled: boolean) => void;
|
||||
setSummarizeMessageTTS: (enabled: boolean) => void;
|
||||
@@ -635,6 +652,71 @@ export const useConfigStore = create<ConfigStore>()(
|
||||
}
|
||||
return '';
|
||||
})(),
|
||||
// OpenAI-compatible custom server URL
|
||||
openaiCompatibleUrl: (() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = localStorage.getItem('openaiCompatibleUrl');
|
||||
if (saved) return saved;
|
||||
}
|
||||
return '';
|
||||
})(),
|
||||
// OpenAI-compatible custom server voice
|
||||
openaiCompatibleVoice: (() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = localStorage.getItem('openaiCompatibleVoice');
|
||||
if (saved) return saved;
|
||||
}
|
||||
return 'af_sky';
|
||||
})(),
|
||||
// STT provider: 'browser' (Web Speech API) or 'server' (OpenAI-compat)
|
||||
sttProvider: (() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = localStorage.getItem('sttProvider');
|
||||
if (saved === 'browser' || saved === 'server') return saved;
|
||||
}
|
||||
return 'browser' as const;
|
||||
})(),
|
||||
sttServerUrl: (() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = localStorage.getItem('sttServerUrl');
|
||||
if (saved) return saved;
|
||||
}
|
||||
return 'http://localhost:8001/v1';
|
||||
})(),
|
||||
sttModel: (() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = localStorage.getItem('sttModel');
|
||||
if (saved) return saved;
|
||||
}
|
||||
return 'deepdml/faster-whisper-large-v3-turbo-ct2';
|
||||
})(),
|
||||
sttLanguage: (() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = localStorage.getItem('sttLanguage');
|
||||
if (saved !== null) return saved;
|
||||
}
|
||||
return '';
|
||||
})(),
|
||||
sttSilenceThresholdDb: (() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = localStorage.getItem('sttSilenceThresholdDb');
|
||||
if (saved) {
|
||||
const parsed = parseFloat(saved);
|
||||
if (!isNaN(parsed)) return parsed;
|
||||
}
|
||||
}
|
||||
return -45;
|
||||
})(),
|
||||
sttSilenceHoldMs: (() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = localStorage.getItem('sttSilenceHoldMs');
|
||||
if (saved) {
|
||||
const parsed = parseInt(saved, 10);
|
||||
if (!isNaN(parsed)) return parsed;
|
||||
}
|
||||
}
|
||||
return 1500;
|
||||
})(),
|
||||
// Show TTS buttons on messages - disabled by default until user enables it
|
||||
showMessageTTSButtons: (() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
@@ -1662,6 +1744,62 @@ export const useConfigStore = create<ConfigStore>()(
|
||||
}
|
||||
},
|
||||
|
||||
setOpenaiCompatibleUrl: (url: string) => {
|
||||
set({ openaiCompatibleUrl: url });
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('openaiCompatibleUrl', url);
|
||||
}
|
||||
},
|
||||
|
||||
setOpenaiCompatibleVoice: (voice: string) => {
|
||||
set({ openaiCompatibleVoice: voice });
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('openaiCompatibleVoice', voice);
|
||||
}
|
||||
},
|
||||
|
||||
setSttProvider: (provider: 'browser' | 'server') => {
|
||||
set({ sttProvider: provider });
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('sttProvider', provider);
|
||||
}
|
||||
},
|
||||
|
||||
setSttServerUrl: (url: string) => {
|
||||
set({ sttServerUrl: url });
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('sttServerUrl', url);
|
||||
}
|
||||
},
|
||||
|
||||
setSttModel: (model: string) => {
|
||||
set({ sttModel: model });
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('sttModel', model);
|
||||
}
|
||||
},
|
||||
|
||||
setSttLanguage: (lang: string) => {
|
||||
set({ sttLanguage: lang });
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('sttLanguage', lang);
|
||||
}
|
||||
},
|
||||
|
||||
setSttSilenceThresholdDb: (db: number) => {
|
||||
set({ sttSilenceThresholdDb: db });
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('sttSilenceThresholdDb', String(db));
|
||||
}
|
||||
},
|
||||
|
||||
setSttSilenceHoldMs: (ms: number) => {
|
||||
set({ sttSilenceHoldMs: ms });
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('sttSilenceHoldMs', String(ms));
|
||||
}
|
||||
},
|
||||
|
||||
setShowMessageTTSButtons: (show: boolean) => {
|
||||
set({ showMessageTTSButtons: show });
|
||||
if (typeof window !== 'undefined') {
|
||||
|
||||
Reference in New Issue
Block a user