実験! 進化思考 / 名著 進化思考のLogicを 実験で確かめる(その8:蛇の道と知りつつ、生成AIで 「進化のタイパ」 を遂行する)
いったい 何してたん!?
実に 4ヶ月ぶりの投稿です。
その間、何をしていたのか…
実は サボっていた と言うより 色々試行していたのですが、中々 公表する様な成果に結び付かず、あれよあれよ… という間に 時間が過ぎてしまいました。😵💫
色々とは…
最初のつまずきは、シリーズ その5 まで展開していた 粘菌解析では 色々 計算方法を探索したのですが、ついに 適正な解(=条件により 最適なルートを自動探索する)を見つけられずに断念。 😱
その為、その6で開示しようとしていた プログラミング公開を諦めました。
次に着手したのは、進化テーマを Wikipedia上から 進化思考・時空間マップにおける 解剖/生態/歴史/予測 の情報を抽出するプログラム。
これは、「Wikiから抽出した情報を元に 生成AI(LLM)を使って 文章化する」ものであり、そこそこ出来たのですが、良く考えると 生成AIの餌(元データ)として Wikiは使われているので、いっそ 直接 生成AIに問い合わせた方がスマートじゃん! という無駄な遠回りをした結果、4ヶ月も過ぎてしまいました。 🥴
とは言え、お陰様で プログラミングの感覚を少し思い出し、開発環境にも 少し慣れてきたので ここまでの成果公開をします。
何を作ったんですか?
前述の通り、「進化テーマを (Chat)GPTに投げ込んで、進化思考・時空間マップにおける 解剖/生態/歴史/予測 の情報を抽出するプログラム」になります。
出来上がりは こんな感じ。
この例ですと、ユーザは 「自動車」と入力するだけで、(環境にも依りますが)約50秒くらいで このマップが出来上がります。
このシリーズの初回(その1)で 「生成AIは 進化(思考)にあらず」とブチまけていた割には こんなものを作って 蛇の道に手を染めている感は否めませんが、これも 時代には逆らえず/逆らわず… という事で、圧倒的な 時短/タイパの効果を優先しましょう。
もちろん、進化思考を学ばれた方は 御存知の通り、これは あくまでも "準備段階" であり、進化思考の真骨頂は「"ここから/これをベースに" あらゆる方向への進化を思考する」 ものなので、あくまでも 「進化の準備の為の 時短ツール」になります。
どんな仕組み?
プログラムの仕組みは 至って簡単です。
必要なモジュールを呼び出し、下準備。
進化テーマを入力。
GPTに投げ込む 質問文を作成。
出力準備。 今回は 予め用意した 時空間マップの画像データに 貼り付ける形とした。(なので、抽出した文字も "画像形式"での貼り付け になります ← コピペが出来ないので ここは 後日 改良します)
解剖/生態/歴史/予測 の4つの質問に対する解答を 所定の画像位置に貼り付け
最後に 進化テーマを 画像中央に 貼り付けて 画像出力。
簡単です。 😃
誰にでも作れます。 もしかしたら 既に 作った方もおられるかも。
強いていうと 質問文を それらしく作る所が ミソ(コツ)でしょうか。
詳細は 後ほど…
ざっくり解説
言語は Pyrhon。 環境は Google Colab。 LLMは Open-AI を使用 の事例になります。
下準備
Open-AIは 予め アカウントを作成し、API-Key を取得し、Google Colab のシークレットキーに 設定しておく必要があります。
PILは 画像埋め込み用のモジュール のインポート。
"sw_GPT" は、質問を投げ込む GPTモデルの選択で、本プログラム内部設定用の変数(定数)です。
# ***** 下準備 *****
!pip install openai
from openai import OpenAI
import os
from google.colab import userdata
from PIL import Image, ImageDraw, ImageFont
os.environ["OPENAI_API_KEY"] = userdata.get('OPENAI_API_KEY')
client = OpenAI()
# GPTのモデル選択
sw_GPT = "V4"
# sw_GPT = "35-turbo"
# 画像Path指定
os.chdir("/content/drive/MyDrive/Colab Notebooks")
path = os.getcwd()
# 画像名指定
image_path = "image/baseSheet_2.jpg"
output_path = "image/output_image.jpg"
# フォント指定
font_path = "Fonts/「お好きなフォント」.ttc"
font_size = 14
その後、 画像ファイルの指定、フォントの設定、出力画像の"下地"の画像を読み込み を行います。
OSの機能を使って Path(カレントフォルダ)を指定し、入出力画像ファイル名を指定します。
この例ですと カレントフォルダに "image" フォルダを作成しておいて下さい。
フォントは、日本語で出力したい場合は(当然)日本語フォントを指定下さい。
Google Colab 環境では デフォルトでは 綺麗な日本語フォントは設定されていない(かな?)と思いますので、自分の Driveに 好きなフォントを Copyして読み込みます。
下記の記述例ですと、カレントフォルダに "Fonts" フォルダを作成し、その中に「お好きなフォント」データを Copyしておき、そのファイル名を指定します。(コードの「お好きなフォント」部分を書き換えて下さい)
ちなみに、Windows用のフォントも Copyして使える様ですが、ライセンス的に許容されるか? は 御確認下さい。
2.進化テーマを入力
特に関数化する事も無いですが…
(関数名は 改造経緯の名残ですので 気にせずに…)
# 進化テーマの入力関数
def find_relation_patterns():
word1 = input("\n *進化させたいテーマ(単語)を入力してください。:")
return word1
3.GPTに投げ込む 質問文を作成
まずは、先程の関数を使って "進化テーマ"を入力します。
それを使って GPTに投げ込む質問文のリストを作成します。
全部で 4行。 1行目から 歴史/解剖/生態/予測 用の質問文になります。
"word" は、2.項 で入力した 進化テーマが代入されます。
前述の通り、ここの内容により 出力結果が(大きく)影響を受けます
ので、いい感じの文を試行錯誤してみて下さい。✨
# 探索語 入力
word = find_relation_patterns()
# 質問文作成用のリスト
list_question = [
word + "の歴史に関して 箇条書きにして まとめて下さい。 進化の過程が判る様に説明して下さい。",
word + "の構造に関して 箇条書きにして まとめて下さい。 どんな仕組みで成り立っているのか いくつかの部品に分けて説明して下さい。",
word + "に関連する事項に関して 箇条書きにして まとめて下さい。 "+ word + "と共に進化をしている事や "+ word + "によって影響を受けている様な事を説明して下さい。",
"これらの情報から" + word + "の未来を予測して下さい。 皆がワクワクする様な進化して行く様を 箇条書きにして下さい。"
]
4.出力準備
時空間マップの下地画像は、Excelで作成した物を jpeg形式で保存しました。
時空間マップのフォーマット自体には(太刀川さんの)版権は 掛かっていない(?)かと思いますので、下記に置いてみます。(NG情報が有れば 御連絡を!)
カレントフォルダに "image" フォルダを作成し、そこに Copyして下さい。
5.解剖/生態/歴史/予測 の4つの質問に対する解答を 所定の画像位置に貼り付け
いよいよ メイン部分です。
冒頭の 2つの関数は、解答を得る関数と 解答のテキスト文を画像に貼り付ける関数です。
# 質問に対する解答を得る関数
def ask_question(question):
prompts = f'''以下の質問に対し、回答して下さい
[ユーザの質問]
{question}
'''
if sw_GPT == "V4":
response = client.chat.completions.create(
# model = "gpt-4o",
model = "gpt-4o-mini",
messages = [{"role": "user", "content": prompts}],
# prompt = prompts,
max_tokens = 500
)
return response.choices[0].message.content
else:
response = client.completions.create(
model = "gpt-3.5-turbo-instruct",
prompt = prompts,
max_tokens = 300
)
return response.choices[0].text
# 解答を画像に貼り付ける関数
def add_text_to_image(draw, text, position, font_path, font_size, text_color):
# フォントを設定
font = ImageFont.truetype(font_path, font_size)
# テキストを描画
draw.text(position, text, font=font, fill=text_color)
# 出力用画像を開く
with Image.open(image_path) as img:
# 描画オブジェクトを作成
draw = ImageDraw.Draw(img)
# 解答探索(メイン部分)
for i, question in enumerate(list_question):
answer = ask_question(question)
# 記載位置、色指定
match i:
case 0:
position = (900,920) # x, y座標 / 歴史
text_color = (0, 128, 128) # RGB形式 (この例ではCyan色)
case 1:
position = (100,550) # x, y座標 / 解剖
text_color = (0, 128, 0) # RGB形式 (この例では緑色)
case 2:
position = (1800,550) # x, y座標 / 生態
text_color = (128, 0, 128) # RGB形式 (この例ではピンク色)
case 3:
position = (900,170) # x, y座標 / 予測
text_color = (0, 0, 255) # RGB形式 (この例では青色)
text = answer
# 空白行削除
while '\n\n' in text:
text = text.replace('\n\n', '\n')
print(text)
# 1行の文字数を制限する
line = 90
output=""
cnt=0
while cnt < len(text):
if (cnt + line) < len(text):
output += (text[cnt : cnt+line] + "\n")
else:
output += (text[cnt : len(text)] + "\n")
cnt += line
# 画像に貼り付け
add_text_to_image(draw, output, position, font_path, font_size, text_color)
冒頭の sw_GPTの定数は GPTの種類を指定するものです。
デフォルトでは GPT-4o。 "-mini" をつけて mini版でも ちゃんとした解答が得られています。
(無いとは思いますが)GPT-3.5 Turbo にしたい場合は sw_GPTを "4V以外" にして下さい。 (4oと 3.5 では I/Fに違いが有るのがお解りかと…)
"max_tokens" 変数は、GPTから返ってくる解答の長さになります。
長い方が 情報量が多くなりますが、多過ぎると 画像からハミ出てしまいます。
add_text_to_image は 所定の位置に 文字列を 画像に貼り付ける関数です。
出力用の画像を Openした後、
# "解答探索(メイン部分)" 以下が 作成した質問文を GPTに投げて 解答を得るメインループです。
3. で作成した 質問リストに従い、歴史/解剖/生態/予測 の4回 ループします。
ask_question関数で 質問に対する解答を得ます。
その後、画像に貼り付ける"位置" を指定した後、
見栄えを良くする為に 空白行の削除と 1行の文字数制限をかけます。
(何故か 空白行が 完全に消えない…)
(貼り付ける位置は 下地の画像サイズや デザインを変えると 修正が必要になります。)
下地画像への 文字の貼り付けは、add_text_to_image関数で行います。
6.進化テーマを 画像中央に 貼り付けて 画像出力
最後に "進化テーマ" を中央に貼り付けた後、画像を jpeg形式で出力します。
出力画像は image フォルダに 固定名で "output_image.jpg" と出力されます。
出来上がりの確認は このファイルを ダウンロードして Viewerで 御確認下さい。
# 中央に 検索文言を貼り付け
position = (1100,770) # x, y座標
text_color = (0, 0, 0) # RGB形式 (この例では黒色)
font_size = 40
text = word
add_text_to_image(draw, text, position, font_path, font_size, text_color)
# 結果を保存
img.save(output_path)
【Excuse】
(1) LLMから返ってくる解答が 文章の途中で終了してしまうケースが有ります。 この制御方法(キッチリ 文末で終了する)が判らないので、中途半端な結末になる事が有ります。(この点は 御容赦下さい)
(2) このソースコードは あくまでも参考用のソースです。
このソースコードの一部 もしくは 全文の活用による 障害・著作権問題 等、あらゆる社会的問題に関しては 当方では 対応出来ませんので 御理解の程をお願い致します。
*御指摘事項が有れば 御連絡下さい。問題部分の削除で対応させて頂きます。
その他の出力サンプル
気になったら お試し下さい!
また お気付きの点が有れば 御指摘下さい。
ソースコードは どこかで GitHubで 公開する様にします。
この記事が気に入ったらサポートをしてみませんか?