How to serve an HTML file?

When running Gradio, I am generating an HTML file on the background, that I would like to serve
in a URL like: https://123455a.gradio.live/output.html

I was able to generate the file, but when I try to access, I get:

{"detail":"Not Found"}

What should I do?

Thank you

Hi @mandyvarel ,

That’s a great question. You can’t serve the static pages direct from Gradio, but you can mount Gradio within another FastAPI app.
Then use the FastAPI app StaticFiles to serve the static pages under /static and the Gradio app under /.

Here is a complete example of how to do that:

from pathlib import Path
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
import uvicorn
import gradio as gr
from datetime import datetime


# create a FastAPI app
app = FastAPI()

# create a static directory to store the static files
static_dir = Path('./static')
static_dir.mkdir(parents=True, exist_ok=True)

# mount FastAPI StaticFiles server
app.mount("/static", StaticFiles(directory=static_dir), name="static")

# Gradio code
def predict(text_input):
    file_name = f"{datetime.utcnow().strftime('%s')}.html"
    file_path = static_dir / file_name
    print(file_path)
    with open(file_path, "w") as f:
        f.write(f"""<h2>Hello {text_input} </h2>
        <h3>{file_name}</h3>
        """)

    return f'<a href="/static/{file_name}" target="_blank">{file_name}</a>'


with gr.Blocks() as block:
    text_input = gr.Textbox(label="Name")
    markdown = gr.Markdown(label="Output Box")
    new_btn = gr.Button("New")
    new_btn.click(fn=predict, inputs=[text_input], outputs=[markdown])

# mount Gradio app to FastAPI app
app = gr.mount_gradio_app(app, block, path="/")

# serve the app
if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=7860)

# run the app with
# python app.py
# or
# uvicorn "app:app" --host "0.0.0.0" --port 7860 --reload

To run,

python app.py

or

uvicorn "app:app" --host "0.0.0.0" --port 7860 --reload

If you’re running on Colab you need an slightly different approach:

Here’s an example

1 Like

Thanks for your explanation Radames.
I copied your entire code on a file called app.py
And ran the command as you suggested

uvicorn "app:app" --host "0.0.0.0" --port 7860 --reload

I got the following answer:


INFO:     Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
INFO:     Started reloader process [4637] using StatReload
Starting to load FastAPI app...
INFO:     Started server process [4639]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

But, I couldn’t access the app anywhere. As it didn’t offer me a local or remote address. What am I doing wrong?

Thanks!

hi @mandyvarel,

Your app is now running on http://0.0.0.0:7860 , can you try open that link on your browser?
Just to double check, you’re not on colab/jupyter but on your localmachine right?

Hi @mandyvarel , I’ve published a live demo here if that helps

Great @radames, I managed to move one step forward and making it run. In your code, you had:

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=7860)

I changed to:

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=7862)

And it’s working. Locally (never worked with 0.0.0.0)
Now, the question, can I make this work with the automatic external address creation? Like it works when I use launch(share=True) on gradio?

And yes, I am not on Jupyter or Collab. I am on my machine.

Thank you

Hi @mandyvarel just chiming in here. So we don’t support share links using this approach (there are other free solutions like ngrok which can allow you create a public link for any arbitrary local server you could try)

But I wanted to potentially suggest a simpler solution. If you do not need the URL to be exactly https://123455a.gradio.live/output.html, then Gradio does allow you to serve static files in the same directory (or child directory) using the https://123455a.gradio.live/file= URL prefix. In your case, something like: https://123455a.gradio.live/file=output.html would produce the HTML file. (This approach means that you wouldn’t have to mount Gradio at all and should work locally and using the share links)

2 Likes

amazing @abidlabs, that’s much better, no need to mount Gradio with FastAPI then,

here is the solution now with the share=True feature!

from pathlib import Path
import gradio as gr
from datetime import datetime
import sys


# create a static directory to store the static files
static_dir = Path('./static')
static_dir.mkdir(parents=True, exist_ok=True)


def predict(text_input):
    file_name = f"{datetime.utcnow().strftime('%s')}.html"
    file_path = static_dir / file_name
    print(file_path)
    with open(file_path, "w") as f:
        f.write(f"""
        <script src="https://cdn.tailwindcss.com"></script>
        <body class="bg-gray-200 dark:text-white dark:bg-gray-900">
        <h1 class="text-3xl font-bold">
        Hello <i>{text_input}</i> From Gradio Iframe
        </h1>
        <h3>Filename: {file_name}</h3>
        """)
    iframe = f"""<iframe src="file={file_path}" width="100%" height="500px"></iframe>"""
    link = f'<a href="file={file_path}" target="_blank">{file_name}</a>'
    return link, iframe


with gr.Blocks() as block:
    gr.Markdown("""
## Gradio + FastAPI + Static Server
This is a demo of how to use Gradio with FastAPI and a static server.
The Gradio app generates dynamic HTML files and stores them in a static directory. FastAPI serves the static files.
""")
    with gr.Row():
        with gr.Column():
            text_input = gr.Textbox(label="Name")
            markdown = gr.Markdown(label="Output Box")
            new_btn = gr.Button("New")
        with gr.Column():
            html = gr.HTML(label="HTML preview", show_label=True)

    new_btn.click(fn=predict, inputs=[text_input], outputs=[markdown, html])

block.launch(debug=True, share=True)
2 Likes

Yes! Working beautifully! Thank you legends!

2 Likes

Hello, I am curious, is it possible to show it on a gr.HTML? (With tailwind and so on?) I’ve already tried it but I could not, thank you!

Regards