FR ▾
https://api.unrestrictedaiapi.com/v1uncensored2026-10-06
Obtenir une clé API

Créez un bot Discord ou Telegram sur une API IA sans restrictions

Un chat bot est le moyen le plus rapide de placer un modèle sans censure devant les utilisateurs. Ce guide construit à la fois un bot discord.py et un bot python-telegram-bot sur un module partagé qui gère l'appel API, afin que l'historique par canal, la limitation de débit, les tentatives et un contrôle d'âge soient écrits une fois et réutilisés.

Mis à jour

Points clés

  1. Isolez la logique API dans un module et gardez chaque adaptateur de plateforme minimal.
  2. Conservez un historique borné séparé par canal ou chat pour que les conversations ne se mélangent jamais.
  3. Throttlez en trois couches : délai d'attente par utilisateur, une fenêtre glissante globale sous 300 requêtes par minute et un cap de concurrence.
  4. Porte pour les adultes : uniquement les canaux Discord marqués NSFW et confirmation explicite /adult sur Telegram.

Ce que nous construisons

Deux petits bots, un cerveau partagé. Un fichier nommé llm.py possède tout ce qui touche à l'API : la persona, le limiteur de débit, la logique de retry. Un bot Discord et un bot Telegram ne font ensuite que traduire les événements de la plateforme en une liste de messages et vice versa. Ajoutez une troisième plateforme plus tard et vous n'écrivez que l'adaptateur.

Installez les dépendances avec pip install httpx discord.py python-telegram-bot. Exportez API_KEY depuis votre page de compte, ainsi que DISCORD_TOKEN et/ou TELEGRAM_TOKEN depuis la configuration bot de chaque plateforme. Les deux bots ci-dessous supposent Python 3.10 ou supérieur.

Le format de la requête est la forme standard de chat-completions OpenAI, couverte dans le guide de démarrage rapide multi-langues. Rien ici ne nécessite un SDK.

Le noyau partagé : persona, limiteur et tentatives

Placez la partie délicate à un seul endroit. Le module ci-dessous conserve une fenêtre glissante des horodatages de requête et attend lorsqu'il s'approche de 240 appels par minute, une marge délibérée sous les 300 par minute autorisés par clé. Un sémaphore limite la concurrence à quatre afin qu'un canal occupé ne puisse pas déclencher vingt requêtes à la fois.

# 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."

Examinez la gestion des statuts. Un 429 ou 503 fait une pause de 1, 2 puis 4 secondes et réessaie. Un 403 signifie que le filtre de contenu a été déclenché, donc le bot répond avec une ligne neutre au lieu de réessayer. Toute autre erreur lève une exception, ce que votre bibliothèque de plateforme enregistrera. Si vous voyez un 402, votre solde est vide ou l'essai est terminé ; rechargez le crédit prépayé.

L'adaptateur Discord

Les bots Discord nécessitent l'activation de l'intent message-content dans le portail développeur ainsi que dans le code, sinon msg.content arrive vide. Le bot ne répond que lorsqu'il est mentionné, ce qui l'empêche de lire chaque message dans un serveur occupé.

# 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"])

L'historique est un deque avec maxlen=10 indexé par l'identifiant du canal, de sorte que chaque canal constitue sa propre conversation et les anciens messages sont automatiquement supprimés. Préfixer chaque ligne de l'utilisateur avec le nom d'affichage de l'orateur permet au modèle de distinguer les personnes dans une salle partagée. Dix messages constituent une valeur par défaut prudente ; la fenêtre de contexte est de 100 000 tokens, vous pouvez donc l'augmenter considérablement avant que cela n'ait une incidence.

L'adaptateur Telegram

python-telegram-bot v20 et versions ultérieures est asynchrone, ce qui s'associe naturellement au noyau partagé. chat_data est un dictionnaire par chat que la bibliothèque conserve pour vous, donc l'historique et l'état de délai d'attente n'ont pas besoin de code de stockage supplémentaire.

# 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() est le moyen le plus simple pour démarrer et ne nécessite pas d'URL publique. Gardez à l'esprit que chat_data réside en mémoire, donc un redémarrage l'efface. Si vous avez besoin que l'historique survive aux redémarrages, stockez vous-même le contenu du deque dans un fichier ou une base de données.

Contrôle d'âge et règle du canal NSFW

Cette API est réservée aux adultes, et tout ce que vous construisez dessus hérite de cette responsabilité. Traitez le contrôle d'âge comme une fonctionnalité, pas une après-pensée.

  • Discord : répondez uniquement dans les canaux de guilde marqués comme restreints aux adultes. La vérification channel.is_nsfw() ne coûte rien et le bot refuse ailleurs, y compris dans les messages directs.
  • Telegram : exigez une confirmation explicite /adult par chat avant toute génération, et indiquez la règle dans le texte de bienvenue.
  • Les deux : ne proposez pas le bot dans des espaces destinés aux jeunes, et retirez l'accès rapidement si vous apprenez qu'un utilisateur a moins de 18 ans.

Une commande de confirmation est une porte, pas une preuve d'âge. Le contenu sexuel impliquant des mineurs est toujours bloqué par l'API avec un 403, y compris la fiction et le jeu de rôle, et votre bot ne devrait jamais essayer de contourner cette réponse.

