reading_idm / app.R
Martin Nguyen
Add more dependancy
2029588
raw
history blame
5.11 kB
# Load required libraries
library(caret)
library(dplyr)
library(shiny)
library(jsonlite) # For JSON conversion
# Use the system's Python executable or configure Python path
python_path <- "python3"
model= readRDS("model.rds")
# Sample data table to display
difficulty_table <- data.frame(
Grade = c("Grade 3", "Grade 4", "Grade 5", "Grade 6", "Grade 7", "Grade 8"),
`Mean Grade-Level Difficulty` = c(0.3, 0.431, 0.533, 0.611, 0.656, 0.7)
)
# Define UI for the Shiny application
ui <- fluidPage(
titlePanel("Reading comprehension difficulty prediction using BERT embeddings"),
fluidRow(
column(
width = 12,
h4("How does this work?"),
p("This app predicts average difficulty for an item. Difficulty can be interpreted using the table below. As the table shows, difficulty increases with grade level.
For example, an item of difficulty 0.3 is of average difficulty for Grade 3, an item of difficulty 0.4 is of average difficulty for Grade 4, and so on. Note that as difficulty increases, probability of correct answer reduces."),
# Display the table as a rendered output
h5(""),
tableOutput("difficultyTable"),
# Add external link for NWEA norms
p("Difficulty outputs are on a linear scale. The scale is defined to have mean difficulty of 0.3 at Grade 3 and mean difficulty 0.7 at Grade 8. This scale is based on grade level growth norms reported by ",
a("NWEA MAP Spring 2020 Reading Student Achievement Norms",
href = "https://www.nwea.org/uploads/MAP-Growth-Normative-Data-Overview.pdf", target = "_blank"))
)
),
# App UI elements
sidebarLayout(
sidebarPanel(
width = 12,
textInput("passage", "Passage", placeholder = "Enter passage text here"),
textInput("question", "Question Text", placeholder = "Enter question text here"),
textInput("correctAnswer", "Correct Answer", placeholder = "Enter the correct answer here"),
# Numeric input to ask how many incorrect options (distractors)
numericInput("numDistractors", "Number of Incorrect Options:", value = 1, min = 1, max = 10),
# Dynamic UI for the distractors
uiOutput("distractorsInputs"),
actionButton("printBtn", "Estimate difficulty")
),
mainPanel(
h3("Estimated difficulty"),
verbatimTextOutput("inputsOutput")
)
)
)
# Function to call Python script and get combined input
call_python_script <- function(passage, question, distractors) {
# Prepare input data as JSON
input_data <- toJSON(list(
Passage = passage,
QuestionText = question,
Distractors = distractors
), auto_unbox = TRUE)
# Call the Python script and capture the output
result <- system2(
command = python_path, # Python executable
args = c("bertembedtoy.py"), # Python script name
input = input_data, # Pass input data as JSON
stdout = TRUE # Capture script output
)
# Return the result from Python
return(result)
}
# Read the CSV data into a dataframe
#embedding_df <- read.csv(text =result)
# Define server logic
server <- function(input, output, session) {
# Reactive value to store predictions
predictions <- reactiveVal(NULL)
#df <- reactiveVal(data.frame())
# Render the difficulty table in the UI
output$difficultyTable <- renderTable({
difficulty_table
}, rownames = FALSE) # Avoid showing rownames in the table
# Dynamically generate text inputs for distractors based on user input
output$distractorsInputs <- renderUI({
n <- input$numDistractors # Get the number of distractors
if (is.null(n) || n <= 0) return(NULL) # No inputs if value is invalid
# Generate textInput fields dynamically
lapply(1:n, function(i) {
textInput(inputId = paste0("distractor", i),
label = paste("Wrong answer", i),
placeholder = paste("Enter wrong answer", i))
})
})
# Event triggered when the button is clicked
observeEvent(input$printBtn, {
distractors <- c(sapply(1:input$numDistractors, function(i) {input[[paste0("distractor", i)]]}))
# Combine the distractors into a single string
for (i in 1:length(distractors)) {
distractors[i]= paste0("wrong answer ",i,":", distractors[i])
}
distractors <- c(paste0("Correct answer:",input$correctAnswer), distractors)
distractors=paste(distractors, collapse = " \n")
print(distractors)
# Call the Python script and capture the dataframe
python_output <- call_python_script(input$passage,
input$question,
distractors)
result_vector <- as.numeric(unlist(strsplit(python_output, ",")))
result_vector= as.data.frame(t(result_vector) )
names(result_vector) = paste0("embed.bert", 1:768)
model_predictions= predict(model, result_vector)
predictions(model_predictions)
})
# Output predictions to the UI (or use it elsewhere)
output$inputsOutput <- renderPrint({
predictions()
})
}
# Run the Shiny App
shinyApp(ui = ui, server = server)