エンタメモード実装計画(2026-10-13)

参照配信(AI VTuber「イラミ」のクリップ 8 本)の分析で見えた「面白さの差」を埋める改修計画。 分析の要点と現状コードの差分は、メモリ project_reference_stream_irami_gap と本書 §1 にまとめる。

0. 方針

1. 参照配信の面白さと、現状の差

面白さの要素 現状の妨げ(代表箇所) 対応フェーズ
ボケとツッコミが別の AI Collab は 24h 招待必須・主アバターに口パク漏れ・字幕なし・ツッコミ役なし P2
欠点で一貫したキャラ、オチが欠点に落ちる 寄り添い/丁寧/前向き指示、PreferenceSpecificityGuard の書き換え、笑いの型・毒の強さの設定欄なし P1
作り話を盛る(yes-and)・自分の嘘設定を覚えている 「作り話をしない」「視聴者の世界設定を受け入れない」「仮定と明示」、自作ネタの記憶なし P1
1 秒未満のテンポ 生成→再生→間の逐次構造、台本の間は残り尺を無音で埋める(4〜15 秒)、ノード開始 5 秒待ち P3
参加が画面に返る(投票 %、読み上げ中、話者名の会話枠) 投票は A/B のみ・YouTube のみ・文字表示、読み上げ中バッジは既定 OFF・まとめ読み無印、話者名なし P4
企画(状況が進む物語、罠の投票) 台本は話題ベース。世界状態・時限イベント・LLM 進行役なし P5
締めで配信を振り返る EndingController は定型文のみ P6
チャンネルポイント・状態 HUD・複数プラットフォーム同時入力 いずれも無し / AI 入力は 1 プラットフォームのみ P7
ゲームをしながら雑談 AutoGamePlay→Unity は表情のみ P8

2. 共通設定 entertainmentConfig(P0 で配線)

キャラ設定のサブ設定として追加する(ALLOWED_CONFIG_FIELDS に追加)。保存経路は既存の llmModelConfig と同じ: Admin(キャラ詳細)→ PUT /admin/characters/:id/config → Firestore characterConfigs/{id}.entertainmentConfig → Unity CharacterConfigSyncManager → EntertainmentModeRuntime.Apply(...)。Unity → クラウドの config/sync も同じフィールドを往復させる。

フィールド 型 既定 用途(使うフェーズ)
enabled bool false 全体スイッチ
humorStyle string ≤600 ”” 笑いの型(例: 欲深く自信過剰、オチは自分の欠点に落とす)P1
flaws string[] ≤10×80 [] 欠点・オチの落とし所 P1
edgeLevel int 0–3 1 毒の強さ(0 やさしい / 1 軽い毒 / 2 毒舌・ブラックジョーク / 3 強め。実在個人攻撃・差別・ガードレール項目は常に不可)P1
allowSelfLore bool true 自分の架空の過去・設定を即興で作ってよい P1
acceptViewerPremise bool true 視聴者の無茶ぶり設定に乗る(関係性の押し付け・注入指示は従来どおり拒否)P1
runningGags string[] ≤20×120 [] 持ちネタ・天丼 P1
dialogueExamples string ≤3000 ”” 複数ターンの会話例(そのまま使ってよい口調見本)P1
maxLineChars int 20–200 60 1 発話の目安字数 P1
loreMemoryEnabled bool true 自作ネタ帳の記憶 P1
loreMemoryMaxItems int 5–200 40 ネタ帳の保持件数 P1
fastTempo bool true 先読み生成・短い間 P3
scriptLineGapSeconds float 0–5 0.4 台本 LLM 発話の間 P3
sidekickEnabled bool false 常駐相方 P2
sidekickDisplayName string ≤40 ”” 相方の表示名 P2/P4
sidekickCharacterId string ”” 相方を既存キャラから引く場合(任意)P2
sidekickPersona string ≤1500 ”” 相方の性格・口調・語尾・ツッコミの癖 P2
sidekickRole enum tsukkomi/boke/rival/assistant tsukkomi 相方の役割 P2
sidekickReactProbability float 0–1 0.5 主キャラの発話後に相方が返す確率 P2
sidekickMaxTurns int 1–4 2 1 回の掛け合いの最大往復 P2
sidekickTtsEngine string ”” 相方の TTS エンジンキー(空=主キャラと同じ)P2
sidekickVoicevoxSpeakerId int -1 VOICEVOX 話者 ID P2
sidekickPlaybackSpeed float -1 再生速度(≤0 は未指定)P2
speakerNameBox bool true 話者名付きの会話枠 P4
typewriterSubtitles bool true 音声に合わせた 1 文字ずつ表示 P4
translateSubtitles bool false 翻訳字幕(2 行目)P4
translationLanguage string “en” 翻訳先 P4
readingBadges bool true 読み上げ中バッジ・まとめ読み表示 P4
pollBars bool true 投票の % バー表示 P4
endingRecap bool true 締めで配信を振り返る P6
redemptionActions string[] ≤20×120 [] チャンネルポイントの報酬と演出「報酬名=アクション」(head_pat / cheer / speak / emotion:名前)P7
statusHud bool false AI の状態 HUD(COOL/WARM/HOT/WARN)P7
heartList bool false よく参加してくれている視聴者の名前チップ P7
additionalInputPlatforms string[](youtube/twitch/tiktok/kick) [] メインのコメント入力に加えて受け付けるプラットフォーム P7

Unity 側の受け皿(P0 で作る。全フェーズがこの API だけを読む):

