Creating Interactive Shiny Apps with Reactive Conductors for Efficient Text Analysis Using Tesseract

Reactive Conductor for Shiny App

In this example, we will use the reactive conductor to create a Shiny app that displays an image and generates text using the tesseract package.

app.R

library(shiny)
library(flexdashboard)
library(tesseract)

# Load necessary packages and set up tesseract engine
eng <- tesseract("eng", silent = TRUE)

# Define reactive conductor for generating text
imageInput <- reactive({
  if (input$imagesToChoose == "Language example 1") {
    x <- "images/receipt.png"
  } else if (input$imagesToChoose == "Language example 2") {
    x <- "images/french.JPG"
  } else if (input$imagesToChoose == "Jounal example") {
    x <- "images/journal.jpg"
  }
  return(x)
})

text_output <- reactive({
  eng <- tesseract("eng", silent = TRUE)
  text_output <- tesseract::ocr(imageInput(), engine = eng)
  return(text_output)
})

# Define Shiny app
ui <- fluidPage(
  flexdashboard::sidebarLayout(
    flexdashboard::sidebar(
      selectInput("n_breaks", label = "Number of bins:", choices = c(10, 20, 35, 50), selected = 20),
      sliderInput("bw_adjust", label = "Bandwidth adjustment:", min = 0.2, max = 2, value = 1, step = 0.2)
    ),
    flexdashboard::mainPanel(
      plotOutput("plot"),
      textOutput("tesseract")
    )
  ),
  fluidPage(
    div(id = "busy", style = "position: fixed; z-index: 1000; top: 50%; left: 50%; margin-top: -100px; margin-left: -50px; display: none; background-color: rgba(230,230,230,.8); text-align: center; padding-top: 20px; padding-left: 30px; padding-bottom: 40px; padding-right: 30px; border-radius: 5px;")
  )
)

server <- function(input, output) {
  output$plot <- renderPlot({
    Sys.sleep(5) # simulates a time-consuming task
    hist(faithful$eruptions, probability = TRUE, breaks = as.numeric(input$n_breaks), xlab = "Duration (minutes)", main = "Geyser Eruption Duration")
    dens <- density(faithful$eruptions, adjust = input$bw_adjust)
    lines(dens, col = "blue")
  })

  output$tesseract <- renderText({
    text_output()
  })

  observeEvent(input$tesseract, {
    updateShinyAction("showBusy", invisible)
  })
  observeEvent(input$plot, {
    updateShinyAction("showBusy", visible)
  })

  def visible = "visible"
  def hidden = "hidden"

  updateShinyAction("showBusy", visible)
}

shiny::initUI(ui)

shiny::appOutput(server)

In this example, we use the reactiveConductor package to create a Shiny app that displays an image and generates text using the tesseract package. The imageInput reactive conductor is used to generate the input for the tesseract function, while the text_output reactive conductor is used to display the output of the tesseract function.

We also define a div element with an ID of “busy” that will be displayed when the app is in use. The showBusy action is defined to show or hide the “busy” div based on whether the plot input is being recalculated or not.

How it works

  1. When the user selects an image from the imagesToChoose selectInput, the imageInput reactive conductor generates the input for the tesseract function.
  2. The text_output reactive conductor displays the output of the tesseract function as text.
  3. When the user recalculates the plot or changes the n_breaks or bw_adjust inputs, the showBusy action is triggered to show or hide the “busy” div.
  4. The Sys.sleep(5) statement in the renderPlot function simulates a time-consuming task that takes 5 seconds to complete.

Note: This example assumes that you have already installed and loaded the necessary packages, including tesseract, flexdashboard, and shiny.


Last modified on 2023-10-30