Moderación de texto

Cada comentario recibe una respuesta, y su porqué

Manda un comentario, una publicación o un mensaje a /v1/text antes de publicarlo. Vuelve con allow, review o block, puntuado en quince categorías, con una frase que explica el motivo y el fragmento que lo ha provocado. Casi todo se resuelve en torno a un milisegundo, sin modelo.

Cómo funciona

  1. Mandas el texto

    Un POST a /v1/text con el contenido y, si quieres, los idiomas que esperas, dónde se va a mostrar y las reglas que se aplican. Tu propio identificador vuelve con la respuesta.

  2. Lo leen las comprobaciones gratuitas

    Listas de palabras y patrones de frases en ocho idiomas, sobre una copia normalizada del texto: p*ta, p u t a o una letra griega en mitad de la palabra se leen como lo que son. En la misma pasada se miran los enlaces, los datos de contacto, el texto repetido y el alfabeto que no toca.

  3. El modelo, solo si aporta algo

    Si las comprobaciones gratuitas lo resuelven, no se ejecuta nada más y la comprobación cuesta un crédito. Si dejan la duda abierta, lo lee el modelo y se suman los tokens que ha usado.

  4. Recibes una decisión que puedes explicar

    allow, review o block, una puntuación por categoría y señales que indican la categoría, el detector, el motivo en palabras y el fragmento que lo ha provocado.

Míralo en acción

  1. 01 Un comentario normal
  2. 02 Una palabrota en un elogio
  3. 03 Un insulto disfrazado
  4. 04 Enlaces y poco más
  5. 05 Una amenaza

Un comentario normal POST /v1/text

Qué fotos tan bonitas. ¿Dónde está este lago? Me gustaría ir en primavera.

allow 8 ms

Casi todos los comentarios son así. Lo resuelven las comprobaciones gratuitas y no se paga nada aparte de la comprobación.

La respuesta, resumida
{
  "decision": "allow",
  "flagged": [],
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 8
}

Una palabrota en un elogio POST /v1/text

Este tráiler es la puta hostia, lo he visto cinco veces.

allow 2 ms
  • Contains 2 profanity. On its own this says the tone is casual, not that the content is abusive.

La palabrota se anota en toxicity y, sola, solo dice que el tono es informal. Es una puntuación en una categoría, no un veredicto sobre todo el comentario.

