aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnuj Solanki <anuj603362@gmail.com>2024-09-29 15:57:43 +0530
committerAnuj Solanki <anuj603362@gmail.com>2024-09-29 16:16:41 +0530
commit053ba8d80e405ca84a0e179c1551c3d440829579 (patch)
treeafcbe6698afcef799d15f0730d6346e859a5e469
parent539efac2637415a930b3077ff91abe003ce2fcd4 (diff)
Implemented auto-mode
- Implemented auto-mode in flutter-speechrecognition-demo to recognize the wake word and start the voice assistant automatically. Bug-AGL: SPEC-5200 Change-Id: Ic946a3f4535a7b16a4e45a5ffdf4a3b4015fdb6f Signed-off-by: Anuj Solanki <anuj603362@gmail.com>
-rw-r--r--lib/models/app_state.dart1
-rw-r--r--lib/screens/home_screen.dart77
-rw-r--r--lib/widgets/wake_word_command_processing.dart61
-rw-r--r--lib/widgets/wake_word_recording.dart71
4 files changed, 195 insertions, 15 deletions
diff --git a/lib/models/app_state.dart b/lib/models/app_state.dart
index 8325b50..4c97654 100644
--- a/lib/models/app_state.dart
+++ b/lib/models/app_state.dart
@@ -9,4 +9,5 @@ class AppState extends ChangeNotifier {
String commandProcessingText = "Processing...";
String sttFramework = "vosk";
bool onlineMode = false;
+ int recordingTime = 4;
}
diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart
index 4c2407f..d2d8898 100644
--- a/lib/screens/home_screen.dart
+++ b/lib/screens/home_screen.dart
@@ -16,6 +16,8 @@ import '../grpc/generated/voice_agent.pbgrpc.dart';
import '../grpc/voice_agent_client.dart';
import '../utils/app_config.dart';
import '../widgets/stt_model_choice.dart';
+import '../widgets/wake_word_command_processing.dart';
+import '../widgets/wake_word_recording.dart';
class HomePage extends StatefulWidget {
final AppConfig config;
@@ -203,24 +205,56 @@ class HomePageState extends State<HomePage> {
// Function to start listening for wake word status responses
void _startWakeWordDetection(BuildContext context) {
final appState = context.read<AppState>();
+ // Base condition
+ if(appState.isWakeWordMode==false){
+ return;
+ }
+ setState(() {});
voiceAgentClient = VoiceAgentClient(_config.grpcHost, _config.grpcPort);
+ appState.isWakeWordDetected = false;
+ appState.isCommandProcessing = false;
_wakeWordStatusSubscription = voiceAgentClient.detectWakeWord().listen(
- (response) {
+ (response) async {
if (response.status) {
- // Wake word detected, you can handle this case here
- // Set _isDetectingWakeWord to false to stop the loop
+ // Wake word detected, handle this case here
_stopWakeWordDetection();
appState.isWakeWordDetected = true;
- addChatMessage(
- 'Wake word detected! Now you can send your command by pressing the record button.');
- setState(() {}); // Trigger a rebuild
+ addChatMessage('Wake word detected! Starting recording...');
+
+ // Start recording
+ appState.isCommandProcessing = false;
+ String streamId = await startRecording();
+ if (streamId.isNotEmpty) {
+ addChatMessage('Recording started. Please speak your command.');
+
+ // Wait for 4-5 seconds
+ await Future.delayed(Duration(seconds: appState.recordingTime));
+
+ // Stop recording and get the response
+ appState.isCommandProcessing = true;
+ RecognizeResult recognizeResult = await stopRecording(streamId, appState.intentEngine,appState.sttFramework,appState.onlineMode);
+ // Execute the command
+ await executeCommand(recognizeResult);
+
+ // Wait for 1-2 seconds before resuming wake word detection
+ await Future.delayed(Duration(seconds: 1));
+
+ // Resume wake word detection
+ _startWakeWordDetection(context);
+ } else {
+ addChatMessage('Failed to start recording. Please try again.');
+ // Resume wake word detection
+
+ _startWakeWordDetection(context);
+ }
}
},
onError: (error) {
- // Handle any errors that occur during wake word detection
print('Error during wake word detection: $error');
// Set _isDetectingWakeWord to false to stop the loop
_stopWakeWordDetection();
+ // Resume wake word detection
+ _startWakeWordDetection(context);
},
cancelOnError: true,
);
@@ -679,11 +713,11 @@ class HomePageState extends State<HomePage> {
theme: _config.theme,
),
SizedBox(height: 10),
- if (!appState.isWakeWordMode || appState.isWakeWordDetected)
+ if (!appState.isWakeWordMode)
TryCommandsSection(
onCommandTap: handleCommandTap, theme: _config.theme),
SizedBox(height: 30),
- if (!appState.isWakeWordMode || appState.isWakeWordDetected)
+ if (!appState.isWakeWordMode)
if (!appState.isCommandProcessing)
Center(
child:
@@ -712,13 +746,26 @@ class HomePageState extends State<HomePage> {
),
])
else
- Center(
- child: Consumer<AppState>(
+ if(!appState.isWakeWordDetected)
+ Center(
+ child: Consumer<AppState>(
builder: (context, appState, _) {
- return ListeningForWakeWordSection();
- },
+ return ListeningForWakeWordSection();
+ },
+ ),
+ )
+ else
+ if (!appState.isCommandProcessing && appState.isWakeWordDetected)
+ Center(
+ child:
+ Consumer<AppState>(builder: (context, appState, _) {
+ return WakeWordRecording();
+ }),
+ )
+ else
+ Center(
+ child: ProcessingCommandSection(),
),
- ),
SizedBox(height: 30),
],
),
@@ -727,4 +774,4 @@ class HomePageState extends State<HomePage> {
),
);
}
-}
+} \ No newline at end of file
diff --git a/lib/widgets/wake_word_command_processing.dart b/lib/widgets/wake_word_command_processing.dart
new file mode 100644
index 0000000..9872d36
--- /dev/null
+++ b/lib/widgets/wake_word_command_processing.dart
@@ -0,0 +1,61 @@
+import 'package:flutter/material.dart';
+
+class ProcessingCommandSection extends StatefulWidget {
+ @override
+ ProcessingCommandSectionState createState() => ProcessingCommandSectionState();
+}
+
+class ProcessingCommandSectionState extends State<ProcessingCommandSection>
+ with SingleTickerProviderStateMixin {
+ late AnimationController _controller;
+
+ @override
+ void initState() {
+ super.initState();
+
+ // Create an animation controller
+ _controller = AnimationController(
+ vsync: this,
+ duration: Duration(seconds: 2), // Adjust the duration as needed
+ );
+
+ // Start the animation
+ _controller.repeat();
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose(); // Dispose of the animation controller
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ AnimatedBuilder(
+ animation: _controller,
+ builder: (context, child) {
+ return Transform.rotate(
+ angle: _controller.value * 2.0 * 3.1415927, // 2 * pi
+ child: Icon(
+ Icons.autorenew, // Replace with your processing icon
+ size: 60,
+ color: Colors.blueAccent,
+ ),
+ );
+ },
+ ),
+ SizedBox(height: 8),
+ Text(
+ 'Processing...',
+ style: TextStyle(
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ],
+ );
+ }
+} \ No newline at end of file
diff --git a/lib/widgets/wake_word_recording.dart b/lib/widgets/wake_word_recording.dart
new file mode 100644
index 0000000..38ccc77
--- /dev/null
+++ b/lib/widgets/wake_word_recording.dart
@@ -0,0 +1,71 @@
+import 'package:flutter/material.dart';
+
+class WakeWordRecording extends StatefulWidget {
+ @override
+ WakeWordRecordingState createState() => WakeWordRecordingState();
+}
+
+class WakeWordRecordingState extends State<WakeWordRecording>
+ with SingleTickerProviderStateMixin {
+ late AnimationController _controller;
+ late Animation<double> _bounceAnimation;
+
+ @override
+ void initState() {
+ super.initState();
+
+ // Create an animation controller
+ _controller = AnimationController(
+ vsync: this,
+ duration: Duration(milliseconds: 500), // Adjust the duration as needed
+ );
+
+ // Create a bounce animation
+ _bounceAnimation = Tween<double>(
+ begin: 0,
+ end: 10,
+ ).animate(CurvedAnimation(
+ parent: _controller,
+ curve: Curves.easeInOut,
+ ));
+
+ // Start the animation
+ _controller.repeat(reverse: true);
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose(); // Dispose of the animation controller
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ AnimatedBuilder(
+ animation: _controller,
+ builder: (context, child) {
+ return Transform.translate(
+ offset: Offset(0, _bounceAnimation.value),
+ child: Icon(
+ Icons.mic, // Replace with your recording icon
+ size: 60,
+ color: Colors.redAccent,
+ ),
+ );
+ },
+ ),
+ SizedBox(height: 8),
+ Text(
+ 'Recording...',
+ style: TextStyle(
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ],
+ );
+ }
+} \ No newline at end of file