AIに頼ってツール開発してみた

# はじめに

本記事は、AIに頼ってちょっとしたツール開発をした、という体験記です。開発したツールそのものの紹介ではなく、AIと対話しながら開発を進めた具体的なプロセスをお伝えします。
AIをあまり触ったことがなかったり、うまく活用できていない方の参考になれば幸いです。
なお、記事中に「プロンプト」という表現が出てきますが、これはAIに渡す入力文のことを指します。

また、AIに同じプロンプトを与えても毎回同じ結果になるわけではなく、多少変化します。記事中で使っているプロンプトを使っても同じ結果にはならないとは思うので、どういう会話をして開発を進めているのか、というプロセスの部分に目を向けてもらうのが良いかと思います（そういうわけで、作成されたコードも全文を載せているわけではなく主要部分に絞っています）。

# 開発しようと思ったきっかけ

先日GitHubで、日本語文書に特化したOCR,ドキュメント画像解析を行うPythonパッケージ「YomiToku」が公開されました。

■GitHub
https://github.com/kotaro-kinoshita/yomitoku

■note
https://note.com/kotaro_kinoshita/n/n70df91659afc

画像やPDFなどをOCRして文字起こしできるのですが、精度が高く、ローカルサーバー上で処理が完結するのが魅力的です。
指定のファイルを処理対象とするのはもちろん、フォルダ内のファイルすべてを処理対象にもできるため使い勝手もよく、これもまたありがたい点です。

処理を実行するためにコマンドをたたく必要があるのですが、ここでふと、「画面からできたら楽だよな…」と思ったのが今回開発しようと思ったきっかけです。
とはいえ、画面で実行できたら楽だとは思うものの、そういう開発の知見がほぼないので0から始めるとなるとハードルが高すぎて、やる気になりません。
そこで、自分ではわからないけど、AIに頼んだらできるんじゃないか、ということでやってみました。

# 使用したAIについて

使用したモデルは「Claude 3.5 Sonnet」です。最近のお気に入りで基本的にこのモデルを使っています。
また、チャットそのものは[Poe](https://poe.com/)というサービスで行いました（なので記事中のスクリーンショットもその画面になっています）。
Poeは様々なモデルが使えるサービスで、他にGPT-4oやo1-preview、Gemini 1.5 Proなどのテキスト系のモデルだけでなく、StableDiffusionやFLUXといった画像生成系のモデルも使えるので、いろいろなモデルを試すのに便利です。

なお、[Claude](https://claude.ai/)の公式を確認したところ、「Claude 3.5 Sonnet」は無料版では使えなくなっているようでした（2024年12月時点）。
ただ、性能は落ちるものの無料でも使えるHaiku（Claude 3.5 Haiku）でも本記事のゴールには到達できたので、無料版でも十分試せるかと思います。チャットでのやり取りの回数も大して変わらなかったので、思いのほか優秀な印象です。

# 開発してみる

本題です。まずはAIにYomiTokuを理解してもらうため、READMEとdockerfileを渡して認識してもらいます。
GUIを作るにあたりYomiTokuの実行環境や実行方法を知っていれば十分かと思ったので、これ以外は渡しませんでした。

プロンプト：
**添付ファイルについて、コマンドでyomitokuを実行するのではなくGUIでOCR対象を指定したり実行したりしたいのですが、実現できるでしょうか？windowsのdocker上で動かしたいです。**
※READMEとdockerfileを添付

回答（主要部分のみ載せていきます）：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/a489fa5b-3997-ae04-3334-fd8d3425339a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/ba05e2a5-d7ae-b441-b302-5c9cc911a9b3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/0caa1f63-727d-e083-537d-94196acbc8a2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/76df6b9f-460c-7d54-e292-77484b99fef5.png)


いきなりそれっぽいものができました。ビルド方法からアクセス方法まで書いてあって助かります。
とりあえず動かしてみます。言われたとおりにファイルを作って、ビルド実行。
ビルド中にエラーとなりました。エラーメッセージをすべて渡して解決してもらいます。

プロンプト：
**Docker Compose でビルドしたところ、下記のエラーが発生しました。解決できますか？
[エラーメッセージを記載]**

回答：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/8da5080e-e52e-ab8e-0940-f3efde78e5ce.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/7d84ae29-fc76-c3d6-83f8-e03ebd645228.png)



修正案をもらったのでファイルに反映して、もう一度ビルド。今度はうまくいきました。
次はdocker-compose up。ここでまたエラーとなったので、なんとかしてもらいます。

プロンプト：
**ありがとうございます。ビルドは成功しました。
ただ、docker-compose upでエラーとなりました。エラーメッセージは下記のようになっていますが、解決できますか？
[ここにエラーメッセージ添付]**

回答：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/295ac5e8-337b-88c3-cb5e-130540dde71b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/3a721d65-d954-075c-0013-afa29f783ca2.png)



解決法が示されたので、言うとおりにやってみます。
ただ、コードを変更したのでビルドし直さなくていいのかが気になったので、一応聞いてみます。

プロンプト：
**再度のビルドは不要なのでしょうか？**

回答：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/9e9becaa-2609-6964-a086-73aa3cfe3d21.png)

なるほど、マウントしているファイルだから修正不要とのことです。
ただ、これまで作られたコードの中にはマウントされていそうな箇所は見受けられませんでした。

試しに、docker-compose downしてコード修正後、ビルドせずにdocker-compose upを実行してみたところ同じエラーとなったので、やはりビルドは必要そうです。

というわけでビルドし直してみたのですが、yomitokuのインポート部分でエラー。同じようにエラーメッセージを渡してみてインポート文の修正がされるものの、同じ個所でエラー。
インポート文を直してくれているけど、そのやり方は根本的に違うんじゃないの？と思ったので投げてみます。

