動かざることバグの如し

近づきたいよ 君の理想に

無知フクロウ二次創作をAIに作ってもらう

無知フクロウとは

無知フクロウは、あにゃ氏が生み出した「無知」をテーマにしたユニークなフクロウのキャラクターである。名の通り大抵のことを知らない。

例えばこの漫画

トリカブトを知らない無知フクロウ

picture 2

だが

だが無知フクロウは重要な問題を抱えている。それは公式供給が少ない。公式はTwitterによる4コマ漫画が主だが、2021年12月に初めての無知フクロウの4コマが投稿されてから、2024年8月13日現在まで20個しかない。

ということで AIに二次創作を作成してもらう ことにした。

特徴抽出

まずはPerplexityに無知フクロウの特徴を聞いてみた。

無知フクロウは、人気クリエイターのあにゃ氏が生み出したキャラクターです。このキャラクターについて、以下のように特徴をまとめました:

性格と特徴

  • シュールでキュートな外見を持つフクロウのキャラクター
  • 名前の通り、「無知」であることが最大の特徴
  • 知らないことや分からないことが多い

    特徴的な行動

  • 「知らなかった」「分からない」といった反応をすることが多い
  • 「プー」という独特の鳴き声を発する

    言動の特徴

  • 無知ゆえに、素直で率直な発言をする傾向がある
  • 知識不足から来る誤解や勘違いを元にした発言をすることがある

    その他の特徴

  • LINEスタンプとして商品化されており、人気を集めている
  • 「ちみたん」というキャラクターと一緒に登場することが多い
  • プライズ景品として商品化されるなど、グッズ展開も行われている
    無知フクロウは、その無知さゆえに起こす珍妙な行動や発言が魅力となっており、多くのファンを獲得しているキャラクターだと言えます。

もうこれでいいじゃんとは思ったが、Few-shot promptingいわく、 より精度の高い4コマ漫画のストーリーを作ってもらうためには参考となる例を示したほうがよい。

まずはプロンプトを作成するために筆者自身が無知フクロウの理解を深めるしかない。無知フクロウの全画像をダウンロードした。

picture 1

そしてここから「芋ハンコを作るが使えなかった話」「転職初日からミスしまくって電源ブレーカーを落とそうとする話」「QOL向上のために家具を発注するが家に入らなかった話」を箇条書きで言語化し、再度AIに特徴分析をさせてみる。

無知フクロウの性格、特徴的な行動、言動を分析した結果、以下のようにまとめることができます:
- 単純で純粋な性格で、物事を深く考えずに行動する傾向がある
- 新しいことに対して熱心に取り組むが、結果を予測せずに行動してしまう
- 「〜プ」という独特の言葉遣いをする
- 社会常識や状況判断が欠如している
- 自分の行動が周囲に与える影響に気づかない
- 失敗しても反省せず、さらに大きな問題を引き起こそうとする
- 妄想や空想にふけることがある
- 言葉の意味を正確に理解していないことがある(例:「優雅」を「ゆーが」と言う)
- 衝動的な購買行動をする
- 困難な状況に直面しても、その原因を理解できない
- 周囲の状況を把握せずに自分の世界に没頭する
- 失敗や問題を引き起こしても、悪意はなく無邪気な様子である
これらの特徴から、無知フクロウは純粋で善意の行動が多いものの、その無知さゆえに周囲に迷惑をかけてしまう愛すべきキャラクターであることがわかります。

社会常識や状況判断が欠如している」 ん〜AI辛辣ッ!

衝動的な購買行動をするなどは個別のストーリーに依存している特徴でもあるので一部を省いてストーリー生成プロンプトは無事完成した。

早速試してみる。モデルは小説系に優れていると噂のClaude 3.5 Sonnet

お題: かき氷

  • タイトル:無知フクロウたん、かき氷に挑戦プ!
  • 起:真夏の暑い日、汗だくの無知フクロウが氷の塊を持ち、かき氷機の前で興奮している。
  • 無知フクロウ「暑すぎプ~。かき氷作って涼しくなるプ!」
  • 承:かき氷機に氷を入れずに、そのまま氷の塊を機械の上に乗せて一生懸命かき始める無知フクロウ。
  • 無知フクロウ「よいしょ、よいしょ。かき氷は氷をかくんだプね~」
  • (背景で溶け始める氷から水が滴り落ちている)
  • 転:氷がほとんど溶けてしまい、水浸しになったテーブルの上で困惑する無知フクロウ。かき氷機は使われずに横に置かれている。
  • 無知フクロウ「あれ~?かき氷が水になっちゃったプ?魔法?」
  • (背景で電化製品がショートして煙を上げている)
  • 結:水浸しの部屋で、溶けた氷の水たまりに浮かぶ氷の欠片をスプーンですくって食べる無知フクロウ。
  • 無知フクロウ「でも冷たくて美味しいプ♪これがかき氷の進化系カモ?」
  • (背景で隣人が「また水漏れ?」と怒鳴っている)

