ES ▾
https://api.unrestrictedaiapi.com/v1uncensored2026-10-06
Obtener clave de API

Construye un bot de Discord o Telegram en una API de IA sin restricciones

Un chat bot es la forma más rápida de poner un modelo sin restricciones frente al público. Esta guía construye un bot con discord.py y un bot con python-telegram-bot sobre un módulo compartido que maneja la llamada a la API, de modo que el historial por canal, el límite de peticiones, los reintentos y la verificación de edad se escriben una vez y se reutilizan.

Actualizado

Puntos clave

  1. Aísla la lógica de la API en un módulo y mantén cada adaptador de plataforma pequeño.
  2. Mantén un historial acotado separado por canal o chat para que las conversaciones nunca se mezclen.
  3. Controla la velocidad en tres capas: enfriamiento por usuario, una ventana deslizante global inferior a 300 peticiones por minuto y un límite de concurrencia.
  4. Controla el uso adulto: solo canales Discord marcados como NSFW y confirmación explícita /adult en Telegram.

Lo que estamos construyendo

Dos bots pequeños, un cerebro compartido. Un archivo llamado llm.py posee todo lo que toca la API: la personalidad, el limitador de velocidad, la lógica de reintentos. Un bot de Discord y un bot de Telegram luego solo traducen eventos de la plataforma en una lista de mensajes y viceversa. Añade una tercera plataforma más tarde y solo escribirás el adaptador.

Instala las dependencias con pip install httpx discord.py python-telegram-bot. Exporta API_KEY desde tu página de cuenta, además de DISCORD_TOKEN y/o TELEGRAM_TOKEN desde la configuración de bot de cada plataforma. Ambos bots asumen Python 3.10 o superior.

El formato de la petición es la forma estándar de chat-completions de OpenAI, descrita en la guía rápida multilingüe. Aquí no necesitas un SDK.

El núcleo compartido: personalidad, limitador y reintentos

Pon la parte peligrosa en un solo lugar. El módulo a continuación mantiene una ventana deslizante de marcas de tiempo de peticiones y espera cuando se acerca a 240 llamadas por minuto, un margen deliberado bajo los 300 por minuto permitidos por clave. Un semáforo limita la concurrencia a cuatro para que un canal ocupado no dispare veinte peticiones a la vez.

# llm.py - shared by both bots
import asyncio
import os
import time
from collections import deque

import httpx

URL = "https://api.unrestrictedaiapi.com/v1/chat/completions"
PERSONA = "You are Pip, a sardonic bar-room storyteller. Keep replies under 150 words."

_stamps = deque()            # timestamps of recent calls
_gate = asyncio.Semaphore(4) # at most 4 requests in flight
_client = httpx.AsyncClient(timeout=60.0)

async def _wait_for_slot(limit=240, window=60.0):
    # Stay below the 300 requests/minute per-key limit with headroom.
    while True:
        now = time.monotonic()
        while _stamps and now - _stamps[0] > window:
            _stamps.popleft()
        if len(_stamps) < limit:
            _stamps.append(now)
            return
        await asyncio.sleep(window - (now - _stamps[0]) + 0.05)

async def chat(history):
    """history: list of {"role","content"} dicts, oldest first."""
    messages = [{"role": "system", "content": PERSONA}] + list(history)
    async with _gate:
        for attempt in range(3):
            await _wait_for_slot()
            r = await _client.post(
                URL,
                headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
                json={"model": "uncensored", "messages": messages, "max_tokens": 400},
            )
            if r.status_code in (429, 503):
                await asyncio.sleep(2 ** attempt)
                continue
            if r.status_code == 403:
                return "I can't continue with that."
            r.raise_for_status()
            return r.json()["choices"][0]["message"]["content"]
    return "The service is busy. Try again in a moment."

Revisa el manejo de estados. Un 429 o 503 espera 1, 2 y luego 4 segundos e intenta de nuevo. Un 403 significa que el filtro de contenido se activó, así que el bot responde con una línea neutral en lugar de reintentar. Cualquier otro error lanza una excepción, que la biblioteca de tu plataforma registrará. Si ves un 402, tu saldo está vacío o la prueba terminó; recarga el saldo prepago.

El adaptador de Discord

Los bots de Discord necesitan que la intención de contenido de mensaje esté activada en el portal de desarrolladores y también en el código, o msg.content llega vacío. El bot solo responde cuando se le menciona, lo que evita que lea cada mensaje en un servidor ocupado.

# discord_bot.py
import os
import time
from collections import defaultdict, deque

import discord

from llm import chat

intents = discord.Intents.default()
intents.message_content = True      # also enable it in the developer portal
bot = discord.Client(intents=intents)