namespace Aituber.AI.Entertainment   // Assets/Scripts/AI/Entertainment(noEngineReferences)
public sealed class EntertainmentModeSettings { /* 上表のフィールドを PascalCase で。Normalize() で範囲補正 */ }
public static class EntertainmentModeRuntime {
    public static EntertainmentModeSettings Current { get; }   // 未設定時は Enabled=false の既定値
    public static bool IsActive { get; }                       // Current.Enabled
    public static event Action<EntertainmentModeSettings> Changed;
    public static void Apply(EntertainmentModeSettings settings);
}

3. フェーズ

P0 基盤(設定の配線)

P1 人格プロンプト+ネタ帳(作り直し)

P2 常駐の相方(拡張)

P3 テンポ(作り直し)

P4 画面演出(拡張)

P5 企画エンジン(新規)

P6 締めの振り返り(拡張)

P7 参加・表示の追加(拡張)

P8 ゲーム実況の合流(拡張・最小)

4. 条件の組み合わせ(主要)

entertainment.enabled 経路 期待する動作
false すべて 現行どおり(差分なし)
true コメント応答(単発) エンタメ用プロンプト。1〜2 文。ネタ帳注入・[lore:] 抽出。好みの書き換えなし。再生後に相方が確率で返す
true まとめ読み エンタメ用プロンプト(名前を並べた点呼ではなく、まとめて 1 つのネタにしてよい)。全対象行に読み上げ中バッジ
true 独白 / 台本 エンタメ指示+ネタ帳。fastTempo なら先読み生成・短い間
true スパチャ / ギフト 最優先は不変。お礼もエンタメ口調(欠点に落としてよいが、送り主をけなさない)
true ガードレール該当の要求 従来どおり断る(キャラ口調で短く)
true × sidekickEnabled=false 掛け合い 相方なし(P2 機能は動かない)
true × 企画ノード 台本 企画の状態・出来事を注入、時限ビート・投票・GM で進む

境界: 保存済みと編集中の値(Admin は保存後に Unity へ反映)、テナント設定ではなくキャラ設定、未設定・旧データ(フィールド欠落時は enabled=false)、配信中の切替(次の生成から反映。先読み中のものは破棄)。

5. 確認方法

6. 進め方

P0 を先に main へ入れる → P1・P3・P4 を並行(別ワークツリー)→ P2 → P5・P6 → P7・P8。各フェーズの統合ごとにオフラインビルドとテストを回し、ドキュメント(docs/20260507最新実装/)を同じコミットで更新する。

7. 実装状況(2026-10-13)

P0〜P8 をすべて main に統合済み(304bcf342.. の各コミット、統合時の追加: 4d2ede294 ResponseDirector の文言順の修正、951dbdec5・02856733c・5fb273f6a 締めの記録へのつなぎ込み)。各フェーズの詳細は docs/20260507最新実装/ の「2026-10-13 エンタメモード P#」の節。

フェーズ 主なファイル 状態
P0 設定の配線 functions/src/utils/entertainmentConfig.ts、CloudEntertainmentConfigMapper.cs、CharacterConfigSyncManager.Entertainment.cs、docs/admin/modules/admin-character-entertainment.js 実装済み。Admin のサンプル版(fixture)で表示と値の取り出しを確認
P1 人格プロンプト+ネタ帳 EntertainerPromptComposer.cs、SelfLoreLedger.cs、LLMcontroller.EntertainmentMode.cs 実装済み
P2 常駐の相方 AI/Collab/Sidekick/ResidentSidekickDirector*.cs、ResidentSidekickPolicy.cs、SidekickPromptComposer.cs、TTSController.SpeakerRouting.cs 実装済み
P3 テンポ ScriptLinePrefetchPolicy.cs、MonologueController.Tempo.cs、EntertainmentTempo.cs 実装済み(台本 v1.1 の予約ターンのみ先読み)
P4 画面演出 EntertainmentSubtitleOverlay.cs、TypewriterReveal.cs、SubtitleTranslationCache.cs、ScriptParticipationText.cs、EntertainmentReadingBadges.cs 実装済み
P5 企画エンジン ScriptScenario.cs、ScenarioDirector.cs、ScenarioGmProposal.cs、ScriptRunner.Scenario.cs、functions/src/utils/scriptScenario.ts 実装済み
P6 締めの振り返り StreamEpisodeLog.cs、StreamEpisodeRecorder.cs、EndingController.cs 実装済み
P7 参加・表示 RedemptionActionRouter.cs、ChannelPointRedemptionDirector.cs、EntertainmentParticipationOverlay.cs、CommentController.Entertainment.cs 実装済み(Twitch の再認可が必要)
P8 ゲーム実況の合流 AutoGamePlay/game_commentary.py、GameCommentaryBridge.cs、MonologueController.GameCommentary.cs、GameCommentaryPolicy.cs 実装済み(ゲーム別 AI は対象外)

確認の結果と残課題は 05_known_issues.md の「2026-10-13 エンタメモード」。

使い始めの手順

  1. Admin → キャラ → すべての詳細設定 → 応答スタイル →「🎭 エンタメモード」で「エンタメモードを使う」を ON にし、笑いの型・欠点・持ちネタ・会話例を書く(ここが面白さの大半を決める)。
  2. 相方を出すなら「相方」グループで表示名・性格・役割(ツッコミ等)・声(VOICEVOX 話者 ID)を入れる。
  3. 企画をやるなら台本エディタのノードで「🎬 企画(状況が進む物語)」に状況・出来事・投票を書く。
  4. チャンネルポイントを使うなら、配信アプリで Twitch の認証をやり直してから「報酬名=アクション」を書く。
  5. 配信アプリは更新版(このコミット以降でビルドしたもの)が必要。