/// <summary> /// Loaded event for the chat window. /// /// Initialization happens here /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ChatWindow_Loaded(object sender, RoutedEventArgs e) { // Enumerate all currently downloaded topics to allow the user to // select which ones to use topics = (from topic in TopicChooser.Topics(order) select new SelectableTopic(topic)).ToList(); // If there are no topics, then we have to bail out here and wait for the // user to download some. if (topics.Count == 0) return; // Create and initialize the first topic markov = TopicChooser.GetRandomTopicAsync(order).Result; markov.MaxSentenceLength = sentenceLength; ChatView.CurrentTopic = markov.CurrentTopic; ChatView.CurrentSubtopic = markov.CurrentSubtopic; // Make the AI start the conversation so we don't start off // with an empty conversation box. Status = "ArmchairIntellectual is typing..."; Message.IsEnabled = false; ChatView.AiSay(await markov.GetUnpromptedSentenceAsync()); Message.IsEnabled = true; Message.Focus(); Status = "Ready."; }
/// <summary> /// Get the next topic from a predefined list of topic names /// </summary> /// <param name="input"></param> /// <param name="currentTopic"></param> /// <param name="topics"></param> /// <returns></returns> public static MarkovChain GetNextTopic(string input, MarkovChain currentTopic, List<string> topics) { string existingTopic = FindExistingTopicName(input, topics); if (existingTopic != null) return new MarkovChain(existingTopic, currentTopic.Order); return currentTopic; }
/// <summary> /// Change the Markov order by copying the state of the current /// Markov chain into a new object with a different order. /// </summary> /// <param name="markov"></param> /// <param name="order"></param> /// <returns></returns> public static MarkovChain UpdateMarkovOrder(MarkovChain markov, int order) { var probabilityHash = TextCorpus.GetProbabilityHashAsync(markov.CurrentTopic, order).Result; var newMarkov = new MarkovChain(probabilityHash, markov.CurrentTopic); newMarkov.CurrentSubtopic = markov.CurrentSubtopic; newMarkov.MaxSentenceLength = markov.MaxSentenceLength; return newMarkov; }
/// <summary> /// Given a current Markov chain and user input, get the next /// major topic (or return the current one if no switch is to be made). /// </summary> /// <param name="input"></param> /// <param name="currentTopic"></param> /// <returns></returns> public static async Task<MarkovChain> GetNextTopicAsync(string input, MarkovChain currentTopic) { // Check if there is an existing topic that matches the user's input string existingTopic = FindExistingTopicName(input, currentTopic.Order); if (existingTopic != null) return new MarkovChain(existingTopic, currentTopic.Order); // If not, get the name of the new article that should be downloaded string newTopic = FindNewTopicName(input); if (newTopic != null) { try { // Load a new Markov chain from the new topic name return await MarkovChain.CreateMarkovChainAsync(newTopic, currentTopic.Order); } catch (CorpusLoadFailedException) { return currentTopic; } } return currentTopic; }
/// <summary> /// Click event for the send button. /// /// Fires when the user sends a message to the AI /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void Send_Click(object sender, RoutedEventArgs e) { // immediately disable the send function to wait for the AI's response. Message.IsEnabled = false; // Let the user know work is happening Status = "ArmchairIntellectual is typing..."; // Find the next topic of conversation, if any if (anyTopic == true) markov = await TopicChooser.GetNextTopicAsync(Message.Text, markov); else markov = TopicChooser.GetNextTopic(Message.Text, markov, (from topic in topics where topic.Selected == true select topic.TopicName).ToList()); // Asynchronously process the user's input to find the new seed and subtopic. await markov.ProcessInputAsync(Message.Text); // Update the chatview's conversation boxes ChatView.CurrentTopic = markov.CurrentTopic; ChatView.CurrentSubtopic = markov.CurrentSubtopic; // Add the user's text to the new subtopic box, rather than the one that // was active when the message was sent ChatView.UserSay(Message.Text); // Asynchronously generate a sentence in response ChatView.AiSay(await markov.GetSentenceAsync()); // Give control of the chat back to the user. Status = "Ready."; Message.Text = ""; Message.IsEnabled = true; Message.Focus(); }
/// <summary> /// Updates the markov chain after a change of options has taken place /// </summary> private async Task UpdateMarkovChainAsync() { // If the program started and there were no existing topics, // the markov chain will be null and we should now just pick one. if (markov == null) { markov = await TopicChooser.GetRandomTopicAsync(order); } else { // If the user removed the topic that was currently in use, // the AI has to abandon that topic and pick a new one. if ((from t in topics where t.TopicName.ToLower() == markov.CurrentTopic.ToLower() select t).Count() == 0) markov = await TopicChooser.GetRandomTopicAsync(order); } // Update markov settings. markov.MaxSentenceLength = sentenceLength; MarkovChain.UpdateMarkovOrder(markov, order); }