見出し画像

google Gemini ProをWEBアプリにして使う/画像解析編

あけましておめでとうございます。makokonです。
前回Gemini Pro chatのWEBアプリを作成しました。
完成度はまだ低いのですが、いまは性能確認中なのでとりあえず色々用意していってます。
今回は、前回のチャットアプリに、画像解析機能を追加します。



準備 Gemini Proのモデルの準備

さっそく、モデルの準備をしましょう。
今回使用するモデルは、チャット用のGemini ProおよびGemini Pro Visionです。

import os
import datetime

import google.generativeai as genai

GEMINI_API_KEY=os.getenv('GEMINI_API_KEY')
genai.configure(api_key=GEMINI_API_KEY)

# chat model
# モデルの設定
generation_config = {
  "temperature": 0.9,  # 生成するテキストのランダム性を制御
  "top_p": 1,          # 生成に使用するトークンの累積確率を制御
  "top_k": 1,          # 生成に使用するトップkトークンを制御
  "max_output_tokens": 2048,  # 最大出力トークン数を指定
}
model = genai.GenerativeModel(model_name="gemini-pro",
                              generation_config=generation_config)
                              
chat_llm = model.start_chat(history=[])
model_image = genai.GenerativeModel('gemini-pro-vision')

チャットモデルをcaht_llmに画像モデルをmodel_imageにセットします。

gradioの内での準備

ライブラリ import

 #gradio 
import gradio as gr
import requests
from urllib.parse import urlparse
import base64
from PIL import Image
from io import BytesIO

gradioで使用するライブラリをインポートします。今回は画像解析のためにインターネットから画像を読み込んだり、適当にコード化するためにimportるすライブラリが少し増えています

コンテンツデザイン

ブラウザ上のデザイを決めます。
今回は一番上にGemini Proの回答を表示するボックス
二段目にチャット用のテキスト入力画面
三段目にチャット履歴の保存とリセットボタン
四段目に画像解析用のファイルパスを入力するテキストボックスと、指定した画像を確認するためのイメージウィンドウがあります。

with gr.Blocks() as demo:
     # コンポーネント
    chatbot = gr.Chatbot()
    msg = gr.Textbox()
    with gr.Row():
        reset_w_save = gr.Button("Save&reset history")
        reset_wo_save = gr.Button("reset history")
    with gr.Row():
        analyze_picture = gr.Textbox(label="画像の説明 URLを貼り付けてください。")
        image_box = gr.Image()

url確認用関数

urlが正しいことを確認するための関数を用意します。
is_valid_url(url) 指定したurlがhttp、httpsで始まっていてアドレスがあるか体裁を確認
is_image_url(url): 指定したurlが体裁を満たしていて、headerのcontent-typeがimageで始まっているかを確認。
なお、これらのチェックは完璧ではありません。サイトの設計によっては、正しいヘッダ情報がなかったり、情報の実体がなかったりします。実際のところ対処しようがないのでブラウザ上で画像が表示できることを確認してそのアドレスを入力するようにしたほうが遥かに安全です。(そのためにWEBアプリにしたという側面もある。大量のアドレスを自動で処理するならコンソールアプリで作ったほうが多分楽です)

    def is_valid_url(url):
        result = urlparse(url)
        # スキーマがhttpまたはhttpsであることも確認
        return all([result.scheme in ['http', 'https'], result.netloc])
        return False

    def is_image_url(url):
        # URLが正当であることを確認
        if not is_valid_url(url):
            return False

        # Send a HTTP HEAD request
        try:
            response = requests.head(url)
        except Exception as e:
            return False
        # Check if "content-type" header exists and starts with "image"
        if "content-type" in response.headers and response.headers["content-type"].startswith("image"):
            return True
        else:
            return False

会話履歴の管理 保存とリセット

会話履歴の保存とリセットをします。gradioのchatboxの履歴を管理すると同時にGemini Proのチャット履歴も合わせてリセットします。

    def save_chat_history(message,chat_history):
        filename = "chatlog"+datetime.datetime.now().strftime("%Y%m%d-%H%M%S")+".txt" 
        with open(filename, 'w',encoding='utf-8') as f:
            for chat in chat_history:
                f.write(f"User: {chat[0]}\nAI: {chat[1]}\n")
        chat_history=[]
        chat_llm.history=[] #チャットメモリも空に 
        return "",""

    def reset_chat_history(message,chat_history):
        chat_history=[]
        chat_llm.history=[] # チャットメモリも空に

        return "",""
        

チャット処理