おおー脳内再生できそう

お題: パリ旅行

  • タイトル: 無知フクロウたんのパリ珍道中
  • 起: パリに到着した無知フクロウ。エッフェル塔を見上げながら興奮している。
    • 無知フクロウ「わーい!東京タワーがデカくなったプ!」
  • 承: パリの街を歩いている無知フクロウ。カフェでクロワッサンを注文しようとするが...
    • 無知フクロウ「ボンジュールプ!クロワッサンをワンプリーズ!」
    • ウェイター「Pardon? Je ne comprends pas.」(すみません?理解できません。)
    • 無知フクロウ「えっ?日本語通じないプ?」
  • 転: ルーブル美術館モナ・リザを見る無知フクロウ。しかし、絵の前で予想外の行動を取る。
    • 無知フクロウ「モナリザさん、一緒に自撮りするプ!」
    • 警備員「Arrêtez! Ne touchez pas le tableau!」(やめてください!絵に触らないで!)
    • 無知フクロウ「えっ?モナリザさん写真嫌いなの?」
  • 結: パリから帰国する無知フクロウ。空港で手荷物検査を受けている。
    • 税関職員「Qu'est-ce que c'est?」(これは何ですか?)
    • 無知フクロウ「エッフェル塔のミニチュアプ!本物持って帰りたかったけど重すぎたプ...」
    • 税関職員「...」(絶句)

思ったよりおもしろい

脱curl コマンドラインからChatGPTを簡単に使う方法

やりたいこと

コマンドラインでChatGPTを使いたい。

curlで叩くのが正攻法だが、コマンド長くて毎回このコマンド用意するのはダルいし、パラメーターの変更も面倒

curl http://0.0.0.0:8000/v1/chat/completions -H 'Content-Type: application/json' -d '{"model": "gpt-3.5-turbo","messages": [{"role": "user", "content": "東京の魅力を3つ教えてください。"}]}' | jq .

で、調べてみると結構コマンドで動くChatGPTクライアントはある。ただどれも候補からは外れた。

そんな中で以下のアプリは良かったのでメモ

kardolus/chatgpt-cli

このアプリのメリットは

  • Goで開発: 軽量で高速なGo言語で開発されているから、パフォーマンス抜群。
  • バイナリ配布: コンパイル済みのバイナリを利用できるため、環境セットアップが簡単。面倒な依存関係もなし。
  • パラメーター変更が簡単: 環境変数を使って設定値を手軽に変更できるので、その都度コンフィグをいじる必要がない。
  • 活発な開発: 現在も定期的にアップデートされているので、新機能や修正が期待できる。
  • リッチな機能: シンプルなコマンドで、多様なオプションを活用できるのが魅力。

インストール

brewでインストールできる

brew install kardolus/chatgpt-cli/chatgpt-cli

すると chatgpt コマンドが使用できるようになっているはず

❯ chatgpt --config
name: openai
api_key: ""
model: gpt-3.5-turbo
max_tokens: 4096
context_window: 8192
role: You are a helpful assistant.
temperature: 1
top_p: 1
frequency_penalty: 0
presence_penalty: 0
thread: default
omit_history: false
url: https://api.openai.com
completions_path: /v1/chat/completions
models_path: /v1/models
auth_header: Authorization
auth_token_prefix: 'Bearer '
command_prompt: '[%datetime] [Q%counter]'

APIキーの設定

APIキーを設定するためには、次のように環境変数をセットする。

export OPENAI_API_KEY=sk-dummy

これで使えるようになる。

❯ chatgpt ハローキティは何年生まれですか?
ハローキティは1974年11月1日に誕生しました。

モデルの変更

モデルを変更するには、次のコマンドを入力するだけ。

OPENAI_MODEL=gpt-4o-mini chatgpt ハローキティは何年生まれですか?

Max tokensの変更

最大トークン数を設定したいときは、これ。

OPENAI_MAX_TOKENS=512 chatgpt ハローキティは何年生まれですか?

temperatureの変更

OPENAI_TEMPERATURE=0.4 chatgpt ハローキティは何年生まれですか?

システムプロンプトの変更

