Skip to content

Instantly share code, notes, and snippets.

@callmephil
Created May 8, 2024 22:56
Show Gist options
  • Save callmephil/f16c00cc3d2e22639410d29509f7a0f9 to your computer and use it in GitHub Desktop.
Save callmephil/f16c00cc3d2e22639410d29509f7a0f9 to your computer and use it in GitHub Desktop.
ai assistant
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