wellnua-lite/components/TTSErrorBoundary.tsx
Sergei b2639dd540 Add Sherpa TTS voice synthesis system
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
2026-01-14 19:09:27 -08:00

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,
},
});