//TODO: save information persistently between sessions /// <summary> /// Based on last statistics it calculates the time the current interaction queue will take /// </summary> /// <returns>Time in seconds</returns> public static double TimeForecast() { // it should be run only if there are already some statistics about how much an interaction takes time float time = 0; foreach (var category in CategoryNInter) { if (averageTimeOfInteractionPerCategory.Exists(x => x.Item1 == category.Key)) { var categoryStat = averageTimeOfInteractionPerCategory.Find(x => x.Item1 == category.Key); // N interactions scheduled * ( Average time per category + Average pause time) time = time + category.Value * (categoryStat.Item2 + AveragePauseTime()); } else { SharedHelper.Log("Unacounted category in TimeForecast'" + category + "'"); } } // TODO: consider that reaction interactions take less pause time // TODO: reactions are not acounted (category "MakeStatement" for example) return(time); }
public static void SetAsUsed(string Name) { for (int i = 0; i < list.Count; i++) { if (list[i].Name == Name) { list[i].IsUsed = true; SharedHelper.Log("Uncertain question " + Name + " is set to used."); list[i].TimeLastAsked = DateTime.Now; if (allRepeatingQuestionsTimeoutsInMinutes.Count == 0) { GenerateRepeatingQuestionsTimeouts(); } list[i].TimeOutSeconds = allRepeatingQuestionsTimeoutsInMinutes.Dequeue() * 60; return; } } SharedHelper.LogError("Uncertain Fact Name '" + Name + "' not found in SetAsUsed!"); }
//TODO: addt the ability the N distribution to be changed over time float IBaseDistributions.GetNextInteactionPause(bool isReacting) { if (!isReacting) { //SharedHelper.Log("Pause time set following default distribution."); if (allInteractionPauses.Count == 0) { var normalDist = from seconds in Normal(3.7, 0.25) //default 4.7, 1 select seconds; string singleStringAllPauses = ""; for (var i = 0; i < 101; i++) { float value = (float)normalDist.Sample(); //sampling singleStringAllPauses = singleStringAllPauses + "," + value; allInteractionPauses.Enqueue(value); } } return(allInteractionPauses.Dequeue()); } else //if it is a response, we try to react quicker than starting a new interaction { float value = pauseUniformAfterReaction.Next(1, 2) / 10f; SharedHelper.Log("Pause time set as a reaction to question: " + value); return(value); } }
public bool AdjustProbVariablesDuringPlanning(int bufferedInteractionsCount) { bool regenerate = false; //1. About bot //exclude this action because there are no items for it if (ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current].Value != 0 && KorraModelHelper.GetItemsLeftForSubCategory(ActionsEnum.SharePureFactInfoAboutBot, ItemProviders) == 0) { //adjust pure facts probabilities: disable AboutBot and boost AboutUser ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current] = Prob(0); SharedHelper.LogWarning("Disabled all pure facts about bot, because there were no items."); //we re-inforce AboutUser so that it is stronger than Suggestion action if (ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current].Value > 0) { ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current] = ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Increased]; } regenerate = true; } //2. About User //exclude this action because there are no items for it if (ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current].Value != 0 && KorraModelHelper.GetItemsLeftForSubCategory(ActionsEnum.AskPureFactQuestionAboutUser, ItemProviders) == 0) { //adjust pure facts probabilities: disable AboutUser and boost AboutBot ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current] = Prob(0); SharedHelper.Log("Disabled all pure facts about user, because there were no items."); //we re-inforce AboutBot so that it is stronger than Suggestion action if (ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current].Value > 0) { ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current] = ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Increased]; } regenerate = true; } //3. Suggestions //if there are no Pure or Uncertain facts left then we boost suggestions bool noFactsLeft = (ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current].Value == 0 && ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current].Value == 0); if (noFactsLeft && ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current] != ProbVariables.Bot.PrMakeSuggestion[(int)PV.Default]) { ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current] = ProbVariables.Bot.PrMakeSuggestion[(int)PV.Default]; SharedHelper.Log("All pure facts used. PrMakeSuggestion changed to: " + ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current]); } //Keep suggestions decreased if there are more pure facts if (!noFactsLeft && ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current] != ProbVariables.Bot.PrMakeSuggestion[(int)PV.Descreased]) { SharedHelper.Log("PrMakeSuggestion changed decreased."); ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current] = ProbVariables.Bot.PrMakeSuggestion[(int)PV.Descreased]; } return(regenerate); }
//NOT ADAPTED for category and subcategory private static void DisableAcion(ref ItemProb <string>[] items, string actionToRemove) { SharedHelper.Log("Error category PureFact"); SharedHelper.Log("Action removed: " + actionToRemove.ToString()); items = items.Where(x => x.Item != actionToRemove).ToArray(); }
private Queue <string> GenerateActions(string[] disabledActions) { allActions.Clear(); #region Create a list of all possible actions ItemProb <string>[] items = { ItemProb(ActionsEnum.MakeSuggestion, ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current]), ItemProb(ActionsEnum.AskUncertanFactQuestion, ProbVariables.Bot.PrAskUncertanFactQuestion), ItemProb(ActionsEnum.AskPureFactQuestionAboutUser, ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current]), //to be packed as one ItemProb(ActionsEnum.SharePureFactInfoAboutBot, ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current]), //to be packed as one ItemProb(ActionsEnum.ChangeVisualAppearance, SharedHelper.GetProb(ProbVariables.Bot.ChangeVisualAppearance)), ItemProb(ActionsEnum.ExpressMentalState, SharedHelper.GetProb(ProbVariables.Bot.ExpressMentalState)), }; #endregion #region Disable actions - NOT ADAPTED for category and subcategory if (BotConfigShared.DisableAskQuestions) { SharedHelper.LogError("NOT ADAPTED for category and subcategory"); //two actions are removed //DisableAcion(ref items, ActionsEnum.AskPureFactQuestionAboutUser); //DisableAcion(ref items, ActionsEnum.AskUncertanFactQuestion); } //foreach (string da in disabledActions) //{ // DisableAcion(ref items, da); //} #endregion #region Sampling var Action = CategoricalF(items).Normalize(); SharedHelper.Log("Actions Histogram:\r\n" + Action.Histogram()); var actionDist = Action.ToSampleDist(); for (var i = 0; i < 100; i++) { string sample = actionDist.Sample(); allActions.Enqueue(sample); } #endregion return(allActions); }
public static void PrintSuggestionsProbabilities() { SharedHelper.Log("SUGGESTIONS Probabilities: \r\n" + "Suggest Go out: " + SharedHelper.GetProb(Bot.SuggestGoOut).Value.ToString() + "\r\n" + "Tell Joke: " + SharedHelper.GetProb(Bot.TellJoke).Value.ToString() + "\r\n" + "Suggest To WatchMovie: " + SharedHelper.GetProb(Bot.SuggestToWatchMovie).Value.ToString() + "\r\n" + "Tell Weather Forecast: " + SharedHelper.GetProb(Bot.TellWeatherForecast).Value.ToString() + "\r\n" //not used + "Suggest Listen To Song: " + Bot.PrSuggestListenToSong.Value.ToString() + "\r\n" ); }
public static void PrintActionsProbabilities() { SharedHelper.Log("ACTIONS Probabilities: \r\n" + "PrMakeSuggestion: " + Bot.PrMakeSuggestion[(int)PV.Current].Value.ToString() + "\r\n" + "PrAskUncertanFactQuestion: " + Bot.PrAskUncertanFactQuestion.Value.ToString() + "\r\n" + "PrAskPureFactQuestionAboutUser: "******"\r\n" + "PrSharePureFactInfoAboutBot: " + Bot.PrSharePureFactInfoAboutBot[(int)PV.Current].Value.ToString() + "\r\n" + "PrChangeVisualAppearance: " + SharedHelper.GetProb(Bot.ChangeVisualAppearance).Value.ToString() + "\r\n" + "PrExpressMentalState: " + SharedHelper.GetProb(Bot.ExpressMentalState).Value.ToString() + "\r\n" ); }
public static void SetProb(string Name, double newProb) { foreach (var q in list) { if (q.Name == Name) { SharedHelper.Log("'" + Name + "' prob variable has been updated from " + q.ProbVariable.RefValue.ProbOf(e => e == true).Value + " to " + newProb); q.ProbVariable.RefValue = BernoulliF(Prob(newProb)); } } }
public void BeforeAnalyseUserResponse(PureFact pfact) { //Here you change the responses that were encoded when creating this PureFact, even replace the function responsible for the answers. //This can be useful if you have new information about the user and its environment and this could not be encoded in advance. bool isAnswerd = pfact.IsAnswered; string responseValue = pfact.Value; //if (context.Phrases.IsYes(responseValue)) //{ // fact.StatementOnPositiveResponse = ""; //} SharedHelper.Log("Pure fact updated: " + pfact.Name); }
public static void PrintSummary() { string result = ""; int i = 0; foreach (var key in CategoryNInter.Keys) { i++; result += "|" + key + ": " + CategoryNInter[key] + Environment.NewLine; } SharedHelper.LogWarning("Interactions statistics: " + Environment.NewLine + result); TimeSpan time = TimeSpan.FromSeconds(TimeForecast()); SharedHelper.Log("Time (hh:mm) forecast scheduled interactions will take: " + time.ToString(@"hh\:mm")); }
public static void CoupleTwoInteractionsTogether(ref List <CommItem> list, string name1, string name2) { int p = 0; int itemNamePos1 = -1; int itemNamePos2 = -1; for (p = 0; p < list.Count; p++) { if (list[p].IsPureFact) { if (list[p].Name == name1) { itemNamePos2 = p; } if (list[p].Name == name2) { itemNamePos1 = p; } if (itemNamePos2 != -1 && itemNamePos1 != -1) { break; } } } if (itemNamePos2 != -1 && itemNamePos1 != -1 && (Math.Abs(itemNamePos2 - itemNamePos1) != 1)) { int pos1 = Math.Min(itemNamePos1, itemNamePos2); int pos2 = Math.Max(itemNamePos1, itemNamePos2); var temp = list[pos2]; list.RemoveAt(pos2); list.Insert(pos1 + 1, temp); SharedHelper.Log("Two interactions were coupled together: " + name1 + " and " + name2); //string DebugItem = ""; //int i = 0; //foreach (string e in interactions.Select(e => e.TextToSay)) //{ // i++; // DebugItem += "|" + i + ". " + e; //} //SharedHelper.LogWarning("Interactions list: " + DebugItem); } }
public static void SetJokeAsUsed(string Name) { for (int i = 0; i < jokes.Count; i++) { if (jokes[i].Name == Name) { jokes[i].IsUsed = true; SharedHelper.Log("Joke '" + Name + "' is set to used. Joke text: '" + jokes[i].Text + "'"); FlagsShared.RequestSavePersistentData = true; return; } } SharedHelper.LogError("Joke '" + Name + "' not found in SetJokeAsUsed!"); }
private Queue <string> GenerateSuggestions() { #region Update suggstions based on new information allSuggestions.Clear(); ProbVariables.PrintSuggestionsProbabilities(); var Suggestion = CategoricalF( //Multiple times ItemProb(SuggestionsEnum.ListenToSong, ProbVariables.Bot.PrSuggestListenToSong), //Can be multiple times ItemProb(SuggestionsEnum.TellJoke, SharedHelper.GetProb(ProbVariables.Bot.TellJoke)), //we can say several jokes in a row, no need to reduce the probability of saying a joke //A few times per evening ItemProb(SuggestionsEnum.GoOut, SharedHelper.GetProb(ProbVariables.Bot.SuggestGoOut)), //A few times per evening ItemProb(SuggestionsEnum.WatchMovie, SharedHelper.GetProb(ProbVariables.Bot.SuggestToWatchMovie)), //NOT USED! //Once per Morning (current day) / evening (tomorrow) //ItemProb(Suggestions.TellWeatherForecast, ProbVariables.PrTellWeatherForecast), ItemProb(SuggestionsEnum.DoSport, SharedHelper.GetProb(ProbVariables.Bot.SuggestDoSport)) ).Normalize(); SharedHelper.Log("Suggestion Histogram:\r\n" + Suggestion.Histogram()); var suggestionDist = Suggestion.ToSampleDist(); for (var i = 0; i < 100; i++) { string sample = suggestionDist.Sample(); allSuggestions.Enqueue(sample); } #endregion return(allSuggestions); }
//public override void Add(Item fact) //{ // //check if ID already exists // bool existsAlready = list.Any(cus => cus.Name == fact.Name); // if (existsAlready) // SharedHelper.Log("Pure Fact with this Name already exists: '" + fact.Name + "'. Second one was ignored."); // else // list.Add((PureFact)fact); //} //public override PureFact[] GetAll() //{ // return list.ToArray(); //} //public static void SetAsUsed(string name) //{ // SetAsUsed(name, true); //} //public static void SetAsUsed(string name, bool isUsed) //{ // for (int i = 0; i < list.Count; i++) // { // if (list[i].Name == name) // { // SharedHelper.Log("Set used to " + isUsed + " : " + list[i].Name); // list[i].IsUsed = isUsed; // return; // } // } // SharedHelper.LogError("Pure Fact Name '" + name + "' not found in SetAsUsed!"); //} public void MarkForSaving(string name) { SharedHelper.Log("Marking for saving: " + name); for (int i = 0; i < items.Count; i++) { if (items[i].Name == name) { if (items[i].Name != "UserMovieYesterday") { FlagsShared.RequestSavePersistentData = true; } return; } } SharedHelper.LogError("Pure Fact Name '" + name + "'not found in MarkForSaving!"); }
public bool ModelUpdate(TimeSpan timeSinceStart, bool isPureFactUpdated, bool isUncertainFactUpdated) { bool regenerationRequested = false; if (!isInitialized) { SharedHelper.LogError("Not initialized."); return(regenerationRequested); } //Execute triggers that perform inference and update probabilistic variables foreach (var trigger in ModelTriggers) { int oldExecuteCount = trigger.TriggeredCount; if ( (trigger is IModelUpdateTrigger) && ( (trigger.IsTimeBased || (isPureFactUpdated && trigger.IsUserResponseBased)) && ((trigger.IsOneTimeTrigger && trigger.TriggeredCount == 0) || !trigger.IsOneTimeTrigger) ) ) { //Updating model regenerationRequested = ((IModelUpdateTrigger)trigger).Process(isPureFactUpdated, timeSinceStart, this); if (trigger.TriggeredCount > oldExecuteCount) { SharedHelper.Log("Trigger executed: '" + trigger.ToString() + "'"); } } } if (isUncertainFactUpdated) { regenerationRequested = true; } return(regenerationRequested); }
public void InteractionsUpdate(TimeSpan timeSinceStart, int interactionsDoneSinceStart, ref Queue <CommItem> interactions) { if (!isInitialized) { SharedHelper.LogError("Not initialized."); return; } //Evaluate triggers that represent 'Surprise' for example //These triggers evaluate a model and add a new interaction foreach (var trigger in ModelTriggers) { int oldExecuteCount = trigger.TriggeredCount; if (trigger is IModelEvaluateTrigger && ( (trigger.IsOneTimeTrigger && trigger.TriggeredCount == 0) || (!trigger.IsOneTimeTrigger) ) ) { CommItem?newInteraction = ((IModelEvaluateTrigger)trigger).Process(this); if (newInteraction != null) { if (interactions.Peek().Name != newInteraction.Value.Name) { KorraModelHelper.InsertFirstInteractionList(ref interactions, newInteraction.Value); //TODO: this custom code should be moved to another place if (trigger is VideoGameSurpriseTrigger) { FlagsShared.RequestSurpriseExpression = true; } SharedHelper.Log("Trigger executed: '" + trigger.ToString() + "'"); } } } } }
public static void AddInteractionTimeElapsed(string category, float time) { bool categoryExists = averageTimeOfInteractionPerCategory.Exists(x => x.Item1 == category); if (!categoryExists) { averageTimeOfInteractionPerCategory.Add(new Tuple <string, float, int>(category, time, 1)); } else { var itemOld = averageTimeOfInteractionPerCategory.First(x => x.Item1 == category); //Calculate Incremental Averaging : https://math.stackexchange.com/questions/106700/incremental-averageing Tuple <string, float, int> itemNew = new Tuple <string, float, int>(category, itemOld.Item2 + (time - itemOld.Item2) / (itemOld.Item3 + 1), itemOld.Item3 + 1); averageTimeOfInteractionPerCategory.Remove(itemOld); averageTimeOfInteractionPerCategory.Add(itemNew); } SharedHelper.Log("The elapsed time of an interaction of type '" + category + "' is: " + time); }
public void LoadAll(ItemManager[] providers) { this.providers = providers; LoadAllPureFacts(); LoadAllUncertainFacts(); LoadAllJokes(); //PureFacts must be already loaded because some PureFacts are used as jokes LoadAllSongs(); LoadSports(); LoadMovies(); int count = UncertainFacts.GetList().Count + JokesProvider.GetAll().Count(); foreach (var manager in providers) { count += manager.Count(); } SharedHelper.Log("All items loaded: " + count + " " + BotConfigShared.Language); }
public static void RemoveInteraction(ref List <CommItem> list, int position, ItemManager[] managers) { if (position < list.Count) { CommItem tobeRemoved = list[position]; ItemManager manager = managers.SingleOrDefault(x => x.Is(tobeRemoved)); if (manager != null) { list.RemoveAt(position); manager.SetAsPlanned(tobeRemoved.Name, false); SharedHelper.Log("Interaction removed: " + tobeRemoved.Name); } else { SharedHelper.LogError("Could not remove interaction from list:" + tobeRemoved.Name + " " + tobeRemoved.Category + " " + tobeRemoved.SubCategory); } } else { SharedHelper.LogError("Could not remove interaction at position: " + position); } }
public bool Process(bool isPureFactUpdated, TimeSpan timeSinceStart, IKorraAIModel model) { //SharedHelper.LogWarning("Inside movies trigger"); #region Get Fact Manager PureFacts pfManager = (PureFacts)model.ItemProviders.SingleOrDefault(x => x is PureFacts); if (pfManager == null) { SharedHelper.LogError("No manager in Process in MoviesModelUpdateTrigger."); return(false); } #endregion var context = model.GetContext(); PureFact factJob = (PureFact)pfManager.GetByName("UserHasJob"); PureFact factWatchedMovieYesterday = (PureFact)pfManager.GetByName("UserMovieYesterday"); if (factJob == null || factWatchedMovieYesterday == null) { SharedHelper.LogError("factJob or factWatchedMovieYesterday is NULL in MoviesModelUpdateTrigger."); } if (!IsTimeOfDayUpdated && !isPureFactUpdated) { return(false); } SharedHelper.Log("Inside MoviesModelUpdateTrigger"); var oldSuggestToWatchMovie = SharedHelper.GetProb(ProbVariables.Bot.SuggestToWatchMovie).Value; //TODO: this model can be replaced by a Bayesian network, because of the too many IFs //if no job or weekend if ((factJob.IsAnswered && context.BasePhrases.IsNo(factJob.Value)) || StatesShared.IsWeekend) { ProbVariables.Bot.SuggestToWatchMovie = BernoulliF(Prob(0.18)); //KorraBaseHelper.Log("Prob SuggestToWatchMovie changed to: 0.18, no job or weekend"); } else if (factJob.IsAnswered && context.BasePhrases.IsYes(factJob.Value)) //if has job { #region working and evening if (StatesShared.IsEvening /*TODO: or after work hours*/) { //has NOT watched movie yesterday (is working and evening) if (factWatchedMovieYesterday.IsAnswered && context.BasePhrases.IsNo(factJob.Value)) { ProbVariables.Bot.SuggestToWatchMovie = BernoulliF(Prob(0.18)); //KorraBaseHelper.Log("Prob SuggestToWatchMovie changed to: 0.18, evening"); } //has watched movie yesterday (is working and evening) else if (factWatchedMovieYesterday.IsAnswered && context.BasePhrases.IsYes(factJob.Value)) { ProbVariables.Bot.SuggestToWatchMovie = BernoulliF(Prob(0.12)); // KorraBaseHelper.Log("Prob SuggestToWatchMovie changed to: 0.12. Watched movie yesterday."); } } #endregion else //is working and not evening, no time because working and not evening { ProbVariables.Bot.SuggestToWatchMovie = BernoulliF(Prob(0.05)); //KorraBaseHelper.Log("Prob SuggestToWatchMovie changed to: 0.05"); } } else //has job is unknown { ProbVariables.Bot.SuggestToWatchMovie = BernoulliF(Prob(0.10)); } double newSuggestToWatchMovie = SharedHelper.GetProb(ProbVariables.Bot.SuggestToWatchMovie).Value; if (Math.Abs(oldSuggestToWatchMovie - newSuggestToWatchMovie) > (1 / 1000)) { executedCount = executedCount + 1; SharedHelper.Log("Prob SuggestToWatchMovie changed from " + oldSuggestToWatchMovie + " to: " + SharedHelper.GetProb(ProbVariables.Bot.SuggestToWatchMovie)); //return new ModelUpdateTriggerReturn { IsTriggered = true, IsResamplingRequired = true, Value = "" }; return(true); //re-sampling requested } else { return(false); //no re-sampling } }