diff --git a/examples/plumber/Dockerfile b/examples/plumber/Dockerfile new file mode 100644 index 00000000..c93d0afb --- /dev/null +++ b/examples/plumber/Dockerfile @@ -0,0 +1,11 @@ +FROM rstudio/plumber + +WORKDIR /app + +COPY . /app + +RUN R -e "install.packages('caret', repos='http://cran.rstudio.com/')" + +EXPOSE 80 + +ENTRYPOINT ["Rscript", "main.R"] \ No newline at end of file diff --git a/examples/plumber/README.md b/examples/plumber/README.md new file mode 100644 index 00000000..00fba31f --- /dev/null +++ b/examples/plumber/README.md @@ -0,0 +1,78 @@ +# REST API with Plumber + +A RESTful API built with the Plumber package in R. +The API provides three main functions: +- Checking the server status of the API with a GET request. +- Predicting iris petal length based on various parameters with a POST request. +- Displaying a plot that compares actual to predicted petal lengths with a GET request. + +## Steps for Testing Locally + +To run the API locally, use the following command in your terminal: +```sh +Rscript main.R +``` + +Now you can explore your Swagger Docs at `http://127.0.0.1/__docs__/`. + +### Health Check (GET) +Check the API's server status with: +```sh +curl -X 'GET' 'http://127.0.0.1/health_check' +``` + +### Predict Petal Length (POST) + +To predict petal length with only the petal width: +```sh +curl -X 'POST' 'http://127.0.0.1/predict_petal_length' -d 'petal_width=10' +``` + +To include petal width, sepal length, sepal width, and species of the flower: +```sh +curl -X 'POST' 'http://127.0.0.1/predict_petal_length' -d "petal_width=1.2" -d "sepal_length=3.5" -d "sepal_width=2.1" -d "species=setosa" +``` + +### Plot Actual vs Predicted (GET) +To download a plot comparing actual and predicted petal lengths: +```sh +curl -X 'GET' 'http://127.0.0.1/plot_actual_vs_predicted' --output plot.png +``` + +## Steps for Deploying on Ploomber Cloud +### Prerequisites +- [Ploomber Cloud account](https://www.platform.ploomber.io/applications) +- A Dockerfile +- Your code + +Note: Docker deployment option is available exclusively to Pro, Teams, and Enterprise users. Start your 10-day free trial [here.](https://ploomber.io/pricing/) + +There are two ways you can deploy it on Ploomber Cloud: via (1) [Graphical User Interface](https://docs.cloud.ploomber.io/en/latest/quickstart/app.html), and (2) [Command Line Interface](https://docs.cloud.ploomber.io/en/latest/user-guide/cli.html). Let's take a look at the CLI method. + +### Command Line Interface + +If you haven't installed `ploomber-cloud`, run +```sh +pip install ploomber-cloud +``` + +Then, set your API key following to [this documentation](https://docs.cloud.ploomber.io/en/latest/quickstart/apikey.html). +```sh +ploomber-cloud key YOURKEY +``` + +Navigate to your project directory where your Dockerfile is located and initialize the project. Confirm the inferred project type (Docker) when prompted. +```sh +cd +ploomber-cloud init +``` + +Now, deploy your application. +```sh +ploomber-cloud deploy +``` + +Once its deployment is complete, access your endpoints deployed on Ploomber Cloud using your app's URL. For example, you can send a `GET` request with +```sh +curl -X 'GET' 'https://.ploomberapp.io/health_check' +``` \ No newline at end of file diff --git a/examples/plumber/main.R b/examples/plumber/main.R new file mode 100644 index 00000000..61815e2e --- /dev/null +++ b/examples/plumber/main.R @@ -0,0 +1,3 @@ +library(plumber) +pr <- plumb("plumber.R") +pr$run(port = 80, host = "0.0.0.0") diff --git a/examples/plumber/plot.png b/examples/plumber/plot.png new file mode 100644 index 00000000..81cf7e45 Binary files /dev/null and b/examples/plumber/plot.png differ diff --git a/examples/plumber/plumber.R b/examples/plumber/plumber.R new file mode 100644 index 00000000..1b5642be --- /dev/null +++ b/examples/plumber/plumber.R @@ -0,0 +1,69 @@ +#* @apiTitle Iris Petal Length Prediction API +#* @apiDescription This API allows users to interact with a linear regression model predicting iris petal length based on petal width, and optionally, sepal length, sepal width, and species. +#* It provides endpoints for health checks, petal length predictions, and visualizations comparing actual to predicted lengths. + +library(caret) +# Prepare the model +dataset <- iris + +# Set seed for reproducibility +set.seed(42) + +# Split data into training and testing sets +train_index <- createDataPartition(iris$Petal.Length, p = 0.8, list = FALSE) +train_data <- iris[train_index, ] +test_data <- iris[-train_index, ] + +# Train the model using all parameters on the training data +model_all <- lm(Petal.Length ~ Sepal.Length + Sepal.Width + Petal.Width + Species, data = train_data) + +# Train the model using only petal width on the training data +model_petal_width <- lm(Petal.Length ~ Petal.Width, data = iris) + +#* Health check - Returns the API status and the current server time +#* @get /health_check +function() { + list( + status = "The API is running", + time = Sys.time() + ) +} + +#* Predict petal length - Returns a predicted petal length based on available parameters +#* @param petal_width Numeric: Width of the petal (required) +#* @param sepal_length Numeric: Length of the sepal +#* @param sepal_width Numeric: Width of the sepal +#* @param species Character: Species of the iris (setosa, versicolor, virginica) +#* @post /predict_petal_length +function(petal_width, sepal_length = NA, sepal_width = NA, species = NA) { + # Validate petal_width + if (is.na(petal_width) || is.na(as.numeric(petal_width))) { + return(list(error = "Invalid or missing parameter: petal_width")) + } + # Check which parameters are provided and create the input data frame accordingly + if (!is.na(sepal_length) && !is.na(sepal_width) && !is.na(species)) { + input_data <- data.frame( + Sepal.Length = as.numeric(sepal_length), + Sepal.Width = as.numeric(sepal_width), + Petal.Width = as.numeric(petal_width), + Species = as.factor(species) + ) + prediction <- predict(model_all, input_data) + } else { + input_data <- data.frame(Petal.Width = as.numeric(petal_width)) + prediction <- predict(model_petal_width, input_data) + } + list(petal_width = petal_width, predicted_petal_length = prediction) +} + +#* Plot actual vs predicted - Displays a plot comparing actual vs predicted petal lengths for model_all +#* @serializer png +#* @get /plot_actual_vs_predicted +function() { + predictions <- predict(model_all, test_data) + plot(test_data$Petal.Length, predictions, + xlab = "Actual Petal Length", ylab = "Predicted Petal Length", + main = "Actual vs Predicted Petal Length" + ) + abline(0, 1, col = "red") # 1:1 line +}