--- title: "Get started" resource_files: - images/ vignette: > %\VignetteIndexEntry{Get started} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup, echo=FALSE} library(shinychat) ``` This article will cover how to build a chatbot powered by a Large Language Model (LLM) using shinychat and [ellmer](https://ellmer.tidyverse.org/). ellmer will handle connecting to and communicating with the model, while shinychat will handle the user interface for your chatbot. You will need to install both shinychat and ellmer. ```r install.packages(c("shinychat", "ellmer")) ``` ## Setup ### Choose a model First, choose a model to power your chatbot. ellmer and shinychat support a [wide variety](https://ellmer.tidyverse.org/#providers) of LLM providers including Anthropic, OpenAI, Vertex, Snowflake, Groq, Perplexity, and more. With ellmer, you specify the LLM provider by choosing the corresponding `chat_*()` function, e.g., `chat_anthropic()`, `chat_openai()`, etc. This makes it easy to swap out the chat provider to a different one at any time. Model providers also typically offer a variety of models. To specify a particular model, use the `chat_*()` function's `model` argument. For example: ```r ellmer::chat_openai(model = "o3") ``` If you don't specify the `model` argument, the `chat_*()` function will use a reasonable default. For more information, see the individual `chat_*()` function's [documentation](https://ellmer.tidyverse.org/reference/index.html#chatbots).
Help me choose!
If you're not sure which provider to choose, ellmer provides a [guide](https://ellmer.tidyverse.org/#providermodel-choice) to help you decide.
### Set up credentials Next, authenticate with your LLM provider. Popular model providers like OpenAI and Anthropic require an API key. We recommend storing these API keys in your `.Renviron` (e.g., as `OPENAI_API_KEY` or `ANTHROPIC_API_KEY`). You can find some helpful links and tips for getting set up with credentials (e.g., an API key) on the relevant reference page for the `chat_*()` provider you'd like to work with ([`chat_openai()`](https://ellmer.tidyverse.org/reference/chat_openai.html), [`chat_anthropic()`](https://ellmer.tidyverse.org/reference/chat_anthropic.html)). ## Create a basic chatbot Once you've identified which model provider you want to use and set up the necessary credentials, you're ready to create a chatbot. The following code creates a basic chatbot in a Shiny app. Copy and paste the code into an R script, switching out `ellmer::chat_openai()` for your desired chat function. Save the file as `app.R` and then run the app. ```r library(shiny) library(shinychat) ui <- bslib::page_fluid( chat_ui("chat") ) server <- function(input, output, session) { chat <- ellmer::chat_openai() observeEvent(input$chat_user_input, { stream <- chat$stream_async(input$chat_user_input) chat_append("chat", stream) }) } shinyApp(ui, server) ``` Congrats, you now have a chat interface powered by an LLM of your choice! 🎉 ```{r, echo=FALSE, fig.cap="Screenshot of a conversation using shinychat.", fig.align='center', out.extra='class="rounded shadow"', out.height='50%'} knitr::include_graphics("images/chat-quick-start.png") ``` ### Inspect the code Let's take a closer look at the code in `app.R`. ```r library(shiny) library(shinychat) ui <- bslib::page_fluid( # Add a chat UI element chat_ui("chat") ) server <- function(input, output, session) { # Initialize a chat with your chosen model provider chat <- ellmer::chat_openai(system_prompt = "You are a helpful assistant.") # Listen for user input and communicate with the model observeEvent(input$chat_user_input, { stream <- chat$stream_async(input$chat_user_input) chat_append("chat", stream) }) } shinyApp(ui, server) ``` A shinychat chatbot includes three core steps: 1. **Create a chat UI element** with [`chat_ui()`](https://posit-dev.github.io/shinychat/reference/chat_ui.html). 2. **Initialize a chat** with a `chat_*()` function, like `chat_openai()`, in the server function. Use a different `chat_*()` function (`chat_ollama()`, `chat_anthropic()`, etc.) to use a different model provider. You can also use the `system_prompt` argument to supply a [system prompt](https://ellmer.tidyverse.org/articles/prompt-design.html). 3. **Set up a reactive listener** with `observeEvent()` that waits for the user to submit a message (`input$chat_user_input`). When a message is received: * Send the input to the LLM using `chat$stream_async()`, which returns asynchronously streaming results from the LLM. This means the results will appear in chunks, so the user doesn’t have to wait for the full response. * Append the response to the `chat_ui()` element with `chat_append()`, so the user can see the model’s reply appear live as it's generated. ### Add a system prompt Use the `chat_*()` function's `system_prompt` argument to provide the LLM with more information about how you would like it to behave. ```r chat <- ellmer::chat_ollama(system_prompt = "You are a helpful assistant") ``` To learn more about writing system prompts, see ellmer's [Prompt design](https://ellmer.tidyverse.org/articles/prompt-design.html) vignette. Generally, we recommend writing the system prompt in a separate markdown file, but if your prompt is short you can also supply it directly as a string to the `system_prompt` argument. ### Add greetings and suggestions #### On startup To show a greeting when the chat first loads, set the `greeting` argument of `chat_ui()` or `page_chat()`. You can format the greeting with markdown or HTML. ```r chat_ui( id = "chat", greeting = "**Hello!** How can I help you today?" ) ``` ```{r, echo=FALSE, fig.cap="Screenshot of a chatbot with a welcome message.", fig.align='center', out.extra='class="rounded shadow"', out.width='100%'} knitr::include_graphics("images/chat-messages.png") ``` You can also suggest inputs to the user by adding the `suggestion` CSS class to the relevant portions of the greeting. Similarly, use the `submit` class to make clicking on the suggestion submit the input automatically. ```r greeting <- ' **Hello!** How can I help you today? Here are a couple suggestions: * Tell me a joke * Tell me a story ' ui <- bslib::page_fillable( chat_ui( id = "chat", greeting = greeting ) ) ``` ```{r, echo=FALSE, fig.cap="Screenshot of a chatbot with input suggestions.", fig.align='center', out.extra='class="rounded shadow"', out.width='100%'} knitr::include_graphics("images/chat-suggestions.png") ``` A markdown list (`