1. はじめに
未経験からWebエンジニアを目指して学習中の身ですが、ポートフォリオとして「YouTubeのコメントを感情分析するWebアプリ」を開発しました。
本アプリケーションの最大の特徴は、OpenAIなどの外部APIに依存し続けるのではなく、
「AIモデルを独自に蒸留・量子化し、Cloud Run上でサーバーレスに運用している」点です。
フロントエンド開発、バックエンド開発、AIモデルチューニングなどすべて自分1人で行いました。
アプリのURL :
https://emo-reader.jp/
動機 :
「AIを使ったアプリを作りたい」という技術的欲求と、YouTubeを見ていて「この動画、みんなはどう感じたんだろう?(共感・反感)」を一目で知りたいというユーザー視点の欲求からスタートしました。
また動画投稿経験もあり、みんなの感情や反応をざっくりとでも知りたいということを実現するため、開発することにしました。
AIにより感情を分析し、さらにその分析してふるい分けをしたコメントを分析し、AIによるレポート作成機能も実装しました。
2. 作ったもの:『EmoReader』
どんな動画でも、YouTubeのコメントの感情を分析することができます。
(※ただし日本語のコメントしか正しく分析できません!)

どんなアプリ?:
YouTubeのURLを貼るだけで、コメントを最大300件取得し、AIが感情を分析・要約・可視化するツールです。
①単なるポジティブ/ネガティブだけでなく、8つの感情(喜び・信頼・恐れなど)に分類
「エモちゃん」というキャラクターが、分析結果に合わせて表情を変えてコメントをしてくれる。
②コメントを分析してトピックを作成
③AIがコメントと感情を分析して、レポートを作成
それぞれの感情をもとにAIがコメントの分析をし、
①全体的な傾向と雰囲気
②ポジティブ
③ネガティブ
④特筆すべき点
⑤まとめ
と様々なユニークな分析をしてくれます。
④感情別のピックアップコメントを表示

