1. 入力から応答が届くまで

対象・調査限界は README を参照。以下の数値はコードの値であり、本番の実効設定を意味しない。

1.1 全体の責務

flowchart TD
    A[YouTube / Twitch / TikTok / Kick / 音声 / 手動] --> B[CommentController: 正規化]
    B --> C[ChatGPTController: 受付条件・安全検査]
    C --> D[CommentStock: 用途別キューと採用]
    O[運営カンペ] --> D
    G[認証済みゲームイベント] --> D
    D --> E[ChatGPTController: 台本・発話権の確認]
    E --> F[SituationSnapshotを固定]
    F --> H[LLMController: 人格・記憶・状況・演出の統合]
    H --> I[LLM生成・再試行・出力整形]
    I --> J[安全性・長さ・鮮度・実行scopeを再検査]
    J --> K[TTSController: 音声・表情・口パク]
    K --> L[実際に再生された本文の確定]
    L --> M[記憶・質問受付・話題の続きへ反映]
    S[ScriptRunner / MonologueController] --> H
    S --> K

中心はUnity。Functionsがすべての返答を生成してUnityへ配信する構造ではなく、Unityの LLMController が各プロバイダーへHTTP要求し、Unityの TTSController が音声を配送する。クラウドにはキャラ設定、台本、記憶同期、運営コマンド、状態報告などの役割がある。

主な責務 主な実装
入力 取得元の違いを共通イベントへ変換 CommentControllerNormalizedComment
採用 用途別優先度、古さ、順序、公平性、台本の受付 CommentStockScriptRunner
応答の進行 1件/複数件、処理ロック、取消、最終配送 ChatGPTController
内容生成 プロンプト、モデル、再試行、補助タグ LLMController と各partial
聞こえる表現 合成、チャンク、感情、再生、停止、配送結果 TTSController
番組の進行 台本ノード、自発発話、質問待ち、寄り道 MonologueController、ScriptRunner

1.2 入力の種類と区別

CommentPlatform は Unknown / YouTube / TikTok / Twitch / Voice / Manual / System / WebVoice / Discord / Kick。CommentWorkKind は「どこから来たか」と独立し、「何として扱うか」を表す。

CommentTrace はプラットフォーム、source、元message ID、投稿UTC時刻、安定user ID、課金イベント由来、owner/moderatorバッジ、Web Voiceとの相関情報を持つ。元時刻が無い入力は受信時刻を使い、未来時刻は受信時刻へ補正する。元の投稿時刻が取れない経路では、実際の投稿からの鮮度までは判定できない。

表示名と安定IDは分けられ、ViewerIdentityRegistry.RegisterObservedIdentity が観測を記録する。IDが常に全プラットフォームから来るという保証ではない。バッジによる役割も、名前の文字列から推測しない。

入力が正規化されたこと、コメント欄に表示されたこと、AIが採用したこと、音声になったことは別の段階である。OnNormalizedComment と応答用のイベントも分かれている。

1.3 通常コメントの入口で起こること

ChatGPTController.HandleNewComment の順序に沿う。

  1. source message IDとuser IDを補完する。
  2. コメント応答OFF、配信切替中、空文字を拒否する。Adminの練習入力には一部バイパスがある。
  3. 原則3文字未満を拒否する。回答受付中で短文回答が許可される場合は通す。
  4. 「申し訳ありませんが」「お応えできません」「お答えできません」「エラーが発生しました」を含む文を、AI拒否/エラー文として拒否する。
  5. 通常コメントは投稿基準60秒を超えていれば破棄する。
  6. @ で始まる本文をリスナー同士の会話とみなし、AI応答経路を通さない。
  7. 台本がコメントを受け付けない間は、安全検査後にキューへ保留する。相槌や視聴者情報抽出の経路へ進めない。
  8. 通常時は安全検査後、視聴者情報抽出、コメント欄の雰囲気、来訪・関係性を更新する。
  9. HumanLikenessの方針により、無視 / 短い相槌 / 完全応答へ分岐する。相槌は睡眠・別処理・音声再生中には抑止される。
  10. キュー投入に成功した入力を質問への回答候補として記録し、処理ポンプを動かす。

体験への含意: 「草」「w」「うん」などは、回答受付の特例外では3文字条件で落ち得る。AIエラー文に似た言い回しも文意によらず弾かれる。短い盛り上がり反応を拾えるかは、生成モデルより手前の仕様に左右される。

1.4 キューと優先順位

CommentStock.DequeueNextSingleLocked / GetWorkPriority の順序。

優先順 用途 優先値 注意
1 緊急カンペ 500 割り込みと生成取消の連携あり
2 通常カンペ 400 視聴者応答ON/OFFとは別レーン
3 認証済みGameEvent 350 専用キュー。15秒の鮮度、最大8件
4 課金イベント 300 視聴者応答・台本のゲート条件を受ける
5 練習コメント 200 追跡可能な通常応答として扱う
6 SystemGenerated 100 運営カンペと同一ではない
7 一般コメント 0 関連度、公平性、待ち時間で選ぶ

