import gradio as gr import openai import base64 import pandas as pd import uuid import io import os def analyze_image(image_path, api_key): """ 画像を読み込み、base64エンコードした上で 指定したOpenAI API (gpt-4o-mini) に投げてCSVを取得し、 テーブル表示用データとダウンロード用ファイルを返す """ # 画像またはAPIキーが未入力の場合はメッセージを返す if not image_path: return "画像をアップロードしてください。", None if not api_key: return "API Key を入力してください。", None # 画像をbase64に変換 with open(image_path, "rb") as f: image_data = f.read() image_base64 = base64.b64encode(image_data).decode("utf-8") # UUIDはOpenAI側に生成を指示してもよいですが、こちらで生成してもOKです。 # ここではOpenAIに完全に任せるため、プロンプトで生成を依頼する例とします。 # 必要に応じてこちらで生成した UUID を挿入することも可能です。 # ChatGPT(gpt-4o-mini)に送るユーザープロンプト user_prompt = f""" 以下の画像に写っている各部位の計測値(首、肩、二の腕L、二の腕R、胸、ウエスト、ヒップ、太腿L、太腿R、ふくらはぎL、ふくらはぎR)を読み取り、 次のCSVフォーマットで出力してください。なお、CSVの1行目には列名を、2行目には画像から抽出した数値を入れてください。 左端のID列には自動生成したUUIDを記載してください。 出力には余計な説明文を加えず、CSVテキストのみとせよ。 - CSVフォーマット例: ID,首,肩,二の腕L,二の腕R,胸,ウエスト,ヒップ,太腿L,太腿R,ふくらはぎL,ふくらはぎR <自動生成UUID>,<首の数値>,<肩の数値>,<二の腕L>,<二の腕R>,<胸>,<ウエスト>,<ヒップ>,<太腿L>,<太腿R>,<ふくらはぎL>,<ふくらはぎR> もし画像から読み取れない数値があれば空欄や"N/A"としてください。 """ try: # OpenAI API呼び出し client = openai.OpenAI(api_key=api_key) response = client.chat.completions.create( model="gpt-4o-mini", messages=[ { "role": "user", "content": [ { "type": "text", "text": user_prompt, }, { "type": "image_url", "image_url": { "url": f"data:image/png;base64,{image_base64}", } }, ] } ], temperature=0.0 ) except Exception as e: return f"API呼び出しエラー: {str(e)}", None # APIの応答(CSVテキスト想定) csv_text = response.choices[0].message.content.strip() csv_text = csv_text.replace('```', '') # pandasでテーブルに変換を試みる try: df = pd.read_csv(io.StringIO(csv_text)) except Exception as e: # CSVとしてパースできなければテキストのみ返す return f"CSVとして解析できませんでした。応答内容:\n{csv_text}", None # CSVをtemp.csvに出力する df.to_csv('temp.csv', index=False) return df, 'temp.csv' # Gradioアプリの定義 with gr.Blocks() as demo: gr.Markdown("# 画像から数値を読み取り、CSVを生成するデモアプリ") api_key_input = gr.Textbox( label="OpenAI API Key", placeholder="sk-...", type="password", show_label=True ) image_input = gr.Image( label="画像アップロード", type="filepath" ) generate_button = gr.Button("CSV生成", variant="primary") download_button = gr.DownloadButton("CSVダウンロード") # 出力は DataFrame と File (ダウンロード用) output_table = gr.DataFrame(label="CSVプレビュー") # ボタンクリック時の動作 generate_button.click( fn=analyze_image, inputs=[image_input, api_key_input], outputs=[output_table, download_button] ) if __name__ == "__main__": demo.launch()