0
0

Gradioでhtmlファイルを読み込み、iframe(srcdoc)とgradio.HTMLで表示する方法

Last updated at Posted at 2024-07-27

ツイーティ・ザ・フォックスと申します。
Qiita初投稿です。新参者なのでマサカリ歓迎です。
Zennにもエラー対処法を中心に投稿を行っています。
https://zenn.dev/tweeteafox300?tab=scraps

記事概要と検証環境

PythonでWebアプリを作成できるライブラリのGradioで、ディレクトリに配置したhtmlファイルを、iframe(srcdoc)とgradio.HTMLを使って表示させる方法を、サンプルによって説明します。

Hugging Faceのフォーラムで提案されていた別の方法:★参考にした記事(本記事とは別の方法)に、難しい部分や原因不明のエラー発生があったので、それらよりもシンプルな方法を考えてみました。

 
検証環境
・pythonは3.11、Gradioは4.37.2です。
・ローカル環境(Win10のPowershell)に起動したローカルサーバーで確認。
・本番環境(Hugging Face等)にデプロイした時の挙動は確認していません。

pyproject.toml
[tool.poetry.dependencies]
python = "^3.11"
gradio = "^4.37.2"

[本題]:Gradioでhtmlファイルを読み込み、iframe(srcdoc)とgradio.HTMLで表示

0:ディレクトリ構成

Pythonのプログラムとhtmlファイルのみです。

ディレクトリ構成
.
├── app.py
└── html/
    └── test.html
    

1:表示させるhtmlファイルを準備

GradioのUI上に表示させたいhtmlファイルを./html/test.htmlに作成します。

今回準備した簡単なhtmlファイル
   --------------折りたたみ----------------
test.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <style>
    body{
      background-color:aquamarine;
    }
  </style>

</head>
<body>

  <h1>html埋め込みテスト</h1>
  <h2>テスト1</h2>
  <h3>テスト2</h3>
  <textarea id="testtextarea">あああああ</textarea>
  <button id="testbutton">JavaScriptテストボタン</button>

  <script>
    // ボタンを押すとテキストエリアの中身を変えるだけ
    const tarea = document.getElementById("testtextarea");
    document.getElementById("testbutton")
      .addEventListener("click", function () {
        tarea.value = "ボタンが押されるとこの文字列を表示\n\nこれが表示できている\n=JavaScriptの動作に成功";
    });
  </script>

</body>
</html>

2:iframe(srcdoc)とgradio.HTMLを使ってGradio上で表示!

  1. ディレクトリに配置したhtmlをopenで読み込み、文字列として取得します。
     
  2. Python標準モジュールのHTML.escapeを使用して、html文字列内にあるhtml特殊文字をエスケープします。
    https://docs.python.org/ja/3/library/html.html
     
  3. f文字列を使って「iframeタグのsrcdocプロパティに、エスケープ済みのhtml文字列を入れ込んだ文字列」を作成します。srcdocプロパティにエスケープしていないhtml文字列(特に")を入れ込んでしまうと、iframeタグが機能しなくなってしまうので注意です。
    https://developer.mozilla.org/ja/docs/Web/API/HTMLIFrameElement/srcdoc
     
  4. 作成したiframeタグ文字列をgradio.HTMLのコンポーネントに入力すると、htmlを表示することができます!
    https://www.gradio.app/docs/gradio/html
     
app.py
import gradio as gr

# gradionのHTMLと重複してエラー出た?ので別名に
import html as html_lib

# 表示させるhtmlファイルのパス
html_file_pass = "./html/test.html"


def load_html():
    # htmlファイルを文字列として読み込む
    html_string = open(html_file_pass, "r", encoding="UTF-8").read()

    # python標準のhtmlモジュールでHTML特殊文字をエスケープする
    # iframeのsrcdoc内にいれる関係で、ダブルクォート(")含めエスケープが必要
    # https://docs.python.org/ja/3/library/html.html
    html_escaped = html_lib.escape(html_string, quote=True)

    # iframeのsrcdoc内に読み込んだhtmlの文字列を入れる
    # https://developer.mozilla.org/ja/docs/Web/API/HTMLIFrameElement/srcdoc
    iframe = (
        f"""<iframe srcdoc="{html_escaped}" width="100%" height="300px"></iframe>"""
    )
    return iframe


with gr.Blocks() as html_test:
    gr.Markdown("# エメラルド色の部分がiframeで埋め込んだhtml")
    view_btn = gr.Button("./html/test.htmlを読み込み表示", variant="primary")

    # iframeのタグをgr.HTMLに入れて表示させる
    view_html = gr.HTML(label="HTML preview", show_label=True)
    view_btn.click(fn=load_html, outputs=view_html)


html_test.launch()

3:実際に表示される画面

上記のプログラムをgradio app.pyで実行、ローカルサーバーを起動してアクセスすると、このようになります。CSSでの色変更(エメラルド色)と、JavaScriptの動作(ボタンのイベントリスナー)が効いていることを確認できます。

iframe.PNG

★参考にした記事(本記事とは別の方法)

Gradio上でhtmlファイルを生成し、それのファイルパスをiframeのsrcでfile={ファイルパス}と指定して表示

Hugging Faceのフォーラム「How to serve an HTML file?」の8番目の投稿で共有されている方法
https://discuss.huggingface.co/t/how-to-serve-an-html-file/33921/8

  • この方法を本記事のサンプルと同じようなやつで試した所、iframeの部分で{“detail”:“File not allowed: /html/test.html.”}というエラーが出て失敗してしまいました。hugging faceのディスカッション「How to access tmp files of a space?」で同様のエラーが報告されているのですが、2024年7月27日時点では、原因不明かつ解決策が出ていないようでした。
    https://discuss.huggingface.co/t/how-to-access-tmp-files-of-a-space/59257

FastAPIアプリにGradioアプリをマウント、Gradio上でhtmlを生成し、FastAPIで静的ページとして公開。Gradioでそれのパスをiframeのsrcに指定して表示

Hugging Faceのフォーラム「How to serve an HTML file?」の2番目の投稿で共有されている方法
https://discuss.huggingface.co/t/how-to-serve-an-html-file/33921/2

★参考にした記事(応用例)

FastAPI+Gradioで、クエリの結果をインタラクティブな表として閲覧できる、DuckDBのSQLエディタを作成した事例

一つ上にあるような「Gradio上でhtmlを生成して、FastAPIで静的ページとして公開」というアプローチを使うと、かなり複雑なことができるみたいです。

Live DuckDB editor on Gradio
https://medium.com/@liquidc/live-duckdb-editor-on-gradio-533addd0666c
duckdb-fastapi-gradio
https://huggingface.co/spaces/liquidcarbon/duckdb-fastapi-gradio

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0