MP Ukagaka の仕組み

How it runs · v2.33.3

訪問者がページを開いてから、キャラクターが一言しゃべるまで。
その間にどのプログラムが動いているかを、四枚の図で追います。

· Capitulum I ·

ページ読み込み

PHP がキャラクターの外枠と最初のセリフをページに直接書き出し、ブラウザが /init で残りの設定を受け取ってから、最初の一言を誰が話すかを順に判定します。

サーバー(PHP) ブラウザ mpu_load_modules()モジュールを決まった順に読み込む キャラクターの HTML を出力最初のセリフ+埋め込み設定 フロントの JS を読み込みコアのバンドル+フリーレンのバンドル GET /init外見・装飾品・絵文字・設定 Canvas の初期化描画の準備ができるまで待つ DOM 準備完了 processSettings():左から順に判定し、最初に当てはまったものが最初の一言になる 睡眠の時間帯寝言を残し、AI は呼ばない起こされるのを待つ 初回の訪問者/visitor-info → /chat/greet来訪元に合わせて一度だけ挨拶 ページ感知の確率に当選3 秒後に /chat/context本文 300 字以上の記事のみ LLM で内蔵セリフを置換/nextmsg(startup)最初のセリフを打ち終えてから それ以外PHP が書き出した最初のセリフのまま どの道も最後は同じ:タイピング演出が終わったら自動会話タイマーを開始(睡眠中は間隔が約 9 倍) 睡眠はブラウザ側で時間帯から判定。初回訪問は Cookie mpu_first_visit_<ドメイン> で記録し、365 日は挨拶しない
青緑はサーバーで、それ以外はブラウザで動く処理です。判定の順番は js/ukagaka-features.js の processSettings() にあります。ページ感知に当たったときは起動時のセリフを先に止め、普通のセリフが記事へのコメントより先に出ないようにしています。
· Capitulum II ·

誰が話すのか

セリフはすべて同じメッセージ欄に書かれます。そのため表示の直前に「今この流れが話してよいか」を確かめます。AI を使う流れは、どれも同じサーバー側の処理を通ります。

きっかけ(ブラウザ) REST エンドポイント サーバー側の処理 ブラウザでの表示 自動会話タイマー ページ感知(記事へのコメント) 初回訪問の挨拶 対話モード(チャット) タッチ・装飾品クリック 贈り物・食べ物 睡眠中に起こされる /nextmsg(LLM モードのみ) /chat/context /chat/greet /chat/user-streamSSE、図 III を参照 /touch/zone/touch/decoration /touch/give /wake-ghost REST コントローラーセッショントークン・回数制限・履歴チェックサム プロンプトの組み立て人格ファイル+管理人の記憶+時刻・天気・観察 MPU_AI_Provider_Factory設定に応じてプロバイダーを選ぶ Gemini・OpenAI・Claude・Ollamaツール呼び出しは最大 5 回、ループ検知あり 応答の正規化感情タグの分離・長さの上限・絵文字の選択 表示前チェック メッセージのブロックを誰かが持っている? 対話モード中?タッチの会話中? まだ起きていない?画面の世代が変わった? 当たれば出さない(チャットの返事は履歴へ) メッセージ欄タイピング演出・絵文字・本をめくる動き JSON / SSE 通過 LLM を使わないとき:起動時に読み込んだセリフ集から一つ選ぶ(AI は通らない)
チャット・ページ感知・挨拶・贈り物・タッチは、それぞれ自分専用の「メッセージのブロック」を持ち、終わるときは自分の分だけを外します。2.33.2 からの仕組みで、以前は一つのフラグを共有していたため、別の流れが先にブロックを外してしまうことがありました。
· Capitulum III ·

チャットの往復

いちばん手順の多い流れです。ブラウザから届いた履歴が書き換えられていないかを確かめ、同じセッションでは一度に一件だけを処理し、返事は少しずつストリーミングで返します。

ブラウザ MPU_REST_Chat 履歴サービス・ロック AI プロバイダー 1 POST:メッセージ・直近 40 件の履歴・session_id 2 セッショントークン(匿名の訪問者)と回数制限(毎分 30 回)を確認 3 履歴のチェックサムを照合(audit は記録のみ、block は拒否) 4 チャットロックを取得(同じセッションは一件ずつ、60 秒) 5 プロンプトを組み立てる:人格ファイル・管理人の記憶・観察バッファ・サイト統計(聞かれたときだけ) 6 generate_chat_stream()、このキャラクターが使えるツールを添えて 7 必要ならツールを呼ぶ(最大 5 回、同じ引数が 2 回続けば中止) 8 文字の断片(ストリーミング) 9 stream.delta / stream.status(感情タグは先に分離) 10 一文字ずつ表示するキュー。45 秒音沙汰がなければ中断 11 この往復のチェックサムを保存 12 stream.done:正規化した返事の全文 13 チャットロックを外す 14 キューが空になったら締めくくり:返事を対応する発言の直後に入れ、絵文字・動きを反映し、入力欄を戻す
手順 3 と 11 は対になっています。サーバーは前回の終わりの履歴を覚えていて、次に届いた履歴と照らし合わせます。待っている間にチャットを閉じたり開き直したりしても 9〜14 は最後まで進みますが、履歴に書くだけで画面には出さないので、次の往復のチェックサムもずれません。ストリーミングを使わない /chat/user も順番は同じで、返事を一度に返します。
· Capitulum IV ·

裏方の処理

その場では話しませんが、データをどこかに残しておき、次にセリフを作るときに使われる処理です。

観察バッファ

記事の閲覧・滞在時間 → POST /observation/push → transient(1 時間)

訪問者がどの記事をどれくらい読んだかを一時的に残し、次のチャットでプロンプトを組むときに取り出して空にします。「さっき読んでいた記事」に触れられるのはこのためです。非公開やパスワード付きの記事は「非公開」とだけ記録し、タイトルは書きません。

管理人の記憶

管理者が /remember と入力 → POST /memory/extract → usermeta

最近の会話から管理人についての事実を抜き出して保存し、以降のシステムプロンプトに毎回添えます。

AI 日記

WP-Cron 毎日 21:00 ごろ → 確率で判定 → 記事を投稿

設定した確率(1〜10%)でその日に書くかを決め、一日に一本までです。チャットとは別の AI プロバイダーを使えます。

Bot 防護

Slimstat の計測リクエスト → 指紋・解像度・頻度で判定 → ブロックまたは記録

怪しいリクエストを止めて記録します。集まった統計は、チャットで彼女に報告してもらうこともできます。