QueryChat is an R6 class built on Shiny, shinychat, and ellmer to enable
interactive querying of data using natural language. It leverages large
language models (LLMs) to translate user questions into SQL queries, execute
them against a data source (data frame or database), and various ways of
accessing/displaying the results.
Details
The QueryChat class takes your data (a data frame or database connection)
as input and provides methods to:
Generate a chat UI for natural language queries (e.g.,
$app(),$sidebar())Initialize server logic that returns session-specific reactive values (via
$server())Access reactive data, SQL queries, and titles through the returned server values
Usage
library(querychat)
# Create a QueryChat object
qc <- QueryChat$new(mtcars)
# Quick start: run a complete app
qc$app()
# Or build a custom Shiny app
ui <- page_sidebar(
qc$sidebar(),
verbatimTextOutput("sql"),
dataTableOutput("data")
)
server <- function(input, output, session) {
qc_vals <- qc$server()
output$sql <- renderText(qc_vals$sql())
output$data <- renderDataTable(qc_vals$df())
}
shinyApp(ui, server)Methods
Method new()
Create a new QueryChat object.
Usage
QueryChat$new(
data_source,
table_name = missing_arg(),
...,
id = NULL,
greeting = NULL,
client = NULL,
data_description = NULL,
categorical_threshold = 20,
extra_instructions = NULL,
prompt_template = NULL,
cleanup = NA
)Arguments
data_sourceEither a data.frame or a database connection (e.g., DBI connection).
table_nameA string specifying the table name to use in SQL queries. If
data_sourceis a data.frame, this is the name to refer to it by in queries (typically the variable name). If not provided, will be inferred from the variable name for data.frame inputs. For database connections, this parameter is required....Additional arguments (currently unused).
idOptional module ID for the QueryChat instance. If not provided, will be auto-generated from
table_name. The ID is used to namespace the Shiny module.greetingOptional initial message to display to users. Can be a character string (in Markdown format) or a file path. If not provided, a greeting will be generated at the start of each conversation using the LLM, which adds latency and cost. Use
$generate_greeting()to create a greeting to save and reuse.clientOptional chat client. Can be:
An ellmer::Chat object
A string to pass to
ellmer::chat()(e.g.,"openai/gpt-4o")NULL(default): Uses thequerychat.clientoption, theQUERYCHAT_CLIENTenvironment variable, or defaults toellmer::chat_openai()
data_descriptionOptional description of the data in plain text or Markdown. Can be a string or a file path. This provides context to the LLM about what the data represents.
categorical_thresholdFor text columns, the maximum number of unique values to consider as a categorical variable. Default is 20.
extra_instructionsOptional additional instructions for the chat model in plain text or Markdown. Can be a string or a file path.
prompt_templateOptional path to or string of a custom prompt template file. If not provided, the default querychat template will be used. See the package prompts directory for the default template format.
cleanupWhether or not to automatically run
$cleanup()when the Shiny session/app stops. By default, cleanup only occurs ifQueryChatgets created within a Shiny session. Set toTRUEto always clean up, orFALSEto never clean up automatically.
Examples
\dontrun{
# Basic usage
qc <- QueryChat$new(mtcars)
# With options
qc <- QueryChat$new(
mtcars,
greeting = "Welcome to the mtcars explorer!",
client = "openai/gpt-4o",
data_description = "Motor Trend car road tests dataset"
)
# With database
library(DBI)
conn <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(conn, "mtcars", mtcars)
qc <- QueryChat$new(conn, "mtcars")
}
Method app()
Create and run a Shiny gadget for chatting with data
Runs a Shiny gadget (designed for interactive use) that provides
a complete interface for chatting with your data using natural language.
If you're looking to deploy this app or run it through some other means,
see $app_obj().
Arguments
...Arguments passed to
$app_obj().bookmark_storeThe bookmarking storage method. Passed to
shiny::enableBookmarking(). If"url"or"server", the chat state (including current query) will be bookmarked. Default is"url".
Method app_obj()
A streamlined Shiny app for chatting with data
Creates a Shiny app designed for chatting with data, with:
A sidebar containing the chat interface
A card displaying the current SQL query
A card displaying the filtered data table
A reset button to clear the query
Arguments
...Additional arguments (currently unused).
bookmark_storeThe bookmarking storage method. Passed to
shiny::enableBookmarking(). If"url"or"server", the chat state (including current query) will be bookmarked. Default is"url".
Returns
A Shiny app object that can be run with shiny::runApp().
Method sidebar()
Create a sidebar containing the querychat UI.
This method generates a bslib::sidebar() component containing the chat
interface, suitable for use with bslib::page_sidebar() or similar layouts.
Arguments
widthWidth of the sidebar in pixels. Default is 400.
heightHeight of the sidebar. Default is "100%".
fillableWhether the sidebar should be fillable. Default is
TRUE....Additional arguments passed to
bslib::sidebar().
Returns
A bslib::sidebar() UI component.
Method ui()
Create the UI for the querychat chat interface.
This method generates the chat UI component. Typically you'll use
$sidebar() instead, which wraps this in a sidebar layout.
Arguments
...Additional arguments passed to
shinychat::chat_ui().
Method server()
Initialize the querychat server logic.
This method must be called within a Shiny server function. It sets up the reactive logic for the chat interface and returns session-specific reactive values.
Usage
QueryChat$server(
enable_bookmarking = FALSE,
session = shiny::getDefaultReactiveDomain()
)Arguments
enable_bookmarkingWhether to enable bookmarking for the chat state. Default is
FALSE. When enabled, the chat state (including current query, title, and chat history) will be saved and restored with Shiny bookmarks. This requires that the Shiny app has bookmarking enabled viashiny::enableBookmarking()or theenableBookmarkingparameter ofshiny::shinyApp().sessionThe Shiny session object.
Returns
A list containing session-specific reactive values and the chat client with the following elements:
df: Reactive expression returning the current filtered data framesql: Reactive value for the current SQL query stringtitle: Reactive value for the current titleclient: The session-specific chat client instance
Method generate_greeting()
Generate a welcome greeting for the chat.
By default, QueryChat$new() generates a greeting at the start of every
new conversation, which is convenient for getting started and development,
but also might add unnecessary latency and cost. Use this method to
generate a greeting once and save it for reuse.
Usage
QueryChat$generate_greeting(echo = c("none", "output"))Method cleanup()
Clean up resources associated with the data source.
This method releases any resources (e.g., database connections) associated with the data source. Call this when you are done using the QueryChat object to avoid resource leaks.
Note: If auto_cleanup was set to TRUE in the constructor,
this will be called automatically when the Shiny app stops.
Examples
if (FALSE) { # \dontrun{
# Basic usage with a data frame
qc <- QueryChat$new(mtcars)
app <- qc$app()
# With a custom greeting
greeting <- "Welcome! Ask me about the mtcars dataset."
qc <- QueryChat$new(mtcars, greeting = greeting)
# With a specific LLM provider
qc <- QueryChat$new(mtcars, client = "anthropic/claude-sonnet-4-5")
# Generate a greeting for reuse
qc <- QueryChat$new(mtcars)
greeting <- qc$generate_greeting(echo = "text")
# Save greeting for next time
writeLines(greeting, "mtcars_greeting.md")
} # }
## ------------------------------------------------
## Method `QueryChat$new`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Basic usage
qc <- QueryChat$new(mtcars)
# With options
qc <- QueryChat$new(
mtcars,
greeting = "Welcome to the mtcars explorer!",
client = "openai/gpt-4o",
data_description = "Motor Trend car road tests dataset"
)
# With database
library(DBI)
conn <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(conn, "mtcars", mtcars)
qc <- QueryChat$new(conn, "mtcars")
} # }
## ------------------------------------------------
## Method `QueryChat$app`
## ------------------------------------------------
if (FALSE) { # \dontrun{
library(querychat)
qc <- QueryChat$new(mtcars)
qc$app()
} # }
## ------------------------------------------------
## Method `QueryChat$app_obj`
## ------------------------------------------------
if (FALSE) { # \dontrun{
library(querychat)
qc <- QueryChat$new(mtcars)
app <- qc$app_obj()
shiny::runApp(app)
} # }
## ------------------------------------------------
## Method `QueryChat$sidebar`
## ------------------------------------------------
if (FALSE) { # \dontrun{
qc <- QueryChat$new(mtcars)
ui <- page_sidebar(
qc$sidebar(),
# Main content here
)
} # }
## ------------------------------------------------
## Method `QueryChat$ui`
## ------------------------------------------------
if (FALSE) { # \dontrun{
qc <- QueryChat$new(mtcars)
ui <- fluidPage(
qc$ui()
)
} # }
## ------------------------------------------------
## Method `QueryChat$server`
## ------------------------------------------------
if (FALSE) { # \dontrun{
qc <- QueryChat$new(mtcars)
server <- function(input, output, session) {
qc_vals <- qc$server(enable_bookmarking = TRUE)
output$data <- renderDataTable(qc_vals$df())
output$query <- renderText(qc_vals$sql())
output$title <- renderText(qc_vals$title() %||% "No Query")
}
} # }
## ------------------------------------------------
## Method `QueryChat$generate_greeting`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Create QueryChat object
qc <- QueryChat$new(mtcars)
# Generate a greeting and save it
greeting <- qc$generate_greeting()
writeLines(greeting, "mtcars_greeting.md")
# Later, use the saved greeting
qc2 <- QueryChat$new(mtcars, greeting = "mtcars_greeting.md")
} # }
