📻

【個人開発】Web3ギャラリーにニュースを音声で聴ける機能を追加した

に公開

はじめに

こんにちは!いけふくろうです。

前回の記事で紹介したWeb3Galleryに、音声ニュース機能を追加しました!

https://zenn.dev/ikefukurou777/articles/48778e947d387c

記事を読む時間がないときでも、通勤中や作業しながら、web3の最新ニュースをサクサク耳で追えるようにした機能です!!

完成したもの

  • 今日/昨日から/1週間のニュースを選択
  • プレイリスト形式で連続再生
  • 記事ごとに2秒の間を空けて聴きやすく

アーキテクチャ

複数のメディアからRSSを収集し、microCMSへ投入するLambda関数を機能拡張しました。
取得した記事に対してはGemini 2.5 Flashを利用し、200〜300文字で要約するようプロンプトを与え、要約文を自動生成しています。
まだ、数件の記事でしか試していないので、精度が怪しければプロンプトのチューニングしていこうと思います。

RSS収集バッチの実行後に、音声生成用のLambda関数を新設しました。
このLambdaでは、microCMSに保存されている要約記事をインプットとして受け取り、AWS Pollyを利用して音声データを生成しています。生成した音声ファイルはS3にアップロードする流れです。

その後、S3にアップロードされた音声データのURLなどを、Next.jsのRoute Handlersで新設した APIを経由してデータベースに保存しています。

これら一連の処理は、Amazon EventBridgeでスケジュール起動しており、毎朝最新の記事を「耳で聴ける形」でユーザーに届ける仕組みを実現しました。

技術スタック(追加分)

技術 用途
Gemini 2.5 Flash URL Context Toolで記事を要約
Amazon Polly Neural音声でテキスト読み上げ(Takumi)
S3 音声ファイルの保存・配信

実装のポイント

Gemini URL Context Toolで記事を要約

const ai = new GoogleGenAI({ apiKey });

const response = await
  ai.models.generateContent({
  model: 'gemini-2.5-flash',
  contents: PROMPT_TEMPLATE + articleUrl,
  config: {
    tools: [{ urlContext: {} }],
  },
});

URL Context Toolを活用するとURLを渡すだけでGeminiが記事の内容を取得・理解して要約してくれます。このようなケースの場合、一昔前までは自前でスクレイピング処理を作っていたかと思いますが、不要になりましたね。

Amazon Pollyで自然な音声生成

インフラはAWSを活用しているので、Geminiで要約した内容をAmazon Pollyのインプットにして、音声データを作成し、S3へアップロードする機構のバッチを作りました。

const command = new
  SynthesizeSpeechCommand({
    Text: `${title}。${summary}`,
    OutputFormat: OutputFormat.MP3,
    VoiceId: VoiceId.Takumi,
    Engine: Engine.NEURAL,
    LanguageCode: 'ja-JP',
  });

日本語のNeural音声はTakumiのみ対応。Mizukiを指定するとエラーになるので注意です。

フロントエンドでの連続再生

const handleEnded = () => {
  if (currentIndex < audios.length - 1) {
    setCurrentIndex(currentIndex + 1);
    // 次のトラックまで2秒間の間を入れる
    setTimeout(() => {
      audioRef.current?.play();
    }, 2000);
  }
};

記事の切れ目がわかりにくかったので、一旦強引な制御ですが、2秒の間を入れてラジオっぽくしました。

詰まったポイント

Geminiモデルの選択

最初、コストの面を鑑みてgemini-2.0-flashを指定したところ「Browse tool is not supported」エラーとなった。URL Context Toolはgemini-2.5-flash以降で対応でした。

Pollyの音声選択

ValidationException: This voice does not support the selected engine: neuralのエラーが発生した。

日本語でNeural音声を使えるのはTakumiだけ(たくみお兄さん!?)。Mizukiではダメでした。

料金について

  • Gemini 2.5 Flash: Input $0.30 / Output $2.50 per 1M tokens(Standard)
  • Amazon Polly Neural voices: $16.00 per 1M characters

https://ai.google.dev/gemini-api/docs/pricing?hl=ja

https://aws.amazon.com/jp/polly/pricing/

1記事あたり約200〜300文字の要約で試算すると、

  • Gemini: 入力約2,000トークン + 出力約150トークン
    → 2,000 × $0.30 / 1,000,000 + 150 × $2.50 / 1,000,000
    → 約 $0.0006 + 約 $0.000375 = 約 $0.0010
  • Polly: 約250文字
    → 250 × $16.00 / 1,000,000 = 約 $0.0040

合計: 1記事あたり約0.005ドル(= 約0.5〜0.8円くらい)程度のはずなので、個人開発の範囲内として許容しました。

おわりに

今までGeminiなどのAPIを使ったり、音声機能のマネージドを活用した設計・実装経験が乏しかったので、音声ニュース機能を通じて、経験することもできて良かったです。

本記事が何らかの一助になれば幸いです。

最後までお読みいただきありがとうございました!!

Discussion