Core TTS infrastructure: - sherpaTTS.ts: Sherpa ONNX integration for offline TTS - TTSErrorBoundary.tsx: Error boundary for TTS failures - ErrorBoundary.tsx: Generic error boundary component - VoiceIndicator.tsx: Visual indicator for voice activity - useSpeechRecognition.ts: Speech-to-text hook - DebugLogger.ts: Debug logging utility Features: - Offline voice synthesis (no internet needed) - Multiple voices support - Real-time voice activity indication - Error recovery and fallback - Debug logging for troubleshooting Tech stack: - Sherpa ONNX runtime - React Native Audio - Expo modules
106 lines
2.9 KiB
TypeScript
106 lines
2.9 KiB
TypeScript
import React, { ReactNode } from 'react';
|
|
import { View, Text, StyleSheet } from 'react-native';
|
|
import { ErrorBoundary } from './ErrorBoundary';
|
|
import { debugLogger } from '@/services/DebugLogger';
|
|
import { AppColors, Spacing, FontSizes, BorderRadius } from '@/constants/theme';
|
|
|
|
interface TTSErrorBoundaryProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
/**
|
|
* TTSErrorBoundary - specialized error boundary for TTS operations
|
|
* Catches crashes during voice synthesis and playback
|
|
*/
|
|
export function TTSErrorBoundary({ children }: TTSErrorBoundaryProps) {
|
|
const handleError = (error: Error, errorInfo: React.ErrorInfo) => {
|
|
// Additional TTS-specific error handling
|
|
debugLogger.error('TTS', '💥 TTS CRASH CAUGHT BY ERROR BOUNDARY', {
|
|
message: error.message,
|
|
name: error.name,
|
|
stack: error.stack,
|
|
componentStack: errorInfo.componentStack,
|
|
});
|
|
|
|
// Check for common TTS errors
|
|
if (error.message.includes('TTSManager')) {
|
|
debugLogger.error('TTS', 'Native module error - TTSManager not initialized or crashed');
|
|
}
|
|
if (error.message.includes('generateAndPlay')) {
|
|
debugLogger.error('TTS', 'Speech generation/playback failed');
|
|
}
|
|
if (error.message.includes('model') || error.message.includes('onnx')) {
|
|
debugLogger.error('TTS', 'TTS model loading error - check if models are bundled');
|
|
}
|
|
};
|
|
|
|
const fallbackUI = (
|
|
<View style={styles.container}>
|
|
<View style={styles.errorCard}>
|
|
<Text style={styles.errorIcon}>🔊</Text>
|
|
<Text style={styles.errorTitle}>Voice Playback Error</Text>
|
|
<Text style={styles.errorMessage}>
|
|
The voice synthesis system encountered an error and was reset.
|
|
</Text>
|
|
<Text style={styles.debugHint}>
|
|
Check the Debug tab for detailed error logs
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
|
|
return (
|
|
<ErrorBoundary
|
|
category="TTS"
|
|
onError={handleError}
|
|
fallback={fallbackUI}
|
|
>
|
|
{children}
|
|
</ErrorBoundary>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
backgroundColor: AppColors.background,
|
|
padding: Spacing.lg,
|
|
},
|
|
errorCard: {
|
|
backgroundColor: AppColors.surface,
|
|
borderRadius: BorderRadius.lg,
|
|
padding: Spacing.xl,
|
|
maxWidth: 360,
|
|
width: '100%',
|
|
alignItems: 'center',
|
|
borderLeftWidth: 4,
|
|
borderLeftColor: AppColors.error || '#E53935',
|
|
},
|
|
errorIcon: {
|
|
fontSize: 48,
|
|
marginBottom: Spacing.md,
|
|
},
|
|
errorTitle: {
|
|
fontSize: FontSizes.xl,
|
|
fontWeight: '700',
|
|
color: AppColors.textPrimary,
|
|
marginBottom: Spacing.sm,
|
|
textAlign: 'center',
|
|
},
|
|
errorMessage: {
|
|
fontSize: FontSizes.base,
|
|
color: AppColors.textSecondary,
|
|
marginBottom: Spacing.md,
|
|
textAlign: 'center',
|
|
lineHeight: 22,
|
|
},
|
|
debugHint: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
textAlign: 'center',
|
|
marginTop: Spacing.xs,
|
|
},
|
|
});
|