Nothing
#* @apiTitle occupationMeasurement API
#* @apiDescription An API to allow the interactive coding of occupations based on free text job descriptions. The flow of coding is to first get a list of [suggestions](#/occupationMeasurement/get_suggestions) based on a free form text answer. Once one of these suggestions has been picked, its id can be used to retrieve potential [followup questions](#/occupationMeasurement/get_followup_questions). Using the suggestion's id and the followup_questions's answer id, the [final codes](#/occupationMeasurement/get_final_codes) can be queried. Please also refer to the official package documentation for a more detailed description of the API coding flow.
#* @apiVersion 0.0.4-beta
#* @apiTag "occupationMeasurement" Endpoints related to the coding of occupations.
#* @apiTag "experimental" API endpoints where major changes are likely.
#* @apiTag "other" Other endpoints of the API.
# Note: Plumber annotations are always on one line per type
# (irrespective of number of characters), as it seems that plumber has some
# issues with parsing multi-line annotations.
#* Generate occupation coding suggestions based on a users free text input.
#*
#* We recommend displaying the "task" and optionally the "task_description" to
#* respondents.
#*
#* @param text:character The raw text input from the user.
#* @param suggestion_type:character Which type of suggestion to use / provide. Possible options are "auxco-1.2.x" and "kldb-2010".
#* @param num_suggestions:integer The maximum number of suggestions to show. This is an upper bound and less suggestions may be returned.
#* @param aggregate_score_threshold:float The total sum of the scores of the suggestions has to be higher than this threshold for suggestions to be returned.
#* @tag "occupationMeasurement"
#* @get /v1/suggestions
function(text, suggestion_type = "auxco-1.2.x", num_suggestions = 5, aggregate_score_threshold = 0.02) {
# Properly convert arguments types (since they are always passed as string)
if (!is.null(num_suggestions)) {
num_suggestions <- as.integer(num_suggestions)
}
if (!is.null(aggregate_score_threshold)) {
aggregate_score_threshold <- as.numeric(aggregate_score_threshold)
}
suggestions <- occupationMeasurement::get_job_suggestions(
text = text,
suggestion_type = suggestion_type,
num_suggestions = num_suggestions,
aggregate_score_threshold = aggregate_score_threshold
)
return(suggestions)
}
#* Get the next followup question to show after a suggestion has been selected
#*
#* Or a previous followup question has just been answered.
#*
#* @param suggestion_id:character The id of the selected suggestion.
#* @param followup_question_id:character The `question_id` of the followup question that has just been answered.
#* @param followup_answer_id:integer The answer_id of the chosen answer to the followup question that has just been answered.
#* @tag "occupationMeasurement"
#* @get /v1/next_followup_question
#* @serializer unboxedJSON
function(res, suggestion_id, followup_question_id = "", followup_answer_id = "") {
# Sanitize input
if (suggestion_id == "" || is.null(suggestion_id)) {
suggestion_id <- NA
}
if (followup_question_id == "" || is.null(followup_question_id)) {
followup_question_id <- NA
}
if (is.null(followup_answer_id)) {
followup_answer_id <- NA
} else {
followup_answer_id <- as.integer(followup_answer_id)
}
# Validate input
if (is.na(suggestion_id)) {
res$status <- 400
return(list(error = "It is mandatory to provide a suggestion_id"))
}
if (xor(is.na(followup_question_id), is.na(followup_answer_id))) {
res$status <- 400
return(list(error = "Specifying only one of followup_answer_id or followup_question_id is not supported"))
}
all_followup_questions <- occupationMeasurement::get_followup_questions(
suggestion_id = suggestion_id
)
next_followup_question <- NULL
response_finished <- list(
coding_is_finished = TRUE
)
if (is.na(followup_question_id)) {
# No follow_question_id provided -> return the first followup question
next_followup_question <- all_followup_questions[[1]]
} else {
# A followup_question_id has been provided, find the question that has been answered
all_question_ids <- sapply(all_followup_questions, function(x) x$question_id)
answered_question_index <- seq_along(all_question_ids)[all_question_ids == followup_question_id]
if (length(answered_question_index) == 0) {
res$status <- 400
return(list(error = paste("Can't find question_id", followup_question_id," in followup questions for suggestion", suggestion_id)))
}
answered_followup_question <- all_followup_questions[[answered_question_index]]
# Determine whether the answer already finished coding
if (answered_followup_question$answers$coding_is_finished[[as.numeric(followup_answer_id)]]) {
return(response_finished)
} else {
# Else return the next followup question
next_followup_question <- all_followup_questions[[answered_question_index + 1]]
}
}
# When there are no followup_questions coding is finished
if (length(all_followup_questions) == 0) {
return(response_finished)
}
# Return the found followup question
if (!is.null(next_followup_question)) {
return(next_followup_question)
} else {
# Return an error upon unexpected behaviour
res$status <- 500
return(list(error = "Unexpected error when trying to find the next followup question."))
}
}
#* Get the final occupation codes
#*
#* This is only needed when using auxco based suggestions, to get the final responses based on answers to followup questions.
#*
#* @param suggestion_id:character The id of the selected suggestion
#* @param followup_answers:[numeric] An Array / a list of integers corresponding to answers to followup questions in exact order.
#* @param isco_skill_level:character Standardized level of skill the respondent indicated (corresponding to ISCO-08 manual).
#* @param isco_supervisor_manager:character Standardized level of management / supervision the respondent indicated (corresponding to ISCO-08 manual).
#* @param:[character] code_type Which type of codes should be returned. Multiple codes can be returned at the same time. Supported types of codes are "isco_08" and "kldb_10". Defaults to "isco_08" and "kldb_10".
#* @tag "occupationMeasurement"
#* @get /v1/final_codes
#* @serializer unboxedJSON
function(suggestion_id,
followup_answers = numeric(),
isco_skill_level = NA_character_,
isco_supervisor_manager = NA_character_,
code_type = c("isco_08", "kldb_10")) {
# Generate named list of followup answers
question_ids <- occupationMeasurement::get_followup_questions(
suggestion_id = suggestion_id
) |>
sapply(function(x) x$question_id)
followup_answers <- as.list(followup_answers)
if (!is.null(followup_answers) && length(followup_answers) > 0) {
length(question_ids) <- length(followup_answers)
names(followup_answers) <- question_ids
}
# Generate list of standardized_answer_levels
standardized_answer_levels <- list()
if (isco_skill_level != "" && !is.na(isco_skill_level)) {
standardized_answer_levels$isco_skill_level <- isco_skill_level
}
if (isco_supervisor_manager != "" && !is.na(isco_supervisor_manager)) {
standardized_answer_levels$isco_supervisor_manager <- isco_supervisor_manager
}
final_codes <- occupationMeasurement::get_final_codes(
suggestion_id = suggestion_id,
# Converting to numeric here, to match the format used in the auxco
followup_answers = followup_answers,
standardized_answer_levels = standardized_answer_levels,
code_type = code_type
)
return(final_codes)
}
#* Default API root response showing the API status and a link to its documentation.
#* @tag "other"
#* @get /
#* @serializer html
function() {
"<html>
<body>
<h1>occupationMeasurement Api</h1>
<p>Status: \U0001f7e2 Running</p>
<p><a href=\"/__docs__/\">Documentation</a></p>
</body>
</html>"
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.