Retour aux projets
Archived

HalfwayBot

Bot Discord permettant de partager un abonnement Midjourney entre plusieurs utilisateurs.

décembre 2022
JavaScriptDiscord.js v14Node.jsREST API

Contexte

En 2022, Midjourney vient de sortir, c'est la révolution de la génération d'images par IA. Comme beaucoup, je me suis amusé à le tester et à rapidement payer un abonnement pour generer encore plus d'images. Mes amies sont tout aussi curieux que moi, d'autre veulle absolument tester eux même, mais on ateint rapidement le quotas de génération d'image sans abonnement.

Me viens donc une idée : Comment faire pour partager mon abonnement MidJourney afin que mon entourage puisse en bénéficier autant que moi ? Sachant qu'avec mon abonnement, je ne l'utilisais pas tout les jours...

Le problème

A cette époque, il n'y a pas d'API, pas d'interface web - rien. Juste un bot Discord propriétaire proposé par Midjourney qu'on peut inviter dans son serveur. Ce bot nécessitait d'avoir un compte Discord avec abonnement Midjourney actif.

Donc pour partager l'accès, il fallait partager les identifiants Discord.

Et même si les ToS n'autorisait pas ce cas d'usage, je voulais quand même permettre à mes amis de découvrir la génération d'images IA sans compromis sur la sécurité de mon compte discord. Oh le petit filou

La solution

J'ai créé HalfwayBot, un bot proxy qui relaie les commandes vers le vrai bot Midjourney avec mon compte, puis renvoie les résultats aux utilisateurs.

Objectif : reproduire l'expérience Midjourney sans exposer les identifiants du compte principal.

Utilisateur -> HalfwayBot -> Bot Midjourney officiel -> HalfwayBot -> Utilisateur

Fonctionnalités principales

  • 🧠 Reprise des mêmes usages que le bot Midjourney officiel
  • 👥 Utilisation partagée d'un seul abonnement, de manière encadrée
  • ✅ Contrôle d'accès par rôles Discord
  • 🔒 Accès sécurisé
  • 🗑️ Gestions des erreurs et requêtes non autorisées

Concrètement, l'objectif était de copier l'expérience utilisateur Midjourney :

  • /imagine pour lancer une génération
  • boutons de variations (V1, V2, V3, V4)
  • boutons d'upscale (U1, U2, U3, U4)
  • redo / reroll pour relancer une proposition
  • autres paramètres et comportements identique au bot officiel

Interface HalfwayBot - interactionInterface HalfwayBot - interaction Interface HalfwayBot - générationInterface HalfwayBot - génération

Pourquoi ne pas faire un site web ?

Plusieurs raisons pragmatiques ont motivé ce choix :

1. Sécurité avant tout
Un bot Discord reste dans un serveur privé. Aucun port HTTP public ouvert, seulement des connexions sortantes (WebSocket) vers Discord. Un site web aurait nécessité :

  • une authentification à sécuriser
  • des ports HTTP/HTTPS publiquement accessibles
  • une surface d'attaque bien plus large (formulaires, API endpoints, injections, DDoS...)
  • des risques d'intrusion ou d'abus

2. Infrastructure gratuite
Discord fournit gratuitement :

  • une interface utilisateur
  • l'authentification (OAuth2)
  • le système de permissions (rôles)
  • la messagerie temps réel
  • les notifications

3. Zéro friction utilisateur
Mes amis utilisaient déjà Discord. Pas besoin de leur faire créer un compte sur un site externe, tout se passe là où ils sont déjà.

4. Rapidité de développement
Un site web complet avec auth, UI, real-time, notifications, aurait été plus long à mettre en place.

Limitations

La limite principale venait de l'abonnement qui bloque 3 jobs simultanés maximum.

En pratique, tout le monde ne l'utilisait pas au même moment, donc ça passait très bien la plupart du temps. Mais c'est vrai que dès que 2 ou 3 utilisateurs lançaient des générations en même temps, la file d'attente se remplissait et il fallait patienter un petit moment.

Résultats

Quelques personnes pouvaient tester Midjourney facilement !

Ce que ce projet m'a apporté

Au-delà de l'idée, ce projet m'a surtout permis de me familiariser concrètement avec l'écosystème Discord :

  • architecture et événements de bots
  • gestion des permissions
  • flux asynchrones
  • logique produit orientée usage réel

Aujourd'hui, c'est un ancien projet. Bien que Midjourney ne propose toujours pas d'API officielle, ils ont depuis lancé un site web complet pour générer des images. Le projet a rempli sa mission : permettre à mes amis de découvrir l'IA générative. Il a surtout été un excellent tremplin pour progresser rapidement en développement back-end.

Fonctionnement technique

Le principe : Un double-bot

Pour contourner la limitation (1 compte = 1 utilisateur), j'ai créé un système à deux bots qui collaborent :

┌─────────────────────┐
│    UTILISATEURS     │
└────────────┬────────┘
             │
             │ /imagine "Une maison bleue"
             ▼
┌─────────────────────────────────────────────┐
│    BOT Halfway                              │
│  • Reçoit les commandes des utilisateurs    │
│  • Vérifie les permissions                  │
│  • Enregistre la demande en base de données │
└────────────┬────────────────────────────────┘
             │
             │ Données stockées : 
             │ • Qui a demandé quoi ?
             │ • Identifiant unique (seed)
             ▼
┌────────────────────────────────────────────┐
│    MONGODB                                 │
│  • Suivi de chaque génération (job)        │
│  • État : en attente → en cours → terminé  │
└────────────┬───────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────────────────┐
│    SELFBOT (Compte Discord Proxy)                   │
│  • Vrai compte Discord avec abonnement Midjourney   │
│  • Envoie /imagine au vrai bot Midjourney           │
└────────────┬────────────────────────────────────────┘
             │
             │ /imagine "Une maison bleue --seed 123456"
             ▼
