chore: retire zen-backed summarization
Disable the active Zen summarization flow because the unauthenticated/free Zen provider is no longer available and now returns usage-limit errors for this feature.
Keep /api/text/summarize as an API-compatible stub that returns local sanitized or distilled fallback text with summarized=false, rather than attempting external model calls.
Remove notification and voice playback summary behavior from runtime paths. Notification {last_message} now always uses normalized truncated text, and TTS playback ignores historical summarize request fields.
Hide the notification summary settings and voice summarize-before-playback controls while preserving legacy persisted settings for compatibility. Also disable Zen model startup validation and make Zen model list routes return empty results.
Update module documentation and tests to describe the retired provider behavior and the remaining compatibility stubs.
This commit is contained in:
@@ -35,7 +35,7 @@ import { getSyncMessages, getSyncParts } from '@/sync/sync-refs';
|
||||
import { useConfigStore } from '@/stores/useConfigStore';
|
||||
import { useServerTTS } from './useServerTTS';
|
||||
import { useSayTTS } from './useSayTTS';
|
||||
import { summarizeText, shouldSummarize, sanitizeForTTS } from '@/lib/voice/summarize';
|
||||
import { sanitizeForTTS } from '@/lib/voice/summarize';
|
||||
|
||||
export type BrowserVoiceStatus = 'idle' | 'listening' | 'processing' | 'speaking' | 'error';
|
||||
|
||||
@@ -151,8 +151,6 @@ export function useBrowserVoice(): UseBrowserVoiceReturn {
|
||||
const openaiCompatibleVoice = useConfigStore((state) => state.openaiCompatibleVoice);
|
||||
const openaiCompatibleUrl = useConfigStore((state) => state.openaiCompatibleUrl);
|
||||
const openaiCompatibleTtsModel = useConfigStore((state) => state.openaiCompatibleTtsModel);
|
||||
const summarizeVoiceConversation = useConfigStore((state) => state.summarizeVoiceConversation);
|
||||
const summarizeCharacterThreshold = useConfigStore((state) => state.summarizeCharacterThreshold);
|
||||
|
||||
const shouldCheckOpenAIAvailability = voiceModeEnabled && (voiceProvider === 'openai' || voiceProvider === 'openai-compatible');
|
||||
const shouldCheckSayAvailability = voiceModeEnabled && voiceProvider === 'say';
|
||||
@@ -476,17 +474,7 @@ export function useBrowserVoice(): UseBrowserVoiceReturn {
|
||||
// Speak the response
|
||||
setStatus('speaking');
|
||||
try {
|
||||
// Summarize text if enabled and over threshold
|
||||
let textToSpeak = textParts;
|
||||
if (summarizeVoiceConversation && shouldSummarize(textParts, 'voice')) {
|
||||
console.log('[useBrowserVoice] Summarizing AI response before speaking...');
|
||||
textToSpeak = await summarizeText(textParts, {
|
||||
threshold: summarizeCharacterThreshold,
|
||||
});
|
||||
} else {
|
||||
// Still sanitize for TTS even when not summarizing
|
||||
textToSpeak = sanitizeForTTS(textParts);
|
||||
}
|
||||
const textToSpeak = sanitizeForTTS(textParts);
|
||||
|
||||
// Helper to restart listening after speech ends
|
||||
// Only auto-restart if conversation mode is enabled
|
||||
@@ -613,7 +601,7 @@ export function useBrowserVoice(): UseBrowserVoiceReturn {
|
||||
setStatus('error');
|
||||
processingMessageRef.current = false;
|
||||
}
|
||||
}, [currentSessionId, currentProviderId, currentModelId, currentAgentName, language, sendMessage, setPendingInputText, createSession, speechRate, speechPitch, speechVolume, isServerTTSAvailable, speakServerTTS, isSayTTSAvailable, speakSayTTS, voiceProvider, sayVoice, browserVoice, openaiVoice, openaiCompatibleVoice, openaiCompatibleUrl, openaiCompatibleTtsModel, summarizeVoiceConversation, summarizeCharacterThreshold, conversationMode, startCurrentSTT]);
|
||||
}, [currentSessionId, currentProviderId, currentModelId, currentAgentName, language, sendMessage, setPendingInputText, createSession, speechRate, speechPitch, speechVolume, isServerTTSAvailable, speakServerTTS, isSayTTSAvailable, speakSayTTS, voiceProvider, sayVoice, browserVoice, openaiVoice, openaiCompatibleVoice, openaiCompatibleUrl, openaiCompatibleTtsModel, conversationMode, startCurrentSTT]);
|
||||
|
||||
// Handle speech recognition result
|
||||
const handleSpeechResult = useCallback(async (text: string, isFinal: boolean) => {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useConfigStore } from '@/stores/useConfigStore';
|
||||
import { useServerTTS } from './useServerTTS';
|
||||
import { useSayTTS } from './useSayTTS';
|
||||
import { browserVoiceService } from '@/lib/voice/browserVoiceService';
|
||||
import { summarizeText, shouldSummarize, sanitizeForTTS } from '@/lib/voice/summarize';
|
||||
import { sanitizeForTTS } from '@/lib/voice/summarize';
|
||||
|
||||
export interface UseMessageTTSReturn {
|
||||
/** Whether TTS is currently playing for this message */
|
||||
@@ -34,8 +34,6 @@ export function useMessageTTS(): UseMessageTTSReturn {
|
||||
const openaiCompatibleVoice = useConfigStore((state) => state.openaiCompatibleVoice);
|
||||
const openaiCompatibleUrl = useConfigStore((state) => state.openaiCompatibleUrl);
|
||||
const openaiCompatibleTtsModel = useConfigStore((state) => state.openaiCompatibleTtsModel);
|
||||
const summarizeMessageTTS = useConfigStore((state) => state.summarizeMessageTTS);
|
||||
const summarizeCharacterThreshold = useConfigStore((state) => state.summarizeCharacterThreshold);
|
||||
const showMessageTTSButtons = useConfigStore((state) => state.showMessageTTSButtons);
|
||||
|
||||
const isServerProvider = voiceProvider === 'openai' || voiceProvider === 'openai-compatible';
|
||||
@@ -66,16 +64,7 @@ export function useMessageTTS(): UseMessageTTSReturn {
|
||||
setIsPlaying(true);
|
||||
|
||||
try {
|
||||
// Summarize text if enabled and over threshold
|
||||
let textToSpeak = text;
|
||||
if (summarizeMessageTTS && shouldSummarize(text, 'message')) {
|
||||
textToSpeak = await summarizeText(text, {
|
||||
threshold: summarizeCharacterThreshold,
|
||||
});
|
||||
} else {
|
||||
// Still sanitize for TTS even when not summarizing
|
||||
textToSpeak = sanitizeForTTS(text);
|
||||
}
|
||||
const textToSpeak = sanitizeForTTS(text);
|
||||
|
||||
if (isServerProvider && isServerTTSAvailable) {
|
||||
const voice = voiceProvider === 'openai-compatible' ? openaiCompatibleVoice : openaiVoice;
|
||||
@@ -87,7 +76,7 @@ export function useMessageTTS(): UseMessageTTSReturn {
|
||||
speed: speechRate,
|
||||
pitch: speechPitch,
|
||||
volume: speechVolume,
|
||||
summarize: false, // We already summarized client-side
|
||||
summarize: false,
|
||||
baseURL,
|
||||
onEnd: () => setIsPlaying(false),
|
||||
onError: () => setIsPlaying(false),
|
||||
@@ -132,8 +121,6 @@ export function useMessageTTS(): UseMessageTTSReturn {
|
||||
openaiCompatibleVoice,
|
||||
openaiCompatibleUrl,
|
||||
openaiCompatibleTtsModel,
|
||||
summarizeMessageTTS,
|
||||
summarizeCharacterThreshold,
|
||||
isServerTTSAvailable,
|
||||
isSayTTSAvailable,
|
||||
speakServerTTS,
|
||||
|
||||
@@ -134,14 +134,11 @@ export function useServerTTS(options: UseServerTTSOptions = {}): UseServerTTSRet
|
||||
const audioSourceRef = useRef<AudioBufferSourceNode | null>(null);
|
||||
const abortControllerRef = useRef<AbortController | null>(null);
|
||||
|
||||
// Get current model, threshold, and max length from config store for summarization
|
||||
// Get current model and API settings from config store.
|
||||
const currentProviderId = useConfigStore((state) => state.currentProviderId);
|
||||
const currentModelId = useConfigStore((state) => state.currentModelId);
|
||||
const summarizeCharacterThreshold = useConfigStore((state) => state.summarizeCharacterThreshold);
|
||||
const summarizeMaxLength = useConfigStore((state) => state.summarizeMaxLength);
|
||||
const openaiApiKey = useConfigStore((state) => state.openaiApiKey);
|
||||
const openaiCompatibleUrl = useConfigStore((state) => state.openaiCompatibleUrl);
|
||||
const settingsZenModel = useConfigStore((state) => state.settingsZenModel);
|
||||
|
||||
// Check if server TTS is available
|
||||
const checkAvailability = useCallback(async (): Promise<boolean> => {
|
||||
@@ -275,19 +272,14 @@ export function useServerTTS(options: UseServerTTSOptions = {}): UseServerTTSRet
|
||||
model: options?.model || undefined,
|
||||
speed: options?.speed || 0.9,
|
||||
instructions: options?.instructions,
|
||||
summarize: options?.summarize ?? true, // Summarize by default for voice output
|
||||
summarize: false,
|
||||
// Use provided provider/model, or fall back to current chat model
|
||||
providerId: options?.providerId || currentProviderId || undefined,
|
||||
modelId: options?.modelId || currentModelId || undefined,
|
||||
// Use provided threshold, or fall back to user setting, or default to 200
|
||||
threshold: options?.threshold ?? summarizeCharacterThreshold ?? 200,
|
||||
// Max character length for summaries
|
||||
maxLength: summarizeMaxLength ?? 500,
|
||||
// Send API key from settings if available
|
||||
apiKey: openaiApiKey || undefined,
|
||||
// Send custom base URL for OpenAI-compatible servers
|
||||
baseURL: options?.baseURL || undefined,
|
||||
...(settingsZenModel ? { zenModel: settingsZenModel } : {}),
|
||||
}),
|
||||
signal: abortControllerRef.current.signal,
|
||||
});
|
||||
@@ -350,7 +342,7 @@ export function useServerTTS(options: UseServerTTSOptions = {}): UseServerTTSRet
|
||||
options?.onError?.(errorMsg);
|
||||
setIsPlaying(false);
|
||||
}
|
||||
}, [stop, currentProviderId, currentModelId, summarizeCharacterThreshold, summarizeMaxLength, openaiApiKey, settingsZenModel]);
|
||||
}, [stop, currentProviderId, currentModelId, openaiApiKey]);
|
||||
|
||||
// Cleanup on unmount
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user