Last active
June 1, 2017 20:32
-
-
Save slopp/96ef090cd97bb304f12da8e714de55ea to your computer and use it in GitHub Desktop.
Pachyderm Shiny App
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# App requires a pachyderm pipeline with | |
# input repo "images" | |
# output repo "edges" | |
# The app assumes that pachyderm is being run locally with minikube. | |
# See: http://pachyderm.readthedocs.io/en/latest/getting_started/beginner_tutorial.html | |
# Setup ------------------------------------------------------------------- | |
library(shiny) | |
source("flickr_api.R") # file for querying flickr | |
# set the ADDRESS environment variable | |
# TODO: Change this to the true IP address of pachyderm service if you're not using minikube | |
IP <- system2("minikube", "ip", stdout = TRUE) | |
ADDRESS <- paste0(IP, ":30650") | |
Sys.setenv(ADDRESS = ADDRESS) | |
# User-Interface ------------------------------------------------------------------- | |
ui <- fluidPage( | |
titlePanel("Image Edge Detector"), | |
sidebarLayout( | |
sidebarPanel( | |
textInput("img", "Enter a search term for an interesting image:"), | |
actionButton("search","Search"), | |
br(), | |
uiOutput("edges") | |
), | |
mainPanel( | |
p("This application searches flicker for the user's search term and returns the top result."), | |
p("Then the application submits the image to a pachyderm pipeline that does edge detection."), | |
p("Once the pipeline finishes, the application displays the result."), | |
htmlOutput("img_raw"), | |
plotOutput("img_edges") | |
) | |
) | |
) | |
server <- function(input, output, session) { | |
# Search flickr and return the url for the top result | |
img_url <- eventReactive(input$search, { | |
flickr_photo_url(flickr_photos_search_one(input$img)) | |
}) | |
# Add an img tag with the original image | |
output$img_raw <- renderText({ | |
req(input$img) | |
capture.output(img(src = img_url())) | |
}) | |
# Once a user searches for an image, present the option to run edge detection | |
output$edges <- renderUI({ | |
req(input$img) | |
actionButton("run_edges", "Detect Edges") | |
}) | |
# Create a name for the image based on the search string | |
tmp_img_name <- reactive({ | |
paste0(input$img, ".png") | |
}) | |
# When a user clicks "Detect Edges", add the image to the pachyderm pipeline | |
# This action kicks off a job to do edge detection | |
observeEvent(input$run_edges, { | |
system2("rm", "www/tmp.png") | |
system2("pachctl", paste0("put-file images master ", tmp_img_name(), " -c -f ", img_url())) | |
}) | |
# Helper function to check if pachyderm is done processing the image | |
check_pachyd_for_output <- function(){ | |
output <- system2("pachctl", paste0("list-file edges master"), stdout = TRUE) | |
sum(grepl(pattern = tmp_img_name(), x = output, fixed = TRUE)) | |
} | |
# Run the helper function ever 500 ms | |
# This is a crude re-implementation of reactivePoll when the result is an image file | |
ready <- reactive({ | |
invalidateLater(500) | |
check_pachyd_for_output() | |
}) | |
# If the edge detection image is ready, render it | |
output$img_edges <- renderImage({ | |
req(input$run_edges) | |
# ensure pachyd output is ready | |
req(ready() > 0) | |
# get file from pachyd | |
outfile <- tempfile(fileext = ".png") | |
width <- session$clientData$output_img_edges_width | |
height <- session$clientData$output_img_edges_height | |
system2("pachctl", paste0("get-file edges master ", tmp_img_name(), " >> ", outfile)) | |
list(src = outfile, | |
width = width, | |
height = height) | |
}, deleteFile = TRUE) | |
} | |
shinyApp(ui = ui, server = server) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
library(httr) | |
# Please don't copy my API key. Get your own here, it's fast and free: | |
# https://www.flickr.com/services/api/keys/apply/ | |
api_key <- "d500440eceeb202efc5414d5b23d050c" | |
# Get a data frame for the search term; one photo will be selected at random | |
# from the top 10 most relevant | |
flickr_photos_search_one <- function(query) { | |
resp <- GET( | |
sprintf( | |
"https://api.flickr.com/services/rest/?method=flickr.photos.search&format=json&api_key=%s&text=%s&safe_search=1&content_type=1&per_page=10&sort=relevance", | |
api_key, | |
utils::URLencode(query) | |
), | |
accept_json() | |
) | |
resp <- jsonlite::fromJSON(sub("^jsonFlickrApi\\((.*)\\)$", "\\1", rawToChar(resp$content))) | |
if (length(resp$photos$photo) == 0 || nrow(resp$photos$photo) == 0) | |
return(NULL) | |
resp$photos$photo[sample.int(nrow(resp$photos$photo), 1),] | |
} | |
# Form image URLs from flickr photos data frame | |
flickr_photo_url <- function(photo) { | |
if (is.null(photo) || nrow(photo) == 0) | |
return(character(0)) | |
sprintf( | |
"https://farm%s.staticflickr.com/%s/%s_%s.jpg", | |
photo$farm, | |
photo$server, | |
photo$id, | |
photo$secret | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment