Caso de uso

Um filtro de chat com IA para servidores de Minecraft

Os filtros de chat com listas de palavras bloqueiam palavras inocentes e deixam passar insultos sem palavrões. A VigiMod lê o sentido de cada mensagem, em 26 idiomas, e verifica as regras do seu servidor, como «Sem publicidade a outros servidores».

O que torna difícil

As listas de palavras falham nos dois sentidos

Bloqueiam palavras inocentes que contêm um palavrão e deixam passar «aqui ninguém te quer». Um modelo pontua o sentido, não palavras soltas.

Jogadores de todas as idades

Muitos jogadores são jovens. A categoria opcional child_safety (beta) assinala tentativas de aliciar um menor, como alerta para a staff.

Anúncios de servidores e vendas

Fazer publicidade a outros servidores ou vender contas é uma regra, não um palavrão. Escreva-a como regra e a VigiMod pontua-a.

Como funciona com a VigiMod

  1. 1

    Um plugin escuta o chat (AsyncChatEvent no Paper), que corre fora da thread principal.

  2. 2

    Envia à VigiMod a mensagem, o UUID do jogador e as suas regras, com um timeout curto.

  3. 3

    Se for assinalada, cancela a mensagem e avisa o jogador; várias marcações podem ativar o seu comando de mute ou aviso.

Regras para copiar

Envie-as no campo rules: cada uma volta com a sua própria pontuação, como uma categoria integrada.

{
  "rules": {
    "no-server-ads": "Sem publicidade a outros servidores de Minecraft ou de Discord",
    "no-selling": "Sem vender contas, itens ou ranks por dinheiro real",
    "no-personal-info": "Não perguntar aos jogadores a idade, a morada ou o telefone",
    "portuguese-only": "No chat global, só português"
  }
}

Exemplo

Um listener para um plugin Paper em Java: o evento do chat é assíncrono, por isso a chamada HTTP não abranda o tick do servidor.

Java (Paper plugin)

// A listener for a Paper plugin: register it in onEnable() with
// getServer().getPluginManager().registerEvents(new ChatFilter(), this);
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.papermc.paper.event.player.AsyncChatEvent;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public final class ChatFilter implements Listener {
  private final HttpClient http = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(2)).build();
  private final String key = System.getenv("VIGIMOD_KEY");

  // AsyncChatEvent runs off the main thread: waiting for the answer does not slow the server
  @EventHandler(ignoreCancelled = true)
  public void onChat(AsyncChatEvent event) {
    JsonObject rules = new JsonObject();
    rules.addProperty("no-server-ads", "No advertising other Minecraft servers or Discord servers");
    JsonObject body = new JsonObject();
    body.addProperty("text", PlainTextComponentSerializer.plainText().serialize(event.message()));
    body.addProperty("user_id", event.getPlayer().getUniqueId().toString());
    body.addProperty("scope", "my-server");
    body.add("rules", rules);

    HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.vigimod.com/moderate"))
        .timeout(Duration.ofSeconds(2))
        .header("X-API-Key", key)
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(body.toString()))
        .build();
    try {
      HttpResponse<String> response = http.send(request, HttpResponse.BodyHandlers.ofString());
      if (response.statusCode() != 200) return;
      JsonObject result = JsonParser.parseString(response.body()).getAsJsonObject();
      if (result.get("flagged").getAsBoolean()) {
        event.setCancelled(true);
        event.getPlayer().sendMessage(Component.text("Your message was not sent: it breaks the server rules."));
      }
    } catch (Exception e) {
      // slow or down: let the message through
    }
  }
}

Dicas

  • Use um timeout curto (cerca de dois segundos) e deixe passar a mensagem se a verificação falhar, para o chat nunca congelar.
  • Adicione child_safety às categorias em servidores com jogadores jovens e envie essas marcações à staff em vez de agir sozinho.
  • Envie o UUID do jogador como user_id: a mesma mensagem repetida sem parar aumenta a pontuação de spam.

Perguntas

Funciona em Spigot, Paper e Velocity?
O exemplo usa o AsyncChatEvent do Paper. O Spigot tem AsyncPlayerChatEvent e os proxies como o Velocity têm os seus próprios eventos de chat; a chamada HTTP à VigiMod é igual em todos.
Vai causar lag no servidor?
Não, se a chamar a partir do evento assíncrono do chat como no exemplo: a thread principal nunca fica bloqueada.
Apanha truques de escrita como o l33t speak?
Muitas vezes, porque o modelo lê frases inteiras, mas nem sempre. Para os piores casos, acrescente as suas palavras bloqueadas no plugin que já usa.
Quantas mensagens consegue verificar?
A beta gratuita permite 120 mensagens por minuto por chave API. Redes maiores podem pedir ao suporte um limite mais alto.

Experimente na sua comunidade

Crie uma chave API gratuita em dois minutos. Sem cartão, sem período de teste.