前回からの課題

前回の記事: OBSスクショ要約をAITuberKitに渡してVOICEVOXで発話させるPoC

前回のPoCは動いたものの、実際に回すと次の問題が目立った。

  • 要約の精度が安定しない
  • 1分固定だとゲーム進行に追従できない
  • 条件次第でほとんど喋らない、または逆に喋りすぎる

今日やったこと

1. 要約の出力を構造化

要約を自由文ではなく、以下のJSONで返すようにした。

  • scene
  • facts
  • change_level
  • should_speak
  • speak_line

これで「画面の事実」と「実際に喋る文」を分けて扱えるようになった。

2. 直近履歴を渡して重複発話を抑制

直近の発話候補をモデル入力に渡して、似た内容の連投を減らした。

3. 可変周期に変更

固定1分をやめて、通常時と活動時で周期を切り替えるようにした。

  • 通常: CAPTURE_INTERVAL_SEC
  • 活動時: FAST_CAPTURE_INTERVAL_SEC
  • 活動後の高速維持: BOOST_DURATION_SEC

4. 発話制御を追加

  • 変化量しきい値: MIN_CHANGE_LEVEL_TO_SPEAK
  • 発話クールダウン: SPEAK_COOLDOWN_SEC
  • 類似文スキップ: SUMMARY_SIMILARITY_THRESHOLD

リファクタ内容

main.py に寄っていた責務を分離した。

  • prompt_builder.py: プロンプト構築
  • summary_parser.py: JSONパースとフォールバック
  • decision_engine.py: 発話可否判定
  • interval_controller.py: 可変周期制御
  • models.py: SummaryPacket 定義

テストも追加して、判定ロジックと周期判定を個別に確認できるようにした。

テストに使った設定(Slay the Spire)

GAME_CONTEXT=Slay the Spireをプレイしている。画面内のテキスト、ライフ、手札、エナジー、敵の意図に注目して要約する。
CAPTURE_INTERVAL_SEC=12
FAST_CAPTURE_INTERVAL_SEC=2
BOOST_DURATION_SEC=24
SPEAK_COOLDOWN_SEC=5
MIN_CHANGE_LEVEL_TO_SPEAK=none
SUMMARY_SIMILARITY_THRESHOLD=0.97

この設定で、戦闘中の追従性はかなり改善した。

まだ気になる点

  • モデルがたまに should_speak=false を強く返しすぎる
  • scene が長文になることがある
  • OCRで画面内テキストや数値を補助すると、要約の安定性はさらに上げられそう

次は OCR を軽く足して、facts の信頼性を上げる予定。

あわせて、VOICEVOXの既存音声だけでなく、よりオリジナリティのある声で発話させる方法も調べたい。