PT ▾
https://api.unrestrictedaiapi.com/v1uncensored2026-10-06
Obter chave de API

Crie um bot do Discord ou Telegram em uma API de IA sem restrições

Um chat bot é a maneira mais rápida de colocar um modelo sem censura à disposição das pessoas. Este tutorial cria um bot do discord.py e um bot do python-telegram-bot em um único módulo compartilhado que trata a chamada à API, assim o histórico por canal, limite de requisições, novas tentativas e verificação de idade são escritos uma vez e reutilizados.

Atualizado

Pontos principais

  1. Isole a lógica da API em um módulo e mantenha cada adaptador de plataforma pequeno.
  2. Mantenha um histórico separado e limitado por canal ou chat para que as conversas nunca se misturem.
  3. Controle o fluxo em três camadas: atraso por usuário, uma janela deslizante global abaixo de 300 requisições por minuto e um limite de concorrência.
  4. Restrição de uso adulto: apenas canais Discord marcados como NSFW e confirmação explícita /adult no Telegram.

O que estamos construindo

Dois bots pequenos, um cérebro compartilhado. Um arquivo chamado llm.py cuida de tudo que toca a API: a persona, o limitador de requisições, a lógica de novas tentativas. Um bot do Discord e um bot do Telegram então não fazem nada além de traduzir eventos da plataforma em uma lista de mensagens e vice-versa. Adicione uma terceira plataforma mais tarde e você só escreve o adaptador.

Instale as dependências com pip install httpx discord.py python-telegram-bot. Exporte API_KEY da sua página de conta, além de DISCORD_TOKEN e/ou TELEGRAM_TOKEN da configuração de bot de cada plataforma. Ambos os bots abaixo assumem Python 3.10 ou superior.

O formato da requisição é o formato simples de chat-completions da OpenAI, coberto em o guia rápido multi-idioma. Nada aqui precisa de um SDK.

O núcleo compartilhado: persona, limitador e tentativas

Coloque a parte perigosa em um único lugar. O módulo abaixo mantém uma janela deslizante de carimbos de data/hora das requisições e aguarda quando se aproxima de 240 chamadas por minuto, uma margem deliberada abaixo dos 300 por minuto permitidos por chave. Um semáforo limita a concorrência a quatro para que um canal ocupado não dispare vinte requisições de uma 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."

Observe o tratamento de status. Um 429 ou 503 aguarda por 1, 2 e depois 4 segundos e tenta novamente. Um 403 significa que o filtro de conteúdo foi acionado, então o bot responde com uma linha neutra em vez de tentar novamente. Qualquer outro erro levanta uma exceção, que sua biblioteca de plataforma registrará. Se você ver um 402, seu saldo está vazio ou o teste acabou; recarregue o crédito pré-pago.

O adaptador Discord

Bots do Discord precisam que a intenção de conteúdo de mensagem seja ativada no portal do desenvolvedor e também no código, ou msg.content chega vazio. O bot responde apenas quando mencionado, o que evita que ele leia todas as mensagens em um 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"])

O histórico é um deque com maxlen=10 indexado por id do canal, então cada canal é sua própria conversa e as mensagens antigas saem automaticamente. Prefixar cada linha do usuário com o nome de exibição do locutor permite que o modelo distinga as pessoas em uma sala compartilhada. Dez mensagens são um padrão conservador; a janela de contexto tem 100.000 tokens, então você pode aumentar isso muito antes que faça diferença.

O adaptador Telegram

python-telegram-bot v20 e posteriores é assíncrono, o que combina naturalmente com o núcleo compartilhado. chat_data é um dicionário por conversa que a biblioteca mantém para você, então histórico e estado de resfriamento não precisam de código de armazenamento extra.

# 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() é a maneira mais simples de iniciar e não precisa de URL público. Lembre-se de que chat_data vive na memória, então uma reinicialização o limpa. Se precisar que o histórico sobreviva a reinicializações, armazene os conteúdos do deque você mesmo em um arquivo ou banco de dados.

Restrição de idade e regra do canal NSFW

Esta API é apenas para adultos, e qualquer coisa que você construir nela herda essa responsabilidade. Trate a restrição de idade como um recurso, não como um pensamento tardio.

  • Discord: responda apenas em canais de guilda marcados como restritos por idade. A verificação channel.is_nsfw() não custa nada e o bot se recusa em outros lugares, incluindo mensagens diretas.
  • Telegram: exija uma confirmação explícita /adult por chat antes de qualquer geração e indique a regra no texto de boas-vindas.
  • Ambos: não ofereça o bot em espaços voltados para jovens e remova o acesso prontamente se souber que um usuário tem menos de 18 anos.

Um comando de confirmação é uma porta, não prova de idade. Conteúdo sexual envolvendo menores é sempre bloqueado pela API com um 403, incluindo ficção e roleplay, e seu bot nunca deve tentar contornar essa resposta.

