In this example, we’ll demonstrate how you can host a frontend app with Gradio that runs on Beam.

This example illustrates a few capabilities of Beam:

Import Beam modules

You’ll start by importing a Beam App and Runtime

  • App is the namespace for a project. You’ll give it a unique name as an identifier.
  • Inside the App is a Runtime. The Runtime is a definition of the hardware your container will run on.
app.py
import subprocess
import time

import httpx
from beam import App, Image, Runtime
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.responses import Response as StarletteResponse

runtime = Runtime(
    cpu=1,
    memory="2Gi",
    image=Image(
        python_version="python3.8",
        python_packages=["gradio", "fastapi", "uvicorn", "requests", "httpx"],
    ),
)

app = App(name="gradio-app", runtime=runtime)

Creating a Gradio Frontend

This app has two files: app.py and frontend.py.

We use FastAPI to route traffic to the Gradio server.

app.py
import subprocess
import time

import httpx
from beam import App, Image, Runtime
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.responses import Response as StarletteResponse

runtime = Runtime(
    cpu=1,
    memory="2Gi",
    image=Image(
        python_version="python3.8",
        python_packages=["gradio", "fastapi", "uvicorn", "requests", "httpx"],
    ),
)
app = App(name="gradio-app", runtime=runtime)


GRADIO_URL = "http://127.0.0.1:7860"  # Assuming default Gradio port.


def start_frontend():
    subprocess.Popen(["python3", "frontend.py"])
    start_time = time.time()
    elapsed = 0
    # Wait for Gradio server to be up.
    while elapsed < 60:
        try:
            with httpx.Client() as client:
                response = client.get(GRADIO_URL)
                if response.status_code == 200:
                    print("Gradio app is ready")
                    break
        except httpx.RequestError:
            print("Gradio server is not up yet, waiting...")
            time.sleep(1)
            elapsed = time.time() - start_time


# FastAPI Entry Point
@app.asgi(loader=start_frontend, authorized=False)
def fastapi_app():
    asgi_app = FastAPI()

    @asgi_app.route("/health")
    async def health(request: Request):
        return JSONResponse({"OK": True})

    @asgi_app.route("/{path:path}", include_in_schema=False, methods=["GET", "POST"])
    async def proxy_all(request: Request):
        """
        Proxy all requests to Gradio.
        """
        path = request.url.path.lstrip("/")  # strip leading slash
        headers = dict(request.headers)

        async with httpx.AsyncClient() as client:
            response = await client.request(
                request.method,
                f"{GRADIO_URL}/{path}",
                headers=headers,
                data=await request.body(),
                params=request.query_params,
            )

            content = await response.aread()
            response_headers = dict(response.headers)
            return StarletteResponse(
                content=content,
                status_code=response.status_code,
                headers=response_headers,
            )

    return asgi_app

In our same folder, we have a file with a simple Gradio frontend:

frontend.py
import random
import gradio as gr


def random_response(message, history):
    return random.choice(["Yes", "No"])


demo = gr.ChatInterface(random_response)

demo.launch()

Developing your app on Beam

Beam includes a live-reloading feature that allows you to run your code on the same environment you’ll be running in production.

By default, Beam will sync all the files in your working directory to the remote container. This allows you to use the files you have locally while developing. If you want to prevent some files from getting uploaded, you can create a .beamignore.

In your shell, run beam serve app.py. This will:

  1. Spin up a container
  2. Run the container on a cloud machine
  3. Print a cURL request to invoke the API
  4. Stream the logs to your shell

You should keep this terminal window open while developing.

(.venv) user@MacBook demo % beam serve app.py
 i  Using cached image.
 ✓  App initialized.
 i  Uploading files...
 ✓  Container scheduled, logs will appear below.
⠴ Starting container... 5s (Estimated: 3m20s)

================= Call the API =================

curl -X GET https://eh1dq-655a376a6d7360000745eaef.apps.beam.cloud

============= Logs Streamed Below ==============

Gradio server is not up yet, waiting...
Gradio app is ready
INFO:     | GET - /
INFO:     | GET - /assets/index-5550136d.js
INFO:     | GET - /assets/index-449ec8c6.css

Now, head back to your IDE, and change a line of code. Hit save.

If you look closely at the shell running beam serve, you’ll notice the server reloading with your code changes.

You’ll use this workflow anytime you’re developing an app on Beam. Trust us — it makes the development process uniquely fast and painless.

Call the API

Open a browser window and paste the URL printed when you ran beam serve.

https://eh1dq-655a35a06d73600009707a99.apps.beam.cloud

If you paste this URL in your browser, you’ll see the Gradio frontend:

Deployment

Now it’s time to deploy the app to create a persistent endpoint. In your shell, run this command to deploy your app:

beam deploy app.py

Unlike a temporary beam serve session, this will create a persistent deployment and will remain active until you stop it.

Further Reading