La respuesta, resumida
{
  "decision": "allow",
  "flagged": [],
  "scores": {
    "toxicity": 0.4
  },
  "signals": [
    {
      "category": "toxicity",
      "score": 0.4,
      "reason": "Contains 2 profanity. On its own this says the tone is casual, not that the content is abusive.",
      "evidence": [
        "hostia",
        "puta"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 2
}

Un insulto disfrazado POST /v1/text

nadie te ha preguntado, eres un 1mb3c1l. vuelve a tu cueva

block 2 ms
  • Contains 1 insult(s), aimed at the reader.

Los números se devuelven a sus letras antes de buscar nada, y el insulto va dirigido a quien lee: es harassment y se rechaza.

La respuesta, resumida
{
  "decision": "block",
  "flagged": [
    "harassment"
  ],
  "scores": {
    "harassment": 0.8
  },
  "signals": [
    {
      "category": "harassment",
      "score": 0.8,
      "reason": "Contains 1 insult(s), aimed at the reader.",
      "evidence": [
        "imbecil"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 2
}

Enlaces y poco más POST /v1/text

¡¡¡Gana 300 euros al día desde casa!!! Entra ya: https://bit.ly/3xCash y https://t.me/cashvip_ya

review 7 ms
  • 2 links in about 19 words: mostly links, barely a message.
  • Uses a link shortener, which hides where the link goes.
  • Links to a chat invite or a free landing page, which is where promotion parks itself.

Un acortador, una invitación a un chat y dos enlaces en diecinueve palabras. Con los umbrales de serie se retiene para que lo mire alguien; una regla en la llamada puede convertirlo en un rechazo.

La respuesta, resumida
{
  "decision": "review",
  "flagged": [
    "spam"
  ],
  "scores": {
    "spam": 0.7
  },
  "signals": [
    {
      "category": "spam",
      "score": 0.65,
      "reason": "2 links in about 19 words: mostly links, barely a message.",
      "evidence": [
        "https://bit.ly/3xCash",
        "https://t.me/cashvip_ya"
      ]
    },
    {
      "category": "spam",
      "score": 0.7,
      "reason": "Uses a link shortener, which hides where the link goes.",
      "evidence": [
        "https://bit.ly/3xCash"
      ]
    },
    {
      "category": "spam",
      "score": 0.55,
      "reason": "Links to a chat invite or a free landing page, which is where promotion parks itself.",
      "evidence": [
        "https://t.me/cashvip_ya"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 7
}

Una amenaza POST /v1/text

Sé dónde vives y te voy a encontrar. Vas a pagar por esto.

block 1 ms
  • Contains 2 phrase(s) threatening harm, aimed at the reader.

Dos frases que amenazan con hacer daño, dirigidas a quien lee. La violencia es de las categorías que bloquean antes.

La respuesta, resumida
{
  "decision": "block",
  "flagged": [
    "violence"
  ],
  "scores": {
    "violence": 0.95
  },
  "signals": [
    {
      "category": "violence",
      "score": 0.95,
      "reason": "Contains 2 phrase(s) threatening harm, aimed at the reader.",
      "evidence": [
        "te voy a encontrar",
        "se donde vives"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 1
}

Míralo en acción

Un comentario normal POST /v1/text

Qué fotos tan bonitas. ¿Dónde está este lago? Me gustaría ir en primavera.

allow 8 ms

Casi todos los comentarios son así. Lo resuelven las comprobaciones gratuitas y no se paga nada aparte de la comprobación.

La respuesta, resumida
{
  "decision": "allow",
  "flagged": [],
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 8
}

Una palabrota en un elogio POST /v1/text

Este tráiler es la puta hostia, lo he visto cinco veces.

allow 2 ms
  • Contains 2 profanity. On its own this says the tone is casual, not that the content is abusive.

La palabrota se anota en toxicity y, sola, solo dice que el tono es informal. Es una puntuación en una categoría, no un veredicto sobre todo el comentario.

La respuesta, resumida
{
  "decision": "allow",
  "flagged": [],
  "scores": {
    "toxicity": 0.4
  },
  "signals": [
    {
      "category": "toxicity",
      "score": 0.4,
      "reason": "Contains 2 profanity. On its own this says the tone is casual, not that the content is abusive.",
      "evidence": [
        "hostia",
        "puta"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 2
}

Un insulto disfrazado POST /v1/text

nadie te ha preguntado, eres un 1mb3c1l. vuelve a tu cueva

block 2 ms
  • Contains 1 insult(s), aimed at the reader.

Los números se devuelven a sus letras antes de buscar nada, y el insulto va dirigido a quien lee: es harassment y se rechaza.

La respuesta, resumida
{
  "decision": "block",
  "flagged": [
    "harassment"
  ],
  "scores": {
    "harassment": 0.8
  },
  "signals": [
    {
      "category": "harassment",
      "score": 0.8,
      "reason": "Contains 1 insult(s), aimed at the reader.",
      "evidence": [
        "imbecil"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 2
}

Enlaces y poco más POST /v1/text

¡¡¡Gana 300 euros al día desde casa!!! Entra ya: https://bit.ly/3xCash y https://t.me/cashvip_ya

review 7 ms
  • 2 links in about 19 words: mostly links, barely a message.
  • Uses a link shortener, which hides where the link goes.
  • Links to a chat invite or a free landing page, which is where promotion parks itself.

Un acortador, una invitación a un chat y dos enlaces en diecinueve palabras. Con los umbrales de serie se retiene para que lo mire alguien; una regla en la llamada puede convertirlo en un rechazo.

La respuesta, resumida
{
  "decision": "review",
  "flagged": [
    "spam"
  ],
  "scores": {
    "spam": 0.7
  },
  "signals": [
    {
      "category": "spam",
      "score": 0.65,
      "reason": "2 links in about 19 words: mostly links, barely a message.",
      "evidence": [
        "https://bit.ly/3xCash",
        "https://t.me/cashvip_ya"
      ]
    },
    {
      "category": "spam",
      "score": 0.7,
      "reason": "Uses a link shortener, which hides where the link goes.",
      "evidence": [
        "https://bit.ly/3xCash"
      ]
    },
    {
      "category": "spam",
      "score": 0.55,
      "reason": "Links to a chat invite or a free landing page, which is where promotion parks itself.",
      "evidence": [
        "https://t.me/cashvip_ya"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 7
}

Una amenaza POST /v1/text

Sé dónde vives y te voy a encontrar. Vas a pagar por esto.

block 1 ms
  • Contains 2 phrase(s) threatening harm, aimed at the reader.

Dos frases que amenazan con hacer daño, dirigidas a quien lee. La violencia es de las categorías que bloquean antes.

La respuesta, resumida
{
  "decision": "block",
  "flagged": [
    "violence"
  ],
  "scores": {
    "violence": 0.95
  },
  "signals": [
    {
      "category": "violence",
      "score": 0.95,
      "reason": "Contains 2 phrase(s) threatening harm, aimed at the reader.",
      "evidence": [
        "te voy a encontrar",
        "se donde vives"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 1
}

Moderar comentarios con una API, explicado

Qué te devuelve, cómo lee el texto disfrazado, cuánto cuesta y cómo ajustar los umbrales.

Cómo funciona una API de moderación de comentarios

Tu web manda el texto antes de publicarlo y actúa según la respuesta: lo publica, lo retiene para que lo vea una persona o lo rechaza. Con ToxicFilter es un POST a /v1/text con el contenido. Puedes añadir los idiomas que esperas, dónde va a aparecer (un comentario, un anuncio, un perfil), la política que se aplica y tu propia referencia. La respuesta lleva un identificador que nombra esa decisión concreta, para la cola de revisión, para avisar de un falso positivo o para preguntar a soporte.

Quince categorías, no una nota de toxicidad

Spam, toxicidad, acoso, odio, contenido sexual, violencia, autolesiones, la seguridad de los menores, estafas, datos personales, texto disfrazado, texto sin sentido, contenido fuera de tema, inyección de instrucciones y tus propias listas de palabras. Cada una tiene un umbral para revisar y otro para bloquear. Algunas no bloquean nunca de serie: la toxicidad solo retiene, porque una palabrota no es un ataque, y las autolesiones también, porque a quien perjudica borrar ese mensaje es a quien lo escribió. Temas como las apuestas o las criptomonedas se miden en un eje aparte y no hacen nada hasta que una regla lo dice.

Insultos disfrazados y leetspeak

Un filtro que busca en el texto tal cual solo pilla a quien no lo intenta. Aquí no se busca nada sin normalizar antes: las letras de otros alfabetos que se parecen a las nuestras, los números en lugar de letras, los caracteres invisibles, los asteriscos, las tildes y las letras alargadas vuelven a la palabra que representan. Lo mucho que hubo que desenmascarar una palabra se mide por separado, en evasion. Las palabras permitidas se tapan antes de buscar, así que Scunthorpe, assess o cockpit no saltan nunca.

Rápido por la vía gratuita, y el modelo solo cuando aporta

Casi todos los comentarios son alguien escribiendo una frase normal, y pagar un modelo para leer cada uno es la forma de que la moderación cueste más que la web que protege. Las comprobaciones gratuitas se ejecutan siempre, y el modelo solo lee lo que ellas han dejado abierto. Una comprobación cuesta un crédito; cuando la lee el modelo se suman los tokens que ha usado, unos ocho créditos en total por comentario. Si el proveedor del modelo está caído, la respuesta lo dice con degraded en lugar de dar el comentario por leído.

Reglas por cuenta o por llamada

Empieza con los umbrales de serie o con una de las plantillas de política, para una comunidad, un marketplace o una web infantil. Una política guardada tiene versiones, y un cambio puede ejecutarse en modo sombra junto a la que está en vigor, para ver qué habría hecho con tu propio tráfico antes de que decida nada. Si prefieres no configurar nada, manda rules en la llamada: "bloquea el contenido sexual a partir de 0,7" es una sola petición, y las categorías que no mencionas no deciden nada.

Comentarios en ocho idiomas

Las listas de palabras y los patrones de frases cubren inglés, español, portugués, francés, italiano, alemán, catalán y neerlandés. Dile a la API qué idiomas esperas, y un texto en otro, o lleno de otro alfabeto, se señala como tal. El modelo lee muchos más idiomas, y effort: high lo hace entrar con un texto fuera de esos ocho.

Cómo se reparte el trabajo

Las comprobaciones instantáneas resuelven los casos claros en torno a un milisegundo, el modelo lee lo que depende del contexto, y tus reglas y tu equipo tienen la última palabra.

  • El contexto lo lee el modelo

    Las comprobaciones instantáneas resuelven los casos claros en torno a un milisegundo, en ocho idiomas, y están pensadas para no pasarse: las palabras permitidas se borran del texto antes de buscar nada. La ironía, una forma nueva de decirlo o una amenaza velada son cosa del modelo, que entra con effort high.

  • El contenido, no la persona

    Juzga el contenido, no a la persona. El historial de una cuenta puede mover un poco el umbral si una política lo pide, y nunca bloquea por sí solo.

  • La última palabra es de una persona

    Tu web publica, retiene o quita el comentario a partir de la respuesta, y lo retenido espera en la cola de revisión a que decida alguien de tu equipo.

Preguntas frecuentes

¿Qué devuelve una API de moderación de comentarios?

ToxicFilter devuelve una decisión (allow, review o block), la puntuación más alta de cada categoría, las categorías que han cruzado un umbral y una lista de señales. Cada señal indica la categoría, el detector, el motivo en palabras y el fragmento de texto que la ha provocado, así que puedes explicárselo al autor y depurar una respuesta equivocada.

¿Por qué quince categorías y no una nota de toxicidad?

Porque un único número mete en tu web la política de otro. Una palabrota en un elogio, un insulto dirigido a alguien y un enlace a un casino son tres cosas distintas, y un foro de videojuegos y una web infantil quieren tratarlas de forma diferente. Cada categoría tiene sus propios umbrales y tú mueves los que te importan.

¿Cuánto tarda?

Para un comentario corto, las comprobaciones gratuitas tardan una fracción de milisegundo, y la petición entera, tal como la mide took_ms, ronda el milisegundo. Un texto de varios miles de caracteres tarda unos pocos. Cuando el modelo tiene que leerlo, esa llamada tarda lo que tarde el modelo.

¿Detecta insultos escritos con símbolos o números?

Sí, dentro de las palabras que conoce. Antes de buscar, el texto se normaliza: letras de otros alfabetos que se parecen a las nuestras, números en lugar de letras, caracteres invisibles, asteriscos en mitad de la palabra, tildes y letras repetidas. Se hace palabra a palabra, así que una frase rusa o griega de verdad no se toma por un disfraz.

¿Puedo poner mis propias reglas?

Sí, de dos maneras. Una política guardada en tu cuenta, con versiones, tus propios umbrales y tus listas de palabras, que puedes probar antes en modo sombra. O reglas en la propia llamada, que solo actúan sobre lo que mencionan. Se pueden combinar, y la respuesta indica cuándo una llamada ha sobrescrito la política.

¿Qué idiomas cubre?

Las listas de palabras y los patrones de frases instantáneos cubren inglés, español, portugués, francés, italiano, alemán, catalán y neerlandés. El modelo lee muchos más. Tus propias listas de palabras funcionan en cualquier idioma.

Pruébalo con tu tráfico real

2.000 créditos al mes en el plan gratuito, sin tarjeta. Suficiente para pasarle una semana de tu propio contenido y ver qué opina de él.