diff options
Diffstat (limited to 'lib/screens/home_screen.dart')
-rw-r--r-- | lib/screens/home_screen.dart | 380 |
1 files changed, 282 insertions, 98 deletions
diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index a9d567b..4c2407f 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -1,8 +1,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter_voiceassistant/widgets/online_mode_choice.dart'; import 'package:flutter_voiceassistant/widgets/try_commands.dart'; import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'dart:async'; import '../models/app_state.dart'; import '../widgets/nlu_engine_choice.dart'; @@ -13,6 +15,7 @@ import '../widgets/chat_section.dart'; import '../grpc/generated/voice_agent.pbgrpc.dart'; import '../grpc/voice_agent_client.dart'; import '../utils/app_config.dart'; +import '../widgets/stt_model_choice.dart'; class HomePage extends StatefulWidget { final AppConfig config; @@ -36,18 +39,30 @@ class HomePageState extends State<HomePage> { super.initState(); _config = widget.config; // Initialize _config in the initState _wakeWord = widget.wakeWord; // Initialize _wakeWord in the initState - addChatMessage( - "Assistant in Manual mode. You can send commands directly by pressing the record button."); + final appState = context.read<AppState>(); + if(appState.isWakeWordMode){ + addChatMessage( + 'Switched to Wake Word mode. I\'ll listen for the wake word "$_wakeWord" before responding.'); + _startWakeWordDetection(context); + } + else{ + addChatMessage( + "Assistant in Manual mode. You can send commands directly by pressing the record button."); + } + } - void changeAssistantMode(BuildContext context, AssistantMode newMode) { + Future<void> changeAssistantMode(BuildContext context, AssistantMode newMode) async { final appState = context.read<AppState>(); clearChatMessages(); appState.streamId = ""; appState.isWakeWordDetected = false; appState.isCommandProcessing = false; + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (newMode == AssistantMode.wakeWord) { + await prefs.setBool('isWakeWordMode', true); addChatMessage( 'Switched to Wake Word mode. I\'ll listen for the wake word "$_wakeWord" before responding.'); @@ -62,6 +77,7 @@ class HomePageState extends State<HomePage> { toggleWakeWordDetection(context, true); } } else if (newMode == AssistantMode.manual) { + prefs.setBool('isWakeWordMode', false); addChatMessage( 'Switched to Manual mode. You can send commands directly by pressing record button.'); @@ -74,15 +90,17 @@ class HomePageState extends State<HomePage> { setState(() {}); // Trigger a rebuild } - void changeIntentEngine(BuildContext context, NLUEngine newEngine) { + Future<void> changeIntentEngine(BuildContext context, NLUEngine newEngine) async { final appState = context.read<AppState>(); - + SharedPreferences prefs = await SharedPreferences.getInstance(); if (newEngine == NLUEngine.snips) { appState.intentEngine = "snips"; + await prefs.setString("intentEngine","snips"); addChatMessage( 'Switched to 🚀 Snips engine. Lets be precise and accurate.'); } else if (newEngine == NLUEngine.rasa) { appState.intentEngine = "rasa"; + await prefs.setString("intentEngine","rasa"); addChatMessage( 'Switched to 🤖 RASA engine. Conversations just got smarter!'); } @@ -90,6 +108,42 @@ class HomePageState extends State<HomePage> { setState(() {}); // Trigger a rebuild } + Future<void> changeSTTFramework(BuildContext context, STTModel newModel) async { + final appState = context.read<AppState>(); + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (newModel == STTModel.vosk) { + appState.sttFramework = "vosk"; + await prefs.setString("sttFramework", "vosk"); + // vosk is fast and efficient + addChatMessage( + 'Switched to 🚀 Vosk framework. Lets be quick and efficient.'); + } else if (newModel == STTModel.whisper) { + appState.sttFramework = "whisper"; + await prefs.setString("sttFramework", "whisper"); + addChatMessage( + 'Switched to 🤖 Whisper framework. Conversations just got smarter!'); + } + print(appState.sttFramework); + setState(() {}); // Trigger a rebuild + } + + Future<void> toggleOnlineMode(BuildContext context, OnlineModeEnum mode) async { + final appState = context.read<AppState>(); + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (mode == OnlineModeEnum.enabled) { + appState.onlineMode = true; + await prefs.setBool('onlineMode', true); + addChatMessage( + 'Switched to Online mode. I\'ll be connected to the internet for better results.'); + } else { + appState.onlineMode = false; + await prefs.setBool('onlineMode', false); + addChatMessage( + 'Switched to Offline mode. I\'ll be disconnected from the internet.'); + } + setState(() {}); // Trigger a rebuild + } + void addChatMessage(String text, {bool isUserMessage = false}) { final newMessage = ChatMessage(text: text, isUserMessage: isUserMessage); setState(() { @@ -123,7 +177,7 @@ class HomePageState extends State<HomePage> { setState( () {}); // Trigger a rebuild to ensure the loading indicator is shown, tis a bad practice though but deosn't heavily affect the performance final response = - await stopRecording(appState.streamId, appState.intentEngine); + await stopRecording(appState.streamId, appState.intentEngine,appState.sttFramework,appState.onlineMode); // Process and store the result if (response.status == RecognizeStatusType.REC_SUCCESS) { appState.commandProcessingText = "Executing command..."; @@ -204,19 +258,31 @@ class HomePageState extends State<HomePage> { } Future<RecognizeResult> stopRecording( - String streamId, String nluModel) async { + String streamId, String nluModel, String stt,bool isOnlineMode) async { + try { NLUModel model = NLUModel.RASA; if (nluModel == "snips") { model = NLUModel.SNIPS; } + STTFramework sttFramework = STTFramework.VOSK; + if (stt == "whisper") { + sttFramework = STTFramework.WHISPER; + } + OnlineMode onlineMode = OnlineMode.OFFLINE; + if (isOnlineMode) { + onlineMode = OnlineMode.ONLINE; + } // Create a RecognizeControl message to stop recording final controlMessage = RecognizeVoiceControl() ..action = RecordAction.STOP ..nluModel = model ..streamId = streamId // Use the same stream ID as when starting recording - ..recordMode = RecordMode.MANUAL; + ..recordMode = RecordMode.MANUAL + ..sttFramework = sttFramework + ..onlineMode = onlineMode; + // Create a Stream with the control message final controlStream = Stream.fromIterable([controlMessage]); @@ -375,116 +441,234 @@ class HomePageState extends State<HomePage> { style: TextStyle(fontSize: 26, fontWeight: FontWeight.bold), ), SizedBox(height: 15), - Row( - mainAxisAlignment: MainAxisAlignment.center, + Column( children: [ - Flexible( - flex: 1, - child: ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), - child: Card( - color: _config.theme == "textured-dark" || - _config.theme == "textured-light" - ? Colors.transparent - : null, - elevation: 4, // Add elevation for shadow - shadowColor: _config.theme == "textured-dark" || - _config.theme == "textured-light" - ? Colors.transparent - : null, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Assistant Mode', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + flex: 1, + child: ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Card( + color: _config.theme == "textured-dark" || + _config.theme == "textured-light" + ? Colors.transparent + : null, + elevation: 4, // Add elevation for shadow + shadowColor: _config.theme == "textured-dark" || + _config.theme == "textured-light" + ? Colors.transparent + : null, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Assistant Mode', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 16), // Add spacing if needed + Center( + child: Consumer<AppState>( + builder: (context, appState, _) { + return AssistantModeChoice( + onModeChanged: (newMode) { + changeAssistantMode( + context, newMode); + print(newMode); + }, + theme: _config.theme, + ); + }, + ), + ), + ], ), - SizedBox(height: 16), // Add spacing if needed - Center( - child: Consumer<AppState>( - builder: (context, appState, _) { - return AssistantModeChoice( - onModeChanged: (newMode) { - changeAssistantMode( - context, newMode); - print(newMode); + ), + ), + ), + ), + ), + + SizedBox(width: 20), // Add spacing between buttons + + Flexible( + flex: 1, + child: ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Card( + color: _config.theme == "textured-dark" || + _config.theme == "textured-light" + ? Colors.transparent + : null, + elevation: 4, // Add elevation for shadow + shadowColor: _config.theme == "textured-dark" || + _config.theme == "textured-light" + ? Colors.transparent + : null, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Intent Engine', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 16), // Add spacing if needed + Center( + child: Consumer<AppState>( + builder: (context, appState, _) { + return NLUEngineChoice( + onEngineChanged: (newEngine) { + changeIntentEngine( + context, newEngine); + print(newEngine); + }, + theme: _config.theme, + ); }, - theme: _config.theme, - ); - }, - ), + ), + ), + ], ), - ], + ), ), ), ), ), - ), + ], ), - SizedBox(width: 20), // Add spacing between buttons - - Flexible( - flex: 1, - child: ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), - child: Card( - color: _config.theme == "textured-dark" || + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + flex: 1, + child: ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Card( + color: _config.theme == "textured-dark" || _config.theme == "textured-light" - ? Colors.transparent - : null, - elevation: 4, // Add elevation for shadow - shadowColor: _config.theme == "textured-dark" || + ? Colors.transparent + : null, + elevation: 4, // Add elevation for shadow + shadowColor: _config.theme == "textured-dark" || _config.theme == "textured-light" - ? Colors.transparent - : null, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Intent Engine', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), + ? Colors.transparent + : null, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Speech-to-Text Model', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 16), // Add spacing if needed + Center( + child: Consumer<AppState>( + builder: (context, appState, _) { + return STTModelChoice( + onModelChanged: (newModel) { + changeSTTFramework( + context, newModel); + print(newModel); + }, + theme: _config.theme, + ); + }, + ), + ), + ], ), - SizedBox(height: 16), // Add spacing if needed - Center( - child: Consumer<AppState>( - builder: (context, appState, _) { - return NLUEngineChoice( - onEngineChanged: (newEngine) { - changeIntentEngine( - context, newEngine); - print(newEngine); + ), + ), + ), + ), + ), + + SizedBox(width: 20), // Add spacing between buttons + + Flexible( + flex: 1, + child: ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Card( + color: _config.theme == "textured-dark" || + _config.theme == "textured-light" + ? Colors.transparent + : null, + elevation: 4, // Add elevation for shadow + shadowColor: _config.theme == "textured-dark" || + _config.theme == "textured-light" + ? Colors.transparent + : null, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Online Mode', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 16), // Add spacing if needed + Center( + child: Consumer<AppState>( + builder: (context, appState, _) { + return OnlineModeChoice( + onModeChanged: (mode) { + toggleOnlineMode(context, mode); + print(mode); + }, + theme: _config.theme, + ); }, - theme: _config.theme, - ); - }, - ), + ), + ), + ], ), - ], + ), ), ), ), ), - ), + ], ), + + ], ), SizedBox(height: 15), |