--- title: "screenllm quickstart" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{screenllm quickstart} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` This vignette walks through the six-call workflow `screenllm` implements. Everything below runs on a laptop against a locally-served Ollama backend. If you don't yet have Ollama installed and the four default models pulled, `check_setup()` will tell you what's missing. ## 1. Verify setup ```{r, eval=FALSE} library(screenllm) check_setup() ``` ## 2. Load a corpus Any tibble with `title` and `abstract` columns works; `read_records()` also accepts CSV, XLSX, or RIS paths and normalises common column-name variations (Scopus, Web of Science, EndNote). The package ships with a 40-record toy dataset drawn from the *Community-Based Fisheries Management* (CBFM) review used in the manuscript, which we use here for demonstration. ```{r} library(screenllm) toy_path <- system.file("extdata", "toy_cbfm.csv", package = "screenllm") records <- read_records(toy_path) head(records[, c("id", "title")]) ``` ## 3. Define the inclusion criteria ```{r} criteria <- define_criteria( scope = "Articles potentially relevant to community-based fisheries management (CBFM) in Pacific Island contexts.", inclusions = c( "It is possible that the study includes a case study from a Pacific Island country (e.g. Fiji, Solomon Islands, Vanuatu, Papua New Guinea, Samoa, Tonga, or similar).", "It is possible that the study discusses fisheries and/or marine resource management.", "It is possible that the study discusses a community-based approach." ) ) print(criteria) ``` ## 4. Rank the corpus Real screening uses `default_ensemble()`, which talks to Ollama. For this vignette we use `backend_mock()` so the code runs without Ollama. ```{r} mock_ensemble <- custom_ensemble( models = c("gemma3:27b", "gpt-oss:20b"), replicates = 2, backend = backend_mock() ) ranked <- rank_records(records, criteria, ensemble = mock_ensemble, verbose = FALSE) head(ranked[, c("id", "title", "universal_best_score", "rank")]) ``` For a real run, swap the mock for the default: ```{r, eval=FALSE} ranked <- rank_records(records, criteria, ensemble = default_ensemble()) ``` ## 5. Plan the human screening set ```{r} plan <- plan_screening(ranked) plan ``` The `to_screen` element is the tibble of records the reviewer should inspect. Everything below the stopping point is treated as excluded. ## 6. Screen and report Interactive screening via the Shiny app: ```{r, eval=FALSE} launch_screening_app(plan, ranked, out_file = "screening_decisions.csv") ``` Offline screening (spreadsheet round-trip): ```{r, eval=FALSE} export_worksheet(plan, path = "to_screen.xlsx") # Reviewer fills in the human_decision column and saves as # 'to_screen_completed.xlsx'. decisions <- read_decisions("to_screen_completed.xlsx") ``` Summarise the run and surface any strong LLM-human disagreements as a manual audit queue: ```{r, eval=FALSE} report <- summarise_screening(ranked, decisions, plan = plan) print(report) disagreements <- audit_disagreements(ranked, decisions) disagreements ```