文件 工具

頭頂氣泡與本機模型

讓遊戲裡任意單位以任意身分在頭頂彈出對話氣泡;接上本機 LLM,一句話輸入,一句回覆就出現在單位頭上。

氣泡屬於觀賞層:不影響勝負,適合直播、賽事解說和偵錯。

  • 任意單位、任意身分都能說話;多個單位可以同時說;
  • 每個氣泡的字級、顏色、寬度、尾巴、透明度、打字速度都能個別自訂;
  • 能直接接上本機 LLM(LM Studio),支援串流輸出:一邊生成一邊更新氣泡。

從 Bot 裡使用

最簡單的方式是 SDK 內建的 say:

g.say(hero, "跟我衝!", seconds=4)

啟動與介面

最省事:遠見首頁「控制中心」——先點「本地大模型 → 啟動並載入模型」(LM Studio 本機服務 + 把設定好的模型載入顯示記憶體),再點「頭頂聊天氣泡 → 啟動」。卡片上能看日誌、停止、重新啟動。

介面在遠見左側的「頭頂氣泡」頁:讓單位說話(選單位、輸入文字、調整樣式、和模型對話)、農民茶話會、鏡頭對白、戰況觸發、模型設定,都針對頂端列選取的實例操作。

也可以用命令列:

python speech/speak_launch.py              # 啟動本機模型服務 + 載入模型並預熱 + 啟動氣泡 API
python speech/speak_launch.py --restart    # 修改程式碼後重新啟動 API
python speech/speak_launch.py --stop       # 停止 API,並把模型從顯示記憶體卸載

每一步都是「已存在就略過」,重複執行沒有副作用。

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": "第一波獸人還有 30 秒抵達。",
      "style": { "tail": false, "type_ms": 0 } },
    { "world": [-4684, 2644], "key": 2, "text": "集合點", "style": { "font_px": 16 } }
  ]
}
欄位說明
unit / world / screen三選一:跟著單位移動(有血條時貼在血條正上方)/地圖座標/螢幕像素(旁白用)
name第一行顯示的說話者,隨意填寫,不必是這個單位
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 個氣泡;每幀開銷平均約 0.1 ~ 0.2 ms。

和本機模型對話 POST /api/chat

{
  "inst": 16, "unit": "0x14A12614", "name": "山丘之王",
  "persona": "你扮演魔獸爭霸裡的山丘之王穆拉丁,豪爽、愛喝酒。一兩句口語,不超過40個字。",
  "message": "前面有一群食人魔,我們衝不衝?",
  "stream": true
}

回傳 {"reply": "...", "first_token_ms": 283, "total_ms": 342},同時這句回覆已經出現在那個單位頭上。同一個單位會記住最近 6 輪對話。

其他

API說明
GET /api/instances執行中的遊戲
GET /api/units?inst=16&mine=true&heroes=true單位清單(含中文名稱、座標、血量)
POST /api/clear清除一個或全部氣泡
GET /api/llm、POST /api/llm查看/修改模型設定(base_url、model、max_tokens、temperature)
POST /api/banter農民茶話會:家裡的工人依人設輪流吐槽,開局報幕(戰況全是真實資料)
POST /api/camtalk鏡頭對白:鏡頭裡的英雄和隨從依身分對話
POST /api/events戰況觸發:開戰、打完、英雄陣亡、升級主堡、被拆……有事發生才說話

本機模型怎麼選

在一張 RTX 5090 上實測(5 句遊戲台詞):

模型顯示記憶體速度一句回覆結論
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 秒顯示記憶體吃緊時使用,中文略顯平淡
Qwen3.6-27B(稠密),Q417.2 GB約 39 token/s5.5 秒後仍在思考不適合即時對話
  • 速度看「每次啟用的參數量」,不看總參數量:35B 的 MoE 只啟用 3B,比 27B 稠密模型快 3 ~ 4 倍。
  • 一定要關閉「思考」:不關的話 token 全花在思考上,一個字都沒回。
  • 氣泡逐字打出的速度約每秒 22 個字,生成速度已經不是瓶頸,真正影響體驗的是首字延遲。

讓台詞「像真的」

給模型的戰況一律使用真實資料(場次、勝負、兵力、庫存),並明確要求「只能使用這些事實」。實測發現,不加這條限制時,模型會編造出沒發生過的戰鬥。