Introducing Gradio Clients

Watch
  1. Other Tutorials
  2. Using Gradio In Other Programming Languages

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 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:

// 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:

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:

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:

// 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:

cargo build --release

Now, we can call this Rust program from Python and use Gradio to build the interface:

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:

install.packages("reticulate")

Once installed, you can use the package to run Gradio directly from within an R script.

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

greeting <- \(name) paste("Hello", name)

app <- gr$Interface(
  fn = greeting,
  inputs = gr$Text(label = "Name"),
  outputs = gr$Text(label = "Greeting"),
  title = "Hello! &#128515 &#128075"
)

app$launch(server_name = "localhost", 
           server_port = as.integer(3000))

Credit to @IfeanyiIdiaye for contributing this section. You can see more examples here, including using Gradio Blocks to build a machine learning application in R.