Spaces:
Running
Running
Update app.R
Browse files
app.R
CHANGED
|
@@ -1,58 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
library(shiny)
|
|
|
|
|
|
|
| 2 |
library(bslib)
|
| 3 |
-
library(
|
| 4 |
-
library(ggplot2)
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
df_num <- df |> select(where(is.numeric), -Year)
|
| 9 |
|
|
|
|
| 10 |
ui <- page_sidebar(
|
| 11 |
-
theme = bs_theme(bootswatch = "
|
| 12 |
-
title = "
|
| 13 |
sidebar = sidebar(
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
),
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
checkboxInput("
|
| 22 |
-
|
|
|
|
|
|
|
| 23 |
),
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
)
|
| 26 |
|
|
|
|
| 27 |
server <- function(input, output, session) {
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
})
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
)
|
| 43 |
-
|
| 44 |
-
if (input$show_margins) {
|
| 45 |
-
margin_type <- if (input$by_species) "density" else "histogram"
|
| 46 |
-
p <- p |> ggExtra::ggMarginal(
|
| 47 |
-
type = margin_type, margins = "both",
|
| 48 |
-
size = 8, groupColour = input$by_species, groupFill = input$by_species
|
| 49 |
-
)
|
| 50 |
}
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
}
|
| 57 |
|
| 58 |
-
|
|
|
|
|
|
| 1 |
+
# app.R: Shiny App for Generating Organizational Embeddings using LinkOrgs
|
| 2 |
+
|
| 3 |
+
# Required libraries
|
| 4 |
library(shiny)
|
| 5 |
+
library(LinkOrgs)
|
| 6 |
+
library(DT)
|
| 7 |
library(bslib)
|
| 8 |
+
library(shinyWidgets)
|
|
|
|
| 9 |
|
| 10 |
+
# Startup code
|
| 11 |
+
options(shiny.maxRequestSize = 30 * 1024^2)
|
|
|
|
| 12 |
|
| 13 |
+
# UI definition
|
| 14 |
ui <- page_sidebar(
|
| 15 |
+
theme = bs_theme(bootswatch = "flatly"),
|
| 16 |
+
title = "OrgEmbed: Generate Organizational Embeddings",
|
| 17 |
sidebar = sidebar(
|
| 18 |
+
radioButtons("input_mode", "Input Method:", choices = c("CSV Upload" = "csv", "Paste Text" = "text")),
|
| 19 |
+
conditionalPanel(
|
| 20 |
+
condition = "input.input_mode == 'csv'",
|
| 21 |
+
fileInput("file", "Upload CSV", accept = ".csv"),
|
| 22 |
+
selectInput("col_select", "Names Column:", choices = NULL)
|
| 23 |
+
),
|
| 24 |
+
conditionalPanel(
|
| 25 |
+
condition = "input.input_mode == 'text'",
|
| 26 |
+
textAreaInput("text_names", "Paste Names (one per line)", rows = 5)
|
| 27 |
),
|
| 28 |
+
numericInput("max_rows", "Max Rows to Process", value = 5000, min = 1),
|
| 29 |
+
selectInput("ml_version", "ML Version:", choices = c("v1", "v2", "v3", "v4"), selected = "v4"),
|
| 30 |
+
checkboxInput("include_original", "Include Original Names in Output", value = TRUE),
|
| 31 |
+
actionButton("process", "Generate Embeddings", class = "btn-primary"),
|
| 32 |
+
bs_tooltip(id = "text_names", title = "Names should be one per row, e.g., 'Apple Inc.'"),
|
| 33 |
+
actionButton("help_btn", "Help")
|
| 34 |
),
|
| 35 |
+
mainPanel(
|
| 36 |
+
DTOutput("preview"),
|
| 37 |
+
uiOutput("summary_card"),
|
| 38 |
+
downloadButton("download", "Download Embeddings CSV", class = "btn-success"),
|
| 39 |
+
uiOutput("progress_ui")
|
| 40 |
+
)
|
| 41 |
)
|
| 42 |
|
| 43 |
+
# Server logic
|
| 44 |
server <- function(input, output, session) {
|
| 45 |
+
|
| 46 |
+
# On startup, initialize backend
|
| 47 |
+
observe({
|
| 48 |
+
tryCatch({
|
| 49 |
+
BuildBackend(conda = "auto")
|
| 50 |
+
showNotification("Backend initialized successfully.")
|
| 51 |
+
}, error = function(e) {
|
| 52 |
+
showNotification("Backend setup failed—check internet or conda path.", type = "error")
|
| 53 |
+
})
|
| 54 |
})
|
| 55 |
+
|
| 56 |
+
# Reactive: Parse user input
|
| 57 |
+
input_df <- reactive({
|
| 58 |
+
req(input$process)
|
| 59 |
+
if (input$input_mode == "csv") {
|
| 60 |
+
req(input$file)
|
| 61 |
+
df <- read.csv(input$file$datapath, stringsAsFactors = FALSE)
|
| 62 |
+
updateSelectInput(session, "col_select", choices = colnames(df))
|
| 63 |
+
req(input$col_select)
|
| 64 |
+
if (!input$col_select %in% colnames(df) || nrow(df) == 0) {
|
| 65 |
+
showNotification("Invalid names column—please select again.", type = "error")
|
| 66 |
+
return(NULL)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
}
|
| 68 |
+
data.frame(names = df[[input$col_select]])
|
| 69 |
+
} else {
|
| 70 |
+
req(input$text_names != "")
|
| 71 |
+
names_list <- trimws(strsplit(input$text_names, "\n")[[1]])
|
| 72 |
+
names_list <- names_list[names_list != ""]
|
| 73 |
+
data.frame(names = names_list)
|
| 74 |
+
}
|
| 75 |
+
})
|
| 76 |
+
|
| 77 |
+
# Preview table
|
| 78 |
+
output$preview <- renderDT({
|
| 79 |
+
req(input_df())
|
| 80 |
+
datatable(head(input_df(), 10), options = list(pageLength = 10))
|
| 81 |
+
})
|
| 82 |
+
|
| 83 |
+
# Reactive: Embeddings result
|
| 84 |
+
embeddings <- reactiveVal(NULL)
|
| 85 |
+
|
| 86 |
+
# Trigger embedding generation
|
| 87 |
+
observeEvent(input$process, {
|
| 88 |
+
df <- input_df()
|
| 89 |
+
if (is.null(df) || nrow(df) == 0) {
|
| 90 |
+
showNotification("Please provide at least one valid name.", type = "error")
|
| 91 |
+
return()
|
| 92 |
+
}
|
| 93 |
+
if (nrow(df) > input$max_rows) {
|
| 94 |
+
showModal(modalDialog("Large dataset detected—processing may take time. Proceed?",
|
| 95 |
+
footer = tagList(modalButton("Cancel"), actionButton("proceed_large", "Proceed"))))
|
| 96 |
+
return()
|
| 97 |
+
}
|
| 98 |
+
process_embeddings()
|
| 99 |
+
})
|
| 100 |
+
|
| 101 |
+
# Handle large input confirmation
|
| 102 |
+
observeEvent(input$proceed_large, {
|
| 103 |
+
removeModal()
|
| 104 |
+
process_embeddings()
|
| 105 |
+
})
|
| 106 |
+
|
| 107 |
+
# Function to process embeddings with progress
|
| 108 |
+
process_embeddings <- function() {
|
| 109 |
+
withProgress(message = "Generating Embeddings", value = 0, {
|
| 110 |
+
incProgress(0.1, detail = "Parsing input...")
|
| 111 |
+
df <- head(input_df(), input$max_rows)
|
| 112 |
+
showNotification(sprintf("Processing %d names...", nrow(df)))
|
| 113 |
+
|
| 114 |
+
incProgress(0.2, detail = "Initializing model...")
|
| 115 |
+
tryCatch({
|
| 116 |
+
rep_x <- LinkOrgs(
|
| 117 |
+
x = df, y = NULL, by.x = "names",
|
| 118 |
+
algorithm = "ml", ml_version = input$ml_version,
|
| 119 |
+
ExportEmbeddingsOnly = TRUE
|
| 120 |
+
)
|
| 121 |
+
embed_df <- rep_x$embedx
|
| 122 |
+
if (!input$include_original) embed_df <- embed_df[, -1]
|
| 123 |
+
embeddings(embed_df)
|
| 124 |
+
incProgress(0.7, detail = "Generating embeddings...")
|
| 125 |
+
}, error = function(e) {
|
| 126 |
+
showNotification(sprintf("Error: %s", e$message), type = "error")
|
| 127 |
+
embeddings(NULL)
|
| 128 |
+
})
|
| 129 |
+
incProgress(1, detail = "Complete!")
|
| 130 |
+
})
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
# Summary card
|
| 134 |
+
output$summary_card <- renderUI({
|
| 135 |
+
req(embeddings())
|
| 136 |
+
card(
|
| 137 |
+
sprintf("Embeddings generated for %d names. Dimensions: %d.",
|
| 138 |
+
nrow(embeddings()), ncol(embeddings()))
|
| 139 |
+
)
|
| 140 |
+
})
|
| 141 |
+
|
| 142 |
+
# Download handler
|
| 143 |
+
output$download <- downloadHandler(
|
| 144 |
+
filename = "org_embeddings.csv",
|
| 145 |
+
content = function(file) {
|
| 146 |
+
req(embeddings())
|
| 147 |
+
write.csv(embeddings(), file, row.names = FALSE)
|
| 148 |
+
}
|
| 149 |
)
|
| 150 |
+
|
| 151 |
+
# Help modal
|
| 152 |
+
observeEvent(input$help_btn, {
|
| 153 |
+
showModal(modalDialog(
|
| 154 |
+
title = "Usage Guide",
|
| 155 |
+
"1. Upload/paste names.\n2. Click Process.\n3. Download embeddings for use in linkage models."
|
| 156 |
+
))
|
| 157 |
+
})
|
| 158 |
}
|
| 159 |
|
| 160 |
+
# Run the app
|
| 161 |
+
shinyApp(ui = ui, server = server)
|