最初に
1歳児を育児中のエンジニアです。もうすぐエンジニア歴7年目に突入しそうです。
年齢のせいか、現場でコードを書くことがなくなりつつあります。諸事情あって数年間ずっと資格勉強ばかりしていたのですが、いい加減資格だけのハリボテエンジニアなのが恥ずかしくなってきました。せっかくAWS SAPをとったので、その知見を活かしたサービスをなるべく早く、なるべく安く作ってみました。その記録になります。
要件定義
家庭教育の一環として「おうち英語」を実施中です。英語環境を家庭で作り、0歳時のころから英語に慣れ親しむことで、ハリーポッターを原書で読める小学生を目指します。昔、自分がTOEIC900を目指して地道に頑張っていたころ、留学経験がないのに英語がペラペラな同僚がいました。コツを聞いたところ「小学生の時におばあちゃんがハリーポッターの原書を読み聞かせしてくれたんだ」と返ってきて、英語は本人の努力云々ではなく親ガチャであったことに衝撃を受けました。よって、子供ができたら絶対におうち英語をやると決めていたのです。
まず英語の絵本を調達しました。が、親の私は純正日本人ゆえ英語の発音が汚すぎて絵本の朗読ができません。そこでAIに朗読してもらうことにしました。AWS Pollyを使えば簡単です。ページをめくる時間は間を置いたりなどもマークアップで操作できます。お値段も無料期間すぎても毎月100万字で16ドルとのことだったので、採用することにしました。
次に、声優AIの検討をします。イギリスのアンパンマン枠として「Peppa Pig」という幼児アニメがあります。うちの子はそれが大好きで1歳になってから毎日欠かさず見ているのですが、その絵本版を買いました。しかしただのAIの朗読は少し味気ない。どうせならアニメの声優さんに読んでほしいです。そこでOSSの合成音声AIを試してみました。
最低3秒の音源があれば対象の音声を合成して、好きな文章を読んでもらえるらしいです。岸田首相のアレです。将来的にはいきなり電話がかかってきて合成で作られたわが子の声が「助けて」と言ってくるのを想像してしまいました。今から親子間パスワードを決めておかねば。
それはさておきデモサイトがあったので試してみましたが、ちょっと微妙でした。自分の録音音声で作ったAIに文章をしゃべらせてみましたが、全体的に中国人っぽかったです。また、声優のAIを勝手に作って絵本を朗読させたり、アンパンマンがしゃべるおもちゃのpeppa pig版を作ってしまうのはさすがに著作権的にまずいのでは?と思い、この案は保留です。(むしろAmazon audibleで読んでもらったほうが...略)
また、「はらぺこあおむし」など定番・名作の原作絵本を100冊単位で輸入しました(1冊あたり数百円程度)が、文字が多すぎて1歳児には読めません。0~2歳児でも読める、文字が少ない仕掛け絵本もあるにはあるのですが、家庭の予算も限られているので節約したいです。そこで、家にある乳児用の絵本の日本語を打ち込んで、機械翻訳してもらおうと思いました。そこでAWS Translateを使って試したのですが、少し残念でした。絵本の文字情報が少なすぎ、擬音や幼児語の多用、日本語の主語の少なさ、比喩など文学表現、などなど壁が多く、全体的に残念な仕上がりでした。
最後に絵本朗読の音声をおうち英語コミュニティのママ友と共有するためのサイトが欲しいです。英語の絵本が何百冊とあり、ガチ勢のママ友さんは1冊1冊丁寧に音声化しているのですが、それを世帯ずつやっていくのは非効率です。音源を作って共有サイトにアップロードし、みんなで共有できればその苦労も減るのではないかと思いました。
まとめ やりたいこと(やらないこと)
4つ案が出たので整理です。
1,AIによる英文朗読機能(作りたい)
2,声優AIの作成(やらない)
3,日本語の絵本の英訳(やらない)
4,音源共有サイト(作る)
よって音源共有サイトを作っていきます。
音源共有サイトの構成
環境: WSL2, Docker
フロントエンド: react
バックエンド: Amplify, Lambda, Polly, DynamoDB, S3
インフラ: Amplify
コーディング補助: Github Copilot
全部未経験の技術ですが、Copilotもいるしなんとかなると見切り発車。
環境構築 WSL2 + Docker
DockerFileに設定を書いてコンテナを作るときにreact関連のモジュールを全部入れた状態にしておきたかったのですが、コンテナにインストールしてもファイルマウントするさいに、ローカルファイルでモジュール情報がすべてかき消されたので、うまくいきませんでした。そんな不便なことないでしょ?と思いつつ、いろいろ調べたのですが、結局解決策まで至らず。結局コンテナの中に入って一行ずつyarn add "モジュールの名称"してモジュール情報をローカルファイルに保存。一応DockerFileにも情報を残して後で追えるようにしました。
振り返ってみると、サーバーレスでアプリが動くのに、Dockerで仮想サーバーを立てる必要性はなかったかもです。
UI作成
cssが大の苦手なのですが、技術の進歩のおかげでほぼ自分で書かなくてよかったです。以下使った技術をまとめます。
MUI(マテリアルUI)
ボタンやテーブルなど基本的なコンポーネントは全部そろってるので基本的に持ってくるだけです。コード読むのも面白かったです。
Amplify Studio
awsの機能の一つなのですが、figmaというデザイン制作サイトと連動しており、figmaで作りたい部品をGUIで作ったらそのままコード化してくれます。figmaの慣れが必要、デザインの崩れあり、jsからtsへの書き換え、結局全部書き直すなど、いくつかハードルはあるのですが、フロント初心者としてはとても参考になりました。
Copilot
Copilotが思いのほか役立たずでした。実際に使ってみて感じたことですが、Copilotは「自分が調べずに時間をかければ自力でかけるコード」しか書いてくれません。Copilot(副操縦士)という言葉通り、正操縦士である自分がまず書きたいものやそのための道筋を完璧に理解できていないと、書かれたコードが正しいのか判断がつかないのです。
よって結局reactの状態遷移の考え方もリアルタイム更新機能も全部自分でググって実装しました。逆に言えば今回で概念を理解できたので、次回同じ機能を作るときはCopilotが爆速で作ってくれる気がします。
生成AI
createという文章で説明しただけで、webサイトを作ってくれる生成AIを試してみました。最高でした。華やかなデザインも各部品のデザインも、簡単な検索機能もすべて作ってくれました。それぞれreactのコード付きです。
デザインの統一性とか、結局細かいカスタマイズはコードを理解しないとできない、などいくつか課題はありますが、日本語で説明すれば何回でも作り直してくれるというのは、とてもありがたかったです。
バックエンド設定
認証
amplifyでログイン機能を全部自動で作ってほしかったのですが、うまくいかず、結局認証・認可の仕組みを最初から学びなおしました。
まとめがこちら。
また、音源の共有は著作権的にすれすれなのでサイトは一般公開をせず、内輪で運営することにしています。よってサインインの際に既存会員からの招待コードを持たせることにしました。lambdaで招待コードの認証機能を書いて、ユーザープールのサインアップ前の挙動として、作ったlambdaを設定しました。
GraphQL → AppSync → DynamoDB 呼び出し
絵本情報を格納するDBは、安く済ませたかったので、RDBではなくNoSQLのDynamoDBとGraphQLを選択しました。あくまで初学者の感想ですが、NoSQLは開発中のデータスキーマ変更がとても楽でした。RDBだとカラム追加・削除でいちいちnullの問題など発生して影響範囲が広くなりがちなのですが、表の形でかっちりとデータを持たないNoSQLだとそこらへんが柔軟です。
また、GraphQLでAPI呼び出し時に、出力値となるデータ情報を指定できるので、DB改修時のテストの切り分けがとても楽です。RDBで運用する場合、最初の設計段階でDBの仕様を決めた後、運用でそれを変えるのはとても大変なのですが、NoSQLであれば運用しながらデータ形式の変更を試してみるのも楽になるのでは?と感じました。(あくまで初学者の意見です)
reactでぬるぬる動くのが楽しくて油断しているとapiの呼び出し回数が上がってしまうので、どうやってデータの呼び出し量の節約をするか考えながら設計するのは楽しかったです。
amplifyがAPIのCRUDのメソッドを全部自動で書いてくれるので、とても楽でしたが、データの呼び出し量の節約という観点でいうと、自分で実装しなおしたほうがよさそうですね。データ量が増えてきたときに改修したいです。
Polly 呼び出し
テキストをPollyが読み上げるだけの単純な機能だけならamplifyが自動でコードを書いてくれるのですが、テキストではなくマークアップ言語でpollyを動かしたい。Pollyが読んだ音源をs3にアップロードしたい、などの機能まではできなかったので、lambdaでその機能を実装して、サイトからはlambdaを呼び出すだけにしました。
S3接続
肝心の音源はs3に格納し、ファイルパスはDynamoDBに格納することにしました。DynamoDBに絵本の名前などの情報を入れ、絵本の音源をダウンロードするときはファイルパスを使ってS3にアクセスします。
セキュリティ
不特定多数が音源をアップロードして、不特定多数がダウンロードするサイトになります。仮にs3に対してマルウェアなど仕込まれたら大変です。そこでバケットポリシーをいじり、アップロードできるファイル拡張子を音源関係に限定しました。(サイトから文字情報をlambdaに送って、そこでlambdaが音源を生成してs3に突っ込んでいるので、無駄といえば無駄ですが、よい機能だなと思ったので紹介です。)
また、必要最小限の権限の法則に基づいて、適切なAWSのポリシー(権限)をつけられたのではないかと思います。
インフラ
amplifyによるボタンポチポチで簡単にデプロイできました。表はJavascript、裏はAPIやlambdaで動いているので、S3にコードをアップロードするだけで、サーバーレスで運営できています。(つまりほぼ無料です。)
DynamoDBもサーバーレスモードで動いてくれるので、初期はほぼ無料で運営できます。s3の音源をダウンロードするときだけデータ量が多いのでどうなるか未知数ですが、そんなものはサービスが成長してから考えます。ひとまずはほぼ無料で運営できそうです。
ただ、管理・運用が難しい構成だと我ながら思います。コード量自体はとても軽いですが、AWS上のあちこちにコードが散らばっているので、一括管理が難しいです。Terraformを使えば、全部コード化して一つのファイルとして管理ができるらしいです(似た機能としてcloudFormationがありますが、Terraformの場合awsだけでなく、ほかの三大クラウドとも互換可能らしいです)。が、今回は見送り。今自分が頑張らなくても、もうしばらく待つとAWSから「タグ情報をもとにこのサービスの構成図やTerraformのテンプレートをAIで書いてみたよー」みたいなサービスができるんじゃないかと淡い期待を抱いています。未来に期待です。
最後に
おうち英語を頑張ったおかげで親の英語力が伸びており、公式ドキュメントを原文のままで読むのが苦ではなくなっていました。amplifyの進化が早すぎて、日本人による個人ブログのハンズオンを試してもうまく動かないことが多いので、公式ドキュメントを読めるようになったのは、とてもうれしかったです。
一番大事なこれからの運用ですが、親の親の努力が子供にばれてしまうと白けてしまうので、いかになにくわぬ顔をして日常に溶け込ませるかが最大の難関です。が、努力が全部無駄になることも含めて教育の醍醐味だと思って気楽にやろうと思います。
*早期英語教育は安易にマネするとリスクも大きいので、マネするときは専門家の指示に従ってくださいね。