| Title: | LLM Integration Framework for BFH Packages |
|---|---|
| Description: | AI-driven insights and text generation for healthcare quality improvement. Provides LLM chat interface, RAG (Retrieval Augmented Generation) integration with knowledge stores, and SPC-specific improvement suggestions. Designed for standalone use with BFHcharts or integration in Shiny applications. |
| Authors: | Johan Reventlow [aut, cre] |
| Maintainer: | Johan Reventlow <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.2.0 |
| Built: | 2026-06-04 14:14:24 UTC |
| Source: | https://github.com/johanreventlow/BFHllm |
Builds Ragnar knowledge store from markdown documents. This is typically run once during package development, not at runtime.
bfhllm_build_knowledge_store(docs_path, output_path)bfhllm_build_knowledge_store(docs_path, output_path)
docs_path |
Character string, path to markdown documents directory |
output_path |
Character string, path to output store directory |
Requirements:
ragnar package installed
GOOGLE_API_KEY or GEMINI_API_KEY set (for embeddings)
Markdown documents in docs_path
Process:
Initialize Ragnar store with Gemini embeddings
Read markdown files
Chunk documents (markdown-aware)
Generate embeddings via Gemini API
Build BM25 search index
Persist store to output_path
invisible(NULL)
## Not run: # Build store (typically run in data-raw/build_ragnar_store.R) bfhllm_build_knowledge_store( docs_path = "inst/spc_knowledge", output_path = "inst/ragnar_store" ) ## End(Not run)## Not run: # Build store (typically run in data-raw/build_ragnar_store.R) bfhllm_build_knowledge_store( docs_path = "inst/spc_knowledge", output_path = "inst/ragnar_store" ) ## End(Not run)
Concatenates multiple prompt components into a single prompt string. Useful for building complex prompts from modular pieces.
bfhllm_build_prompt(..., sep = "\n\n")bfhllm_build_prompt(..., sep = "\n\n")
... |
Character strings or named list, prompt components |
sep |
Character string, separator between components (default: "\n\n") |
Named Arguments: If using named arguments, names are ignored (only values are used).
NULL Handling: NULL components are automatically filtered out.
Whitespace: Leading/trailing whitespace is trimmed from each component before concatenation.
Character string with concatenated prompt
## Not run: # Build SPC analysis prompt system_msg <- "You are an SPC analysis expert." context <- "Chart type: run chart. Data points: 24." question <- "What does stable variation indicate?" prompt <- bfhllm_build_prompt( system_msg, context, question, sep = "\n\n" ) # With conditional components prompt <- bfhllm_build_prompt( "Analyze this chart:", if (has_signals) "Signals detected: Run of 8", "Suggest actions." ) ## End(Not run)## Not run: # Build SPC analysis prompt system_msg <- "You are an SPC analysis expert." context <- "Chart type: run chart. Data points: 24." question <- "What does stable variation indicate?" prompt <- bfhllm_build_prompt( system_msg, context, question, sep = "\n\n" ) # With conditional components prompt <- bfhllm_build_prompt( "Analyze this chart:", if (has_signals) "Signals detected: Run of 8", "Suggest actions." ) ## End(Not run)
Creates a generic cache object for storing LLM responses. Cache uses hash-based keys and enforces TTL (time-to-live) on retrieval.
bfhllm_cache_create(ttl_seconds = 3600)bfhllm_cache_create(ttl_seconds = 3600)
ttl_seconds |
Numeric, time-to-live in seconds (default: 3600 = 1 hour) |
Cache Structure: Each cache entry is stored as:
list(value = response_text, timestamp = Sys.time())
TTL Enforcement:
Cache entries are checked on retrieval. If age exceeds TTL, NULL is returned
(cache miss). Expired entries are not automatically removed - use clear()
for manual cleanup.
Thread Safety: Cache is stored in an R environment. Not thread-safe - use separate cache instances per thread/process.
Cache object (environment) with methods:
Retrieve cached value, or NULL if not found/expired
Store value with current timestamp
Remove all cached entries
Return cache statistics
## Not run: # Create cache with 1 hour TTL cache <- bfhllm_cache_create(ttl_seconds = 3600) # Store value cache$set("key1", "response text") # Retrieve value value <- cache$get("key1") # Check stats stats <- cache$stats() print(stats$entries) # 1 # Clear cache cache$clear() ## End(Not run)## Not run: # Create cache with 1 hour TTL cache <- bfhllm_cache_create(ttl_seconds = 3600) # Store value cache$set("key1", "response text") # Retrieve value value <- cache$get("key1") # Check stats stats <- cache$stats() print(stats$entries) # 1 # Clear cache cache$clear() ## End(Not run)
Creates a cache object that stores data in Shiny session's userData. Cache is automatically cleaned up when session ends.
bfhllm_cache_shiny(session, ttl_seconds = 3600)bfhllm_cache_shiny(session, ttl_seconds = 3600)
session |
Shiny session object |
ttl_seconds |
Numeric, time-to-live in seconds (default: 3600) |
Storage Location:
Cache is stored in session$userData$bfhllm_cache as a reactiveVal.
This ensures cache is session-scoped and automatically cleaned on disconnect.
Automatic Cleanup:
Registers session$onSessionEnded() callback to clear cache when user
disconnects, preventing memory leaks.
Idempotent: Safe to call multiple times - will reuse existing cache if already initialized.
Use Cases:
Shiny applications using BFHllm for AI suggestions
Reduce API calls and costs within a user session
Consistent responses for repeated queries
Cache object with same interface as bfhllm_cache_create()
## Not run: # In Shiny server function server <- function(input, output, session) { # Create session cache (call once per session) cache <- bfhllm_cache_shiny(session, ttl_seconds = 3600) # Use cache with LLM calls observeEvent(input$generate_btn, { key <- bfhllm_generate_cache_key( prompt = input$prompt_text, model = "gemini-2.5-flash-lite" ) # Check cache first cached <- cache$get(key) if (!is.null(cached)) { output$result <- renderText(cached) return() } # Make API call response <- bfhllm_chat(input$prompt_text) # Cache response cache$set(key, response) output$result <- renderText(response) }) } ## End(Not run)## Not run: # In Shiny server function server <- function(input, output, session) { # Create session cache (call once per session) cache <- bfhllm_cache_shiny(session, ttl_seconds = 3600) # Use cache with LLM calls observeEvent(input$generate_btn, { key <- bfhllm_generate_cache_key( prompt = input$prompt_text, model = "gemini-2.5-flash-lite" ) # Check cache first cached <- cache$get(key) if (!is.null(cached)) { output$result <- renderText(cached) return() } # Make API call response <- bfhllm_chat(input$prompt_text) # Cache response cache$set(key, response) output$result <- renderText(response) }) } ## End(Not run)
Generic chat function with provider abstraction, caching, circuit breaker protection, and response validation.
bfhllm_chat( prompt, model = NULL, provider = "gemini", timeout = NULL, max_chars = NULL, cache = NULL, validate = TRUE )bfhllm_chat( prompt, model = NULL, provider = "gemini", timeout = NULL, max_chars = NULL, cache = NULL, validate = TRUE )
prompt |
Character string, prompt to send to LLM |
model |
Character string, model identifier (default: from config) |
provider |
Character string, provider name (default: "gemini") |
timeout |
Numeric, timeout in seconds (default: from config) |
max_chars |
Integer, maximum response length (default: from config) |
cache |
Cache object from |
validate |
Logical, whether to validate and sanitize response (default: TRUE) |
Features:
Provider abstraction (currently Gemini, extensible to others)
Circuit breaker protection (opens after threshold failures)
Optional caching (reduces API calls and costs)
Response validation (HTML removal, markdown balancing)
Timeout handling
Configuration:
Default values are read from configuration (set via bfhllm_configure() or
environment variables). Function arguments override configuration.
Caching:
If cache is provided, responses are cached based on prompt + model hash.
Cache hits avoid API calls entirely. Use bfhllm_cache_create() for
standalone or bfhllm_cache_shiny() for Shiny apps.
Error Handling:
Returns NULL on errors (timeout, API failure, validation failure).
Check circuit breaker status with bfhllm_circuit_breaker_status().
Character string with LLM response, or NULL on error
## Not run: # Basic usage Sys.setenv(GOOGLE_API_KEY = "your_api_key") response <- bfhllm_chat("Explain SPC in 2 sentences") print(response) # With caching cache <- bfhllm_cache_create() response1 <- bfhllm_chat("What is variation?", cache = cache) response2 <- bfhllm_chat("What is variation?", cache = cache) # Cache hit # Custom configuration response <- bfhllm_chat( "Analyze this data pattern", model = "gemini-2.0-flash-exp", timeout = 15, max_chars = 500 ) # In Shiny app server <- function(input, output, session) { cache <- bfhllm_cache_shiny(session) observeEvent(input$generate_btn, { response <- bfhllm_chat( input$prompt, cache = cache ) output$result <- renderText(response) }) } ## End(Not run)## Not run: # Basic usage Sys.setenv(GOOGLE_API_KEY = "your_api_key") response <- bfhllm_chat("Explain SPC in 2 sentences") print(response) # With caching cache <- bfhllm_cache_create() response1 <- bfhllm_chat("What is variation?", cache = cache) response2 <- bfhllm_chat("What is variation?", cache = cache) # Cache hit # Custom configuration response <- bfhllm_chat( "Analyze this data pattern", model = "gemini-2.0-flash-exp", timeout = 15, max_chars = 500 ) # In Shiny app server <- function(input, output, session) { cache <- bfhllm_cache_shiny(session) observeEvent(input$generate_btn, { response <- bfhllm_chat( input$prompt, cache = cache ) output$result <- renderText(response) }) } ## End(Not run)
Quick check if chat functionality is available (API key configured, packages installed, etc.)
bfhllm_chat_available()bfhllm_chat_available()
Logical, TRUE if chat is available
## Not run: if (bfhllm_chat_available()) { response <- bfhllm_chat("Hello") } else { message("Chat not available - check API key") } ## End(Not run)## Not run: if (bfhllm_chat_available()) { response <- bfhllm_chat("Hello") } else { message("Chat not available - check API key") } ## End(Not run)
Performs RAG-enhanced LLM chat by retrieving relevant knowledge, injecting
it as context, and calling the LLM. Combines bfhllm_query_knowledge() and
bfhllm_chat().
bfhllm_chat_with_rag( question, context = NULL, store = NULL, top_k = 5, method = "hybrid", ... )bfhllm_chat_with_rag( question, context = NULL, store = NULL, top_k = 5, method = "hybrid", ... )
question |
Character string, the question to answer |
context |
Character string, additional context (optional). Will be combined with RAG-retrieved context. |
store |
ragnar_store object (optional). If NULL, loads from cache/default. |
top_k |
Integer, number of knowledge chunks to retrieve (default: 5) |
method |
Character string, RAG search method: "hybrid", "semantic", "bm25" |
... |
Additional arguments passed to |
Workflow:
Query knowledge store for relevant chunks
Format retrieved context
Build structured prompt with RAG context + user context + question
Call LLM via bfhllm_chat()
Graceful Degradation: If RAG query fails, proceeds with non-RAG chat (uses only user-provided context). Logs warning but does not fail.
Prompt Structure:
Uses bfhllm_create_structured_prompt() to organize:
System: (optional, via ... or config)
Context: RAG results + user context
Question: User question
Format: (optional, via ... or config)
Character string with LLM response, or NULL on error
## Not run: # Basic RAG-enhanced question answer <- bfhllm_chat_with_rag("What is a run chart?") # With additional context answer <- bfhllm_chat_with_rag( question = "Should I use a run chart or SPC chart?", context = "Data: 24 observations, stable process" ) # With chat options answer <- bfhllm_chat_with_rag( question = "Interpret this control chart", context = "8 points above centerline", model = "gemini-2.5-flash-lite", max_chars = 500, cache = my_cache ) ## End(Not run)## Not run: # Basic RAG-enhanced question answer <- bfhllm_chat_with_rag("What is a run chart?") # With additional context answer <- bfhllm_chat_with_rag( question = "Should I use a run chart or SPC chart?", context = "Data: 24 observations, stable process" ) # With chat options answer <- bfhllm_chat_with_rag( question = "Interpret this control chart", context = "8 points above centerline", model = "gemini-2.5-flash-lite", max_chars = 500, cache = my_cache ) ## End(Not run)
Manually resets circuit breaker state. Useful for testing or administrative intervention after resolving API issues.
bfhllm_circuit_breaker_reset()bfhllm_circuit_breaker_reset()
## Not run: # After fixing API connectivity issues bfhllm_circuit_breaker_reset() ## End(Not run)## Not run: # After fixing API connectivity issues bfhllm_circuit_breaker_reset() ## End(Not run)
Returns current circuit breaker state for monitoring and debugging.
bfhllm_circuit_breaker_status()bfhllm_circuit_breaker_status()
List with circuit breaker status:
Logical, TRUE if circuit breaker is open
Integer, current failure count
POSIXct, timestamp of last failure (or NULL)
## Not run: status <- bfhllm_circuit_breaker_status() if (status$is_open) { message("Circuit breaker is open - API calls blocked") } ## End(Not run)## Not run: status <- bfhllm_circuit_breaker_status() if (status$is_open) { message("Circuit breaker is open - API calls blocked") } ## End(Not run)
Set runtime configuration for LLM provider, model, and behavior. Configuration is stored in package environment and persists for the session.
bfhllm_configure( provider = NULL, model = NULL, timeout_seconds = NULL, max_response_chars = NULL, circuit_breaker = NULL, cache = NULL, rate_limit = NULL )bfhllm_configure( provider = NULL, model = NULL, timeout_seconds = NULL, max_response_chars = NULL, circuit_breaker = NULL, cache = NULL, rate_limit = NULL )
provider |
Character string, LLM provider name (default: "gemini") |
model |
Character string, model identifier (default: "gemini-2.5-flash-lite") |
timeout_seconds |
Numeric, API timeout in seconds (default: 10) |
max_response_chars |
Integer, maximum response length (default: 350) |
circuit_breaker |
List with circuit breaker settings (optional) |
cache |
List with cache settings (optional) |
rate_limit |
List with rate limit settings (optional):
|
Invisibly returns the updated configuration list
## Not run: # Basic configuration bfhllm_configure( model = "gemini-2.0-flash-exp", timeout_seconds = 15 ) # Advanced configuration bfhllm_configure( circuit_breaker = list( enabled = TRUE, failure_threshold = 3, reset_timeout_seconds = 180 ), cache = list( enabled = TRUE, ttl_seconds = 7200 ) ) ## End(Not run)## Not run: # Basic configuration bfhllm_configure( model = "gemini-2.0-flash-exp", timeout_seconds = 15 ) # Advanced configuration bfhllm_configure( circuit_breaker = list( enabled = TRUE, failure_threshold = 3, reset_timeout_seconds = 180 ), cache = list( enabled = TRUE, ttl_seconds = 7200 ) ) ## End(Not run)
Creates a prompt with structured sections (system, context, question). Useful for RAG-enhanced prompts or complex multi-part queries.
bfhllm_create_structured_prompt( question, context = NULL, system = NULL, format = NULL )bfhllm_create_structured_prompt( question, context = NULL, system = NULL, format = NULL )
question |
Character string, main question or instruction |
context |
Character string, additional context (optional) |
system |
Character string, system message or role (optional) |
format |
Character string, desired output format instructions (optional) |
Character string with structured prompt
## Not run: prompt <- bfhllm_create_structured_prompt( question = "What causes special cause variation?", context = "Run chart shows 8 consecutive points above centerline", system = "You are an SPC methodology expert", format = "Respond in Danish, max 2 sentences" ) ## End(Not run)## Not run: prompt <- bfhllm_create_structured_prompt( question = "What causes special cause variation?", context = "Run chart shows 8 consecutive points above centerline", system = "You are an SPC methodology expert", format = "Respond in Danish, max 2 sentences" ) ## End(Not run)
Extracts structured SPC metadata from BFHcharts/qicharts2 result objects for use in AI prompt generation.
bfhllm_extract_spc_metadata(spc_result)bfhllm_extract_spc_metadata(spc_result)
spc_result |
List from BFHcharts or qicharts2 with components:
|
Named list with extracted metadata:
chart_type: Chart type code
chart_type_dansk: Danish name
n_points: Number of observations
signals_detected: Anhøj rule violations
longest_run: Longest run above/below centerline
n_crossings: Centerline crossings
n_crossings_min: Expected minimum crossings
centerline: Mean centerline value
start_date: First x value
end_date: Last x value
process_variation: "naturligt" or "ikke naturligt"
Returns NULL if spc_result is invalid or missing required components.
## Not run: # With BFHcharts result spc_result <- BFHcharts::create_spc_chart(data, ...) metadata <- bfhllm_extract_spc_metadata(spc_result) # With qicharts2 result qic_result <- qicharts2::qic(x, y, chart = "run", return.data = TRUE) metadata <- bfhllm_extract_spc_metadata(qic_result) ## End(Not run)## Not run: # With BFHcharts result spc_result <- BFHcharts::create_spc_chart(data, ...) metadata <- bfhllm_extract_spc_metadata(spc_result) # With qicharts2 result qic_result <- qicharts2::qic(x, y, chart = "run", return.data = TRUE) metadata <- bfhllm_extract_spc_metadata(qic_result) ## End(Not run)
Opretter en cache der gemmer data i en .rds-fil paa disk. Cachen overlever R-sessions og kan deles mellem koersler.
bfhllm_file_cache_create(cache_dir)bfhllm_file_cache_create(cache_dir)
cache_dir |
Character, sti til cache-mappe |
Cachen bruger en enkelt RDS index-fil til at gemme alle entries.
Filen placeres i en .bfhllm_cache undermappe af cache_dir.
Fordi data gemmes paa disk, overlever cachen R-sessions. Designet til single-process brug – ikke egnet til concurrent adgang.
Liste med get/set/has/clear/stats funktioner:
Hent vaerdi fra cache, eller NULL hvis ikke fundet
Gem vaerdi i cache
Returnerer TRUE/FALSE om key eksisterer
Fjern alle cache-entries
Returnerer cache-statistik
## Not run: # Opret cache i midlertidig mappe cache <- bfhllm_file_cache_create(cache_dir = tempdir()) # Gem og hent vaerdi cache$set("key1", "analyse tekst") cache$get("key1") # "analyse tekst" # Tjek om key eksisterer cache$has("key1") # TRUE # Statistik cache$stats() # list(entries = 1L, cache_dir = "...") # Ryd cache cache$clear() ## End(Not run)## Not run: # Opret cache i midlertidig mappe cache <- bfhllm_file_cache_create(cache_dir = tempdir()) # Gem og hent vaerdi cache$set("key1", "analyse tekst") cache$get("key1") # "analyse tekst" # Tjek om key eksisterer cache$has("key1") # TRUE # Statistik cache$stats() # list(entries = 1L, cache_dir = "...") # Ryd cache cache$clear() ## End(Not run)
Formats RAG search results into a structured context string suitable for inclusion in LLM prompts. Combines retrieved chunks with metadata.
bfhllm_format_rag_context(results, max_chunks = 5, include_scores = FALSE)bfhllm_format_rag_context(results, max_chunks = 5, include_scores = FALSE)
results |
Data frame from |
max_chunks |
Integer, maximum chunks to include (default: 5) |
include_scores |
Logical, include similarity scores in output (default: FALSE) |
Output Format:
Context from knowledge base: [1] <chunk text> [2] <chunk text> ...
NULL Handling: Returns NULL if results is NULL or empty. Calling code should handle this gracefully (e.g., proceed without RAG context).
Character string with formatted context, or NULL if no results
## Not run: # Query and format results <- bfhllm_query_knowledge("run chart") context <- bfhllm_format_rag_context(results) # Include scores for debugging context <- bfhllm_format_rag_context(results, include_scores = TRUE) # Limit chunks context <- bfhllm_format_rag_context(results, max_chunks = 3) ## End(Not run)## Not run: # Query and format results <- bfhllm_query_knowledge("run chart") context <- bfhllm_format_rag_context(results) # Include scores for debugging context <- bfhllm_format_rag_context(results, include_scores = TRUE) # Limit chunks context <- bfhllm_format_rag_context(results, max_chunks = 3) ## End(Not run)
Creates deterministic hash from input data using xxhash64 algorithm. Ensures same inputs always produce same cache key.
bfhllm_generate_cache_key(...)bfhllm_generate_cache_key(...)
... |
Named arguments to include in cache key |
Usage: Pass all relevant parameters that should distinguish cached responses. Exclude volatile data (timestamps, random values, reactive triggers).
Hash Algorithm: Uses xxhash64 via digest package - fast and collision-resistant.
Character string (hex hash)
## Not run: # Basic key generation key <- bfhllm_generate_cache_key( prompt = "What is SPC?", model = "gemini-2.5-flash-lite" ) # With metadata key <- bfhllm_generate_cache_key( prompt = prompt_text, metadata = list(chart_type = "run", n_points = 24), context = list(title = "Chart Title") ) ## End(Not run)## Not run: # Basic key generation key <- bfhllm_generate_cache_key( prompt = "What is SPC?", model = "gemini-2.5-flash-lite" ) # With metadata key <- bfhllm_generate_cache_key( prompt = prompt_text, metadata = list(chart_type = "run", n_points = 24), context = list(title = "Chart Title") ) ## End(Not run)
Retrieve current configuration with environment variable fallbacks.
bfhllm_get_config()bfhllm_get_config()
List with current configuration settings
## Not run: config <- bfhllm_get_config() print(config$model) ## End(Not run)## Not run: config <- bfhllm_get_config() print(config$model) ## End(Not run)
Replaces placeholders in prompt template with values from data list.
Placeholders use {{variable}} syntax (double curly braces).
bfhllm_interpolate(template, data)bfhllm_interpolate(template, data)
template |
Character string, prompt template with |
data |
Named list with values to interpolate |
Placeholder Syntax:
Use {{variable_name}} in template. Spaces inside braces are allowed
({{ variable }} works).
Missing Variables: If a placeholder variable is not found in data, it is left unchanged in the output (no error thrown).
Type Coercion:
All values are coerced to character strings via as.character().
Character string with interpolated prompt
## Not run: # Basic interpolation template <- "Hello {{name}}, you are {{age}} years old" data <- list(name = "Alice", age = 30) prompt <- bfhllm_interpolate(template, data) # "Hello Alice, you are 30 years old" # SPC prompt template template <- paste( "Analyze this {{chart_type}} chart with {{n_points}} data points.", "The process shows {{variation_type}} variation.", "Suggest improvements." ) data <- list( chart_type = "run chart", n_points = 24, variation_type = "stable" ) prompt <- bfhllm_interpolate(template, data) ## End(Not run)## Not run: # Basic interpolation template <- "Hello {{name}}, you are {{age}} years old" data <- list(name = "Alice", age = 30) prompt <- bfhllm_interpolate(template, data) # "Hello Alice, you are 30 years old" # SPC prompt template template <- paste( "Analyze this {{chart_type}} chart with {{n_points}} data points.", "The process shows {{variation_type}} variation.", "Suggest improvements." ) data <- list( chart_type = "run chart", n_points = 24, variation_type = "stable" ) prompt <- bfhllm_interpolate(template, data) ## End(Not run)
Loads the pre-built Ragnar knowledge store. Store is loaded once per session and cached for performance. Automatically detects development vs production mode and adjusts paths accordingly.
bfhllm_load_knowledge_store(store_path = NULL)bfhllm_load_knowledge_store(store_path = NULL)
store_path |
Character string, path to store (optional). If NULL, auto-detects based on package installation status. |
Path Detection:
Production: system.file("ragnar_store", package = "BFHllm")
Development: inst/ragnar_store (relative to package root)
API Key Setup:
Ragnar requires GEMINI_API_KEY. If not set, automatically falls back to
GOOGLE_API_KEY if available.
Caching: Store is cached in package environment after first successful load. Subsequent calls return cached store (fast).
Error Handling: Returns NULL on errors (store not found, ragnar not installed, load failure). Check return value before querying.
ragnar_store object, or NULL if store not found/cannot be loaded
## Not run: # Load store (auto-detect path) store <- bfhllm_load_knowledge_store() if (!is.null(store)) { # Query store results <- bfhllm_query_knowledge("run chart", store) } # Force reload (clears cache) bfhllm_reset_knowledge_store_cache() store <- bfhllm_load_knowledge_store() ## End(Not run)## Not run: # Load store (auto-detect path) store <- bfhllm_load_knowledge_store() if (!is.null(store)) { # Query store results <- bfhllm_query_knowledge("run chart", store) } # Force reload (clears cache) bfhllm_reset_knowledge_store_cache() store <- bfhllm_load_knowledge_store() ## End(Not run)
Translates English SPC chart type codes to Danish display names.
bfhllm_map_chart_type_danish(chart_type)bfhllm_map_chart_type_danish(chart_type)
chart_type |
Character string, chart type code (e.g., "run", "p", "c") |
Supported Chart Types:
run: Serieplot (run chart)
i: I-chart (individuelle værdier)
mr: MR-chart (moving range)
xbar: X-bar chart (gennemsnit)
s: S-chart (standardafvigelse)
t: T-chart (tid mellem events)
p: P-chart (andel)
pp: PP-chart (andel per periode)
c: C-chart (antal events)
u: U-chart (rate per enhed)
g: G-chart (events mellem)
prime: Prime chart
Unknown Types: Returns original English name if chart type not recognized.
Character string with Danish chart type name
bfhllm_map_chart_type_danish("run") # "serieplot (run chart)" bfhllm_map_chart_type_danish("p") # "P-chart (andel)" bfhllm_map_chart_type_danish("unknown") # "unknown"bfhllm_map_chart_type_danish("run") # "serieplot (run chart)" bfhllm_map_chart_type_danish("p") # "P-chart (andel)" bfhllm_map_chart_type_danish("unknown") # "unknown"
Queries the Ragnar knowledge store for relevant information. Supports both semantic search (embeddings) and keyword search (BM25), or hybrid mode combining both.
bfhllm_query_knowledge(query, store = NULL, top_k = 5, method = "hybrid")bfhllm_query_knowledge(query, store = NULL, top_k = 5, method = "hybrid")
query |
Character string, the query to search for |
store |
ragnar_store object (optional). If NULL, loads from cache/default. |
top_k |
Integer, number of top results to return (default: 5) |
method |
Character string, search method: "hybrid" (default), "semantic", or "bm25" |
Search Methods:
"hybrid": Combines semantic + BM25 (best for most queries)
"semantic": Vector similarity search via embeddings
"bm25": Keyword-based search (fast, good for exact terms)
Store Loading:
If store is NULL, automatically loads via bfhllm_load_knowledge_store().
Store is cached after first load for performance.
Error Handling: Returns NULL if store unavailable or query fails. Check return value before using results.
Data frame with columns: chunk_id, text, score, metadata, or NULL on error
## Not run: # Query with default hybrid search results <- bfhllm_query_knowledge("run chart interpretation") # Query with semantic search only results <- bfhllm_query_knowledge( "special cause variation", method = "semantic", top_k = 3 ) # Use existing store store <- bfhllm_load_knowledge_store() results <- bfhllm_query_knowledge("control limits", store = store) ## End(Not run)## Not run: # Query with default hybrid search results <- bfhllm_query_knowledge("run chart interpretation") # Query with semantic search only results <- bfhllm_query_knowledge( "special cause variation", method = "semantic", top_k = 3 ) # Use existing store store <- bfhllm_load_knowledge_store() results <- bfhllm_query_knowledge("control limits", store = store) ## End(Not run)
Manually resets all rate limiter state. Useful for testing or after resolving rate limit issues.
bfhllm_rate_limit_reset()bfhllm_rate_limit_reset()
## Not run: bfhllm_rate_limit_reset() ## End(Not run)## Not run: bfhllm_rate_limit_reset() ## End(Not run)
Returns current rate limit usage, remaining capacity, and configuration.
bfhllm_rate_limit_status()bfhllm_rate_limit_status()
List with rate limit status:
Integer, requests in current sliding window
Integer, requests since midnight
Integer, configured RPM limit
Integer, configured RPD limit
Integer, remaining RPM capacity
Integer, remaining RPD capacity
Date, when daily counter was last reset
Logical, whether rate limiting is active
Character, "wait" or "degrade"
## Not run: status <- bfhllm_rate_limit_status() message(sprintf("RPM: %d/%d, RPD: %d/%d", status$requests_this_minute, status$rpm_limit, status$requests_today, status$rpd_limit)) ## End(Not run)## Not run: status <- bfhllm_rate_limit_status() message(sprintf("RPM: %d/%d, RPD: %d/%d", status$requests_this_minute, status$rpm_limit, status$requests_today, status$rpd_limit)) ## End(Not run)
Clears cached store and load attempt flag. Use for testing or forcing reload after store rebuild.
bfhllm_reset_knowledge_store_cache()bfhllm_reset_knowledge_store_cache()
invisible(NULL)
## Not run: # Force reload after rebuilding store bfhllm_reset_knowledge_store_cache() store <- bfhllm_load_knowledge_store() ## End(Not run)## Not run: # Force reload after rebuilding store bfhllm_reset_knowledge_store_cache() store <- bfhllm_load_knowledge_store() ## End(Not run)
Main function for generating AI-powered improvement suggestions for SPC charts. Combines metadata extraction, RAG context retrieval, prompt building, and LLM generation into a single high-level interface.
bfhllm_spc_suggestion( spc_result, context, min_chars = 300, max_chars = 375, use_rag = TRUE, cache = NULL, ... )bfhllm_spc_suggestion( spc_result, context, min_chars = 300, max_chars = 375, use_rag = TRUE, cache = NULL, ... )
spc_result |
List from BFHcharts/qicharts2 with metadata and qic_data |
context |
Named list with user context:
|
min_chars |
Minimum characters in response (default: 300) |
max_chars |
Maximum characters in response (default: 375) |
use_rag |
Logical, use RAG for SPC methodology context (default: TRUE) |
cache |
Cache object from bfhllm_cache_create() or bfhllm_cache_shiny() (optional) |
... |
Additional arguments passed to bfhllm_chat() (model, timeout, etc.) |
Workflow:
Extract SPC metadata from result object
Query RAG knowledge store (if use_rag = TRUE)
Build structured prompt with metadata + context + RAG
Call LLM via bfhllm_chat()
Validate and return response
Caching: If cache provided, checks cache before API call and stores result after. Cache key includes metadata, context, and RAG content for uniqueness.
RAG Integration: When use_rag = TRUE, queries knowledge store for relevant SPC methodology based on chart type, signals detected, and target comparison.
Character string with AI-generated improvement suggestion in Danish, or NULL on error
## Not run: # Basic usage spc_result <- BFHcharts::create_spc_chart(data, ...) context <- list( data_definition = "Ventetid til operation", chart_title = "Ventetid ortopædkirurgi 2024", y_axis_unit = "dage", target_value = 30 ) suggestion <- bfhllm_spc_suggestion(spc_result, context) # With caching (Shiny) cache <- bfhllm_cache_shiny(session) suggestion <- bfhllm_spc_suggestion( spc_result, context, cache = cache ) # Without RAG suggestion <- bfhllm_spc_suggestion( spc_result, context, use_rag = FALSE ) ## End(Not run)## Not run: # Basic usage spc_result <- BFHcharts::create_spc_chart(data, ...) context <- list( data_definition = "Ventetid til operation", chart_title = "Ventetid ortopædkirurgi 2024", y_axis_unit = "dage", target_value = 30 ) suggestion <- bfhllm_spc_suggestion(spc_result, context) # With caching (Shiny) cache <- bfhllm_cache_shiny(session) suggestion <- bfhllm_spc_suggestion( spc_result, context, cache = cache ) # Without RAG suggestion <- bfhllm_spc_suggestion( spc_result, context, use_rag = FALSE ) ## End(Not run)
Genererer AI-drevne analyser for flere SPC-diagrammer i batch. Bruger fil-baseret cache til at undgaa gentagne API-kald og respekterer rate limits.
bfhllm_spc_suggestions_batch( contexts, batch_size = 25L, use_cache = TRUE, cache_dir = NULL, force_refresh = FALSE, min_chars = 300, max_chars = 375 )bfhllm_spc_suggestions_batch( contexts, batch_size = 25L, use_cache = TRUE, cache_dir = NULL, force_refresh = FALSE, min_chars = 300, max_chars = 375 )
contexts |
Named list: diagram_key -> list(spc_result, llm_context). Hver kontekst indeholder:
|
batch_size |
Integer, antal diagrammer per API-kald (default: 25) |
use_cache |
Logical, brug fil-baseret cache (default: TRUE) |
cache_dir |
Character, sti til cache-mappe (default: tempdir()) |
force_refresh |
Logical, ignorer cache og kald API igen (default: FALSE) |
min_chars |
Integer, minimum tegn per analyse (default: 300) |
max_chars |
Integer, maksimum tegn per analyse (default: 375) |
Liste med:
Named list: diagram_key -> analyse tekst
Integer, antal analyser hentet fra cache
Integer, antal analyser genereret via API
Character vector, diagram_keys der fejlede
Logical, TRUE hvis daglig rate limit var opbrugt
## Not run: # Opret kontekster for 3 diagrammer contexts <- list( diagram_1 = list( spc_result = list(metadata = list(chart_type = "run", n_points = 24, signals_detected = 0)), llm_context = list(data_definition = "Ventetid", chart_title = "Ventetid 2024", y_axis_unit = "dage", target_value = 30) ), diagram_2 = list( spc_result = list(metadata = list(chart_type = "p", n_points = 12, signals_detected = 2)), llm_context = list(data_definition = "Infektionsrate", chart_title = "Infektioner Q1", y_axis_unit = "procent", target_value = 5) ) ) result <- bfhllm_spc_suggestions_batch(contexts) print(result$analyses) ## End(Not run)## Not run: # Opret kontekster for 3 diagrammer contexts <- list( diagram_1 = list( spc_result = list(metadata = list(chart_type = "run", n_points = 24, signals_detected = 0)), llm_context = list(data_definition = "Ventetid", chart_title = "Ventetid 2024", y_axis_unit = "dage", target_value = 30) ), diagram_2 = list( spc_result = list(metadata = list(chart_type = "p", n_points = 12, signals_detected = 2)), llm_context = list(data_definition = "Infektionsrate", chart_title = "Infektioner Q1", y_axis_unit = "procent", target_value = 5) ) ) result <- bfhllm_spc_suggestions_batch(contexts) print(result$analyses) ## End(Not run)
Checks if all prerequisites for using BFHllm are met:
Required packages installed (ellmer)
API key configured
Configuration valid
bfhllm_validate_setup()bfhllm_validate_setup()
Logical, TRUE if setup is valid, FALSE otherwise (with warnings)
## Not run: if (bfhllm_validate_setup()) { # Proceed with LLM operations } else { # Handle setup issues } ## End(Not run)## Not run: if (bfhllm_validate_setup()) { # Proceed with LLM operations } else { # Handle setup issues } ## End(Not run)
Returns names of all registered LLM providers.
list_providers()list_providers()
Character vector of provider names
## Not run: providers <- list_providers() print(providers) # "gemini" ## End(Not run)## Not run: providers <- list_providers() print(providers) # "gemini" ## End(Not run)
Print Cache Object
## S3 method for class 'bfhllm_cache' print(x, ...)## S3 method for class 'bfhllm_cache' print(x, ...)
x |
Cache object |
... |
Unused |
Print Shiny Cache Object
## S3 method for class 'bfhllm_cache_shiny' print(x, ...)## S3 method for class 'bfhllm_cache_shiny' print(x, ...)
x |
Shiny cache object |
... |
Unused |
Validates API response text and sanitizes it by:
Checking for NULL or empty responses
Removing HTML tags
Normalizing whitespace
Trimming to maximum character limit
Balancing markdown formatting
validate_response(text, max_chars = 350)validate_response(text, max_chars = 350)
text |
Character string, raw response from LLM |
max_chars |
Integer, maximum allowed characters (default: 350) |
Sanitization Steps:
Check for NULL/empty input
Remove HTML tags
Normalize whitespace (collapse multiple spaces)
Trim to max_chars (preserving word boundaries)
Balance markdown asterisks (ensure even count)
Character Limit: When text exceeds max_chars, it is truncated at the last complete word before the limit, and "..." is appended. Markdown formatting is balanced to avoid broken bold/italic markers.
Character string with sanitized text, or NULL if invalid
## Not run: # Valid response text <- validate_response( "This is a **valid** response", max_chars = 100 ) # Long response (will be truncated) long_text <- paste(rep("word", 100), collapse = " ") text <- validate_response(long_text, max_chars = 50) ## End(Not run)## Not run: # Valid response text <- validate_response( "This is a **valid** response", max_chars = 100 ) # Long response (will be truncated) long_text <- paste(rep("word", 100), collapse = " ") text <- validate_response(long_text, max_chars = 50) ## End(Not run)
Simple check if response is within character limit.
validate_response_length(text, max_chars = 350)validate_response_length(text, max_chars = 350)
text |
Character string |
max_chars |
Integer, maximum allowed characters |
Logical, TRUE if within limit
## Not run: validate_response_length("Short text", max_chars = 100) # TRUE validate_response_length(paste(rep("word", 100), collapse = " "), max_chars = 50) # FALSE ## End(Not run)## Not run: validate_response_length("Short text", max_chars = 100) # TRUE validate_response_length(paste(rep("word", 100), collapse = " "), max_chars = 50) # FALSE ## End(Not run)