┌───────────────────────────────────────┐
│    BOT MidJourney                     │
│  • Génère l'image                     │
│  • Répond dans un canal privé         │
└────────────┬──────────────────────────┘
             │
             │ Images générées + boutons d'intercation V1-V4, U1-U4, etc
             ▼
┌───────────────────────────────────────────────────┐
│    SELFBOT                                        │
│  • Récupère le résultat                           │
│  • Lit le seed pour savoir à qui c'est destiné    │
│  • Met à jour la base de données                  │
└────────────┬──────────────────────────────────────┘
             │
             ▼
┌───────────────────────────────────────────────────┐
│    BOT Halfway                                    │
│  • Retrouve l'utilisateur d'origine et le canal   │
│  • Renvoie l'image + boutons interactifs          │
└────────────┬──────────────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────────┐
│    UTILISATEUR                              │
│   Reçoit ses images + boutons interactifs   │
└─────────────────────────────────────────────┘

L'astuce du "seed"

Le problème : Comment savoir à qui appartient quelle génération d'image quand Midjourney répond ?

La solution : J'utilise le paramètre --seed de Midjourney (normalement utilisé pour reproduire une génération) comme identifiant unique.

Utilisateur A tape : /imagine "Une maison bleue"
    ↓
Bot Halfway enregistre en DB avec ID (ex: 789456)
    ↓
Selfbot envoie à Midjourney : /imagine "Une maison bleue --seed 789456"
    ↓
Bot Midjourney répond : "Une maison bleue --seed 789456" + image
    ↓
Selfbot lit le seed (789456) → cherche en DB → trouve l'utilisateur A
    ↓
Bot Halfway renvoie l'image en notifiant l'utilisateur A

Gestion des interactions (Variations, Upscale, Reroll, etc)

Quand un utilisateur clique sur un bouton (ex: V1 pour faire une variation) :

Utilisateur clique sur V1
         │
         ▼
Bot Halfway détecte le clic
         │
         ├─ Ajoute un emoji de réaction (pour comptabiliser)
         ├─ Vérifie si le bouton à déjà été cliqué
         ├─ Enregistre un nouveau job en DB
         │
         ▼
Selfbot va cliquer le bouton V1 sur le vrai message Midjourney
         │
         ▼
Midjourney génère la variation
         │
         ▼
Même processus de retour

Architecture en canaux Discord

Le système utilise 2 canaux Discord distincts :

┌─────────────────────────────────────────────────────────────┐
│  CANAL #COOKING (Visible aux utilisateurs)                  │
│                                                             │
│  • Les utilisateurs tapent leurs commandes ici              │
│  • Ils reçoivent leurs images ici                           │
│  • Contrôle d'accès par rôle Discord                        │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│  CANAL #BAKING (Privé, invisible aux utilisateurs)          │
│                                                             │
│  • Le selfbot et Midjourney communiquent ici                │
│  • Toutes les vraies générations passent par là             │
│  • Les utilisateurs normaux n'y ont pas accès               │
└─────────────────────────────────────────────────────────────┘

Cette séparation permet de :

  • Garder le canal utilisateur propre
  • Masquer la technique aux utilisateurs
  • Éviter les interférences entre les générations

Suivi de l'état avec MongoDB

Chaque génération est trackée dans une base de données avec un cycle de vie :

STATE 0 : 🆕 Créé
  └─ L'utilisateur vient de taper sa commande
  
STATE 1 : ⏳ En cours
  └─ Envoyé à Midjourney, on attend la réponse
  
STATE 3 : ✅ Terminé
  └─ Image reçue et envoyée à l'utilisateur
  
STATE -1 : ❌ Erreur
  └─ Quelque chose a mal tourné (prompt refusé, etc.)

Cette machine à états permet de :

  • Afficher un statut en temps réel ("Waiting...", "0%", "50%", "Done!")
  • Gérer les timeouts et erreurs
  • Calculer le temps de génération exact
  • Reprendre en cas de crash du bot

Sécurité et filtrage

Contrôle d'accès :

  • ✅ Rôle Discord requis (ex: "SUBS")
  • ✅ Canaux autorisés uniquement
  • ❌ Suppression automatique des messages non autorisés

Filtrage des prompts :

  • Certains paramètres sont interdits (--seed, --quality) car réservés au système
  • Les fichiers uploadés sont validés (.jpg, .png, .webp uniquement)

Isolation :

  • Les utilisateurs ne voient jamais le canal privé
  • Le compte proxy reste totalement caché
  • Chaque utilisateur ne voit que ses propres générations

Stack technique résumé

TechnologieUtilisation
Discord.js v14Bot public pour interagir avec les utilisateurs
discord.js-selfbot-v13Simuler un vrai compte Discord (sans avoir une instance Discord d'ouverte)
MongoDB + MongooseBase de données pour tracer tous les jobs
Node.jsRuntime JavaScript côté serveur

Ce qui rend le système robuste

  1. Traçabilité complète : Chaque génération est en DB avec timestamps, durée, utilisateur
  2. Gestion des erreurs : Si Midjourney refuse (prompt inapproprié), l'erreur est transmise
  3. File d'attente naturelle : Midjourney limite à 3 jobs simultanés, les autres attendent automatiquement
  4. Expérience transparente : L'utilisateur a l'impression d'utiliser Midjourney directement

Cette architecture événementielle permet au bot de gérer plusieurs utilisateurs simultanément sans conflit, tout en gardant une trace précise de qui a demandé quoi.