feat: add AI voice transcription fallback for domestic Android ROMs
This commit is contained in:
@@ -19,6 +19,9 @@ class VoiceService {
|
||||
bool _speechReady = false;
|
||||
bool _ttsInitialized = false;
|
||||
|
||||
void Function(String status)? _statusListener;
|
||||
void Function(String error)? _errorListener;
|
||||
|
||||
Future<void> _initTts() async {
|
||||
if (_ttsInitialized) return;
|
||||
try {
|
||||
@@ -65,6 +68,8 @@ class VoiceService {
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
Future<bool> hasRecordPermission() => _recorder.hasPermission();
|
||||
|
||||
Future<bool> startRecording() async {
|
||||
if (!await _recorder.hasPermission()) return false;
|
||||
final directory = await getApplicationDocumentsDirectory();
|
||||
@@ -125,27 +130,70 @@ class VoiceService {
|
||||
await _player.dispose();
|
||||
}
|
||||
|
||||
Future<bool> initializeSpeech() async {
|
||||
_speechReady = await _stt.initialize();
|
||||
return _speechReady;
|
||||
Future<bool> initializeSpeech({
|
||||
void Function(String status)? onStatus,
|
||||
void Function(String error)? onError,
|
||||
}) async {
|
||||
_statusListener = onStatus;
|
||||
_errorListener = onError;
|
||||
try {
|
||||
_speechReady = await _stt.initialize(
|
||||
onError: (val) {
|
||||
_errorListener?.call(val.errorMsg);
|
||||
},
|
||||
onStatus: (val) {
|
||||
_statusListener?.call(val);
|
||||
},
|
||||
debugLogging: false,
|
||||
);
|
||||
return _speechReady;
|
||||
} catch (_) {
|
||||
_speechReady = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> startListening(
|
||||
void Function(String text, bool finalResult) onResult,
|
||||
) async {
|
||||
if (!_speechReady && !await initializeSpeech()) {
|
||||
void Function(String text, bool finalResult) onResult, {
|
||||
void Function(String status)? onStatus,
|
||||
void Function(String error)? onError,
|
||||
}) async {
|
||||
_statusListener = onStatus;
|
||||
_errorListener = onError;
|
||||
try {
|
||||
if (!_speechReady || !_stt.isAvailable) {
|
||||
final ready = await initializeSpeech(onStatus: onStatus, onError: onError);
|
||||
if (!ready) return false;
|
||||
}
|
||||
|
||||
String? targetLocaleId = 'en_US';
|
||||
try {
|
||||
final locales = await _stt.locales();
|
||||
if (locales.isNotEmpty) {
|
||||
final enLocale = locales.firstWhere(
|
||||
(l) => l.localeId.toLowerCase().startsWith('en'),
|
||||
orElse: () => locales.first,
|
||||
);
|
||||
targetLocaleId = enLocale.localeId;
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
await _stt.listen(
|
||||
onResult: (result) =>
|
||||
onResult(result.recognizedWords, result.finalResult),
|
||||
listenOptions: SpeechListenOptions(
|
||||
localeId: targetLocaleId,
|
||||
listenFor: const Duration(seconds: 30),
|
||||
pauseFor: const Duration(seconds: 4),
|
||||
partialResults: true,
|
||||
cancelOnError: false,
|
||||
),
|
||||
);
|
||||
return _stt.isListening;
|
||||
} catch (e) {
|
||||
if (onError != null) onError(e.toString());
|
||||
return false;
|
||||
}
|
||||
await _stt.listen(
|
||||
onResult: (result) =>
|
||||
onResult(result.recognizedWords, result.finalResult),
|
||||
listenOptions: SpeechListenOptions(
|
||||
localeId: 'en_US',
|
||||
listenFor: const Duration(seconds: 30),
|
||||
pauseFor: const Duration(seconds: 4),
|
||||
),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> stopListening() => _stt.stop();
|
||||
|
||||
Reference in New Issue
Block a user