Executando e testando sem multidão

Inicie cada bot em seu próprio terminal com python discord_bot.py ou python telegram_bot.py. Para a primeira execução, crie um servidor de teste privado ou um chat apenas com você. Percorra uma lista de verificação curta e você pegará quase todos os bugs de iniciante.

  1. Mencione o bot em um canal não NSFW e confirme que ele se recusa. Isso prova que a barreira funciona.
  2. Mencione-o em um canal sinalizado e envie duas mensagens rapidamente. A segunda deve gerar a reação de ampulheta, o que prova que o atraso funciona.
  3. Mantenha uma conversa de quatro mensagens e, em seguida, refira-se à primeira mensagem. Se o bot lembrar, o histórico está conectado corretamente.
  4. Defina temporariamente a chave de API para um valor errado e confirme que a falha aparece nos seus logs em vez de desaparecer silenciosamente.
  5. Cole um bloco longo de texto e veja a resposta dividida em várias mensagens dentro do limite de comprimento da plataforma.

Se as respostas parecerem genéricas, a persona geralmente é o problema, não o código. Altere uma frase de PERSONA, reinicie e compare. Como a persona vive no módulo compartilhado, uma edição altera ambos os bots de uma vez, o que é exatamente o motivo pelo qual a estrutura vale o arquivo extra.

Quando estiver pronto para implantar, qualquer gerenciador de processos sempre ativo serve. Os bots mantêm uma conexão de longa duração com sua plataforma e fazem chamadas HTTPS de saída curtas para a API, então não precisam de portas de entrada e quase nenhuma memória. Adicione uma política de reinicialização para que uma falha não deixe sua comunidade conversando com um bot silencioso.

Limites de requisições, tamanho do histórico e custo

Três controles ajustam como o bot se comporta sob carga. O tempo de espera por usuário impede que uma pessoa monopolize a chave. A janela global protege o teto de 300 requisições por minuto. O semáforo suaviza picos. Se você executar vários processos de bot em uma chave, eles compartilham esse teto, então reduza o limit de cada processo de acordo.

Estime o gasto antes de convidar uma multidão. Suposições: cada chamada envia cerca de 1.200 tokens de entrada (persona mais dez voltas) e retorna 250 tokens. Uma chamada custa 1.200 x $0,25 / 1.000.000 + 250 x $1,00 / 1.000.000 = $0,0003 + $0,00025 = $0,00055. Um servidor produzindo 2.000 respostas por dia gastaria cerca de $1,10 por dia sob essas suposições. Seus números serão diferentes, então registre o campo usage por uma semana e recalcule.

Para ajustar a própria persona, leia o guia de prompts. Os preços estão listados na página de preços.

Endurecimento antes de compartilhar o bot

Mantenha os tokens fora do controle de versão; leia-os do ambiente conforme mostrado. Limite o comprimento da mensagem antes de enviá-la à API para que uma colagem enorme não consuma seu saldo. Registre erros, mas não o texto das mensagens, já que seus usuários razoavelmente esperam que seus chats permaneçam privados. Adicione um comando /reset que limpa o deque de um canal, que é o ajuste mais rápido quando uma conversa sai do trilho. Finalmente, coloque uma nota visível no perfil do bot dizendo que ele escreve ficção adulta e que suas respostas são geradas.

Mais uma escolha de design merece uma frase: os bots aguardam a resposta completa em vez de fazer streaming dela. Editar uma mensagem de chat token por token esbarra diretamente nos limites de edição da plataforma e, para respostas limitadas a cerca de 150 palavras, a espera é curta. Se você quiser digitação ao vivo mais tarde em sua própria interface web, ative stream: true lá, onde você controla o transporte. Até lá, o indicador de digitação que você já envia é a maneira mais barata de mostrar que o bot está funcionando e mantém o código curto o suficiente para ser lido de uma vez e auditado antes de convidar alguém.

Perguntas e respostas

Uma chave de API pode servir vários bots?

Sim, mas eles compartilham o limite de 300 requisições por minuto para essa chave, então divida o controle de fluxo interno entre os processos.

O bot lembra das conversas após uma reinicialização?

Não nestes exemplos; o histórico é mantido na memória. Persista o conteúdo do deque em um arquivo ou banco de dados se precisar de continuidade.

Como manter menores fora?

Restrinja as respostas do Discord a canais restritos por idade, exija um comando de confirmação no Telegram e evite espaços voltados para jovens. Essas são barreiras, não provas, então aja rapidamente a qualquer relatório.

O que acontece quando o saldo acaba?

A API retorna 402 com o código no_credit. Capture isso no módulo principal e informe aos seus usuários que o bot está pausado.

Sua chave está a um formulário de distância

Crie uma conta, copie a chave, altere a base URL. Essa é toda a configuração.

Obter chave de API