見出し画像

ChatGPT(canvas)と会話しながらOpenAI APIを使った語学学習アプリを作ってみた

日本語で英語を学ぶ(左)、英語で日本語を学ぶ(右)

はじめに

これまでに、

でChatGPTを使った学習体験について書いてきた。とはいえ、実際に学習したいのは英会話だったり宿題だったりするわけで、プロンプトをどう書くかというノウハウではないわけです。
それならば、ChatGPTなりCopilotを起動するんじゃなくて、Webアプリを使って、プロンプトなんか気にすることなく勉強しましょう。ということで、ChatGPT 4o with canvas で語学学習アプリをササっと作ってみました。

ChatGPTから始める

Windows版のChatGPTアプリを起動して、モデルには GPT-4o with canvas ベータ版 (ライティングとコードで共同作業する) を選択しました。
最初のプロンプトは、Hello, world! ではなくて、

node.jsを使ってOpenAIのAPIと連携する語学学習ウェブアプリを開発したいです。

ChatGPT 4o with canvas

でした。するとこんな感じでかなり丁寧にExpressフレームワークを使ったNode.jsアプリのひな型の作り方を説明してくれます。

ChatGPT 4o with canvas

ステップは全部で8つあり、ステップ8: アプリの実行で、テキスト入力ボックス、翻訳先言語を選択するプルダウン、翻訳結果を表示する画面までが表示されるはずです。

ChatGPT 4o with canvas

ところが、実行してみるとエラーが出力されるので、これもChatGPT君に解決方法を聞いてみます。

node server.jsを実行したところ、TypeError: Configuration is not a constructorというエラーが出力されてしまいました。new Configurationしている箇所に問題があるようです。解決方法はわかりますか?

ChatGPT 4o with canvas

結論からいうと、サンプルコードで使われているOpenAI JavaScript APIのバージョンがv3であるのに対し、ステップ2: 必要なパッケージのインストールでインストールしているOpenAI JavaScript APIのバージョンが最新版(=v4)だったため、呼び出し方法が一部異なっているのが原因でした。

OpenAI JavaScript API v4ではConfigurationは使用しないで接続するようです。OpenAI JavaScript API v4を使うようにserver.jsを修正してください。

ChatGPT 4o with canvas

指示されたことにはちゃんと対応してくれるので、すぐに動くものが出来上がりました。

ChatGPT 4o with canvas

機能をリッチにしていく

基本的には、自分の目指すアプリケーションになるように、順を追って指示していけば、コードを書き換えてくれます。

機能を追加していくごとに開発途上のアプリケーションのスクリーンショットを撮っておけば良かったのですが、すっかり忘れていたので、どんなプロンプトを投げたのか、いくつかご紹介させていただきます。

現在は入力した文の翻訳が出力されていますが、翻訳の下に、入力した文に含まれる単語のリストを表示したいです。単語のリストには、単語ごとに文中に表示された単語の原型, 指定された言語での意味, スピーカーアイコンが表示されており、スピーカーアイコンをクリックすると、その単語を読み上げてほしいです。

先に進む前に、現時点のプロジェクトをGitHubに登録したいと思います。language-learning-appリポジトリを作成し、どうすればいいですか?

ステップ2までは完了しましたが、ステップ3に進む前に、適切な.gitignoreファイルを用意したいと思います(OpenAIのAPIキーを含む.envファイルが誤って共有されたり、node_modulesを無駄にリポジトリに登録しないように)。適切な.gitignoreファイルの例を示してください。

今回は自分で直接やったほうが早い、確実なことであっても、すべてChatGPTへのプロンプト経由で実行しよう、というのが基本方針ではあったものの、言われた通りに進めていくと、APIキーが(リポジトリをpublicにしていたら)流出しかねないので、上にあげたようなプロンプトを使って、`.gitignore`ファイルを作成してもらっています。

コミットメッセージやREADME.mdファイルなんかは、自分であれこれ考えるよりも、任せてしまったほうが良いと思うことが多いです。

README.md

あとは、生成時のmax_tokenの上限が低くて、出力が尻切れトンボになるのを直してもらったり。

単語リストの出力が意味の途中で途切れてしまっています。おそらく、max_tokensの数が少ないためかと思われますが、どうでしょうか? 適切な値を設定するのは難しいかと思いますが、入力されたテキストの長さから大体の値を設定できないでしょうか?

さて、一番苦労したのはテキスト中の単語を抽出し、それにターゲット言語の意味をつけた表を作成するところでした。

単語の抽出は、入力テキストを言語に合わせた構文解析エンジンで解析し…といったことをやっているわけではなく、自動生成されたプロンプトが単語抽出の指示をOpenAIに対してしています。
プロンプトの指示内容は、プロンプト経由で不具合を指示することで、進化を遂げているものの、だいたいこんな感じ(これは現時点での最終バージョンで使っているもの)。

Extract a list of unique, non-repeated base forms of important words from the following text. Ignore plural forms, verb conjugations, and focus on significant words only. Do not include repeated forms or provide numbers. Output only the words, separated by commas.

そして指定された言語(一般的には学習者の母語)を使って、各単語に意味を付与していくのだが、これが一筋縄ではいかなかったのです。自動生成されたプロンプトはこんな感じです。

Translate the word "${word}" to ${targetLanguage} and provide its concise definition. Only provide the translation without any extra information. Do not include numbers or explanations.

意味を付与するといっても、どこかの権威ある電子辞書を引いて意味を持ってきているわけではなく、どこの馬の骨かもわからないゴミ交じりの意味が付与されてしまうのでした。
最初は混じったゴミを如何にクリーンにしようかと、あれこれ手を尽くすのですが、

Definitionに表示された最後の単語の意味の次の行に"Definition: A list of words and their base forms in English and their corresponding translations in Japanese."と出力されてしまっています。出力されないようにするには、どうすればいいでしょう?

今度は、先頭の単語の意味だけが"- ワークフロー -> ワークフロー"のように表示されてしまっています。

今、テキストに次の英文を指定し、言語にJapaneseを指定しています。
---
In other workflows, the company uses GPT-4 for complex decision-making tasks, allowing the platform to process API requests and other intricate operations efficiently.
---
これに対して、次のような表が出力されています。
+----+----------+------+
|Word|Definition|Listen|
+----+----------+------+
|workflows - workflow|ワークフロー - ワークフロー| |
|2. company - company|2. 会社 - 会社| |
これを次のように出力されるようにしてください。
+---+----+----------+------|
|No.|Word|Definition|Listen|
+---+----+----------+------|
| 1|workflow|ワークフロー|(アイコン)|
| 2|company|会社|(アイコン)|
workflowsはテキスト中に出現しているworkflowの複数形ですが、ここでは出力する必要はありません。usesのような動詞の活用形やoperationsのような名詞の複数形も不要です。ただし、本文中に出現しているのがefficientlyのような副詞であれば、それをそのまま表示し、lyを取ったefficientを表示する必要がありません。

あれこれ手を尽くしてみたものの、どうにもならないので、ChatGPTに頼んで、使用するモデルを(デフォルトで指定されていた)gpt-3.5-turboから変更することにしました。

これですべてが解決したわけではないのですが、生成されたソースコードの上では、これくらいのフィルタリングを経ることで、表示に耐えうる単語の意味が出せるようになりました。

// 定義の取得とフィルタリング
const definitionContent = definitionResponse.choices[0].message.content.trim();
let definition;
if (definitionContent.includes('\n')) {
  definition = definitionContent.split('\n')[0].trim();
} else if (definitionContent.includes('「') && definitionContent.includes('」')) {
  definition = definitionContent.match(/「(.+?)」/)[1].trim();
} else if (definitionContent.includes('"')) {
  definition = definitionContent.match(/"(.+?)"/)[1].trim();
} else {
  definition = definitionContent;
}

いったん完成へ

各単語をつかった例文とその訳文を表示する機能を追加し、いったん完成とすることにしました。ここまでで5時間程度でした。

言語解析や翻訳等を自分でライブラリを用意したりせず、すべてChatGPT任せにしているので、この言語学習アプリは何語用でもありません。英語のテキストでも、日本語のテキストでも、中国語のテキストでも、そして学習者のあなたの母語が何語であっても、修正を加えることなく対応できます。

英語から日本語(From English to Japanese)
中国語から日本語(From Chinese to Japanese)

何語でも対応できるとは言ったものの、日本語テキストを入力すると、カンマ区切りで通知されると想定していた単語のリストが、読点で区切られてしまっているため、正しく動作しません。修正自体は(ChatGPTに頼んでしまえば)簡単ですが、何をテストすべきかというノウハウの蓄積が現時点では品質を担保するうえで重要かと思われます。

日本語から英語(From Japanese to English)

おわりに

ChatGPTによりソフトウェア開発のハードルが下がることは間違いありません。その一方で、意図通り動作しなかったときに、原因にあたりをつけるという意味では、ソースコードを読むことができ、デバッガーを使って追うことができる能力は、今のところは必要なようです。

リポジトリ: https://github.com/mfunaki/language-learning-app

追記

2014/11/13 - 冒頭に写真を追加しましたが、日本語テキストから単語を抽出する際に、カンマ(,)区切りで抽出するように指示しても読点(、)区切りで通知されてしまうため、単語が正しく抽出されなかった問題については、ChatGPTにサクッと修正してもらいました。

いいなと思ったら応援しよう!