2024-03-09

Who?

  • Lynna Jirpongopas
  • Data Scientist in the Central Machine Learning Team
  • Started as a Data Analyst using R
  • Now, developing AI solutions with LLMs and Vector DB

Buzzfeed Quiz

What?

  • Leverage Shiny R framework for fast UI development
  • GET method via R library, httr2
  • Generative AI response for an engaging UX

These are required packages:

library(shiny)
library(shinysurveys)
library(httr2)

When? Where?

  • R Shiny was first published in 2012
  • Shiny Surveys in 2021
    • Create and deploy surveys in Shiny
    • But I’m repurposing it for a quiz!
  • httr2 version 0.1 published in 2021
    • Essential R library for making HTTP request

How?

Define your quiz questions

  • In a spreadsheet and save as CSV
  • Magically see your quiz UI come to life

Quiz UI with radio buttons

Response popup with

Other pieces to the puzzle

  • Generative response: OpenAI API key
  • Image search: Google Cloud Platform API key
  • Alternative APIs: Huggingface, Cohere, Gemini, AWS, Azure

Overview for setting up server.R

User defined functions that make HTTP requests:

  • returns our generative output
  • display an image

Generative AI prompts:

  • to generate personalized insights
  • to filter the keyword for image search

Shiny server.R generative AI function

genAI <- function(body) {
    user_message <- list(list(role = "user", content = message))
    base_url <- "https://api.openai.com/v1"
    api_key <- "<add-openai-api-key>"
    req <- request(base_url)
    resp <-
        req |> 
        req_url_path_append("chat/completions") |> 
        req_auth_bearer_token(token = api_key) |> 
        req_headers("Content-Type" = "application/json") |> 
        req_user_agent("Lynnaj | Test R interface") |> 
        req_body_json(body) |> 
        req_perform()
    openai_chat_response <- resp |> resp_body_json(simplifyVector = TRUE)
    openai_chat_response$choices$message$content
}

Shiny server.R image search function

character_image <- function(character) {
    prefix = "https://customsearch.googleapis.com/customsearch/
              v1?cx=<add-CX-code>&imgSize=SMALL&q="
    search_q = gsub(" ", "%20", character)
    suffix = "&safe=active&key=<add-google-api-key>"
    query = paste(prefix, search_q, suffix, sep = "")
    results <- 
        request(query) |>
        req_perform()
    google_response <- results |> resp_body_json()
    image_link_1 <- google_response$items[[1]][[11]]$metatags[[1]]$'og:image'
    image_link_2 <- google_response$items[[2]][[11]]$metatags[[1]]$'og:image'
    image_link <- ifelse(is.null(image_link_1), image_link_2, image_link_1)
    image_link
}

Prompt for the response

body_text_response <- list(
  model = "gpt-3.5-turbo", # alternatively, try gpt-4o
  messages = list(
    list(role = "system", content = "You are an expert on giving insightful career advice.  
    You are also funny and charming.  
    Compare the user to a famous TV or movies character. For example, characters like:
    Michael Scott from 'The Office' for being a Social Butterfly,
    Liz Lemon from '30 Rock' for being a Free Spirit, 
    Sheldon Cooper from 'The Big Bang Theory' for being an Innovator.
    Only make 2 comparisons to the chosen character.  Give insightful career advice.  
    Limit your response to 5 sentences."),
    list(role = "user", content = paste("I just took a quiz about my career archetype. 
    Give me insightful career advice and compare me to a popular TV or movie character. 
    Here are the questions: ", toString(questions) ,
    "And here are my answers respectively: ", toString(answers)))
    )
)

Prompt for filtering!

body_image_response <- list(
    model = "gpt-3.5-turbo", 
    messages = list(
      list(role = "system", content = "You are a filter for a famous TV or 
           movie character name"),
      list(role = "user", content = paste("Below is the text that should 
      include a name of a famous personality. Filter and respond with the full name.  
      No other descriptions, words, or introduction.
      Here is the text: ", text_response))
    )
)

Putting everything together

server <- function(input, output, session) {
    renderSurvey()
    observeEvent(input$submit, {  
        df <- getSurveyData()
        questions <- unique(df_questions$question)
        answers <- df$response
        # prompt 1, for response, goes here
        text_response <- genAI(body_text_response)
        # prompt 2, for filtering, goes here
        name_response <- genAI(body_image_response)
        link <- character_image(name_response)
        # Remove any characters after .jpg or .jpeg or .png
        chars <- "/revision/latest"
        clean_link <- ifelse(grepl(chars, link), sub("\\.(jpg|jpeg|png).*", 
                                                     ".\\1", link), link)
        image_html <- paste0('<center><img src="', clean_link, 
                      '" alt="Your character image missing" width="300"></center>')
        print(cat(image_html))
    
    showModal(modalDialog(
      title = paste("Congrats, you're like", name_response , "!"),
      HTML(image_html),
      br(),
      text_response
    ))
  })
}

Why?

Quickly put together a POC to test a generative AI use case.

Thank you