L'exécuter et tester sans foule

Démarrez chaque bot dans son propre terminal avec python discord_bot.py ou python telegram_bot.py. Pour la première exécution, créez un serveur de test privé ou un chat avec vous seul. Parcourez une courte liste de contrôle et vous capturerez presque tous les bugs de débutant.

  1. Mentionnez le bot dans un canal non-NSFW et confirmez qu'il refuse. Cela prouve que la porte fonctionne.
  2. Mentionnez-le dans un canal marqué et envoyez deux messages rapidement. Le second devrait obtenir la réaction sablier, ce qui prouve que le délai d'attente fonctionne.
  3. Tenez une conversation de quatre messages, puis faites référence au premier message. Si le bot se souvient, l'historique est correctement câblé.
  4. Définissez temporairement la clé API sur une valeur incorrecte et confirmez que l'échec apparaît dans vos logs plutôt que de disparaître silencieusement.
  5. Collez un long bloc de texte et regardez la réponse se diviser en plusieurs messages sous la limite de longueur de la plateforme.

Si les réponses semblent génériques, le problème vient généralement de la persona plutôt que du code. Modifiez une phrase de PERSONA, redémarrez et comparez. Parce que la persona vit dans le module partagé, une modification change les deux bots à la fois, ce qui est exactement pourquoi la structure vaut le fichier supplémentaire.

Lorsque vous êtes prêt à déployer, n'importe quel gestionnaire de processus toujours actif fera l'affaire. Les bots maintiennent une connexion à longue durée de vie avec leur plateforme et effectuent des appels HTTPS sortants courts vers l'API, donc ils n'ont besoin d'aucun port entrant et presque aucune mémoire. Ajoutez une politique de redémarrage pour qu'un crash ne laisse pas votre communauté parler à un bot silencieux.

Limites de débit, taille de l'historique et coût

Trois boutons de réglage contrôlent le comportement du bot sous charge. Le délai d'attente par utilisateur empêche une personne de monopoliser la clé. La fenêtre globale protège le plafond de 300 requêtes par minute. Le sémaphore lisse les pics. Si vous exécutez plusieurs processus de bot sur une clé, ils partagent ce plafond, donc réduisez le limit de chaque processus en conséquence.

Estimez les dépenses avant d'inviter une foule. Hypothèses : chaque appel envoie environ 1 200 tokens d'entrée (persona plus dix tours) et retourne 250 tokens. Un appel coûte 1 200 x $0,25 / 1 000 000 + 250 x $1,00 / 1 000 000 = $0,0003 + $0,00025 = $0,00055. Un serveur produisant 2 000 réponses par jour dépenserait environ 1,10 $ par jour selon ces hypothèses. Vos chiffres différeront, donc enregistrez le champ usage pendant une semaine et recalculer.

Pour ajuster la persona elle-même, lisez le guide de prompting. Les prix sont listés sur la page des tarifs.

Durcir avant de partager le bot

Gardez les tokens hors du contrôle de source ; lisez-les depuis l'environnement comme indiqué. Limitez la longueur des messages avant de les envoyer à l'API pour qu'un collage énorme ne puisse pas brûler votre solde. Enregistrez les erreurs mais pas le texte des messages, car vos utilisateurs s'attendent raisonnablement à ce que leurs chats restent privés. Ajoutez une commande /reset qui efface le deque d'un canal, ce qui est la solution la plus rapide lorsqu'une conversation dérape. Enfin, mettez une note visible dans le profil du bot disant qu'il écrit de la fiction pour adultes et que ses réponses sont générées.

Un autre choix de conception mérite une phrase : les bots attendent la réponse complète au lieu de la diffuser. Modifier un message de chat token par token se heurte directement aux limites d'édition de la plateforme, et pour les réponses limitées à environ 150 mots, l'attente est courte. Si vous voulez plus tard une frappe en direct dans votre propre interface web, activez stream: true là où vous contrôlez le transport. Jusqu'alors, l'indicateur de frappe que vous envoyez déjà est le moyen le moins cher de montrer que le bot fonctionne, et cela garde le code assez court pour être lu en une seule séance et audité avant d'inviter qui que ce soit.

Questions et réponses

Une clé API peut-elle servir plusieurs bots ?

Oui, mais ils partagent la limite de 300 requêtes par minute pour cette clé, donc répartissez votre throttling interne entre les processus.

Le bot se souvient-il des conversations après un redémarrage ?

Non dans ces exemples ; l'historique est conservé en mémoire. Persistez le contenu du deque dans un fichier ou une base de données si vous avez besoin de continuité.

Comment empêcher l'accès aux mineurs ?

Restreignez les réponses Discord aux channels restreints aux adultes, exigez une commande de confirmation Telegram et évitez les espaces à vocation jeunesse. Il s'agit de filtres, pas de preuves, donc réagissez rapidement à tout signalement.

Que se passe-t-il lorsque le solde est épuisé ?

L'API renvoie 402 avec le code no_credit. Interceptez-le dans le module core et informez vos utilisateurs que le bot est en pause.

Votre clé est à un formulaire de vous

Créez un compte, copiez la clé, modifiez l'URL de base. C'est toute la configuration.

Obtenir une clé API