アシスタントの役割を変更するには、次のように設定する。

OPENAI_ROLE='あなたは優秀なアシスタントです。' chatgpt ハローキティは何年生まれですか?

ローカルLLMを使う場合

ローカルで動かしているLLMを指定する場合のコマンドはこれ。

OPENAI_URL=http://192.168.16.100:8000 chatgpt ハローキティは何年生まれですか?

zshの補完設定

zshの補完機能を使いたいときは、次のコマンドを実行。

chatgpt --set-completions zsh > ~/.zprezto/modules/completion/external/src/_chatgpt

これで、補完がいちいち入力する手間を省いてくれる。

Ruby Time.parseよりTime.newの方が高速

環境

結論

  • Time.parse より Time.new の方がメチャクチャ速い

ベンチマーク

require 'benchmark'
require 'time'

# テスト用の ISO8601 形式の時間文字列
time_string = "2024-07-31T12:34:56+09:00"

# 繰り返し回数
n = 100_000

Benchmark.bmbm do |x|
  x.report("Time.parse") { n.times { Time.parse(time_string) } }
  x.report("Time.iso8601") { n.times { Time.iso8601(time_string) } }
  x.report("Time.new") { n.times { Time.new(time_string) } }
end

結果は以下

Rehearsal ------------------------------------------------
Time.parse     0.766202   0.002829   0.769031 (  0.770122)
Time.iso8601   0.249893   0.001080   0.250973 (  0.251185)
Time.new       0.028568   0.000223   0.028791 (  0.028991)
--------------------------------------- total: 1.048795sec

                   user     system      total        real
Time.parse     0.720353   0.002016   0.722369 (  0.722568)
Time.iso8601   0.247730   0.005323   0.253053 (  0.253272)
Time.new       0.028483   0.000214   0.028697 (  0.028856)

理由

Time.parseが遅いのは、汎用的な日時文字列の解析に対応するために複雑な正規表現を使ってるからだ。一方、Time.newはISO8601形式に特化してるから、余分な処理が省ける。さらに、Time.newはC言語レベルで実装されてるから、Rubyで書かれたTime.parseよりも高速に動く。これが、Time.newがTime.parseよりも速い理由だ。

LLMのContext lengthとMax tokenの違い

LLM触っていてContext lengthとMax tokenの違いが一瞬わからなくなったのでメモ

Context length (コンテキスト長)

  • モデルが一度に処理できるトークンの最大数。
  • モデルの「記憶」や「注意の範囲」を表す。
  • 入力と出力の合計トークン数の上限を決定。
  • モデルごとに固定(例: GPT-3.5は4096トークン、GPT-4は8192トークン)。

Max token

  • APIリクエストで生成される出力の最大トークン数を指定するパラメータ。
  • ユーザーが設定可能。
  • 常にcontext length - 入力トークン数よりも小さい値である必要がある。
  • 出力の長さを制御するために使用。

これらの違いを理解することで、LLMの制約を適切に把握し、効果的に利用できる。context lengthはモデルの能力を示す重要な指標で、max_tokensは出力を調整するための実用的なツール。

シェルスクリプトの対話式入力を自動化する方法

やりたいこと

例えば以下のようなシェルスクリプトがあったとする。

#!/bin/bash

# ユーザーからの入力を受け取る
read -p "aを入力してください: " input_a
read -p "bを入力してください: " input_b
read -p "cを入力してください: " input_c

if [ "$input_a" = "a" ] && [ "$input_b" = "b" ] && [ "$input_c" = "c" ]; then
    echo "OK"
else
    echo "NG"
    exit 1
fi

この場合、a入力してエンター、b入力してエンター、c入力してエンターする。

❯ bash test.sh
aを入力してください: a
bを入力してください: b
cを入力してください: c
OK

通常実行時に入力を求められるLinux操作は珍しくないが、自動化しようとすると面倒

yコマンドだけ実行したいなら yes > bash hoge.sh でも対応できるが複数入力しなくてはいけない対話式のコマンドの場合対応できない。

対応方法

シェルスクリプトの対話式入力を自動化するには、入力データをファイルに保存し、そのファイルをリダイレクトする方法が有効。以下の手順で実行できる。

入力データをファイルに保存する。例えば、cmd.txt というファイルを作成し、以下の内容を記述する。

a
b
c

シェルスクリプトを実行する際に、このファイルをリダイレクトする。

❯ bash test.sh < cmd.txt
OK

この方法で、シェルスクリプトの対話式入力を自動化できる。ファイルに入力データを事前に用意しておくことで、手動入力を省略できる。

参考リンク