diff --git a/DESCRIPTION b/DESCRIPTION index 6da9636..f90084a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: AzimuthAPI Title: Pan-Azimuth Web API Interface -Version: 0.1.0 +Version: 0.2.0 Authors@R: person("Satija", "Lab", email = "satijalabnygc@gmail.com", role = c("aut", "cre")) Description: An R package providing an interface to the Pan-Azimuth Web API for single-cell RNA sequencing analysis. diff --git a/R/api_interface.R b/R/api_interface.R index 2541349..f4656c6 100644 --- a/R/api_interface.R +++ b/R/api_interface.R @@ -2,7 +2,7 @@ #' #' @param url API endpoint URL #' @param file_path Path to the file being processed -#' @return NULL +#' @return Logical indicating success (TRUE) or failure (FALSE) #' @importFrom curl new_handle handle_setform curl_fetch_stream #' @importFrom jsonlite fromJSON #' @export @@ -21,6 +21,8 @@ listen_to_progress <- function(url, file_path, ...) { # Buffer to store partial messages buffer <- "" + # Track whether processing succeeded + success <- NULL # Process the SSE stream in real time curl_fetch_stream( @@ -51,6 +53,11 @@ listen_to_progress <- function(url, file_path, ...) { tryCatch({ parsed <- fromJSON(json_message) + # Check for success flag + if (!is.null(parsed$success)) { + success <<- parsed$success + } + # Print messages based on content if (!is.null(parsed$message)) { cat(parsed$message, "\n") @@ -78,6 +85,8 @@ listen_to_progress <- function(url, file_path, ...) { } } ) + + return(success) } #' Download output file from the API diff --git a/R/cloud.R b/R/cloud.R index 5096c0b..e78d09e 100644 --- a/R/cloud.R +++ b/R/cloud.R @@ -2,23 +2,23 @@ #' #' @param object Seurat object to annotate #' @param assay Name of the assay to use (default: 'RNA') -#' @param ip IP address of the cloud server (default: '34.222.135.233') +#' @param ip Hostname or IP address of the cloud server (default: 'azimuthapi.satijalab.org') #' @param port Port number for the API (default: 5000) #' @return Annotated Seurat object #' @importFrom httr POST GET upload_file content status_code #' @importFrom RCurl url.exists #' @export -CloudAzimuth <- function(object = object, assay = 'RNA', ip = '34.222.135.233', +CloudAzimuth <- function(object = object, assay = 'RNA', ip = 'azimuthapi.satijalab.org', port = 5000, ...) { message("Running Pan-Human Azimuth on the cloud!") layer_name <- 'data' data <- LayerData(object, assay = assay, layer = layer_name) - # check if data has been normalized, just using the first 5 cells + # if data exists, check if normalized, just using the first 5 cells # throw an error if large values, or all integer values, are detected - data_check <- data[,1:min(5,ncol(data))] - if ((max(data_check) > 15) || isTRUE(all.equal(data_check,floor(data_check)))) { + data_check <- if (!IsMatrixEmpty(data)) data[,1:min(5,ncol(data))] else NULL + if (is.null(data_check) || (max(data_check) > 15 || isTRUE(all.equal(data_check, floor(data_check))))) { stop("Please run NormalizeData on the data before running Azimuth") } @@ -46,13 +46,22 @@ CloudAzimuth <- function(object = object, assay = 'RNA', ip = '34.222.135.233', object[[i]] <- srt[[i]] } - # Copy metadata columns except QC ones + # Copy metadata columns except QC ones, matching by cell names md_cols <- grep("nCount_RNA|nFeature_RNA", colnames(srt@meta.data), invert = TRUE, value = TRUE) + + # Only update metadata for cells that were processed (objects can have multiple assays w/ cell IDs formatted differently) + assay_cells <- Cells(srt) + for (i in md_cols) { - object@meta.data[, i] <- srt@meta.data[, i] + # Initialize column with NA only if it doesn't exist + if (!i %in% colnames(object@meta.data)) { + object@meta.data[, i] <- NA + } + # Update only the processed cells + object@meta.data[assay_cells, i] <- srt@meta.data[assay_cells, i] } Idents(object) <- 'azimuth_label' @@ -68,7 +77,12 @@ CloudAzimuth <- function(object = object, assay = 'RNA', ip = '34.222.135.233', process_rds_file <- function(api_base_url, file_path, ...) { progress_url <- paste0(api_base_url, "/process_rds") cat("Uploading file and listening for updates...\n") - listen_to_progress(progress_url, file_path, ...) + success <- listen_to_progress(progress_url, file_path, ...) + + if (isFALSE(success)) { + stop("Processing failed on the server. Please check the error messages above.") + } + output_file_name <- gsub("\\.rds$", "_ANN.rds", basename(file_path)) download_url <- paste0(api_base_url, "/download_output?output_file=/tmp/", output_file_name)