GradioでDatabricksにデプロイされた画像生成AIのフロントエンドを作成する

こちらの続きです。

https://qiita.com/taka_yayoi/items/8d3473847d9ccc8ca00c

今回はHugging FaceのSpaceでGUIを作成します。

こちらを参考にさせていただきました(同僚の方による記事です)。

https://zenn.dev/hiouchiy/articles/1538f0efdbcfaf

このように、GUIからDatabricksにデプロイされた画像生成AIを呼び出して、プロンプトに従った画像を生成します。なお、画像の生成には16秒程度要しています。

**音声はありません**
<iframe width="560" height="315" src="https://www.youtube.com/embed/mOOlr8eRECc?si=n60lkDQlJkCmgwiY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

コードはこちら。

```py:app.py
import itertools
import gradio as gr
import requests
import os
from gradio.themes.utils import sizes
import json
import pandas as pd

import base64
import io
from PIL import Image
import numpy as np
    
def respond(message, history):

    if len(message.strip()) == 0:
        return "指示を入力してください"

    local_token = os.getenv('API_TOKEN')
    local_endpoint = os.getenv('API_ENDPOINT')

    if local_token is None or local_endpoint is None:
        return "ERROR missing env variables"

    # Add your API token to the headers
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {local_token}'
    }

    #prompt = list(itertools.chain.from_iterable(history))
    #prompt.append(message)

    # プロンプトの作成
    prompt = pd.DataFrame(
        {"prompt": [message], "num_inference_steps": 25}
    )

    print(prompt)
    ds_dict = {"dataframe_split": prompt.to_dict(orient="split")}
    data_json = json.dumps(ds_dict, allow_nan=True)

    embed_image_markdown = ""

    try:
        # モデルサービングエンドポイントに問い合わせ
        response = requests.request(method="POST", headers=headers, url=local_endpoint, data=data_json)    
        response_data = response.json()
        #print(response_data["predictions"])

        # numpy arrayに変換
        im_array = np.array(response_data["predictions"], dtype=np.uint8)
        #print(im_array)
        # 画像に変換
        im = Image.fromarray(im_array, 'RGB')

    
        # debug
        #image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg/687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg"
        #print("image_url:", image_url)
        #im = Image.open(io.BytesIO(requests.get(image_url).content))
        #numpydata = np.asarray(im)

        rawBytes = io.BytesIO()
        im.save(rawBytes, "PNG")
        rawBytes.seek(0)  # ファイルの先頭に移動
        # base64にエンコード
        image_encoded = base64.b64encode(rawBytes.read()).decode('ascii')
        #print(image_encoded)

        # マークダウンに埋め込み
        embed_image_markdown = f"![](data:image/png;base64,{image_encoded})"
        #print(embed_image_markdown)
    
    except Exception as error:
        response_data = f"ERROR status_code: {type(error).__name__}" 
        #+ str(response.status_code) + " response:" + response.text    

    return embed_image_markdown


theme = gr.themes.Soft(
    text_size=sizes.text_sm,radius_size=sizes.radius_sm, spacing_size=sizes.spacing_sm,
)


demo = gr.ChatInterface(
    respond,
    chatbot=gr.Chatbot(show_label=False, container=False, show_copy_button=True, bubble_full_width=True),
    textbox=gr.Textbox(placeholder="生成する画像を指示",
                       container=False, scale=7),
    title="Databricks画像生成デモ - モデルサービングエンドポイントによるパーソナライズ画像の生成",
    description="[Databricksにおける生成AIを用いたブランドに沿う画像の生成](https://qiita.com/taka_yayoi/items/8d3473847d9ccc8ca00c)<br>**ファインチューニングに用いた画像**<br>![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d4e3422b-107e-1bd4-ff84-28e0ea0ac156.png)",
    examples=[["A photo of an orange bcnchr chair"],
              ["A photo of an blue hsmnchr chair"],
              ["A photo of an red rckchr chair"],],
    cache_examples=False,
    theme=theme,
    retry_btn=None,
    undo_btn=None,
    clear_btn="Clear",
)

if __name__ == "__main__":
    demo.launch()
```

Gradioでレスポンスに画像を埋め込む方法が見当たらなかったので、マークダウンの中にbase64にエンコードした画像を埋め込んでいます。

ファインチューニングに用いた画像はこちら。
![Screenshot 2024-04-24 at 14.18.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/15e96875-694a-4c4d-e158-68bc2ff8006a.png)

プロンプトを指定すると、それに沿った画像が表示されます。
![Screenshot 2024-04-24 at 14.18.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e81b9608-131b-d3fe-bde7-1b8992fe2674.png)
![Screenshot 2024-04-24 at 14.18.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/eb6f31b4-6940-1255-e985-623d5fd8c2c1.png)

参考資料はこちら。

- [Is it possible to directly embed an image into a Markdown document? \- Super User](https://superuser.com/questions/1199393/is-it-possible-to-directly-embed-an-image-into-a-markdown-document)
- [python \- How do I convert a numpy array to \(and display\) an image? \- Stack Overflow](https://stackoverflow.com/questions/2659312/how-do-i-convert-a-numpy-array-to-and-display-an-image)
- [Convert Python List to numpy Arrays \- GeeksforGeeks](https://www.geeksforgeeks.org/convert-python-list-to-numpy-arrays/)
- [python \- Image\.fromarray just produces black image \- Stack Overflow](https://stackoverflow.com/questions/47290668/image-fromarray-just-produces-black-image)
- [How to create a NumPy image array with the RGB value of each point using python? \- Stack Overflow](https://stackoverflow.com/questions/69783111/how-to-create-a-numpy-image-array-with-the-rgb-value-of-each-point-using-python)
- [python base64 encode to string \- Stack Overflow](https://stackoverflow.com/questions/36714281/python-base64-encode-to-string)
- [python \- How to convert a numpy array \(which is actually a BGR image\) to Base64 string? \- Stack Overflow](https://stackoverflow.com/questions/46598607/how-to-convert-a-numpy-array-which-is-actually-a-bgr-image-to-base64-string)
- [pillowモジュールにおいてURLから直接画像を読み込む \#Python3 \- Qiita](https://qiita.com/tamanobi/items/e135839bb8115792c185)
- [django \- Numpy Array to base64 and back to Numpy Array \- Python \- Stack Overflow](https://stackoverflow.com/questions/6485790/numpy-array-to-base64-and-back-to-numpy-array-python)

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)