public LoaderPlugin() { try { Bot = SimlBot.Instance; VA.Components.Add(Bot); //Perform tick based on Virtual Assistant timer. VA.Timer.Tick += (sender, args) => { Bot.Timer.PerformTick(); }; SimlBot.Logger.LogReceived += (sender, args) => { VirtualAssistant.Instance.Logger.Log(args.Level, args.Message); }; var vaSettings = VA.SettingsManager["VA"]; var simlSettingsPath = Path.Combine(vaSettings["Bot-Directory"].Value, "Commands", "Settings"); SimlFileManager = new SimlFileManager(simlSettingsPath); //When the VA is closing, save both MainUser and Bot settings to files. VA.Closing += (sender, eventArgs) => { SimlFileManager.SaveDocument(UserSettingsFileId, Bot.MainUser.Settings.GetDocument()); SimlFileManager.SaveDocument(BotSettingsFileId, Bot.Settings.GetDocument()); }; Bot.Learning += (sender, learningEventArgs) => { SaveLearned(LearnedFilePath, learningEventArgs.Document); }; Bot.Memorizing += (sender, memorizingEventArgs) => { SaveLearned(MemorizedFilePath, memorizingEventArgs.Document); }; VirtualAssistant.Instance.Logger.LogReceived += (sender, args) => { //Trigger the 'Error-Logged' event only if the level is greater than or equal to 'Warn' if (args.Level >= LogLevel.Warn) { Bot.Trigger("Error-Logged"); } }; VA.Architecture = "SIML"; //Whenever the VA receives a message, the Bot generates a response. VA.Interaction.MessageReceived += (sender, args) => { if (args.Handled) { return; } //Message type is UserMessage if (args.Message.Type == MessageType.UserMessage) { ChatResult result; if (args.Message.User.IsMain) { result = Bot.Chat(args.Message.Text); } else { result = Bot.Chat(args.Message.Text, Bot.CreateUser(args.Message.User.ID)); } var response = new Response { Text = result.BotMessage, Hint = result.Hint, Rank = result.LastResponse.Rank, User = args.Message.User }; args.Handled = true; VA.Interaction.Respond(response); } //Message is an Event message else if (args.Message.Type == MessageType.EventMessage) { if (args.Message.User.IsMain) { Bot.Trigger(args.Message.Text); } else { Bot.Trigger(args.Message.Text, Bot.CreateUser(args.Message.User.ID)); } args.Handled = true; } }; //Whenever the VA receives a textual response, use speech synthesis. VA.Interaction.ResponseReceived += (sender, args) => { if (!args.Response.User.IsMain) { return; } var rank = Enum.Parse(typeof(ResponseRank), VA.SettingsManager["Speech"]["Speech-Rank"].Value); if (args.Response.Rank >= (ResponseRank)rank) { VA.Speech.Synthesizers.Current?.Speak(args.Response.Text); } }; //Whenever the MainUser receives an Event Message, send a response to the VA. Bot.MainUser.ResponseReceived += (sender, args) => { var response = new Response { Text = args.Result.BotMessage, Hint = args.Result.Hint, Rank = args.Result.LastResponse.Rank }; VA.Interaction.Respond(response); }; Emotion currentEmotion = null; //When the Bot emotion changes set the currentEmotion. Bot.EmotionChanged += (sender, args) => { currentEmotion = args.Current; }; //Whenver the current SpeechRecognizer is changed. VA.Speech.Recognizers.RecognizerChanged += (sender, args) => { args.Recognizer.SpeechRecognized += (o, eventArgs) => { var defaultConfidence = 0.5d; if (VA.SettingsManager.Contains("Speech")) { var speechSettings = VA.SettingsManager["Speech"]; if (speechSettings.Contains("Speech-Confidence")) { var confidence = speechSettings["Speech-Confidence"].Value; double outValue; if (double.TryParse(confidence, out outValue)) { defaultConfidence = outValue; } } } if (eventArgs.Confidence >= defaultConfidence) { VA.Interaction.SendMessage(eventArgs.Text); } }; }; //Whenever the Current Speech Synthesizer is changed. VA.Speech.Synthesizers.SynthesizerChanged += (sender, args) => { args.Synthesizer.VisemeReached += (sender1, visemeArrivedEventArgs) => { VA.Avatar.Morph(visemeArrivedEventArgs.Viseme.ToString(), visemeArrivedEventArgs.Duration); }; //If currentEmotion is not null then at the end of speech switch to expression. VA.Speech.Synthesizers.Current.SpeakCompleted += (sender1, args1) => { try { if (currentEmotion == null) { return; } var emotionElement = SynUtility.Xml.RemoveAllNamespaces(currentEmotion.GetElement()); var durationAttribute = emotionElement.Attribute("duration"); var infoElement = emotionElement.Element("info"); var duration = 2000; if (durationAttribute != null) { duration = Convert.ToInt32(durationAttribute.Value); } var simlEmotion = infoElement?.Element("Emotion"); var expressionAttribute = simlEmotion?.Attribute("Expression"); if (expressionAttribute != null) { VA.Avatar.Morph(expressionAttribute.Value, TimeSpan.FromMilliseconds(duration)); } //Reset currentEmotion to null. currentEmotion = null; } catch (Exception exception) { VA.Logger.Error(exception); } }; }; Project = new ProjectManager(); //Path to the functional Commands knowledge-base. var commandsSimlProject = Path.Combine(vaSettings["Bot-Directory"].Value, "Commands.simlproj"); //Path to the General chat knowledge-base. var generalSimlProject = Path.Combine(vaSettings["Bot-Directory"].Value, "General.simlproj"); if (File.Exists(commandsSimlProject)) { Project.LoadFromFile(commandsSimlProject); } if (File.Exists(generalSimlProject)) { Project.LoadFromFile(generalSimlProject); } var externalBotDirectory = vaSettings["External-Bot-Directory"].Value; var externalPluginsDirectory = vaSettings["External-Plugins-Directory"].Value; //if External-Bot-Directory is set then load external Bot Project. if (!string.IsNullOrEmpty(externalBotDirectory)) { LoadProjectFromDirectory(externalBotDirectory); } // Load Knowledge-Base into Bot. //All projects are loaded at this point. Project.LoadIntoBot(Bot); //Add the 'MainUser' Settings so the VA can work with User variables. VA.SettingsManager.Add(Bot.MainUser.Settings); //Create textual choices. foreach (var item in Bot.Examples) { VA.Interaction.Choices.Add(new ChoiceItem("Siml-Bot", item.Value)); } //Load Important Plugins first. AddPlugin(typeof(BotPlugin)); AddPlugin(typeof(UserPlugin)); //Now load external Plugins. LoadPlugins(vaSettings["Plugins-Directory"].Value); //If 'External-Plugins-Directory' is set then load plugins from directory if (!string.IsNullOrEmpty(externalPluginsDirectory)) { LoadPlugins(externalPluginsDirectory); } VA.SettingsManager.SettingsSaved += (sender, args) => { var settingsWindow = VA.Components.Get <SettingsWindow>(); var settingsSavedMessage = !string.IsNullOrEmpty(args.Settings["Settings-Saved-Message"].Value) ? args.Settings["Settings-saved-message"].Value : Settings["Settings-Saved"].Value; settingsWindow.DisplayMessage(args.Settings.Name, settingsSavedMessage); }; VA.Timer.Tick += (sender, args) => { Bot.Timer.PerformTick(); }; //Trigger Greet-User event when the VA is ready. VA.Loaded += (sender, args) => { Bot.Trigger("Load-Time-Event"); Bot.Trigger("Greet-User"); }; //Reset all plugin settings if the VA is reset. VA.Resetting += (sender, args) => { ResetAllPlugins(); }; Bot.Adapters.Add(new CreditAdapter()); Bot.Adapters.Add(new AgentAdapter()); Bot.Adapters.Add(new TextWindowAdapter()); Bot.Adapters.Add(new HelpWindowAdapter()); AddWelcomeWidget(); } catch (Exception exception) { VA.Logger.Error(exception); } }