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.
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.
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"
def start_frontend():
subprocess.Popen(["python3", "frontend.py"])
start_time = time.time()
elapsed = 0
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
@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("/")
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:
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:
- Spin up a container
- Run the container on a cloud machine
- Print a cURL request to invoke the API
- 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:
Unlike a temporary beam serve
session, this will create a persistent deployment and will remain active until you stop it.
Further Reading