Created
May 8, 2024 22:56
-
-
Save callmephil/f16c00cc3d2e22639410d29509f7a0f9 to your computer and use it in GitHub Desktop.
ai assistant
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_tts/flutter_tts.dart'; | |
import 'package:speech_to_text/speech_to_text.dart' as stt; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Speech to Text App', | |
debugShowCheckedModeBanner: false, | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
visualDensity: VisualDensity.adaptivePlatformDensity, | |
), | |
home: const SpeechScreen(), | |
); | |
} | |
} | |
class SpeechScreen extends StatefulWidget { | |
const SpeechScreen({super.key}); | |
@override | |
State<SpeechScreen> createState() => _SpeechScreenState(); | |
} | |
class _SpeechScreenState extends State<SpeechScreen> with DebounceMixin { | |
final stt.SpeechToText _speech = stt.SpeechToText(); | |
final FlutterTts _flutterTts = FlutterTts(); | |
bool _isListening = false; | |
String _text = ''; | |
@override | |
void initState() { | |
super.initState(); | |
initializeTTS(); | |
} | |
void initializeTTS() { | |
_flutterTts.setStartHandler(() { | |
setState(() { | |
print("Playing"); | |
}); | |
}); | |
_flutterTts.setCompletionHandler(() { | |
setState(() { | |
print("Complete"); | |
}); | |
}); | |
_flutterTts.setErrorHandler((msg) { | |
setState(() { | |
print("error: $msg"); | |
}); | |
}); | |
} | |
void _speak(String text) async { | |
print("speak: $text"); | |
stopListening(); | |
_speech.cancel(); | |
await _flutterTts.speak(text); | |
Future.delayed(const Duration(seconds: 3), () { | |
_listen(); | |
}); | |
} | |
void _listen() async { | |
if (_isListening) { | |
return; | |
} | |
bool isInitialized = await _speech.initialize( | |
onStatus: (val) => print('onStatus: $val'), | |
onError: (val) => print('onError: $val'), | |
); | |
if (!isInitialized) { | |
print('Failed to initialize speech'); | |
return; | |
} | |
setState(() => _isListening = true); | |
_speech.listen( | |
onResult: (val) { | |
setState(() { | |
_text = val.recognizedWords; | |
}); | |
resetDebounceTimer(); | |
if (val.hasConfidenceRating && val.confidence > 0) { | |
_analyzeText(_text); | |
} | |
}, | |
); | |
startDebounceTimer(const Duration(seconds: 5), stopListening); | |
} | |
@override | |
void stopListening() { | |
_speech.stop(); | |
setState(() { | |
_isListening = false; | |
}); | |
cancelDebounceTimer(); | |
} | |
final matchingWords = ['order', 'confirm', 'cancel', 'yes', 'no', 'help']; | |
final matchedWords = <String>[]; | |
void _analyzeText(String text) { | |
for (var word in matchingWords) { | |
if (text.toLowerCase().contains(word) && !matchedWords.contains(word)) { | |
matchedWords.add(word); | |
print('Matched words: $matchedWords'); | |
_speak("You said $word. How can I assist further?"); | |
} | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Real-time Speech to Text and TTS'), | |
actions: [ | |
IconButton( | |
icon: Icon(_isListening ? Icons.mic_off : Icons.mic), | |
onPressed: _listen, | |
), | |
IconButton( | |
icon: const Icon(Icons.clear), | |
onPressed: _isListening | |
? null | |
: () { | |
setState(() { | |
_text = ''; | |
_isListening = false; | |
matchedWords.clear(); | |
}); | |
}, | |
), | |
], | |
), | |
body: SingleChildScrollView( | |
reverse: true, | |
child: Padding( | |
padding: const EdgeInsets.all(16.0), | |
child: Text(_text), | |
), | |
), | |
); | |
} | |
} | |
mixin DebounceMixin<T extends StatefulWidget> on State<T> { | |
Timer? _debounceTimer; | |
Duration _duration = const Duration(seconds: 5); | |
@override | |
void dispose() { | |
_debounceTimer?.cancel(); | |
super.dispose(); | |
} | |
void startDebounceTimer(Duration delay, VoidCallback callback) { | |
cancelDebounceTimer(); | |
_debounceTimer = Timer(delay, callback); | |
_duration = delay; | |
} | |
void resetDebounceTimer() { | |
if (_debounceTimer != null) { | |
cancelDebounceTimer(); | |
startDebounceTimer(_duration, stopListening); | |
} | |
} | |
void stopListening(); | |
void cancelDebounceTimer() { | |
if (_debounceTimer?.isActive ?? false) { | |
_debounceTimer?.cancel(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment