必要なサービスを自分で開発する - myglish 発音学習英語表現帳
はじめに
こんにちは、生成AIを活用しながら留学中の空いた時間を使って開発の勉強をしているニートです。
細かい自己紹介は初回の記事に書いてあります。
今回の記事では『myglish』という自分用の単語帳のようなアプリを開発したので、その経緯やプロセスを備忘録的に残せればと思っています。
似たようなサービスはいくつかあったのですが、自分好みのサービスはなかったので、開発の勉強がてら作ってしまおう!ということで開発しました。
こちらが実際に開発したWEBアプリになります。
開発の背景
私自身現在オーストラリアに留学中ですが、英語のコミュニケーションにおいて大きな悩みがあります。
それが
- 発音がかなり悪い
- 表現の幅が少ない
というものです。
表現の幅は日々の学習で何となく伸ばしていくこともできるような感じはしますが、表現の幅が増えたところで発音が悪く相手に伝わらなければ意味がありません。
どうにか発音をよりよくしたくてELSAのようなアプリも継続的にやっていますが、もっと自分の言いたい表現をそのまま良い発音で話せるようになりたいと思っています。
そこで 自分の覚えたい英語表現を自分用に単語帳のように登録できるアプリを作ろう! と思い至りました。もちろん自分用の単語帳アプリなら世の中に山ほどありますが、私はそれにどうしても アメリカ英語での読み上げ機能 と IPA形式の発音記号の表示 をセットでつけたかったのです。
これが myglish というアプリの開発の背景です。
myglishの概要
myglishは、日々の英語学習で学んだ英語表現を日本語とセットで登録できる単語帳のようなサービスです。単語だけでなく、フレーズや文章でも登録できます。(文字数の制限はかけています。)
登録した表現に対して以下の機能を提供する作りにしました。
- 自然なアメリカ英語の発音を再生できる音声出力機能
- IPA(国際音声記号)による正しい発音の表示
- 日本語の読み上げは1.5倍速で、英語よりも素早く音声出力する
- PC、モバイル両方に対応(モバイルはPWA)
これにより、発音記号を参照しながら、自然な発音を聞いて繰り返し練習することが可能になります。
外部サービスの利用
私にとって、バックエンドを含むフルスタック開発は初めての経験でした。開発を始める前に、まずChatGPTを使って構成を相談しながら進めました。外部サービスの選定は、次のような理由で決まりました。
-
データベース : NoSQLのFirebase Firestore
- やりたいことは上述の概要の通りですが、しっかりとしたDB設計をする余裕も能力もなかったため、(というか自分がどこまで開発ができるか分からないので)柔軟に動けるNoSQLを選びました。
- そのうち無料枠をはみ出るかもしれませんが、運用が安定したらRDBに移行しても良いと思っています。
-
発音記号 : openAI APIを利用して生成AIとのやり取りで取得
- 無料で発音記号を取得する方法もありました(以下のリンク参照)が、フレーズや文章を許容するにあたって単語ごとに取得したり、無料で取れる発音記号がIPA形式でなく変換が必要など手間が多そうだったので、単語、フレーズ、文章何が来ても対応できるように生成AIから直接出力させる方針を選びました。
-
音声出力 : Google Cloud TTS(Text to Speech)
- 最初にFirebaseの利用を決めていたので、Googleサービスに合わせる形で音声合成もGoogle Cloud TTSに統一しました。(もちろん無料枠があることも考慮しています。)
- 他の選択肢として親友(chatGPT)はAmazon Polly, Azure AI Speech, IBM Watson Text to Speech を提示してくれました。
-
ユーザー認証 : Firebase Authenticationを利用
- 私個人が利用することだけを想定したアプリケーションであるものの従量課金のAPIを使用するため、他の人が利用する場合の制限を設ける必要があり、Firebase Authenticationを使ってユーザ認証を行い、私以外のユーザには登録できる表現数に制限を設けています。
-
ホスティング : NetlifyとRender
- フロントはNetlify(使ってみたかっただけです)、バックエンドはRenderをホスティングサービスとして利用しました。安く!簡単に!
※発音記号を取得する方法としては以下のサイトが良くまとまっていました。
その他の技術スタック
アプリケーションページは単独ページになることを想定していたので、フロントはReactを使ってSPAを想定しました。基本的にJavaScriptで開発を進めました(これは今となってはTypeScriptにすれば良かったと少し後悔しています)。UIは、TailwindCSSとShadcn/UIを使い、コンポーネントを最大限に活用し、シンプルにレイアウトを作成しました。バックエンドは Node.js(Express) を使って全体をjsで開発しました。
学びと課題
今回の開発で特に新しかったのは、フロントエンドとバックエンドの連携です。Next.jsのserver actionsの実装経験はあったのですが、今回は明確にフロントエンドとバックエンドを切り分けたので、最初はかなり戸惑いましたし、最も時間がかかったのはフロントからバックエンドへのデータ送信とAPIの処理の流れを理解することでした。
特に以下の2つの処理の流れは大きな学びでした。
- 英語と日本語の表現を登録できるフォーム
- 登録した表現を音声と発音記号と一緒に一覧表示
それぞれの処理の流れは以下のような形になっています。
1.1. [client]form機能を含むWordForm.jsx
で登録したい表現を受付(saveボタンの押下アクションでバリデーションをまず実施)
1.2. [client]登録したい表現をapiService.js
に受け渡し、axiosを利用して/api/words にPOST リクエストを送信
1.3. [server]バックエンドのエントリポイント(index.js
)でルーティング
1.4. [server]wordsManager.js
で同一pathのルーティングを受け付けてPOSTかGETで処理を分ける(POSTは1.5の処理に続く)
1.5. [server]wordsManagerController.js
で ①ユーザ単位の登録単語数の制限に引っかからないかの確認 ②google TTSでの音声データの取得 ③openAIでの発音記号の取得 ④まとめてfirebase firestoreに保存 という一連の処理を実行(各処理はそれぞれのエンドポイントを指定した各Controller.jsで処理)
2.1. [client]WordList.jsx
で過去に登録された表現を読み取ろうとする(音声データがbase64で登録されているが、それをblob形式にするのもここの処理)
2.2. [client]apiService.js
を動かしてaxiosを利用して/api/words にGET リクエストを送信
2.3. [server]バックエンドのエントリポイント(index.js
)でルーティング
2.4. [server]wordsManager.js
で同一pathのルーティングを受け付けてPOSTかGETで処理を分ける(GETは同一ファイル内でcollection情報を取得)
ポイントは、つなぎの部分(x.2.とx.3.)が同じ形になっているところだと思います。やり取りする口を揃えるというのは重要な気がします。
今後の展望
今後の改善点として、以下のような機能を追加したいと考えています。
- 登録した単語の編集や削除機能
- 連続再生リストと登録リストを切り分け、覚えた表現をリストから外せるようにする
- 初回読み込みが重いため、キャッシュ機能を実装して速度向上
特にキャッシュ機能を実装した速度向上は最優先修正事項です。キャッシュの理解あまりなく、ここは学習しながらすすめていく予定です。
おわりに
生成AIを活用して個人開発をしている人も多いと思いますが、今回の私のように ほしいサービスがあれば自分で作ってしまえば良いや! という考え方をする人は多くなると思います。
今回開発する中で最も痛感したのは、「何をしたいのか、明確に言語化する」ということが意外と難しいということです。
我々が普段使っている自然言語はかなりの曖昧性を含んでいます。生成AIが理解してコードに落とせるレベルまで表現を具体化するのは、慣れていないと難しいものではないでしょうか?
こういったアウトプットの機会を定期的にもち、言語化能力を高められるように意識していたいと思います。
以上です。ありがとうございました。
Discussion