HISTORY_TURNS = 10                   # user+assistant messages kept per channel
history = defaultdict(lambda: deque(maxlen=HISTORY_TURNS))
last_use = {}                        # user id -> last request time
COOLDOWN = 5.0                       # seconds between requests per user

def chunks(text, size=1900):
    return [text[i:i + size] for i in range(0, len(text), size)] or [""]

@bot.event
async def on_message(msg: discord.Message):
    if msg.author.bot or bot.user not in msg.mentions:
        return
    # Age gate: guild text channels must be flagged NSFW. No DMs.
    if not isinstance(msg.channel, discord.TextChannel) or not msg.channel.is_nsfw():
        await msg.reply("I only chat in channels marked age-restricted (NSFW).")
        return
    now = time.monotonic()
    if now - last_use.get(msg.author.id, 0) < COOLDOWN:
        await msg.add_reaction("\u23f3")
        return
    last_use[msg.author.id] = now

    text = msg.clean_content.replace(f"@{bot.user.display_name}", "").strip()
    if not text:
        return
    h = history[msg.channel.id]
    h.append({"role": "user", "content": f"{msg.author.display_name}: {text}"})
    async with msg.channel.typing():
        answer = await chat(h)
    h.append({"role": "assistant", "content": answer})
    for part in chunks(answer):
        await msg.channel.send(part)

bot.run(os.environ["DISCORD_TOKEN"])

El historial es un deque con maxlen=10 indexado por id de canal, así que cada canal es su propia conversación y los turnos antiguos caen automáticamente. Anteceder cada línea del usuario con el nombre de visualización del hablante permite al modelo distinguir a las personas en una sala compartida. Diez mensajes es un valor conservador; la ventana de contexto es de 100.000 tokens, así que puedes aumentarlo mucho antes de que importe.

El adaptador de Telegram

python-telegram-bot v20 y versiones posteriores es asíncrono, lo que se integra naturalmente con el núcleo compartido. chat_data es un diccionario por chat que la biblioteca mantiene por ti, así que el historial y el periodo de enfriamiento no necesitan código de almacenamiento adicional.

# telegram_bot.py  (python-telegram-bot v20+)
import os
import time
from collections import deque

from telegram import Update
from telegram.ext import (ApplicationBuilder, CommandHandler, ContextTypes,
                          MessageHandler, filters)

from llm import chat

async def adult(update: Update, context: ContextTypes.DEFAULT_TYPE):
    context.chat_data["adult"] = True
    await update.message.reply_text("Noted. Say something.")

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(
        "This bot produces adult fiction. Send /adult only if you are 18 or older."
    )

async def talk(update: Update, context: ContextTypes.DEFAULT_TYPE):
    cd = context.chat_data
    if not cd.get("adult"):
        await update.message.reply_text("Send /adult to confirm you are 18+.")
        return
    if time.monotonic() - cd.get("last", 0) < 4:
        return                                   # per-chat cooldown
    cd["last"] = time.monotonic()

    h = cd.setdefault("history", deque(maxlen=10))
    h.append({"role": "user", "content": update.message.text})
    await context.bot.send_chat_action(update.effective_chat.id, "typing")
    answer = await chat(h)
    h.append({"role": "assistant", "content": answer})
    for i in range(0, len(answer), 4000):        # Telegram limit is 4096 chars
        await update.message.reply_text(answer[i:i + 4000])

app = ApplicationBuilder().token(os.environ["TELEGRAM_TOKEN"]).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(CommandHandler("adult", adult))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, talk))
app.run_polling()

run_polling() es la forma más sencilla de iniciar y no necesita una URL pública. Ten en cuenta que chat_data vive en memoria, así que un reinicio lo borra. Si necesitas que el historial sobreviva a reinicios, guarda el contenido del deque tú mismo en un archivo o base de datos.

Control de edad y la regla del canal NSFW

Esta API es solo para adultos, y cualquier cosa que construyas sobre ella hereda esa responsabilidad. Trata el control de edad como una función, no como un pensamiento secundario.

  • Discord: responde solo en canales de la comunidad marcados como +18. La comprobación channel.is_nsfw() no tiene coste y el bot rechaza en otros lugares, incluidos los mensajes directos.
  • Telegram: requiere una confirmación explícita /adult por chat antes de cualquier generación, y establece la regla en el texto de bienvenida.
  • Ambos: no ofrezcas el bot en espacios dirigidos a jóvenes, y elimina el acceso rápidamente si te enteras de que un usuario tiene menos de 18 años.

Un comando de confirmación es un filtro, no una prueba de edad. El contenido sexual que involucra a menores siempre es bloqueado por la API con un 403, incluyendo ficción y roleplay, y tu bot nunca debería intentar burlar esa respuesta.

Ejecutarlo y probarlo sin multitud

