--- title: "Strand AI Platform Quickstart" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Strand AI Platform Quickstart} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE ) ``` This vignette walks end-to-end through the [Strand AI Platform](https://strandai.com) API using the `strand` R package: upload a Whole Slide Image (WSI), submit a Lattice H&E to multiplex protein inference job, wait for completion, and pull results back as a `SpatialExperiment`. > The chunks below set `eval = FALSE` so the vignette renders cleanly on CRAN > without network access. To run them yourself, mint an API key at > `app.strandai.com/settings/api-keys`, set `STRAND_API_KEY`, and run > interactively. ## 1. Set up ```{r} library(strandai) # Reads STRAND_API_KEY; for local development: # Sys.setenv(STRAND_BASE_URL = "http://localhost:3000") client <- strand_client() client ``` ## 2. Upload a slide `strand_upload_file()` initiates a resumable session and streams the file to GCS in 8 MiB chunks. The final PUT triggers automatic ingest, and the function polls only until the upload status leaves `uploading`. Dimensions can remain unavailable while preprocessing continues; estimation reports when the sample is ready. ```{r} upload <- strand_upload_file(client, "slide.svs", progress = TRUE) upload ``` ## 3. Work with samples `strand_samples_list()` lists owned samples, the public cohort, or both. Every item has an `ownership` discriminator and a canonical `id` accepted by `strand_samples_get()`. Owned detail includes recent inference jobs; public detail contains public geometry and marker channels without job history. ```{r} page <- strand_samples_list(client, scope = "all") sample <- strand_samples_get(client, page$items[[1]]$id) if (sample$ownership == "mine") { sample <- strand_patch_sample( client, sample$id, name = "Baseline biopsy", tags = c("baseline", "responding"), mpp = 0.26 ) } ``` ## 4. Price credits A dry run performs the same validation and pricing as submission without reserving credits or creating a job. ```{r} markers <- c("CD3", "CD8", "Ki67", "PD-L1") est <- strand_predict(client, upload$id, markers, dry_run = TRUE) message( est$patch_count, " patches x ", est$marker_count, " markers = ", est$estimated_credits, " credits" ) message("org balance: ", est$org_balance) ``` ## 5. Submit and wait Submission **atomically reserves** the estimated credits in the same database transaction that creates the job. If your org has insufficient credits, you'll see a `strand_insufficient_credits_error`. ```{r} job <- strand_predict(client, upload$id, markers) status <- strand_job_wait(job, progress = TRUE) stopifnot(status$status == "completed") ``` ### Choosing a model Pass `model = "v0.7"` to select the current dispatchable Lattice version explicitly. Omitting `model` lets the platform pick the same current default. Older `"v0.4"` and `"v0.5"` labels can appear on historical jobs but are sunset for new submissions. ```{r} job <- strand_predict(client, upload$id, markers, model = "v0.7") ``` ### Fire-and-forget For long pipeline runs, pass `wait = FALSE` to `strand_run()` to return the job handle as soon as upload + submit complete. The job continues server-side — you can poll or download later from the same or a fresh process. ```{r} job <- strand_run(client, "slide.svs", markers, wait = FALSE) # ...later: status <- strand_job_wait(job) spe <- strand_download_results(job) ``` ## 6. Download as SpatialExperiment `strand_download_results()` walks the OME-Zarr result store via the API-key-authenticated proxy and assembles the channels into a [`SpatialExperiment`](https://bioconductor.org/packages/SpatialExperiment). Rows are markers, columns are pixels; spatial coordinates are stored in `spatialCoords(spe)`. For very large slides, supply `path = "out/"` to mirror the zarr store to disk and read selectively with `Rarr` instead. ```{r} spe <- strand_download_results(job) spe ``` ## Error handling ```{r} tryCatch( strand_predict(client, upload$id, markers), strand_insufficient_credits_error = function(e) { message("Need ", e$required, " more credits.") } ) ```