ドキュメント ツール

頭上の吹き出しとローカルモデル

ゲーム内の任意のユニットの頭上に、任意の役柄で吹き出しを表示します。ローカル LLM につなげば、1 文を入力すると 1 文の返答がユニットの頭上に表示されます。

吹き出しは観賞用のレイヤーです。勝敗には影響せず、配信、実況、デバッグに向いています。

  • 任意のユニットが任意の役柄で話せます。複数のユニットが同時に話すこともできます。
  • 吹き出しごとに、フォントサイズ、色、幅、しっぽ、透明度、タイピング速度を個別にカスタマイズできます。
  • ローカル LLM(LM Studio)に直接接続でき、ストリーミング出力に対応します。生成しながら吹き出しを更新します。

Bot から使う

最も簡単なのは SDK 組み込みの say です。

g.say(hero, "俺に続け!", seconds=4)

起動と UI

いちばん手軽なのは Farsight のトップページ「コントロールセンター」です。まず「ローカル LLM → 起動してモデルを読み込む」(LM Studio のローカルサーバー + 設定済みのモデルを VRAM に読み込む)をクリックし、次に「頭上のチャット吹き出し → 起動」をクリックします。カードではログの確認、停止、再起動ができます。

UI は Farsight 左側の「頭上の吹き出し」ページにあります。ユニットに話させる(ユニットを選ぶ、テキストを書く、スタイルを調整する、モデルと会話する)、農民の井戸端会議、カメラ会話、戦況トリガー、モデル設定があり、上部バーで選んだインスタンスに対して操作します。

コマンドラインでも起動できます。

python speech/speak_launch.py              # ローカルモデルサーバーを起動 + モデルを読み込んでウォームアップ + 吹き出し API を起動
python speech/speak_launch.py --restart    # コードを変更したあとに API を再起動
python speech/speak_launch.py --stop       # API を停止し、モデルを VRAM からアンロード

各ステップは「すでにあればスキップ」するので、何度実行しても副作用はありません。

HTTP API

デフォルトは http://127.0.0.1:8872/(ポートは openwar3.json の ports.speech)で、どのプログラムからでも呼び出せます。

ユニットに話させる POST /api/say

{
  "inst": 16,
  "bubbles": [
    { "unit": "0x14A12614", "name": "マウンテンキング", "text": "俺に続け!" },
    { "unit": "0x14A12924", "name": "アークメイジ", "text": "ブリザードは任せろ。",
      "style": { "font_px": 26, "text_color": "#FFE080", "bg_color": "#C0102040" } },
    { "screen": [960, 110], "key": 1, "name": "ナレーション", "text": "オークの第 1 波到着まであと 30 秒。",
      "style": { "tail": false, "type_ms": 0 } },
    { "world": [-4684, 2644], "key": 2, "text": "集合地点", "style": { "font_px": 16 } }
  ]
}
フィールド説明
unit / world / screenいずれか 1 つ:ユニットに追従(HP バーがあればその真上に表示)/ マップ座標 / 画面ピクセル(ナレーション用)
name1 行目に表示する話者名。自由に書けて、そのユニットである必要はありません
text本文。自動で折り返します
duration_ms表示時間。0 = 自動で 3 〜 5 秒
keyワールド / 画面の吹き出しの番号。同じ key の新しいメッセージが古いものを置き換えます
update同じ吹き出しがすでにある場合、テキストだけを差し替え、タイマーはリセットしません(ストリーミング出力用)
stylefont_px、max_width_px、text_color、bg_color、border_color、tail、side_px、opacity、type_ms、font……

同時に表示できる吹き出しは最大 32 個です。1 フレームあたりのコストは平均約 0.1 〜 0.2 ms です。

ローカルモデルと会話する POST /api/chat

{
  "inst": 16, "unit": "0x14A12614", "name": "マウンテンキング",
  "persona": "あなたは Warcraft のマウンテンキング、ムラディンを演じます。豪快で酒好き。口語で 1〜2 文、40 文字以内。",
  "message": "この先にオーガの群れがいる。突っ込むか?",
  "stream": true
}

返り値は {"reply": "...", "first_token_ms": 283, "total_ms": 342} で、この返答はすでにそのユニットの頭上に表示されています。同じユニットは直近 6 往復の会話を記憶します。

その他

エンドポイント説明
GET /api/instances実行中のゲーム
GET /api/units?inst=16&mine=true&heroes=trueユニット一覧(中国語名、座標、HP 付き)
POST /api/clear吹き出しを 1 つ、またはすべて消去
GET /api/llm、POST /api/llmモデル設定の確認 / 変更(base_url、model、max_tokens、temperature)
POST /api/banter農民の井戸端会議:拠点のワーカーがキャラ設定に沿って順番にぼやき、開始時に口上を述べます(戦況はすべて実データ)
POST /api/camtalkカメラ会話:画面に映っているヒーローと従者が役柄に応じて会話します
POST /api/events戦況トリガー:開戦、戦闘終了、ヒーロー戦死、ティアアップ、建物破壊……何かが起きたときだけ話します

ローカルモデルの選び方

RTX 5090 1 枚での実測(ゲームのセリフ 5 本):

モデルVRAM速度1 回の返答結論
Qwen3.6-35B-A3B(MoE、毎回 3B のみアクティブ)、Q4、思考オフ20.6 GB約 142 token/s約 0.3 秒(最初のトークンまで約 0.27 秒)推奨:速く、中国語のロールプレイが自然
gpt-oss-20b(MXFP4)、推論 low11.3 GB約 280 token/s0.3 〜 0.8 秒VRAM が厳しいとき向け。中国語はやや平板
Qwen3.6-27B(dense)、Q417.2 GB約 39 token/s5.5 秒経ってもまだ思考中リアルタイム会話には不向き
  • 速度は「毎回アクティブになるパラメータ数」で決まり、総パラメータ数ではありません:35B の MoE は 3B しかアクティブにならず、27B の dense モデルより 3 〜 4 倍速くなります。
  • 「思考」は必ずオフにしてください:オフにしないと、トークンがすべて思考に使われ、1 文字も返答しません。
  • 吹き出しは 1 秒あたり約 22 文字の速さで 1 文字ずつ表示されるため、生成速度はもはやボトルネックではありません。体験を本当に左右するのは最初のトークンまでの遅延です。

セリフを「本物らしく」する

モデルに渡す戦況は必ず実データ(試合数、勝敗、兵力、備蓄)にし、「これらの事実だけを使うこと」と明示してください。実測では、この制約がないとモデルは起きていない戦闘をでっち上げました。