各感情ごとにピックアップコメントを表示します。選定はライク数と返信コメント数で計算しています。
⑤感情推移グラフで時間帯による視聴者の感情をグラフ化
⑥すべてのコメントに感情を振り分け、時間順・いいねされたコメント順に切り替え可能
・そのほかにも「頻出ワードクラウド」や動画のどの時間帯に言及されていたのかを知ることができる「感情が動いた瞬間(ハイライト)」などの機能もあります。
3. 使用技術スタック
| カテゴリ | 技術・ツール | 選定理由 |
|---|---|---|
| Frontend | HTML, CSS, JS | モダンな構成で作成 |
| Backend | Python (FastAPI) | 非同期処理が得意でAIライブラリとの親和性が高いため |
| Infrastructure | Google Cloud Run | コンテナデプロイが容易でオートスケールするため |
| Database | Supabase (PostgreSQL) | 無料かつ高速な扱いが可能なため |
| AI Model | DeBERTa V3 (独自蒸留) | 日本語の文脈理解に優れているため |
| API | YouTube Data API v3 | コメント取得用 |
システム構成・アーキテクチャ設計
フローチャート(簡易版)
ER図(シンプル)
4. 技術的な挑戦
AIモデルの構築
既存のAPIを叩くだけではなく、独自の感情分析モデルを組み込むことにしました。
最初は公開されている学習済みモデルを使うつもりだったのですが、実際にテストしてみるとどうしても分析に時間がかかってしまい、30件のコメントに1分もかかってしまうという問題がありました。
性能(精度)自体は肌感でもかなりいいとは思ったのですが、ONNX化をしたり、バッチ処理や量子化など様々な方法を試しても、やっぱり100件分析するのに1分かかってしまいます。これではどうしても自分が求める基準には達しないので、別の方法を模索することにしました。
そこでふと、以前興味本位でモデルを自作した経験があったことを思い出しました。 https://qiita.com/izaki_shin/items/2b4573ee7fbea5ec8ed6
昔作ったそのモデルを試してみたところ、100件の分析をCPUで行ったにもかかわらず、ものの数秒で完了してしまいました。「これならいける!」とこの方針で進むことを決めたのですが、すぐにまた別の壁にぶつかりました。
データセットの問題です。 以前使った「Wrime」というデータセットは質がかなり高いのですが、研究開発用ということで商用利用ができませんでした。 そこで、データセットを自ら用意し、それを学習させることでオリジナルの感情分析モデルを作ることにしました。
手順としては以下の通りです。
① やり方としてはローカルLLM(Gemma等)に、インターネット上のコメントのような文章を作成してもらう。
② その文章に対し、同じくローカルLLMで8つの感情パラメーターをセットしてもらう。
③ セットしたパラメーターを使い、小規模なモデルをファインチューニングする。
この流れ、いわゆる「AIモデルの蒸留」を行い、独自の感情分析AIモデルを作成しました。
この方式であれば、モデルの単純なコピーではなく、蒸留によって作られた新しいモデルなので、商用利用(広告収入)や改変なども問題なく行えます。
こうして作ったモデルをテストしてみたところ、次のような結果になりました。
【オリジナルモデル 処理パフォーマンス】
総データ数: 2125 件
総分析時間: 55.89 秒
1コメント平均: 0.0263 秒
となっていました。
Hugging Faceで公開されていた似たような8感情分析モデルがありましたので、それと比較テストを行った結果です。
【類似モデル 処理パフォーマンス】
総データ数: 2125 件
総分析時間: 208.25 秒
1コメント平均: 0.098 秒
既存モデルと比較してもそこそこの精度が出ており、なにより速度に関しては私のモデルのほうが3〜4倍ほど速かったです。
要因としては、私のモデルが1.7GBに対し、比較対象モデルは2.2GBありサイズとしても小さく、パラメータ数も小さいです。
またファインチューニングをしたモデルはDeBERTaというテキスト(単語)の関係性を理解することに特化したモデルで、BERTやRoBERTa、そしてLUKEといったモデルよりも後発のモデルです。
そのため、少ないパラメータで賢く文脈を捉える工夫がされており、計算効率と精度のバランス(コスパ)が良いためこのような結果になったのではないかと思います。
そしてここからさらに、徹底的な高速化を行いました。
まずはONNX化です。(AIモデルを『どこでも・誰でも・速く』使える共通フォーマットに変換すること)
さらにモデルの量子化も行いました。(モデルのサイズを小さく圧縮して軽くすること)
これにより、最終的には「1コメント平均: 0.0105 秒」という爆速な分析が可能になり、Cloud RunのCPUのみの駆動でも300コメントを5秒以内で分析できるようになりました。
【自作モデル】
【処理パフォーマンス】(onnx化 + 量子化)
総データ数: 2000 件
総分析時間: 21.08 秒
1コメント平均: 0.0105 秒
FPS (推定): 94.9 件/秒
【基本精度】
正解率 (Accuracy): 0.6915 (1383/2000)
【分類精度レポート】
precision recall f1-score support
喜び 0.87 0.56 0.68 390
悲しみ 0.70 0.79 0.74 205
期待 0.66 0.64 0.65 277
驚き 0.56 0.78 0.65 441
怒り 0.53 0.67 0.59 194
恐れ 0.78 0.56 0.65 215
嫌悪 0.43 0.39 0.41 59
信頼 0.51 0.41 0.45 219
f1-score 0.63 2000
※学習用に使ったデータセットからランダムにピックアップしたテスト用データの結果なので、実際の人が書いたコメントを分析すると精度はまた少し変わってきます。
感情分析タスクにおいて、人間の意見が一致する確率は概ね 70% 〜 80% 前後と言われているため、感情分析モデルとしてはそこそこの性能になるのではないかと思います。
時間があれば、ここからさらなる性能アップを狙いたいところ。
ただこれ以上の性能を上げるにはデータセットの質を上げる必要があり、数%の質を上げるためには様々な思考錯誤と時間が必要になりそうなので、しばらくはこのままこのモデルを使おうと思います。
モデル作成はGoogle Colabを使い、1000円で10 ~ 20個ほどモデルを作成しました。
AIと壁打ちをしながら機械学習のコードを何度も修正し、最終的には満足する分析速度を得ることができました。
ただ、実際にはDBへの問い合わせ・保存、キャッシュ判定、スキーマ判定など様々な処理が入るため、トータルでは10秒以上はどうしてもかかってしまう状態です。ここは今後の最適化で改善していきたいポイントです。
【2/16 追記_1】
数日前にはすでに修正され、並列処理、DB接続の効率化、フロントエンドの通知処理の無駄をなくし、6~9秒ほどで処理できるようになりました(コールドスタートなどの影響で少し伸びる場合はあります)。
コメントが少なければさらに早く処理が完了します。
堅牢性を強化
バックエンドの処理、特にキャッシュがない未分析の動画を扱う際の仕組みにもこだわりました。
JobデータベースとSSEを用いたポーリング処理
今回、WebSocketのようなフロントエンドとの双方向通信ではなく、あえてSSE(Server-Sent Events)とポーリング処理を選びました。
理由としては、WebSocketだとどうしてもサーバー側のリソースが余分に必要になるためです。
基本的に「バックエンドの処理がどこまで進んだか」を伝えていく形式のほうが、クライアント側から何度も「終わりましたか?」と問い合わせてくる無駄をなくせますし、接続数が増えたときの負荷も抑えられると考えました。
具体的な処理としては、分析リクエストが来た際、必ずJobデータベースに対象Youtube動画のIDと、UUIDを付けたデータを追加するようにしています。
そして各ステップごとにステータスを更新し、いまどの処理をしているかを記録していきます。
これをすることで、例えば複数のユーザーが同じ動画を分析しようとした際に、無駄な処理を省くことができます。
動画IDを確認して、すでに誰かが分析を開始していれば、後から来たリクエストは「待機」状態にします。
そしてメインの分析処理が完了次第、待機していたすべてのユーザーに一斉に結果を送信します。
こうすることで、YouTube Data APIへのリクエスト数を節約できます。
また、各ステップごとに進捗(ステータス)を保存しているので、もし何らかのトラブルでコンテナが落ちてしまっても、再起動した際にデータベースを確認しに行き、途中で止まっていたジョブを再開させる、といった復旧も可能です。
このJobデータベースは定期的にチェックを行っており、エラーで止まっているデータがあれば再開させたり、何らかの影響で長時間残ってしまった「ゾンビデータ」は強制的に削除したりして、常にデータをクリーンな状態に保つようにしています。
不正アクセスや攻撃を防止する
セキュリティ面では、基本的にユーザーから送られてくるデータは「動画ID」しか許可しない設計にしました。 管理を楽にしつつ、チェックする内容を最小限にするためです。
FastAPIを使って構築しているので、Pydanticのスキーマクラスを作成し、そこでデータを厳密に定義しています。 送られてきたデータがYouTubeのID形式に則っていない場合など、このスキーマ定義を満たさないリクエストはすべて入り口で弾くようにして、不正なデータの流入を防いでいます。
5. バックエンド開発の苦労と工夫
開発を通して痛感したのは、「準備や計画、開発工程はある程度しっかり決めてから始めたほうが良かった」ということです。
開発経験が浅かったこともあり、ローカル環境でテストや実験を行い、それが完了次第、本番環境にアップして軽くテストすればOKだろう、という軽い構想でいました。
しかし実際には、Dockerコンテナ化やCloud Run上にあげてからのエラーがかなり頻発してしまいました。
結局、本番用として想定していたプロジェクトを「テスト環境」という扱いにし、新たに本番環境を一から作成し直すことになりました。
これによって起きた問題が、クラウド側の設定(IAM認証や環境変数など)のやり直しです。
ある程度日が経ってから再度作成することになったため、記憶が曖昧で、なんとか解決したはずの同じようなエラーにまたハマってしまいました。
念のためにメモを残していたおかげで、長時間ハマり続けることは避けられましたが、細かい点はメモしていなかったり、メモ自体が乱雑で探すのに時間がかかったりと、かなり苦労しました。
開発のやり方やログの残し方といった根本的な方針がないと、あとあと面倒なことになるんだなと身をもって学びました。
AIコーディング(Vibe Coding)の落とし穴
今回はAIを使ったコーディング(Vibe Coding)を中心に開発を行っていましたが、こちらも考えなしに進めていたため、途中でリファクタリングをしっかりとしなくてはならない状況になりました。
AIにお願いをして機能を追加していくと、ひとつのファイルにあらゆる機能を詰め込んで作成してしまう癖があるようで、あとで修正しようとした時に「どこに何の機能があるのか」の判断が難しくなってしまったのです。
そのため、開発の初期段階ではありましたが、自分でファイルの構成を考え直し、機能の分担(責任範囲)を振り分ける作業を行いました。これによって、その後の開発はかなりスムーズに進められるようになりました。
AIとの「認識のズレ」と戦う
システム構成として少し複雑になってしまった部分なのですが、私の実装では、エラーが起きた時にジョブを再実行(リトライ)させるための工夫をしていました。 それぞれの工程ごとにif文を加え、「このステータスの時だけはこの関数を実行できる」という構造にし、最初から作成されたジョブなら初期実行、エラーで途中で止まったジョブなら途中から再開する、という仕組みです。
しかし、そういった「あえての構造」であることを知らないAIは、このif文を「余分で無駄な処理」と判断して削除しようとしたり、ロジックを変えてしまったりすることが何度もありました。
なので、AIに修正をお願いした場合でも、必ずテキスト差分のチェックを行い、必要な処理を勝手に消していないか、戻り値が変わっていないかなどを人間が確認しながら進める必要がありました。
AIは非常に便利ですが、やはり最初の全体像は自分の中で理解し、考えながら進めないと後々大変なことになります。シンプルなWebアプリを意識はしましたが、すべてをAIだけで完結させるのではなく、自分でも確認をしたほうがより安心できそうです。
ただ、この数カ月でもAIは圧倒的に成長しているので、コードというよりか、システムの構造部分や設計部分をより具体的にし、動きが自分の想定通りになっているかを確認していくとよいかもしれません。
AIを使う上で精度が高くなったコツ
開発を通して見つけた、自分なりのAI活用のコツをまとめます。
①詳しく、具体的に伝える
ただ「この処理でエラーが出たらDBに保存して」
と頼むのではなく、
「このファイル『xxx.py』ではDB操作を行っています。バックエンド処理『yyy.py』の関数『zzz』で〜〜という処理を行っているので、ここで例外が起きた場合は "video_ID" や "error" 等の情報をDBに保存してください」
というように、ファイル名や関数の関係性を明確に伝えると精度が上がります。
②説明ファイルを作成して渡す
特にCloud Codeなどではリクエストの制限や節約も重要です。コメントで一気に文章を送るよりも、仕様や前提をまとめた説明ファイルを渡すほうが、指示の理解率が高いように感じました。
③ファイル全体の「置き換えコード」は信用しすぎない
Geminiなどの場合、修正版としてファイル丸ごとのコードを提示してくれることがありますが、それを信用しすぎると、修正箇所以外の必要な処理が消えていたりすることがあります。
面倒でもテキスト差分はしっかり確認したほうが良いです。
④ポイントを絞って修正してもらう
ファイル全体を修正してもらうのではなく、「怪しいと思う関数」だけを渡し、その関数を修正してもらうやり方のほうが、速度も精度も高かったです。
ローカルLLMなどは、読み込ませるテキスト量や生成させる量(トークン数)が多ければ多いほど、処理が難しくなるようです。 なので、修正する部分をピンポイントに絞ることで、AIの性能を高く引き出した状態を維持できます。 そのためにも、リファクタリングをしてファイル構造をシンプルにし、関数を細かく分けておくような「AIに読ませやすい構築」が大事になってくると感じました。
6.今後の展望
・感情分析の制度についてはもっと上げることができると思うのでデータセットをさらに精度を高くするための方法を模索する。
・八つの分析だけでなくモデル自体が非常に高速なので、ポジティブ・ネガティブを判別するモデルを作成し、ダブルチェックのような形で運用することで精度を上げる。
・すべてCPUのみで苦労していますがさらに速度を上げ効率化する方法を模索する。
7. おわりに
ここまで読んでいただきありがとうございました。
未経験からの挑戦でしたが、「企画→モデル構築→Web実装→インフラ構築」を一気通貫で行ったことで、
システム全体のつながりを深く理解できました。 ぜひ使ってみてください!







