ChatGPTをコマンドラインから呼ぶツール chatgpt-cli を作成している話

## はじめに

ChatGPT使っていますでしょうか。

ChatGPTは日本語・英語などの文章の作成、コーディングのお供として非常に優秀です。しかし、ChatGPTは主にブラウザから使うことを想定しています。そこで、ターミナルからChatGPTを使うツールを作成しました。

しかし、すでに、ターミナルからChatGPTを使うツールはたくさんあると思います。
けれども、ターミナルでChatGPTを呼ぶならばこうしたいな、というイメージは最初からあったので、他のツールはあまり参考にせず、それをなるべく実現していく形で作るようにしました。

そして、最初に「こんな機能があったらいいな」という機能は一通り実装し終えたので、現段階で感じたことなどを、記事としてスナップショットに残そうと思います。

https://github.com/kojix2/chatgpt-cli

## 実現したかった機能

なんとなくの全体像

![overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/762c7e6d-fcec-8f8a-0685-b8f48360ec45.png)

ChatGPT APIは、数千から一万（2023/03/30時点で）のTokenにデータを渡すところからはじまります。

### ファイルの埋め込み

ChatGPTに、ファイルを渡せるようにします。パスの展開ができるようにします。
`%{filename}` `%{src/*.py}`

### Webページの埋め込み

ChatGPTに、Webページの内容を渡せるようにします。さすがに html をそのまま渡すと、tokenを消費しすぎるので、文章だけ取り出して `|` でつなぎ合わせるようにしました。
`%%{www.yahoo.co.jp}`

### システムプロンプトをIDで選べる

システムプロンプトを事前に登録されたメッセージからIDで選べるようにします。

`chatgpt -i code`

### マジックコマンドの実行

これは、主に、Postするデータを操作します。具体的には

`system` `model` `edit` `save` `load` `undo` などを用意しました。他にもたくさんあります。

### システムコマンドの実行

ChatGPTの実行中にシステムコマンドが `!` で実行できるようにしました。ChatGPTのレスポンスをコマンドとして実行できるように、コードブロックが含まれていた場合は一時ファイルを作成し `CODE1` `CODE2` `CODE3` といった環境変数にその一時ファイルのパスを含めるようにしました。

また、システムコマンドの結果をキャプチャするときは、`!!` で実行して、`%STDOUT` `%STDERR` などのプレースホルダーを用いてChatGPTに問いかけられるようにしました。

### Ctrl + C を実行してもツール自体が終了せず、クエリのみが終了する。

現状、ChatGPTでレスポンスを受け取るにはかなりの時間がかかります。そのためリクエストを送信してから、誤りに気がついて直したいときなどがあります。そういうときに　`Ctrl + C` を打ち込むと、プログラムが終了してしまいます。そうではなくて、リクエストだけ終了して、また `>` が表示されるようにしたかったのです。これは、カスタムのシグナルハンドラを追加することによって実現しました。具体的には `Ctrl + C` を検出すると HTTP クライアントをクローズします。

### 履歴機能

これは、`.chargpt_history` ファイルをホームディレクトリに保存して、`Readline.read_history` で見に行けるようにしました。 

## これから考えること

### 対話的環境とワークフロー

さて、このようにしてChatGPTのコマンドラインツールを作成しました。しかし、この先にはすこし問題があります。それは、ChatGPTスクリプトとか、ワークフローのようなものをどのように考えていけばよいか、という問題です。

このことを考えると、Readlineのような対話的な環境を用いずに、常にワンラインで実行して終わりにするようなChatGPTのコマンドも便利なのではないかという気がしてきます。この場合、マジックコマンドは第１引数として、標準入力または第２引数が、chatgptに投げるメッセージになるでしょう。ただし、そのようなコマンドラインツールは、「状態」を外部にファイルとして保存している必要があります。

この発想で作られたツールですと、例えば次の例のように、ChatGPTを関数として利用することがより簡単になります。

```sh
echo "Hello" | chatgpt --load translate-ja | tee こんにちは.txt
```

