🧠

TFT液晶にOpenAIのAPIからのレスポンスを表示させてみた

2024/07/29に公開

はじめに

前回の記事では、Raspberry Pi 5に繋げたTFT液晶に文字を出力するところまで行いました。
今回はOpenAIのAPIを使って、生成された文字をTFT液晶に出力する部分を作ってみます。

OpenAIのAPIを使えるようにする

こちらの記事を参考に、OpenAIのAPIを使用するためのキーを発行しました。詳しくはこちらをご参照ください。
https://qiita.com/Isaka-code/items/b50983796636503b44c5#openai-apiをquickstartする手順

キーを発行したら必ずどこかに保管しておいてください。OpenAIのユーザー管理の画面からキー全体を再確認することは不可能です。

OpenAIのAPIをTFT液晶文字出力のソースコードに組み込んでみる

OpenAIのAPIをTFT液晶文字出力のソースコードに組み込んでみます。

事前準備

今回は、「日本の都市を入力したらその都市の情報を取得してTFT液晶に表示させる」ということを試してみます。

事前に回答の出力に関しては以下のように制限を設けます。

  • 実在する都市について説明するキャラクターが回答するものとして設定する
  • 質問者が提示した都市が実在するものであればその都市の場所、人口、面積、特徴、その都市の周りにある都市の5つを説明してもらう
  • 都市が存在しない場合は「その都市は存在しません」と返す
  • 全体の回答は200文字以内とする(漢字一文字とひらがな一文字は同じものとして考える)

また、このスクリプトを実行したら、ターミナルに日本の都市をユーザーに入力してもらうようにします。

今回使用するモデルはgpt-4o-miniとしました。

パッケージのインストール

Pythonの仮想環境を作成し、pipでOpenAIのモジュールをインストールします。

souce .venv/bin/activate
pip install --upgrade openai

※TFT液晶自体を動かすためのモジュールは前回の記事に書かれているため必要とあれば合わせてインストールしてください。

ソースコード

lcd_demo_openai_api.py
from adafruit_rgb_display.ili9341 import ILI9341

from busio import SPI
from digitalio import DigitalInOut
import board
import textwrap

from PIL import Image, ImageDraw, ImageFont

from openai import OpenAI

OPENAI_API_KEY: str = "<OpenAPIのキー>"

def input_city() -> str:
    city: str = input("日本の実在する都市を入力してください。:")
    return city

def create_user_content(city: str) -> str:
    user_content: str = f"日本の{city}について説明してください。"
    return user_content

def draw_image(user_content: str) -> None:
    client: OpenAI = OpenAI(api_key=OPENAI_API_KEY)
    completion = client.chat.completions.create(
      model="gpt-4o-mini",
      messages=[
        {"role": "system", "content": "あなたは実在する都市について説明するキャラクターです。質問者が提示した都市が実在するものであればその都市の場所、人口、面積、特徴、その都市の周りにある都市の5つを説明してください。都市が存在しない場合は「その都市は存在しません」と返してください。"},
        {"role": "system", "content": "漢字一文字とひらがな一文字は同じ文字数と考えてください。全体の回答は200文字以内としてください。"},
        {"role": "user", "content": user_content}
      ]
    )

    # ピンの構成
    cs_pin = DigitalInOut(board.D2)
    dc_pin = DigitalInOut(board.D24)
    rst_pin = DigitalInOut(board.D23)

    # SPIバスを設定
    spi = SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO)

    # ILI9341ディスプレイのインスタンスを作成
    disp = ILI9341(
        spi,
        cs=cs_pin, dc=dc_pin, rst=rst_pin,
        width=240, height=320,
        rotation=90,
        baudrate=24000000
    )

    # イメージサイズを定義
    IMAGE_SIZE = (disp.height, disp.width)

    # フォントを定義
    FONT_NOTO = ImageFont.truetype("NotoSansCJK-Regular.ttc", 18)

    # 色を定義
    COLOR_WHITE = (255, 255, 255)

    # 黒背景を作成
    image = Image.new("RGB", IMAGE_SIZE, (0, 0, 0))

    # テキストを描画
    draw = ImageDraw.Draw(image)
    text = completion.choices[0].message.content

    print(text)
    s_wrap_list = textwrap.wrap(text, 15)
    
    for i, name in enumerate(s_wrap_list):
        draw.text((0, 24*i), name, font=FONT_NOTO, fill=COLOR_WHITE)
    
    # ディスプレイに表示
    disp.image(image)

    return None

def main():
    city = input_city()
    user_content = create_user_content(city=city)
    draw_image(user_content=user_content)

if __name__ == "__main__":
    main()

TFT液晶に表示できる文字数には限界があるため、フォントサイズと画面サイズを考慮して、今回は200文字以内で15文字ごとに文章を改行するようにしました。

結果

スクリプトを実行してみます。例えば今回は「静岡市」と入力してみます。

(.venv) sakashu@raspberrypi:~/Desktop/Programming/lcd $ python lcd_demo_openai_api.py
日本の実在する都市を入力してください。:静岡市

OpenAIからは以下のように返ってきました。

静岡市は日本の静岡県に位置し、人口約38万人、面積は1,400平方キロメートルです。富士山の近くにあり、美しい自然景観が特徴です。茶の産地としても有名で、文化的なイベントも多く開催されます。周囲には浜松市、沼津市、藤枝市、御殿場市、三島市があります。

※静岡市の面積は大まか合っていますが、現在の人口は67万人程度で出力された人口と実際の人口は異なっています。

また、OpenAIのAPIによって得られた結果をTFT液晶に表示させることができました。

最後に

今回はOpenAIのAPIによって得られた結果をTFT液晶に表示させるということを検証してみました。

課題感として、液晶に文字を表示させるときは文字数などを考慮して、サイズ調整をする必要があるということが分かりました。バスのような電光掲示板で文字スクロールができるような仕組みも作ってみようと思います。

次回はOpenAIのAPIから受け取った出力をRaspberry Piから音声出力できるかを試してみます。もしRaspberry Pi AIキットが手に入ればその検証もしてみようと思います。

ヘッドウォータース

Discussion