質問締切後の回答開始猶予中は、優先レーンの次に、その質問に受付済みのmessage IDだけを選ぶ。無関係なコメントで猶予を延ばさない。

公平性が有効なときの採用スコアは、AudienceTurnFairness に定義される。

待ち時間 < 30秒: 関連度 − 直近8配送内の同一視聴者回数 × 0.75 + 待ち秒 / 30
待ち時間 >= 30秒: 1000 + 待ち秒

同じ人を連続で拾い続ける偏りを緩め、長く待った入力は古い順で回収しやすくする。全員への均等配分や、内容の面白さを評価する選別ではない。優先レーンにはこの公平性は適用しない。

1.5 いつ発話を始められるか

ProcessNextCommentSemaphoreSlim で処理を直列化する。配信切替中、別のコメント処理中、自発発話中、TTS実再生中、睡眠、台本ゲートなどを確認する。一般コメントを受け取ることと、処理を開始できることは分離されている。

ASMR中の通常コメントは30秒間隔の制限がある。課金・カンペ・GameEventには優先バイパスがある。台本による応答可否、音声競合など、別のゲートまで一括で解除する意味ではない。

複数コメントのまとめ応答

台本が動いておらず、自由会話の回答待ちでもない場合は、最大20件をバッチ処理できる。少なくとも2件・2人が必要。公平性が有効な場合は同一視聴者の複数件を採用しない。GenerateResponse(... bypassDirector: true) により、単一コメント用の演出・寄り道と区別する。

この経路は混雑への対処だが、1人ずつとの対話を保証しない。通常の単発返答と、バッチで拾われたコメントを同じ「返答率」に数える場合は指標の定義が必要になる。

1.6 1件の生成・配送の詳細

ProcessCommentInternal の通常生成経路は、次の段階を持つ。

段階 処理 失敗・変化が起きた場合
状況固定 Snapshot、返答言語、発話IDを固定 旧scopeなら中止
前準備 入力NG判定、必要なセッションメモリ更新、UI処理中表示 通常入力は安全代替文になることがある
応答生成 生コメントと内部文脈を区別してLLMへ渡す 再試行/経路別失敗処理
生成後検証 実行scope、コメント鮮度、カンペ条件 破棄または限定的な再生成
本文投影 自問自答演出、安全検査、タグ抽出、長さ制限、好みの具体性 本文変更時は解析タグの副作用を抑止
感情確定 タグがあれば利用、なければEmotionManagerで解析 追加解析が待ち時間になることがある
配送直前 安全性・世代・鮮度・発話ループを再確認 発話見送り。ループ時は通常経路に自己回復処理あり
配送 字幕、TTS、表情、必要な操作 TTSのrequestGateでも再検査
配送結果 HasAudibleDeliveryCompletedDeliveredTextを評価 途中まで聞こえた文と全文完了を分ける
確定後 発話履歴、視聴者回答回収、話題候補、記憶 scopeが有効か、配送が完了したかで分岐

感情・思考・ゲーム操作などの補助タグは、そのまま読み上げるための文字列ではない。安全フィルターや長さ制限で本文が変わった場合、元のタグによる操作・記憶更新を無条件に実行しない。

ただしすべての表示/副作用が「音声成功後」に揃っているわけでもない。通常字幕や一部の操作・感情状態更新は再生完了より前に行われる。実可聴の保証は SpeechPlaybackResult とその後のcommitについての契約として読む必要がある。

1.7 カンペとゲームの専用経路

運営カンペ

ChatGPTController.OperatorCueLLMcontroller.RequestScopeOperatorCueAdherenceValidator が中心。

GameEvent

これは一般的なゲーム実況の全経路を指す名前ではなく、認証済みゲーム拡張からの専用入力。現在の処理にはTAERUの接続・画像来歴確認がある。

通常の画面理解や自発ゲームリアクションとの違いは 3章 に記す。

1.8 遅延の構造

投稿→発話開始
  = プラットフォーム/relayの配送待ち
  + 受付・キュー・台本/音声ゲート待ち
  + 状況/画像/記憶/知識の取得
  + LLM要求と全文生成(再試行があれば加算)
  + 出力検査・必要な感情/修正文生成
  + TTSの順番待ち・先頭音声の合成
  + Unityの実再生開始まで

視聴者が聞くまで = 上記 + 配信サービス・視聴端末側の遅延

RequestTransport の一般HTTP経路は DownloadHandlerBuffer で完了を待つ。ChatGPTControllerGenerateResponse 完了後にTTSへ渡す。TTSチャンク分割は存在するが、一般コメントの「LLM生成トークンを逐次音声化する」接続ではない。

一般HTTP要求のtimeoutは60秒。通常生成ループは最大3回の試行を持ち、さらに失敗時の別provider経路もある。これは「1件の返答は60秒以内」という全体締切ではない。むしろ一般コメントの投稿60秒制限と合わさり、時間を使って生成した後で古さにより配送されない場合がある。

実測の秒数・中央値・p95は未取得。現行コードだけから、特定モデルやTTSが遅延の主因だとは断定できない。