-
Notifications
You must be signed in to change notification settings - Fork 2
/
SmartGrading_Application.R
188 lines (152 loc) · 6.82 KB
/
SmartGrading_Application.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
## © 2023 Samuel Tobler
# Run this R Shiny application either from your R Studio or use the following link:
# https://stobler.shinyapps.io/smartgrading
# Load necessary libraries
library(shiny)
library(shinythemes)
library(httr)
# Define UI
ui <- fluidPage(
theme = shinythemes::shinytheme("flatly"),
includeCSS("www/style.css"),
tags$head(tags$style(HTML('.js-irs-0 .irs-single, .js-irs-0 .irs-bar-edge, .js-irs-0 .irs-bar {
background: #58B99D;
border-top: 1px solid #58B99D ;
border-bottom: 1px solid #58B99D ;}
/* changes the colour of the number tags */
.irs-from, .irs-to, .irs-single { background: #58B99D }'
))),br(),
titlePanel("👾 GenAI Smart Grading"),br(),
h2("Instructions", style = "padding-top: 0;margin-top: 0px"), # Reduce top padding
p("This application allows you to use generative AI models to evaluate provided (student)
answers to your questions. Additionally, you can give sample solutions and instruction guidelines
(i.e., how many points should be assigned for a specific answer) and indicate how many points can be achieved."),
p("To get started, upload a .csv file containing student answers and specify the required parameters below.
Once all values are inputted, click on the grading button to utilize generative AI for evaluation."),
p("Please note that it is essential to double-check the provided scores with the scores you would have assigned."),
br(),
h3("Data upload"),
br(),
fileInput("data", "Upload your CSV file with student answers",
multiple = FALSE, accept = c("text/csv", "text/comma-separated-values,text/plain",".csv"), width = "100%"),
checkboxInput("header", "Header", TRUE),
# Input: Select separator ----
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
h5("Data inspection", style = "font-weight: bold;"),
tableOutput("contents"),
br(),
h3("Parameter input"),
h5("Temperature", style = "font-weight: bold;"),
sliderInput("temperature", label = NULL, min = 0,
max = 1, value = 0.7, step = 0.1, width = "100%"),
h5("API key", style = "font-weight: bold;"),
textInput("apiKey", label = NULL, value = "sk-XXXXXXXXXXXXXXXXXXXXXXXXXX", width = "100%"),
h5("GPT model", style = "font-weight: bold;"),
textInput("model", label = NULL, value = "gpt-4o", width = "100%"),
h5("Question", style = "font-weight: bold; padding-bottom: 0; margin-bottom: 0"),
textInput("question", "", value = "Enter here the posed question", "", width = "100%"),
h5("Sample solution", style = "font-weight: bold; padding-bottom: 0; margin-bottom: 0"),
textInput("solution", "", value = "Enter here the sample solution", "", width = "100%"),
h5("Maximal number of achievable points", style = "font-weight: bold;"),
numericInput("points", label = NULL, min = 0, value = 2, width = "100%"),
h5("Instruction", style = "font-weight: bold; padding-bottom: 0; margin-bottom: 0"),
textInput("instruction", "", value = "Enter here the grading instruction", "", width = "100%"),
h5("File name (optional)", style = "font-weight: bold;"),
textInput("name", label = NULL, value = "Question_", width = "100%"), # Added text input for file part
br(),
h3("Performance evaluation"),br(),
actionButton("calculateBtn", "Generate Scores",icon = icon("gear", lib = "font-awesome", style = "padding-right: 5px;")),
br(),br(),
tableOutput("resultOutput"),
br(),
h3("Dowload evaluations"),br(),
downloadButton("downloadBtn", "Download Scores", icon = icon("download", lib = "font-awesome", style = "padding-right: 5px;")),
br(),br(),br(),br(),
HTML("<p style = 'color: #BABFC4;'>© 2023 Samuel Tobler
</p>"),br(),br(),
# ) #main
#),
)
# Define server logic
server <- function(input, output, session) {
output$contents <- renderTable({
req(input$data)
tryCatch(
{
df <- read.csv(input$data$datapath,
header = input$header,
sep = input$sep)
},
error = function(e) {
stop(safeError(e))
}
)
return(df[1:3,])
}, colnames = F)
makeAPICall <- function(answer) {
response <- tryCatch({
POST(
url = "https://api.openai.com/v1/chat/completions",
add_headers(Authorization = paste("Bearer", input$apiKey)),
content_type_json(),
encode = "json",
body = list(
model = input$model,
temperature = input$temperature,
messages = list(
list(
"role" = "system",
"content" = paste("You have to give points to a user-generated answer based on the following information:
This is the question the user tried to answer:", input$question,
"This is the correct answer: ", input$solution,
"The exercise gives", input$points, "Points, and
this is your instruction how to give points:", input$instruction,
"Only return the number of points. If there is no answer, return 0 points. "
)
),
list(role = "user", content = answer)
)
)
)
}, error = function(e) {
showNotification("Error processing the request. Please try again later.", type = "error")
return(NULL)
})
return(response)
}
calculateResult <- eventReactive(input$calculateBtn, {
dfx <- read.csv(input$data$datapath, header = input$header, sep = input$sep)
score <- numeric(nrow(dfx))
withProgress(message = 'Evaluating...', value = 0.01, {
for(i in 1:nrow(dfx)) {
response <- makeAPICall(dfx[i, 1]) # Assuming the student answers are in the first column
if (!is.null(response)) {
result <- httr::content(response)$choices[[1]]$message$content
score[i] <- as.numeric(trimws(result))
}
incProgress(1/nrow(dfx))
}
})
results <- data.frame(Answer = dfx[, 1], Score = as.numeric(score))
return(results)
})
# Display calculation result on the page
output$resultOutput <- renderTable({
req(input$calculateBtn) # Show result only after the button is clicked
calculateResult()
})
output$downloadBtn <- downloadHandler(
filename = function() {
paste(input$name, '_Evaluation_', Sys.Date(), '.csv', sep='')
},
content = function(file) {
write.csv(calculateResult(), file)
}
)
}
# Run the application
shinyApp(ui, server)