Files
EM2_ERP/em2rp/lib/services/smart_text_to_speech_service.dart

164 lines
4.9 KiB
Dart

import 'package:em2rp/services/text_to_speech_service.dart';
import 'package:em2rp/services/cloud_text_to_speech_service.dart';
import 'package:em2rp/utils/debug_log.dart';
/// Service hybride intelligent pour le Text-to-Speech
/// Essaie d'abord Web Speech API (gratuit, rapide), puis fallback vers Cloud TTS
class SmartTextToSpeechService {
static bool _initialized = false;
static bool _webSpeechWorks = true; // Optimiste par défaut
static int _webSpeechFailures = 0;
static const int _maxFailuresBeforeSwitch = 2;
/// Initialiser le service
static Future<void> initialize() async {
if (_initialized) return;
try {
DebugLog.info('[SmartTTS] Initializing...');
// Initialiser Web Speech API
await TextToSpeechService.initialize();
// Pré-charger les phrases courantes pour Cloud TTS en arrière-plan
// (ne bloque pas l'initialisation)
Future.delayed(const Duration(seconds: 2), () {
CloudTextToSpeechService.preloadCommonPhrases();
});
_initialized = true;
DebugLog.info('[SmartTTS] ✓ Initialized (Web Speech preferred)');
} catch (e) {
DebugLog.error('[SmartTTS] Initialization error', e);
_initialized = true; // Continuer quand même
}
}
/// Lire un texte à haute voix avec stratégie intelligente
static Future<void> speak(String text) async {
if (!_initialized) {
await initialize();
}
// Si Web Speech a échoué plusieurs fois, utiliser directement Cloud TTS
if (!_webSpeechWorks || _webSpeechFailures >= _maxFailuresBeforeSwitch) {
return _speakWithCloudTTS(text);
}
// Essayer Web Speech d'abord
try {
await _speakWithWebSpeech(text);
// Si succès, réinitialiser le compteur d'échecs
_webSpeechFailures = 0;
} catch (e) {
DebugLog.warning('[SmartTTS] Web Speech failed ($e), trying Cloud TTS...');
_webSpeechFailures++;
// Si trop d'échecs, basculer vers Cloud TTS par défaut
if (_webSpeechFailures >= _maxFailuresBeforeSwitch) {
DebugLog.info('[SmartTTS] Switching to Cloud TTS as primary');
_webSpeechWorks = false;
}
// Fallback vers Cloud TTS
await _speakWithCloudTTS(text);
}
}
/// Utiliser Web Speech API
static Future<void> _speakWithWebSpeech(String text) async {
DebugLog.info('[SmartTTS] → Trying Web Speech API');
// Timeout pour détecter si ça ne marche pas
await Future.any([
TextToSpeechService.speak(text),
Future.delayed(const Duration(seconds: 3), () {
throw Exception('Web Speech timeout');
}),
]);
DebugLog.info('[SmartTTS] ✓ Web Speech succeeded');
}
/// Utiliser Cloud TTS
static Future<void> _speakWithCloudTTS(String text) async {
DebugLog.info('[SmartTTS] → Using Cloud TTS');
try {
await CloudTextToSpeechService.speak(text);
DebugLog.info('[SmartTTS] ✓ Cloud TTS succeeded');
} catch (e) {
DebugLog.error('[SmartTTS] ✗ Cloud TTS failed', e);
// En dernier recours, réessayer Web Speech
if (!_webSpeechWorks) {
DebugLog.info('[SmartTTS] Last resort: trying Web Speech again');
await TextToSpeechService.speak(text);
} else {
rethrow;
}
}
}
/// Arrêter toute lecture en cours
static Future<void> stop() async {
try {
await TextToSpeechService.stop();
CloudTextToSpeechService.stopAll();
} catch (e) {
DebugLog.error('[SmartTTS] Error stopping', e);
}
}
/// Vérifier si une lecture est en cours
static Future<bool> isSpeaking() async {
try {
return await TextToSpeechService.isSpeaking();
} catch (e) {
return false;
}
}
/// Forcer l'utilisation de Cloud TTS (pour tests ou préférence utilisateur)
static void forceCloudTTS() {
DebugLog.info('[SmartTTS] Forced to use Cloud TTS');
_webSpeechWorks = false;
_webSpeechFailures = _maxFailuresBeforeSwitch;
}
/// Forcer l'utilisation de Web Speech (pour tests ou préférence utilisateur)
static void forceWebSpeech() {
DebugLog.info('[SmartTTS] Forced to use Web Speech');
_webSpeechWorks = true;
_webSpeechFailures = 0;
}
/// Réinitialiser la stratégie (utile pour tests)
static void resetStrategy() {
DebugLog.info('[SmartTTS] Strategy reset');
_webSpeechWorks = true;
_webSpeechFailures = 0;
}
/// Obtenir le statut actuel
static Map<String, dynamic> getStatus() {
return {
'initialized': _initialized,
'webSpeechWorks': _webSpeechWorks,
'failures': _webSpeechFailures,
'currentStrategy': _webSpeechWorks ? 'Web Speech (primary)' : 'Cloud TTS (primary)',
};
}
/// Nettoyer les ressources
static Future<void> dispose() async {
try {
await TextToSpeechService.dispose();
CloudTextToSpeechService.clearCache();
} catch (e) {
DebugLog.error('[SmartTTS] Error disposing', e);
}
}
}