gradioから、メッセージ(ユーザー入力)をチャット履歴をもらって、回答を生成して、chatboxを更新します。

       
    def chat_ai(message,chat_history):
        # 通常のチャット処理
        
        if len(chat_history) == 0:
            chat_llm.history=[] # 履歴が空なら、チャットメモリも空に
        
        prompt=message
        response = chat_llm.send_message(prompt)
        chat_history.append((message, response.text))

        return "", chat_history
       

画像解析 入力した画像をGemini Proに説明してもらう

gradioから画像url、chatbox、image_boxをうけとり、解析結果をchatboxに、入力された画像イメージをimage_boxに表示します。

    def anal_pict(message,chat_history,image_box):
        
        if len(chat_history) == 0:
             chat_llm.history=[] # チャットメモリも空に

        if is_image_url(message): #url  check
            # URLが正しい場合の処理
            url = message        
            #image_box =message
        else:
            chat_history.append((message,"正しい画像URLではありません。"))
            return "", chat_history,""
            
        # gemini pro vision setting
        #model_image  = genai.GenerativeModel('gemini-pro-vision')
        try:
            response = requests.get(url)
        except (requests.exceptions.MissingSchema, requests.exceptions.ConnectionError):
            chat_history.append((message,"画像のダウンロードに失敗しました。URLが正しいか確認してください。"))
            return "",chat_history,""

        try:
            img = Image.open(BytesIO(response.content))
            image_box=img
        except Exception as e:
            chat_history.append((message,"画像読み込み時にエラーが出ました。正しい画像URLを確認してください。"))
            return "",chat_history,""

            
        prompt = "画像について、日本語で説明してください。"
        response = model_image.generate_content([prompt, img])
        
        content = "画像の説明:\n"+response.text
        
        chat_history.append((message, content))

        return "", chat_history,image_box
    

今回の処理のフローです。

  • 画像url、Chat履歴、イメージボックスを受け取ります。

  • 今回はチャットと画像解析に関連性を持たせていないので、会話履歴をリセットします。(画像解析の前に必要なら履歴を保存してください)

  • 入力されたurlをチェックします。HTTPSから始まる体裁とコンテンツタイプがimageであることを確認しています。しかし、私の実力が足りなくて、サイトの設計の問題やライブラリの問題を吸収できていません。実際にブラウザで画像を表示して、その画像のアドレスを確認したあとに使ってください。(大事なことなので2回言った)

  • 画像イメージを取得します。
    response = requests.get(url) 画像データのダウンロード
    img = Image.open(BytesIO(response.content)) イメージデータに変換します。

  • 画像の解析
    response = model_image.generate_content([prompt, img])
    がぞイメージとプロンプトを渡して、解析します。
    今回のプロンプトは"画像について、日本語で説明してください。"です。まだGemini Proとあまり仲良くないので適切なプロンプトがまだよくわからないのですが、たんにイメージだけ渡すと英語で答えてくれます。
    解析結果は、resupense.textで取得できます。

  • リターン
    解析結果とイメージをchat_historyとimage_boxに入力して返します。

呼び出し

  • launch
    テキストボックスの確定、ボタンのクリックをトリガーとして各種関数を呼び出します。gradoの関数呼び出しは、関数名、入力パラメータリスト、出力パラメータリストです。

  • 全体の実行
    with gr.Blocks() as demo: で設定しているので、
    demo.launch(share=True)で実行します。
    share=Trueだと、ローカルネットワーク内で呼び出し可能になります。

実行時結果

実行時のスクリーンショットです。画像はstable diffusionで作成しました。
右下の画像をそれなりに丁寧に説明してくれました。

https://th.bing.com/th/id/OIG.9P5R1vLF9muZ_xMISQMw?pid=ImgGn


画像の説明:
この画像には、設計図や道具が描かれています。設計図の上には拡大鏡が置かれており、その隣で一人の人間がペンを持っています。そのほかにも、のこぎり、ペンチ、定規などの道具が置かれています。
実行時のスクリーンショット

まとめ

Gemini Proとgradoを使ってチャットと画像解析をしてくれるWEBアプリを作成しました。画像イメージををそのまま渡すだけで解析してくれるので、とても便利です。
内部のテキストも読んでくれるようです。OCRとして使うならプロンプトを変えたほうがいいかもしれませんね。シンプルなアプリを自分のために作るのが普段使いとしては最も便利です。将来的にビジネスにするには高機能、多機能がいいかもしれませんが、今回は文房具レベルですね。

#python #google #gemini -pro #gemini -pro-vision #program #WEBアプリ #gradio #チャット #画像解析

この記事が気に入ったらサポートをしてみませんか?