GradioでURLパラメータを使う+IPアドレス取得

# Gradio

Gradioは機械学習のために作られたPythonの簡易Webアプリ作成ライブラリです。最近では生成AIのデモ画面でよく使われています。（[stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui)もGradioで作られています）

https://www.gradio.app/

# URLパラメータ

URLパラメータとはURLにセットできるパラメータのことです。
そのままになってしまいましたが、例で言いますと

「https://www.google.com/search」<br>
がGoogleでの検索ページだとすると<br>
「https://www.google.com/search?q=ChatGPT 」<br>
この"?"の後の **"q=ChatGPT"** がURLパラメータとなります。
例の場合はqが検索ワードとなり検索画面のトップではなく **"ChatGPT"** で検索したページが表示されます。Webページに **「引数を渡す」** イメージで利用されます。

※余談ですが、これを使えばAmazonで販売元がAmazonの商品のみで検索できます。
https://news.mynavi.jp/article/20210429-1880967/


# GradioでURLパラメータの取得

ここから本題でGradioでこのURLパラメータを取得したいと思います。
といっても私が考えた訳ではなく、ここからコードを盗んできただけです。

https://github.com/gradio-app/gradio/pull/5681

```Python:gradioインストール
!pip install gradio
```

```Python:Interface版サンプル
import gradio as gr

def echo(text, request: gr.Request):
    if request:
        print("Request headers dictionary:", request.headers)
        print("IP address:", request.client.host)
        print("Query parameters:", dict(request.query_params))
        print("Session hash:", request.session_hash)
    return text
    
io = gr.Interface(echo, "textbox", "textbox").launch(debug=True)
```
<br>
これで表示されるURL"https://*************.gradio.live"の最後に例えば"?param_1=test"と付けて
<b>"https://*************.gradio.live?param_1=test"</b>としてあげてるとパラメータが取得できます。[Submit]ボタンを押すと次のような出力があります。

```:出力結果（※debug=Trueにして出力）
Request headers dictionary: Headers({'host': 'ab97237a24f1dfc6b2.gradio.live', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36', 'content-length': '88', 'accept': '*/*', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'ja,en-US;q=0.9,en;q=0.8', 'content-type': 'application/json', 'cookie': '_ga=GA1.1.1182675414.1715833129; _ga_R1FN4KJKJH=GS1.1.1716249900.5.1.1716250992.0.0.0', 'origin': 'https://ab97237a24f1dfc6b2.gradio.live', 'priority': 'u=1, i', 'referer': 'https://ab97237a24f1dfc6b2.gradio.live/?param_1=test', 'sec-ch-ua': '"Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'x-amzn-trace-id': 'Root=1-6651e494-1bb07cf15e3ee7c817d0a5e5', 'x-forwarded-for': '124.140.137.144, 172.31.13.118', 'x-forwarded-port': '443', 'x-forwarded-proto': 'https'})
IP address: 172.31.13.118
Query parameters: {'param_1': 'test'}
Session hash: mhserhda9f
```
<br>

dict(request.query_params)に指定した変数と値が辞書型でセットされています。
param_1が目当てのパラメータなら**dict(request.query_params).get("param_1")** で値（この場合は'test'）を取得できます。

あとおまけでIPアドレスも取得できています。
※GoogleColabなどで実行すると自身のアドレスと異なると思いますが**request.headers["x-forwarded-for"]** に送信元アドレスが含まれています

関数の引数に**request: gr.Request**を加えるだけで簡単にできてしまいました。（仕組みは今ひとつ不明です…）

ちなみにgr.Requestは[fastapi.Request](https://fastapi.tiangolo.com/ja/tutorial/body/)クラスからのラッパーとなるようです。

# Blockバージョン
Interfaceではなく[Block](https://www.gradio.app/docs/gradio/blocks)でもできます。
```Python:Blockバージョン
import gradio as gr

block = gr.Blocks()

def echo(text, request: gr.Request):

    if request:
        print("Request headers dictionary:", request.headers)
        print("IP address:", request.client.host)
        print("Query parameters:", dict(request.query_params))
        print("Session hash:", request.session_hash)
        
    return text

with block:
    text_input = gr.Text(label="Input")
    text_output = gr.Text(label="Output")
    btn = gr.Button("Run")
    btn.click(fn=echo, inputs=[text_input], outputs=[text_output])

block.launch(debug=True)
```

出力内容は同じです。

# 用途について
今更ですが **「こんなの何に使うのか？」** と思うかもしれません。
特定の人にだけ使ってもらいたいアプリがある場合に、このパラメータ付きのURLを教えてあげることで利用者の制限ができます。
```Python:URLパラメータによる制御
import gradio as gr

def echo(text, request: gr.Request):

    key = ""

    if request:
        key = dict(request.query_params).get("key")

    if key == os.environ["KEY"]:
        text = "使用できます"
    else:
        text = "使用できません"

    return text

io = gr.Interface(echo, "textbox", "textbox").launch()
```
?key=****が環境変数"KEY"と同じ場合のみ使える制御ができます。

<br>

[Huggingface Spaces](https://huggingface.co/spaces)にGradioのアプリをデプロイできるのですが、以前<b>「DALL·E3を無料で使えますよ！」</b>とAPIキーを自腹で開放したら、謎の外国人にめちゃくちゃ使われたことがあります…（なぜ外国人とわかったかと言うと、閉めたとたんXのリプライで<b>「bring back free dalle-3」</b>と怒られました）

SNSで公開するとき、こういったパラメータ付きにすれば利用者を限定できるはずです。
他にも入力の省略など色々な用途に使えるかと思います！