commit 642bdf21550f509db2462c3e881eaf42db831329
Author: Edgar P. Burkhart <git@edgarpierre.fr>
Date:   Mon Jun 10 09:26:53 2024 +0200

    Initial commit

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cda296d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/env
+/config.toml
+/wordlist.pickle
+__pycache__
diff --git a/botbotbot/__main__.py b/botbotbot/__main__.py
new file mode 100644
index 0000000..64c7894
--- /dev/null
+++ b/botbotbot/__main__.py
@@ -0,0 +1,198 @@
+import asyncio
+import pickle
+import random
+import tomllib
+
+import discord
+
+from .ai import AIBot
+
+description = """BotBotBot"""
+
+with open("config.toml", "rb") as config_file:
+    config = tomllib.load(config_file)
+
+with open("wordlist.pickle", "rb") as word_file:
+    word_list = pickle.load(word_file)
+guild_ids = config.get("guild_ids")
+delay = config.get("delay", 60)
+
+aibot = AIBot(config.get("mistral_api_key"), model="open-mixtral-8x7b")
+
+intents = discord.Intents.default()
+intents.members = True
+
+bot = discord.Bot(description=description, intents=intents)
+
+
+shuffle_tasks = set()
+
+
+@bot.listen("on_ready")
+async def on_ready():
+    print(f"We have logged in as {bot.user}")
+
+
+async def reply(message):
+    if random.random() < 1 / 2:
+        await message.reply(f"<@{message.author.id}>, {random.choice(word_list)}")
+    else:
+        await message.reply(f"{random.choice(word_list)}")
+
+
+async def ai_reply(message):
+    print("Running AI")
+    answer = aibot.answer(message.clean_content)
+    embed = discord.Embed(
+        description=answer,
+        thumbnail="https://mistral.ai/images/favicon/favicon-32x32.png",
+    )
+    await message.reply(embed=embed)
+
+
+async def react(message):
+    await message.add_reaction(random.choice(message.guild.emojis))
+
+
+@bot.listen("on_message")
+async def on_message(message):
+    if message.flags.ephemeral:
+        return
+
+    if random.random() < 1 / 12:
+        await reply(message)
+    elif random.random() < 1 / 48:
+        await ai_reply(message)
+
+    if random.random() < 1 / 6:
+        await react(message)
+
+    if message.author != bot.user and bot.user in message.mentions:
+        if random.random() < 1 / 2:
+            await reply(message)
+        else:
+            await react(message)
+
+
+@bot.listen("on_message")
+async def rando_shuffle(message):
+    if not message.flags.ephemeral and random.random() < 1 / 24 and message.guild:
+        await try_shuffle(message.guild)
+
+
+def save_wordlist():
+    with open("wordlist.pickle", "wb") as word_file:
+        pickle.dump(word_list, word_file)
+
+
+@bot.slash_command(name="bibl", guild_ids=guild_ids, description="Ajouter une phrase")
+async def bibl(ctx, phrase):
+    word_list.append(phrase)
+    embed = discord.Embed(
+        title="BIBL", description=phrase, color=discord.Colour.green()
+    )
+    await ctx.respond(embed=embed)
+    save_wordlist()
+
+
+@bot.slash_command(name="tabl", guild_ids=guild_ids, description="Lister les phrases")
+async def tabl(ctx):
+    embed = discord.Embed(
+        title="TABL", description="\n".join(word_list), color=discord.Colour.green()
+    )
+    await ctx.respond(embed=embed, ephemeral=True, delete_after=delay)
+
+
+@bot.slash_command(name="enle", guild_ids=guild_ids, description="Enlever une phrase")
+async def enle(ctx, phrase):
+    try:
+        word_list.remove(phrase)
+    except ValueError:
+        embed = discord.Embed(
+            title="ERRE ENLE", description=phrase, color=discord.Colour.red()
+        )
+        await ctx.respond(embed=embed)
+    else:
+        embed = discord.Embed(
+            title="ENLE", description=f"~~phrase~~", color=discord.Colour.green()
+        )
+        await ctx.respond(embed=embed, ephemeral=True, delete_after=delay)
+        save_wordlist()
+
+
+async def try_shuffle(guild):
+    if guild.id in shuffle_tasks:
+        return False
+
+    shuffle_tasks.add(guild.id)
+    await shuffle_nicks(guild)
+    shuffle_tasks.discard(guild.id)
+    return True
+
+
+async def shuffle_nicks(guild):
+    print("ALEA")
+    members = guild.members
+    members.remove(guild.owner)
+
+    nicks = [member.nick for member in members]
+
+    random.shuffle(nicks)
+    for member, nick in zip(members, nicks):
+        print(member, nick)
+        await member.edit(nick=nick)
+    print("FIN ALEA")
+
+
+@bot.slash_command(name="alea", guild_ids=guild_ids, description="Modifier les pseudos")
+async def alea(ctx):
+    await ctx.defer()
+    if await try_shuffle(ctx.guild):
+        embed = discord.Embed(title="ALEA", color=discord.Colour.green())
+        await ctx.respond(embed=embed, ephemeral=True, delete_after=delay)
+    else:
+        embed = discord.Embed(title="ERRE ALEA", color=discord.Colour.red())
+        await ctx.respond(embed=embed)
+
+
+@bot.slash_command(
+    name="indu", guild_ids=guild_ids, description="Poser une question à MistralAI"
+)
+async def indu(ctx, prompt):
+    await ctx.defer()
+    answer = aibot.answer(prompt)
+    embed = discord.Embed(
+        title=prompt,
+        description=answer,
+        thumbnail="https://mistral.ai/images/favicon/favicon-32x32.png",
+    )
+    await ctx.respond(embed=embed)
+
+
+@bot.slash_command(
+    name="chan", guild_ids=guild_ids, description="Donner de nouveaux pseudos"
+)
+async def chan(ctx, file: discord.Attachment):
+    await ctx.defer()
+
+    members = ctx.guild.members
+    members.remove(ctx.guild.owner)
+
+    nicks = (await file.read()).decode().splitlines()
+    if len(nicks) != len(members):
+        embed = discord.Embed(title="ERRE CHAN", color=discord.Colour.red())
+        await ctx.respond(embed=embed)
+        return
+
+    random.shuffle(nicks)
+    for member, nick in zip(members, nicks):
+        print(member, nick)
+        await member.edit(nick=nick)
+
+    embed = discord.Embed(
+        title="CHAN", description="\n".join(nicks), color=discord.Colour.green()
+    )
+    await ctx.respond(embed=embed)
+
+
+bot.run(config.get("token"))
diff --git a/botbotbot/ai.py b/botbotbot/ai.py
new file mode 100644
index 0000000..b64349a
--- /dev/null
+++ b/botbotbot/ai.py
@@ -0,0 +1,21 @@
+import tomllib
+
+from mistralai.client import MistralClient
+from mistralai.models.chat_completion import ChatMessage
+
+
+class AIBot:
+    def __init__(self, api_key, model="open-mistral-7b", max_tokens=None):
+        self.client = MistralClient(api_key=api_key)
+        self.model = model
+        self.max_tokens = max_tokens
+
+    def get_responses(self, message):
+        return self.client.chat(
+            model=self.model,
+            messages=[ChatMessage(role="user", content=message)],
+            max_tokens=self.max_tokens,
+        )
+
+    def answer(self, message):
+        return self.get_responses(message).choices[0].message.content
diff --git a/config.sample.toml b/config.sample.toml
new file mode 100644
index 0000000..f9c5085
--- /dev/null
+++ b/config.sample.toml
@@ -0,0 +1,6 @@
+mistral_api_key = ""
+
+token = ""
+
+delay = 30
+guild_ids = [""]
