| # Using Gradio in Other Programming Languages | |
| The core `gradio` library is a Python library. But you can also use `gradio` to create UIs around programs written in other languages, thanks to Python's ability to interface with external processes. Using Python's `subprocess` module, you can call programs written in C++, Rust, or virtually any other language, allowing `gradio` to become a flexible UI layer for non-Python applications. | |
| In this post, we'll walk through how to integrate `gradio` with C++ and Rust, using Python's `subprocess` module to invoke code written in these languages. We'll also discuss how to use Gradio with R, which is even easier, thanks to the [reticulate](https://rstudio.github.io/reticulate/) R package, which makes it possible to install and import Python modules in R. | |
| ## Using Gradio with C++ | |
| Let’s start with a simple example of integrating a C++ program into a Gradio app. Suppose we have the following C++ program that adds two numbers: | |
| ```cpp | |
| // add.cpp | |
| #include <iostream> | |
| int main() { | |
| double a, b; | |
| std::cin >> a >> b; | |
| std::cout << a + b << std::endl; | |
| return 0; | |
| } | |
| ``` | |
| This program reads two numbers from standard input, adds them, and outputs the result. | |
| We can build a Gradio interface around this C++ program using Python's `subprocess` module. Here’s the corresponding Python code: | |
| ```python | |
| import gradio as gr | |
| import subprocess | |
| def add_numbers(a, b): | |
| process = subprocess.Popen( | |
| ['./add'], | |
| stdin=subprocess.PIPE, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE | |
| ) | |
| output, error = process.communicate(input=f"{a} {b}\n".encode()) | |
| if error: | |
| return f"Error: {error.decode()}" | |
| return float(output.decode().strip()) | |
| demo = gr.Interface( | |
| fn=add_numbers, | |
| inputs=[gr.Number(label="Number 1"), gr.Number(label="Number 2")], | |
| outputs=gr.Textbox(label="Result") | |
| ) | |
| demo.launch() | |
| ``` | |
| Here, `subprocess.Popen` is used to execute the compiled C++ program (`add`), pass the input values, and capture the output. You can compile the C++ program by running: | |
| ```bash | |
| g++ -o add add.cpp | |
| ``` | |
| This example shows how easy it is to call C++ from Python using `subprocess` and build a Gradio interface around it. | |
| ## Using Gradio with Rust | |
| Now, let’s move to another example: calling a Rust program to apply a sepia filter to an image. The Rust code could look something like this: | |
| ```rust | |
| // sepia.rs | |
| extern crate image; | |
| use image::{GenericImageView, ImageBuffer, Rgba}; | |
| fn sepia_filter(input: &str, output: &str) { | |
| let img = image::open(input).unwrap(); | |
| let (width, height) = img.dimensions(); | |
| let mut img_buf = ImageBuffer::new(width, height); | |
| for (x, y, pixel) in img.pixels() { | |
| let (r, g, b, a) = (pixel[0] as f32, pixel[1] as f32, pixel[2] as f32, pixel[3]); | |
| let tr = (0.393 * r + 0.769 * g + 0.189 * b).min(255.0); | |
| let tg = (0.349 * r + 0.686 * g + 0.168 * b).min(255.0); | |
| let tb = (0.272 * r + 0.534 * g + 0.131 * b).min(255.0); | |
| img_buf.put_pixel(x, y, Rgba([tr as u8, tg as u8, tb as u8, a])); | |
| } | |
| img_buf.save(output).unwrap(); | |
| } | |
| fn main() { | |
| let args: Vec<String> = std::env::args().collect(); | |
| if args.len() != 3 { | |
| eprintln!("Usage: sepia <input_file> <output_file>"); | |
| return; | |
| } | |
| sepia_filter(&args[1], &args[2]); | |
| } | |
| ``` | |
| This Rust program applies a sepia filter to an image. It takes two command-line arguments: the input image path and the output image path. You can compile this program using: | |
| ```bash | |
| cargo build --release | |
| ``` | |
| Now, we can call this Rust program from Python and use Gradio to build the interface: | |
| ```python | |
| import gradio as gr | |
| import subprocess | |
| def apply_sepia(input_path): | |
| output_path = "output.png" | |
| process = subprocess.Popen( | |
| ['./target/release/sepia', input_path, output_path], | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE | |
| ) | |
| process.wait() | |
| return output_path | |
| demo = gr.Interface( | |
| fn=apply_sepia, | |
| inputs=gr.Image(type="filepath", label="Input Image"), | |
| outputs=gr.Image(label="Sepia Image") | |
| ) | |
| demo.launch() | |
| ``` | |
| Here, when a user uploads an image and clicks submit, Gradio calls the Rust binary (`sepia`) to process the image, and returns the sepia-filtered output to Gradio. | |
| This setup showcases how you can integrate performance-critical or specialized code written in Rust into a Gradio interface. | |
| ## Using Gradio with R (via `reticulate`) | |
| Integrating Gradio with R is particularly straightforward thanks to the `reticulate` package, which allows you to run Python code directly in R. Let’s walk through an example of using Gradio in R. | |
| **Installation** | |
| First, you need to install the `reticulate` package in R: | |
| ```r | |
| install.packages("reticulate") | |
| ``` | |
| Once installed, you can use the package to run Gradio directly from within an R script. | |
| ```r | |
| library(reticulate) | |
| py_install("gradio", pip = TRUE) | |
| gr <- import("gradio") # import gradio as gr | |
| ``` | |
| **Building a Gradio Application** | |
| With gradio installed and imported, we now have access to gradio's app building methods. Let's build a simple app for an R function that returns a greeting | |
| ```r | |
| greeting <- \(name) paste("Hello", name) | |
| app <- gr$Interface( | |
| fn = greeting, | |
| inputs = gr$Text(label = "Name"), | |
| outputs = gr$Text(label = "Greeting"), | |
| title = "Hello! 😃 👋" | |
| ) | |
| app$launch(server_name = "localhost", | |
| server_port = as.integer(3000)) | |
| ``` | |
| Credit to [@IfeanyiIdiaye](https://github.com/Ifeanyi55) for contributing this section. You can see more examples [here](https://github.com/Ifeanyi55/Gradio-in-R/tree/main/Code), including using Gradio Blocks to build a machine learning application in R. | |