Inicia cada bot en su propia terminal con python discord_bot.py o python telegram_bot.py. Para la primera ejecución, crea un servidor de prueba privado o un chat solo contigo. Recorre una lista de verificación corta y capturarás casi todos los errores de principiante.

  1. Menciona al bot en un canal no NSFW y confirma que se niega. Esto prueba que el control funciona.
  2. Menciónalo en un canal marcado y envía dos mensajes rápidamente. El segundo debería obtener la reacción de reloj de arena, lo que prueba que el enfriamiento funciona.
  3. Mantén una conversación de cuatro mensajes, luego refiérete al primer mensaje. Si el bot recuerda, el historial está conectado correctamente.
  4. Establece temporalmente la clave de API a un valor incorrecto y confirma que el error aparece en tus registros en lugar de desaparecer silenciosamente.
  5. Pega un bloque largo de texto y observa cómo la respuesta se divide en varios mensajes bajo el límite de longitud de la plataforma.

Si las respuestas parecen genéricas, el problema suele ser la persona en lugar del código. Cambia una frase de PERSONA, reinicia y compara. Como la persona vive en el módulo compartido, un cambio afecta a ambos bots a la vez, lo cual es precisamente por lo que la estructura vale la pena a pesar del archivo adicional.

Cuando estés listo para desplegar, cualquier administrador de procesos siempre activo servirá. Los bots mantienen una conexión de larga duración con su plataforma y hacen llamadas HTTPS salientes cortas a la API, así que no necesitan puertos entrantes y casi ninguna memoria. Añade una política de reinicio para que un fallo no deje a tu comunidad hablando con un bot silencioso.

Límites de peticiones, tamaño del historial y coste

Tres perillas controlan cómo se comporta el bot bajo carga. El enfriamiento por usuario evita que una persona monopolice la clave. La ventana global protege el techo de 300 peticiones por minuto. El semáforo suaviza los picos. Si ejecutas varios procesos de bot en una clave, comparten ese techo, así que reduce el limit de cada proceso en consecuencia.

Estima el gasto antes de invitar a mucha gente. Suposiciones: cada llamada envía aproximadamente 1200 tokens de entrada (persona más diez turnos) y devuelve 250 tokens. Una llamada cuesta 1200 x $0,25 / 1.000.000 + 250 x $1,00 / 1.000.000 = $0,0003 + $0,00025 = $0,00055. Un servidor que produzca 2000 respuestas al día gastaría aproximadamente $1,10 al día bajo esas suposiciones. Tus números serán diferentes, así que registra el campo usage durante una semana y recalcula.

Para ajustar la personalidad en sí, lee la guía de prompts. Los precios se listan en la página de precios.

Endurecimiento antes de compartir el bot

Mantén los tokens fuera del control de código fuente; léelos desde el entorno como se muestra. Limita la longitud del mensaje antes de enviarlo a la API para que un pegado enorme no queme tu saldo. Registra errores pero no el texto del mensaje, ya que tus usuarios esperarían razonablemente que sus chats se mantengan privados. Añade un comando /reset que borra el deque de un canal, que es la solución más rápida cuando una conversación se desvía. Finalmente, pon una nota visible en el perfil del bot diciendo que escribe ficción para adultos y que sus respuestas son generadas.

Una elección de diseño más merece una frase: los bots esperan la respuesta completa en lugar de hacer streaming. Editar un mensaje de chat token por token choca directamente con los límites de edición de la plataforma, y para respuestas limitadas a unas 150 palabras la espera es corta. Si más tarde quieres escritura en vivo en tu propia interfaz web, activa stream: true allí, donde controlas el transporte. Hasta entonces, el indicador de escritura que ya envías es la forma más barata de mostrar que el bot está funcionando, y mantiene el código lo suficientemente corto como para leerlo en una sola sesión y auditarlo antes de invitar a alguien.

Preguntas y respuestas

¿Puede una clave de API servir para varios bots?

Sí, pero comparten el límite de 300 peticiones por minuto para esa clave, así que distribuye tu control de tráfico interno entre los procesos.

¿El bot recuerda las conversaciones después de un reinicio?

No en estos ejemplos; el historial se mantiene en memoria. Guarda el contenido del deque en un archivo o base de datos si necesitas continuidad.

¿Cómo mantengo a los menores fuera?

Restringe las respuestas de Discord a canales restringidos por edad, requiere un comando de confirmación en Telegram y evita espacios orientados a la juventud. Estas son barreras, no pruebas, así que actúa rápidamente ante cualquier reporte.

¿Qué sucede cuando se agota el saldo?

La API devuelve 402 con el código no_credit. Captúralo en el módulo principal y avisa a tus usuarios de que el bot está en pausa.

Tu clave está a un formulario de distancia

Crea una cuenta, copia la clave, cambia la base URL. Eso es toda la configuración.

Obtener clave de API