Gapminder / app.R
Ifeanyi's picture
Update app.R
5e99ac2 verified
library(shiny)
library(bslib)
library(bs4Dash)
library(ellmer)
library(querychat)
library(gapminder)
library(highcharter)
library(reactable)
library(shinychat)
# get Gemini api key
api_key = Sys.getenv("GOOGLE_API_KEY")
# create data of the first 500 rows in gapminder
gdp_data <- gapminder
# initialize querychat with mtcars dataset and Gemini chat function
querychat_config <- querychat_init(gdp_data,
create_chat_func = purrr::partial(ellmer::chat_google_gemini, model = "gemini-2.0-flash"),
greeting = "")
# define the UI of the dashboard
ui <- tabsetPanel(
id = "tabs",
type = "pills",
tabPanel(
id = "query-tab",
title = strong("Data Query"),
icon = icon("chart-line",lib = "font-awesome",),
page_sidebar(
# hover bounce effect of value boxes
tags$head(
tags$style(HTML("
.bounce-hover:hover {
animation: bounce 0.6s infinite alternate;
}
.bounce-hover {
box-shadow: 0 7px 7px grey;
}
@keyframes bounce {
from {
transform: translateY(0);
}
to {
transform: translateY(-10px);
}
}
"))
),
sidebar = querychat_sidebar("chat",width = "25%"),
# to change div background color on hover: onmouseover = "this.style.backgroundColor='mediumseagreen';", onmouseout="this.style.backgroundColor='DodgerBlue';". In style = "cursor: pointer;
fluidRow(column(4,tags$div(class = "bounce-hover",valueBoxOutput("GDP"), style = "text-align:center; font-size: 20px; font-weight: bold;color:black;")),
column(4,tags$div(class = "bounce-hover",valueBoxOutput("Population"), style = "text-align:center; font-size: 20px; font-weight: bold;")),
column(4,tags$div(class = "bounce-hover",valueBoxOutput("LifeExp"),style = "text-align:center; font-size: 20px; font-weight: bold;"))),
fluidRow(column(6,highchartOutput("line",width = "98%")),
column(6,highchartOutput("column",width = "98%"))),
fluidRow(reactable::reactableOutput("table",width = "100%"))
)
),
tabPanel(
id = "chat-tab",
title = strong("EconoBot"),
icon = icon("robot",lib = "font-awesome"),
h3(strong("🤖 EconoBot"),style="text-align:center;color:DodgerBlue;"),
h5(strong("Answers your economic and financial questions"),style="text-align:center;color:#37474f;"),
chat_ui("gemini_chat",placeholder = "Type your message here...")
)
)
# define the server logic required to interact with the data
server <- function(input, output) {
# create a querychat object using the config from step 1.
query_chat <- querychat_server("chat", querychat_config)
output$table <- reactable::renderReactable({
reactable::reactable(query_chat$df(),
bordered = T,
compact = T,
highlight = T,
striped = T,
searchable = T,
filterable = T,
defaultColDef = colDef(align = "center"),
theme = reactable::reactableTheme(
stripedColor = "#0091ea",
borderColor = "#0091ea",
borderWidth = 3
))
})
output$line <- renderHighchart({
req(query_chat$df())
my_colors <- c("Africa" = "#1f77b4", "Asia" = "#ff7f0e", "Europe" = "#2ca02c",
"Americas" = "#d62728", "Oceania" = "#9467bd")
hchart(query_chat$df(),
type = "line",
hcaes(x = year, y = pop, group = continent)) |>
hc_colors(unname(my_colors)) |>
hc_title(text = "Population Per Continent or Country")
})
output$column <- renderHighchart({
req(query_chat$df())
my_colors <- c("Africa" = "#1f77b4", "Asia" = "#ff7f0e", "Europe" = "#2ca02c",
"Americas" = "#d62728", "Oceania" = "#9467bd")
hchart(query_chat$df(),
type = "column",
hcaes(x = year, y = gdpPercap, group = continent)) |>
hc_colors(unname(my_colors)) |>
hc_title(text = "GDP Per Capita Per Continent or Country")
})
output$GDP <- renderValueBox({
req(query_chat$df())
valueBox(
value = round(mean(query_chat$df()$gdpPercap, na.rm = TRUE), 2),
color = "success",
icon = icon("dollar"),
elevation = 4,
width = 4,
subtitle = " ",
footer = "Average GDP Per Capita"
)
})
output$Population <- renderValueBox({
req(query_chat$df())
valueBox(
value = round(mean(query_chat$df()$pop, na.rm = TRUE), 0),
color = "primary",
icon = icon("people-group"),
elevation = 4,
width = 4,
subtitle = " ",
footer = "Average Population"
)
})
output$LifeExp <- renderValueBox({
req(query_chat$df())
valueBox(
value = round(mean(query_chat$df()$lifeExp, na.rm = TRUE), 2),
color = "warning",
icon = icon("person-walking"),
elevation = 4,
width = 4,
subtitle = " ",
footer = "Average Life Expectancy"
)
})
# write logic for Gemini chat
gemini <- chat_google_gemini(
system_prompt = "You are a friendly and helpful economic and financial expert who only answers questions around country economy and finance. If a user asks a question that is not related to economics or finance, give the following polite response: 'I'm sorry, I can only provide economic and financial information'.
Also, if a user asks for specific or personal financial advice, give the following polite response: 'I'm sorry, I cannot provide specific financial advice. Please consult a financial advisor for personalized guidance.'",
model = "gemini-2.0-flash",
api_key = api_key,
echo = T
)
observeEvent(input$gemini_chat_user_input, {
# input$gemini_chat_user_input is from the chat id in the UI
gemini$chat_async(input$gemini_chat_user_input)$then(function(response) {
chat_append("gemini_chat", response)
})$catch(function(error) {
warning("An error occurred during chat_async: ", error$message)
})
})
}
# Run the application
shinyApp(ui = ui, server = server)