Download R/render.R from fmegahed/decisions: direct link, hf CLI and curl.
- Browser
- Download file 6.07 kB
-
https://huggingface.co/spaces/fmegahed/decisions/resolve/main/R/render.R
- Command line
-
hf download hf://spaces/fmegahed/decisions/R/render.R
-
curl -L -o render.R https://huggingface.co/spaces/fmegahed/decisions/resolve/main/R/render.R
6.07 kB
| # Output builders: the dynamic inputs of the question (answer_rows, | |
| # reference_rows) and the parts of the outputs that the server renders | |
| # (spending meter, stats line, gallery, bundle files). The look is in | |
| # www/theme.css. They use sr(), upload_input() and IMAGE_ACCEPT of R/ui.R, | |
| # which R finds when a builder runs. | |
| # The answers of a question: a name and a description for each answer, with | |
| # buttons to add and remove answers. Yes / no has the fixed names true and | |
| # false, so it has no name inputs and no buttons. | |
| answer_rows <- function(question) { | |
| answers <- question$answers | |
| fixed <- question$type == "noul" | |
| range <- answer_range(question$type) | |
| rows <- purrr::map(seq_along(answers), \(i) { | |
| shiny::div( | |
| class = "answer-row", | |
| if (fixed) { | |
| shiny::span(class = "k", names(answers)[i]) | |
| } else { | |
| shiny::textInput(paste0("answer_name_", i), sr(paste("Name of answer", i)), names(answers)[i]) | |
| }, | |
| shiny::textAreaInput( | |
| paste0("answer_desc_", i), sr(paste("Description of answer", i)), answers[[i]], rows = 3 | |
| ), | |
| if (!fixed && length(answers) > range[1]) { | |
| shiny::actionButton( | |
| paste0("answer_remove_", i), shiny::span(`aria-hidden` = "true", "\u00d7"), | |
| class = "btn-quiet btn-icon", `aria-label` = paste("Remove answer", i) | |
| ) | |
| } | |
| ) | |
| }) | |
| shiny::tagList( | |
| shiny::div( | |
| class = "answer-head", `aria-hidden` = "true", | |
| shiny::span(if (fixed) "Answer" else "Name"), shiny::span("Description") | |
| ), | |
| rows, | |
| if (!fixed && length(answers) < range[2]) { | |
| shiny::actionButton("answer_add", "Add answer", class = "btn-quiet sm") | |
| } | |
| ) | |
| } | |
| # The id of the reference input of each answer: "ref_" and the clean name | |
| ref_input_id <- function(answers) { | |
| paste0("ref_", janitor::make_clean_names(answers, case = "none")) | |
| } | |
| # One row for each answer: its reference images and a file input. `srcs` is a | |
| # named list of image addresses. A score question takes no references. | |
| reference_rows <- function(question, srcs = list()) { | |
| if (question$type == "score") return(shiny::tagList()) | |
| answers <- names(question$answers) | |
| ids <- ref_input_id(answers) | |
| purrr::map(seq_along(answers), \(i) { | |
| thumbs <- purrr::imap(srcs[[answers[i]]] %||% character(), \(src, j) { | |
| shiny::img(src = src, alt = sprintf("Reference %d of %s", j, answers[i])) | |
| }) | |
| shiny::div( | |
| class = "ref-row", | |
| shiny::span(class = "k-plain", answers[i]), | |
| shiny::div( | |
| shiny::div(class = "thumbs", thumbs), | |
| upload_input( | |
| ids[i], sr(paste("References of", answers[i])), IMAGE_ACCEPT, | |
| multiple = TRUE, button = "Add" | |
| ) | |
| ) | |
| ) | |
| }) |> | |
| shiny::tagList() | |
| } | |
| # The spending meter of the visit | |
| spend_meter_ui <- function(spent, limit = LIMIT_SESSION) { | |
| shiny::div( | |
| class = "spend", | |
| shiny::div( | |
| class = "spend-row", shiny::span("This visit"), | |
| shiny::span(class = "mono", sprintf("$%.2f of $%.2f", spent, limit)) | |
| ), | |
| shiny::div( | |
| class = "meter", `aria-hidden` = "true", | |
| shiny::tags$i(style = sprintf("width:%.0f%%", min(100, 100 * spent / limit))) | |
| ) | |
| ) | |
| } | |
| # The stats line of answer_stats(); `note` is a short tag such as "Saved run" | |
| stats_ui <- function(stats, mode, note = NULL) { | |
| item <- \(value, label) { | |
| shiny::span(class = "stat", shiny::span(class = "v", value), shiny::span(class = "l", label)) | |
| } | |
| shiny::div( | |
| class = "stats", | |
| if (!is.na(stats$auc)) item(sprintf("%.2f", stats$auc), "AUC"), | |
| if (!is.na(stats$accuracy)) item(sprintf("%.2f", stats$accuracy), "accuracy"), | |
| item(stats$n, if (mode == "image") "images" else "texts"), | |
| item(sprintf("$%.3f", stats$cost), "cost"), | |
| if (!is.null(note)) shiny::span(class = "chip", note) | |
| ) | |
| } | |
| # The gallery: one tile for each row of answers_table(), with the probability | |
| # of the target as a number and a bar, the answer and the label. `src` holds | |
| # the address of the image of each row. | |
| gallery_ui <- function(table, target, src) { | |
| tiles <- purrr::map(seq_len(nrow(table)), \(i) { | |
| row <- table[i, ] | |
| p <- row$p_target | |
| caption <- c( | |
| if (!is.na(row$answer)) paste("answer", row$answer), | |
| if (!is.na(row$label)) paste("label", row$label) | |
| ) | |
| shiny::tags$figure( | |
| class = "tile", | |
| shiny::img(src = src[i], alt = alt_text(row, target), loading = "lazy"), | |
| shiny::tags$figcaption( | |
| if (is.na(p)) { | |
| shiny::div(class = "t", if (is.na(row$problem)) "No answer" else row$problem) | |
| } else { | |
| shiny::div( | |
| class = "p", sprintf("%.2f", p), | |
| shiny::span( | |
| class = "bar", `aria-hidden` = "true", | |
| shiny::tags$i(style = sprintf("width:%.0f%%", 100 * p)) | |
| ) | |
| ) | |
| }, | |
| shiny::div(class = "t", paste(caption, collapse = " \u00b7 ")) | |
| ) | |
| ) | |
| }) | |
| shiny::div(class = "gallery", tiles) | |
| } | |
| # The files of the bundle, with one line on each. `files` are the names in the | |
| # zip file (a folder ends in "/"). | |
| BUNDLE_FILE_TEXT <- c( | |
| "\\.R$" = "The code above.", | |
| "-setup\\.json$" = "Model, question, references and image settings. Read it with read_setup().", | |
| "-answers\\.csv$" = "Each input: answer, probabilities, label, tokens, seconds.", | |
| "^README\\.md$" = "Versions, date, install, key and citation. Import reopens the setup here.", | |
| "^references/?$" = "The reference images of the run.", | |
| "^data\\.csv$" = "Your texts. The code reads them." | |
| ) | |
| bundle_files_ui <- function(files, zip_name) { | |
| describe <- \(f) { | |
| hit <- purrr::detect_index(names(BUNDLE_FILE_TEXT), \(pattern) stringr::str_detect(f, pattern)) | |
| if (hit == 0) "" else BUNDLE_FILE_TEXT[[hit]] | |
| } | |
| shiny::tagList( | |
| shiny::h3( | |
| class = "eyebrow", shiny::tags$b(`aria-hidden` = "true", "\u203a"), " Bundle \u00b7 ", zip_name | |
| ), | |
| shiny::tags$ul( | |
| class = "files", | |
| purrr::map(files, \(f) { | |
| shiny::tags$li(class = "file", shiny::div(class = "n", f), shiny::div(class = "d", describe(f))) | |
| }) | |
| ) | |
| ) | |
| } | |