Docs Ferramentas

Balões de fala e modelos locais

Faça qualquer unidade do jogo exibir um balão de fala sobre a cabeça, com qualquer identidade; conecte um LLM local e cada frase que entra vira uma resposta sobre a unidade.

Os balões são uma camada visual: não afetam o resultado da partida e servem para lives, narração e depuração.

  • Qualquer unidade fala, com qualquer identidade; várias unidades podem falar ao mesmo tempo;
  • tamanho da fonte, cor, largura, rabicho, transparência e velocidade de digitação podem ser personalizados em cada balão;
  • conecta direto a um LLM local (LM Studio), com saída em streaming: o balão é atualizado enquanto o texto é gerado.

Usando no Bot

O jeito mais simples é o say que vem no SDK:

g.say(hero, "Sigam-me, ataquem!", seconds=4)

Inicialização e interface

O jeito mais fácil: página inicial do Farsight, “Central de controle” — primeiro clique em “LLM local → Iniciar e carregar modelo” (o servidor local do LM Studio + carregar na VRAM o modelo configurado) e depois em “Balões de fala → Iniciar”. No cartão dá para ver os logs, parar e reiniciar.

A interface fica na página “Balões de fala”, na barra lateral esquerda do Farsight: fazer uma unidade falar (escolher a unidade, escrever o texto, ajustar o estilo, conversar com o modelo), roda de conversa dos camponeses, diálogo na câmera, gatilhos da partida e configurações do modelo; tudo atua na instância escolhida na barra superior.

Também dá para usar a linha de comando:

python speech/speak_launch.py              # inicia o servidor do modelo local + carrega e aquece o modelo + inicia a API de balões
python speech/speak_launch.py --restart    # reinicia a API depois de alterar o código
python speech/speak_launch.py --stop       # para a API e descarrega o modelo da VRAM

Cada etapa segue a regra “se já existe, pula”, então rodar de novo não tem efeito colateral.

API HTTP

Padrão: http://127.0.0.1:8872/ (a porta fica em ports.speech, no openwar3.json); qualquer programa pode chamá-la.

Fazer uma unidade falar POST /api/say

{
  "inst": 16,
  "bubbles": [
    { "unit": "0x14A12614", "name": "Rei da Montanha", "text": "Sigam-me, ataquem!" },
    { "unit": "0x14A12924", "name": "Arquimago", "text": "Deixa que eu lanço a Nevasca.",
      "style": { "font_px": 26, "text_color": "#FFE080", "bg_color": "#C0102040" } },
    { "screen": [960, 110], "key": 1, "name": "Narrador", "text": "A primeira leva de orcs chega em 30 segundos.",
      "style": { "tail": false, "type_ms": 0 } },
    { "world": [-4684, 2644], "key": 2, "text": "Ponto de encontro", "style": { "font_px": 16 } }
  ]
}
CampoDescrição
unit / world / screenEscolha um: segue a unidade (se ela tiver barra de vida, fica logo acima dela) / coordenada do mapa / pixel da tela (para narração)
nameQuem fala, exibido na primeira linha; pode ser qualquer texto, não precisa ser esta unidade
textO texto, com quebra de linha automática
duration_msPor quanto tempo fica visível; 0 = automático, 3 ~ 5 segundos
keyIdentificador de balões de mundo / tela; uma mensagem nova com a mesma key substitui a antiga
updateSe o mesmo balão já existir, troca só o texto, sem reiniciar o tempo (para streaming)
stylefont_px, max_width_px, text_color, bg_color, border_color, tail, side_px, opacity, type_ms, font…

No máximo 32 balões ao mesmo tempo; o custo médio é de cerca de 0.1 ~ 0.2 ms por frame.

Conversar com o modelo local POST /api/chat

{
  "inst": 16, "unit": "0x14A12614", "name": "Rei da Montanha",
  "persona": "Você interpreta Muradin, o Rei da Montanha de Warcraft, expansivo e bom de copo. Uma ou duas frases coloquiais, no máximo 40 palavras.",
  "message": "Tem um bando de ogros ali na frente. Vamos atacar?",
  "stream": true
}

Retorna {"reply": "...", "first_token_ms": 283, "total_ms": 342}, e a resposta já aparece sobre aquela unidade ao mesmo tempo. Cada unidade lembra as últimas 6 rodadas de conversa.

Outros

APIDescrição
GET /api/instancesJogos em execução
GET /api/units?inst=16&mine=true&heroes=trueLista de unidades (com nome em chinês, coordenadas, vida)
POST /api/clearRemove um balão ou todos
GET /api/llm, POST /api/llmVer / alterar a configuração do modelo (base_url, model, max_tokens, temperature)
POST /api/banterRoda de conversa dos camponeses: os trabalhadores da base se revezam reclamando conforme a persona de cada um, com abertura narrada (todos os dados da partida são reais)
POST /api/camtalkDiálogo na câmera: os heróis e seguidores em cena conversam conforme seus papéis
POST /api/eventsGatilhos da partida: início de combate, fim de combate, herói morto, subida de tier, construção destruída… só fala quando algo acontece

Como escolher o modelo local

Testado numa RTX 5090 (5 falas de jogo):

ModeloVRAMVelocidadeUma respostaConclusão
Qwen3.6-35B-A3B (MoE, só 3B ativos por vez), Q4, raciocínio desligado20.6 GBcerca de 142 token/scerca de 0.3 s (primeiro token em cerca de 0.27 s)Recomendado: rápido, roleplay natural em chinês
gpt-oss-20b (MXFP4), raciocínio low11.3 GBcerca de 280 token/s0.3 ~ 0.8 sPara quando a VRAM é curta; chinês um pouco sem graça
Qwen3.6-27B (denso), Q417.2 GBcerca de 39 token/sAinda pensando aos 5.5 sNão serve para diálogo em tempo real
  • A velocidade depende dos “parâmetros ativos por vez”, não do total: o MoE de 35B ativa só 3B e é 3 ~ 4 vezes mais rápido que o denso de 27B.
  • É preciso desligar o “raciocínio” (thinking): senão, todos os tokens vão para o raciocínio e nenhuma palavra sai na resposta.
  • O balão digita cerca de 22 caracteres por segundo, então a velocidade de geração já não é o gargalo; o que realmente afeta a experiência é a latência do primeiro token.

Falas que soam reais

Passe ao modelo sempre dados reais da partida (número de partidas, vitórias e derrotas, tropas, estoque) e diga explicitamente “use apenas estes fatos”. Nos testes, sem essa restrição, o modelo inventava batalhas que nunca aconteceram.