これについては一考の余地があると思います。また、全く逆の方向性としては、現状のママ拡張して、独自のスクリプトなどを作り込んでしまうということも考えられます。Crystalは`eval`ができませんが、Anyoliteというツールを使って、`mRuby` を組み込むことが可能です。これを利用して、chatgpt-cli 内部で小さなRubyスクリプトを実行できるようにして、それをワークフローとして利用することも考えられます。こうなってしまうと、かなりマイナーな世界になってしまうと思いますが、ツールとしては非常に面白いと思います。

### 適切なプレースホルダー

%{} とか %%{} のようなプレースホルダーが本当にこのツールに適切なのか考える必要があると思います。特に、%{}はさまざまなプログラミング言語で利用されています。一応は、ファイルを探して、なかったら置換せずに残す方針にしており、これで多くの場合問題は回避できると思いますが、明示的なエスケープも用意しなければならないかもしれません。また、設定ファイルに正規表現を記述することにより、デフォルトのプレースホルダーをユーザーのカスタムのプレースホルダーに変更する方法も余力があれば作りたいと考えています。

### インストールと配布の方法

このツールはCrystalのツールなのですが、配布には問題があります。ソースコードの配布という形にすると、世界のコンピュータのほとんどにはCrystalのコンパイラはインストールされていないため、このツールをビルドすることができません。だから、バイナリの実行形式のファイルにして配布する必要があります。

しかし、実際のところ、ここはかなり骨が折れる気がします。Crystalで作成されたツールが現状あまり多くないため、Crystalのツールの配布方法に対するベストプラクティスはあまり確立していません。かなり地道な試行錯誤が必要になるのではないかと思います。

## ChatGPTとその未来（ポエム）

ChatGPTはとても未来を感じさせます。最も未来を感じさせるのは、そのToken数の少なさです。GPT-3.5-turboではわずか4096、GPT-4でも8192個のtokenしか乗せることができません。それ以上の情報は意識してくれないので、この狭い範囲のtokenに上手に情報を乗せる必要があります。これは、あたかもコンピュータの黎明期に、人々が少ないメモリにいかにデータを乗せるのか苦心していた状況とよく似ているのではないかと思っています。

したがって、ChatGPTのツールに求められることは、いかに上手にこの限られたtokenのスペースを使いこなしていくかということだと思います。

将来的には、扱えるtoken数がどんどんと増えていくのではないかと思います。これがChatGPTに未来を感じる理由ではないかと考えています。一方で、１ヶ月間ChatGPTを追いかけていて、気がついたのですが、AIを追いかけることは、どうも人間にとっては、ある種の疲弊を呼び覚ますような部分があるようです。

これには２つの理由があるのではないかと考えています。

１つ目は、純粋にAIの出力データが多すぎるために、人間がそれを受け止めてしまうと疲れるのではないかと考えています。たとえば、ChatGPTと普通の会話をすることを考えても、ChatGPTは人間の数倍量の文章を、ほとんど時間をかけずに生成してこちらになげかけてきます。これは人間の会話で考えると、常に相手がものすごい量のことを喋ってくるのと同じであり、だから疲れが発生するのではないかという仮設です。

もう１つは、これまで自分のスキルや強みであると考えていたことを、AIがものすごいスピードで軽々とこなしていくのを見て、これまでの考え方や習慣を変えなければならないと感じることによる疲労ではないかと思います。

私達の多くは、学校教育の数年間、社会人になってからも英語学習に費やしてきました。上手なコードが書けるようになるように時間をかけて訓練してきました。ところがChatGPTはとても上手にコードを書くことができます。ですからこれからは仕事の考え方や方法を変えなければなりません。人間は変化することを嫌いますので、それが大きなストレスになってしまう可能性があります。

このAI疲れの２つの理由はいずれも深刻ではあります。特に２番目の問題は、社会のあらゆるところで大きな疲労を起こすと思います。しかし、私としては、軽視されがちな１つ目の疲労にも、実は大きな問題が潜んでいるのではないかと思います。というのは、人間はいずれ慣れます。AIにもやがて適応していくでしょう。一方で、AIの出力するデータは、時間と共にますます膨大になり、我々はその処理に苦労することになるのではないかと思います。

いずれにせよ、AIによって生じる疲れを意識して「休息」をしっかり取ることが大事ではないかと思います。