Back to the Spell Book

Chat with yeoda


A chatbot trained on Jedi wisdom, this is.

Given a question, it finds the most relevant answer with the force.

Blah blah blah

1. Load libraries

library(ggplot2)
library(plotly)
library(dplyr)
library(readr)
library(stringdist)
library(stringr)

2. Input and response data

Input

input_data <- read_lines("input.txt")
head(input_data)
## [1] "Fear leads to anger"              "Anger leads to hate"             
## [3] "Hate leads to suffering"          "Patience you must have"          
## [5] "The greatest teacher, failure is" "Pass on what you have learned"
length(input_data)
## [1] 82

response

response_data <- read_lines("response.txt")
head(response_data)
## [1] "Anger leads to hate"                                     
## [2] "Hate leads to suffering"                                 
## [3] "The dark side that is."                                  
## [4] "Train yourself to let go of everything you fear to lose."
## [5] "The greatest teacher, failure is."                       
## [6] "Jedi must share knowledge."
length(response_data)
## [1] 82

Ensure 1 input to 1 response

if (length(input_data) != length(response_data)) {
  stop("The Dark side lurks: input and response must have the same number of lines.")
}

3. Create dataset

yeoda_quotes <- tibble(
  input = input_data,
  response = response_data)
head(yeoda_quotes)
## # A tibble: 6 × 2
##   input                            response                                     
##   <chr>                            <chr>                                        
## 1 Fear leads to anger              Anger leads to hate                          
## 2 Anger leads to hate              Hate leads to suffering                      
## 3 Hate leads to suffering          The dark side that is.                       
## 4 Patience you must have           Train yourself to let go of everything you f…
## 5 The greatest teacher, failure is The greatest teacher, failure is.            
## 6 Pass on what you have learned    Jedi must share knowledge.

4. The force responds

Using the force to find the best response.

get_best_response <- function(user_input) {
  if (is.null(user_input) || user_input == "") {
    return("Clouded, your question is. Ask again, you should.")
  }
  
  user_input <- tolower(user_input)
  
  # normalise contractions
  user_input <- str_replace_all(user_input, "how's", "how is")
  user_input <- str_replace_all(user_input, "who's", "who is")
  user_input <- str_replace_all(user_input, "what's", "what is")
  
  # some manual responses
  manual_responses <- list(
    "what is a jedi" = "A Jedi, a guardian of peace, is. A lightsabre they wield, but wisdom they value more.",
    "what is the force" = "The Force, an energy field it is. Binds the galaxy together, it does.",
    "how is the force" = "Strong today, the Force feels. But sleepy after boba tea, it gets.",
    "who is yeoda" = "Wise and small, yeoda is. Green, also.",
    "is the dark side stronger" = "No! Quicker, easier, more seductive it is.",
    "how to become a jedi" = "Train hard, you must. Fear, anger, and hate, avoid.",
    "where is the force" = "Everywhere, the Force is. Surrounds us, it does.",
    "who is the greatest teacher" = "Experience, the greatest teacher is, excluding the Force (and me).",
    "what is wisdom" = "Wisdom, knowing what you do not know, it is.",
    "tell me a joke" = "Why did Anakin cross the road? To get to the Dark Side."
  )
  
  for (question in names(manual_responses)) {
    if (str_detect(user_input, fixed(question))) {
      return(manual_responses[[question]])
    }
  }
  
  # ensure data are available for chatting
  if (length(yeoda_quotes$input) == 0) {
    return("Error: No chatbot data found.")
  }
  
  # similarity matching to get responses
  scores <- stringdist::stringsim(user_input, yeoda_quotes$input, method = "cosine")
  best_match_index <- which.max(scores)
  
  if (is.na(best_match_index) || scores[best_match_index] < 0.7) {
    return("Clouded, your question is. Ask again, you should.")
  }
  
  return(yeoda_quotes$response[best_match_index])
}

5. Enable the chat

Function for interactive chat with the force.

chat_with_yeoda <- function() {
  cat("Welcome, young Padawan. Speak, you may. Type 'exit' to leave.\n")

  while (TRUE) {
    # get user input
    user_input <- readline(prompt = "You: ")

    # exit condition
    if (tolower(user_input) == "exit") {
      cat("yeoda: Leave, you must. May the Force be with you!\n")
      break
    }

    # get best response
    best_response <- get_best_response(user_input)

    # display yeoda's response
    cat("yeoda:", best_response, "\n")
  }
}

6. Chat with yeoda

Welcome, young Padawan. Speak to the jedi master in the console, you may :-)

To leave, type “exit”.

# chat_with_yeoda()