プロンプト：
**同じくyomitokuインポート部分でエラーとなりました。そもそもこのアプローチは正しいでしょうか？確認をお願いします。**

回答：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/d25e8e55-4dbd-7913-da13-640725adc9b1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/e411fbd5-2c7d-ddd1-45d7-f8523dcf753e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/5c43e89c-9aaf-d1b8-5c01-065954a78c9f.png)

やり方を変えて修正案を出してくれました。
というわけでいくつかのファイルに修正が入ったので、反映して、再ビルドして、起動。

コンソールログ：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/02519bc2-99ad-b903-4cc8-310484fadcec.png)


エラーなし！ブラウザからアクセスしてみます。
無事に以下のような画面が表示されました。ちょっと感動です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/93e9b360-f41d-050a-93a0-cdcbc5941495.png)


ただ、実際に実行できなければ意味がないので、さっそく実行してみます。

コンソールログ：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/76a6ff8d-bfdb-eef6-0212-6f3257c039f0.png)


ブラウザ上のエラーメッセージ：
```
OCR処理でエラーが発生しました: Command '['yomitoku', 'uploads/20241203_test.png', '-o', '/tmp/tmp6ieapq5i.txt']' returned non-zero exit status 1.
```

惜しい。yomitoku自体は動いていそうなものの、結果ファイルの出力でエラーとなっていそうです。
なんとかしてもらいます。

プロンプト：
**画面上でOCR実行開始、まではできたのですが、そのあとにエラーが発生しました。解決できますか？
ログ上のエラー：
[コンソール上のエラーメッセージ]
画面上のエラー：
[画面に表示されたエラーメッセージ]**

回答：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/eb9c2c93-3ea7-efa8-ce21-cba5cce9d36e.png)


ファイルを修正して、再度実行。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/d47b2c90-e8b0-d699-c24e-2b5603df0dbf.png)


ブラウザ上のエラーメッセージ：
```
OCR結果のファイルが見つかりません
```

yomitokuの処理自体はうまくいってそうなものの、やはりファイル出力部分でうまくいっていないようです。
作成されたコード内にあるコメントを見てみるとディレクトリを作成・削除している個所があり、そこがうまくいっていないかと思ったので、とりあえず動かすために処理をシンプルにします。

プロンプト：
**GUI上に「OCR結果のファイルが見つかりません」と表示されます。出力ディレクトリや一時ディレクトリを処理内で作成・削除するのではなく、出力ディレクトリは最初から作っておいて、処理結果はそこに格納するようにできますか？**

回答：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/468a488c-c4f7-987e-974a-0527eb453cb5.png)


コードを修正し、再ビルド。OCR実行。
なぜか画面上ではエラーが出るものの、ファイル出力されました！（エラーはあとでなんとかするので今はヨシ！）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/0e4ad0fe-802f-7868-b822-86b1d0622c3f.png)


OCRに使った入力画像は、インポート部分でつまづいた際にアプローチ変更をお願いしたところのやり取りです（スクリーンショットを撮ってそれを処理に使用）。
小さな画像だったので解像度が足りなそうですが、ちゃんとOCRできています（jsonで出力されていますが、他にもcsv, html, mdで出力可能）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950448/9a660f07-505b-43cd-993d-9233ef582435.png)

# 終わりに

そんなわけでAIに頼ってGUIを実装することができました。自分でコードを修正した箇所はまったくありません。
いろいろとエラーも出ましたが、そのエラーの内容も渡してなんとかしてもらいました。
こちらからAIに伝えた内容も、やって欲しいことをそのまま伝えただけで難しいテクニックは使っていません。

自分一人だと、開発しようと思っても実装方法わからないし時間もないしそもそも面倒くさいし…となってなかなか難しいところですが、AIの力に頼ることでハードルがぐっと低くなります。
「こういう機能があると便利なんだけどな～」という軽いモチベーションでもこうして実現できてしまうので、参考になれば幸いです。


# おまけ

こうしていったん完成してみると、別の欲が出てきます。
- 実行時のオプションがいくつかあるので、画面上で指定できるようにしたい。かつ、特定のオプションはデフォルトで設定済みとしたい。
- 処理対象のファイルを1つ選ぶ形になっているが、フォルダ内にあるすべてを処理対象にできるようにしたい。
- 処理中の進捗を画面上で確認したい。
- 出力結果ファイルを結合したい。

など、いろいろと出てきました。
これらについては、ここまでに記載したようにやり取りを繰り返して、すべて実装できています。

また、AIとやり取りする際のコツみたいなものを挙げていきます。
- プロンプトは指示や要望が具体的であるほどゴールが近づきます。例えばエラーの原因が自分でわかるのであれば、「ここをこう直して」とお願いするほうが手っ取り早いです。
	- 本記事一発目のプロンプトの中に「windowsのdocker上で動かしたい」と入れていますが、この指定がないとMacやLinuxも考慮してしまったり、サーバー構築から始まってしまうので、前提条件なんかも含められるとより良いと思います（もちろん、会話の中で要望を具体化していくのもOK）。
	- 逆に、よくわからなくても「こんなエラーが出るんだけどなぜかわかる？」みたいに聞けばいろいろと提案してくるのがAIの良い点です。どんなにくだらない質問でも怒られないし嫌な顔もされません！
- 会話を長く続けていると、AIが会話内容を覚えきれなくなって回答が的外れになってくることがあります。そういうときには新しいスレッドで会話を最初から始めるといいです。作成したファイルやその仕様を軽く伝えればまた始められます（本記事の会話開始時のように）。
	- ただ、今回の記事の内容は1つのスレッド内で完結しているので、これくらいは問題ないと思います。