Implement Shuffler and Wordlist classes; enhance TextBot with shuffle and reaction features
This commit is contained in:
parent
bab22747b4
commit
b9c84f16be
5 changed files with 165 additions and 115 deletions
|
@ -1,13 +1,14 @@
|
|||
import logging
|
||||
import pickle
|
||||
import random
|
||||
import tomllib
|
||||
|
||||
import discord
|
||||
|
||||
from botbotbot.ai import AIBot
|
||||
from botbotbot.shuffle import Shuffler
|
||||
from botbotbot.text import TextBot
|
||||
from botbotbot.tts import CambAI
|
||||
from botbotbot.wordlist import Wordlist
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
@ -19,10 +20,7 @@ def main() -> None:
|
|||
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)
|
||||
|
||||
system_prompt = """Tu es une intelligence artificelle qui répond en français.
|
||||
Tu dois faire un commentaire pertinent en lien avec ce qui te sera dit.
|
||||
|
@ -50,123 +48,25 @@ def main() -> None:
|
|||
intents.voice_states = True
|
||||
|
||||
bot = discord.Bot(description=description, intents=intents)
|
||||
shf = Shuffler()
|
||||
wl = Wordlist(bot)
|
||||
|
||||
text_bot = TextBot(bot, aibot, word_list)
|
||||
text_bot = TextBot(bot, wl, aibot=aibot, shuffler=shf)
|
||||
text_bot.init_events()
|
||||
|
||||
shuffle_tasks = set()
|
||||
|
||||
@bot.listen("on_ready")
|
||||
async def on_ready() -> None:
|
||||
logger.info(f"We have logged in as {bot.user}")
|
||||
|
||||
@bot.listen("on_reaction_add")
|
||||
async def add_more_reaction(
|
||||
reaction: discord.Reaction, user: discord.Member | discord.User
|
||||
) -> None:
|
||||
if random.random() < 50 / 100:
|
||||
logger.info(f"Copy reaction from {user}")
|
||||
await reaction.message.add_reaction(reaction.emoji)
|
||||
|
||||
@bot.listen("on_message_edit")
|
||||
async def react_message_edit(
|
||||
before: discord.Message, after: discord.Message
|
||||
) -> None:
|
||||
if (
|
||||
before.content != after.content
|
||||
and after.author != bot.user
|
||||
and random.random() < 50 / 100
|
||||
):
|
||||
logger.info(f"React to edit from {after.author}")
|
||||
await after.add_reaction("👀")
|
||||
|
||||
@bot.listen("on_message")
|
||||
async def rando_shuffle(message: discord.Message) -> None:
|
||||
if not message.flags.ephemeral and random.random() < 5 / 100 and message.guild:
|
||||
logger.info(f"Message shuffle after message from {message.author}")
|
||||
await try_shuffle(message.guild)
|
||||
|
||||
def save_wordlist() -> None:
|
||||
logger.info("Saving updated 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: discord.ApplicationContext, phrase: str) -> None:
|
||||
logger.info(f"BIBL {ctx.author} {phrase}")
|
||||
word_list.append(phrase)
|
||||
embed = discord.Embed(
|
||||
title="BIBL", description=phrase, color=discord.Colour.green()
|
||||
)
|
||||
await ctx.respond(embed=embed)
|
||||
save_wordlist()
|
||||
logger.info("FIN BIBL")
|
||||
|
||||
@bot.slash_command(
|
||||
name="tabl", guild_ids=guild_ids, description="Lister les phrases"
|
||||
)
|
||||
async def tabl(ctx: discord.ApplicationContext) -> None:
|
||||
logger.info(f"TABL {ctx.author}")
|
||||
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: discord.ApplicationContext, phrase: str) -> None:
|
||||
logger.info(f"ENLE {ctx.author} {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)
|
||||
logger.info("ERRE ENLE")
|
||||
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()
|
||||
logger.info("FIN ENLE")
|
||||
|
||||
async def try_shuffle(guild: discord.Guild) -> bool:
|
||||
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: discord.Guild) -> None:
|
||||
logger.info("Shuffle")
|
||||
members = guild.members
|
||||
if guild.owner:
|
||||
members.remove(guild.owner)
|
||||
|
||||
nicks = [member.nick for member in members]
|
||||
|
||||
random.shuffle(nicks)
|
||||
for member, nick in zip(members, nicks):
|
||||
logger.info(f"{member} {nick}")
|
||||
await member.edit(nick=nick)
|
||||
logger.info("Shuffle done")
|
||||
|
||||
@bot.slash_command(
|
||||
name="alea", guild_ids=guild_ids, description="Modifier les pseudos"
|
||||
)
|
||||
async def alea(ctx: discord.ApplicationContext) -> None:
|
||||
logger.info(f"ALEA {ctx.author}")
|
||||
await ctx.defer()
|
||||
if await try_shuffle(ctx.guild):
|
||||
if await shf.try_shuffle(ctx.guild):
|
||||
embed = discord.Embed(title="ALEA", color=discord.Colour.green())
|
||||
await ctx.respond(embed=embed, ephemeral=True, delete_after=delay)
|
||||
await ctx.respond(embed=embed, ephemeral=True, delete_after=30)
|
||||
logger.info("FIN ALEA")
|
||||
else:
|
||||
embed = discord.Embed(title="ERRE ALEA", color=discord.Colour.red())
|
||||
|
@ -177,10 +77,6 @@ def main() -> None:
|
|||
async def on_voice_state_update(
|
||||
member: discord.Member, before: discord.VoiceState, after: discord.VoiceState
|
||||
) -> None:
|
||||
if before.channel is None and random.random() < 5 / 100:
|
||||
logger.info(f"Voice shuffle from {member}")
|
||||
await try_shuffle(member.guild)
|
||||
|
||||
logger.debug("Voice state update")
|
||||
logger.debug(before.channel)
|
||||
logger.debug(after.channel)
|
||||
|
@ -210,6 +106,10 @@ def main() -> None:
|
|||
await vo.play(source, wait_finish=True)
|
||||
await vo.disconnect()
|
||||
|
||||
if before.channel is None and random.random() < 5 / 100:
|
||||
logger.info(f"Voice shuffle from {member}")
|
||||
await shf.try_shuffle(member.guild)
|
||||
|
||||
@bot.slash_command(
|
||||
name="indu", guild_ids=guild_ids, description="Poser une question à MistralAI"
|
||||
)
|
||||
|
|
34
botbotbot/shuffle.py
Normal file
34
botbotbot/shuffle.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
import logging
|
||||
import random
|
||||
|
||||
import discord
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Shuffler:
|
||||
def __init__(self) -> None:
|
||||
self.shuffle_tasks: set[int] = set()
|
||||
|
||||
async def try_shuffle(self, guild: discord.Guild) -> bool:
|
||||
if guild.id in self.shuffle_tasks:
|
||||
return False
|
||||
|
||||
self.shuffle_tasks.add(guild.id)
|
||||
await self.shuffle_nicks(guild)
|
||||
self.shuffle_tasks.discard(guild.id)
|
||||
return True
|
||||
|
||||
async def shuffle_nicks(self, guild: discord.Guild) -> None:
|
||||
logger.info("Shuffle")
|
||||
members = guild.members
|
||||
if guild.owner:
|
||||
members.remove(guild.owner)
|
||||
|
||||
nicks = [member.nick for member in members]
|
||||
|
||||
random.shuffle(nicks)
|
||||
for member, nick in zip(members, nicks):
|
||||
logger.info(f"{member} {nick}")
|
||||
await member.edit(nick=nick)
|
||||
logger.info("Shuffle done")
|
|
@ -6,6 +6,8 @@ import discord
|
|||
import emoji
|
||||
|
||||
from botbotbot.ai import AIBot
|
||||
from botbotbot.shuffle import Shuffler
|
||||
from botbotbot.wordlist import Wordlist
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -16,17 +18,22 @@ class TextBot:
|
|||
def __init__(
|
||||
self,
|
||||
bot: discord.Bot,
|
||||
wordlist: Wordlist,
|
||||
aibot: AIBot | None = None,
|
||||
wordlist: list[str] = [],
|
||||
shuffler: Shuffler | None = None,
|
||||
rnd_weights: list[float] = [10, 5, 10],
|
||||
) -> None:
|
||||
self.bot = bot
|
||||
self.aibot = aibot
|
||||
self.word_list = wordlist
|
||||
self.wl = wordlist
|
||||
self._rnd_weights = rnd_weights
|
||||
self.shf = shuffler
|
||||
|
||||
def init_events(self) -> None:
|
||||
self.bot.add_listener(self.on_message, "on_message")
|
||||
self.bot.add_listener(self.add_more_reaction, "on_reaction_add")
|
||||
self.bot.add_listener(self.react_message_edit, "on_message_edit")
|
||||
self.bot.add_listener(self.rando_shuffle, "on_message")
|
||||
|
||||
@property
|
||||
def rnd_weights(self) -> list[float]:
|
||||
|
@ -77,8 +84,8 @@ class TextBot:
|
|||
)[0]
|
||||
content = random.choice(
|
||||
(
|
||||
f"{mention}, {random.choice(self.word_list)}",
|
||||
f"{random.choice(self.word_list)}",
|
||||
f"{mention}, {self.wl.random()}",
|
||||
f"{self.wl.random()}",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -144,3 +151,31 @@ class TextBot:
|
|||
webhook = await channel.create_webhook(name="BotbotbotHook")
|
||||
|
||||
await webhook.send(content=content, username=name, avatar_url=avatar_url)
|
||||
|
||||
async def add_more_reaction(
|
||||
self, reaction: discord.Reaction, user: discord.Member | discord.User
|
||||
) -> None:
|
||||
if random.random() < 20 / 100:
|
||||
logger.info(f"Copy reaction from {user}")
|
||||
await reaction.message.add_reaction(reaction.emoji)
|
||||
|
||||
async def react_message_edit(
|
||||
self, before: discord.Message, after: discord.Message
|
||||
) -> None:
|
||||
if (
|
||||
before.content != after.content
|
||||
and after.author != self.bot.user
|
||||
and random.random() < 20 / 100
|
||||
):
|
||||
logger.info(f"React to edit from {after.author}")
|
||||
await after.add_reaction("👀")
|
||||
|
||||
async def rando_shuffle(self, message: discord.Message) -> None:
|
||||
if (
|
||||
self.shf
|
||||
and not message.flags.ephemeral
|
||||
and random.random() < 5 / 100
|
||||
and message.guild
|
||||
):
|
||||
logger.info(f"Message shuffle after message from {message.author}")
|
||||
await self.shf.try_shuffle(message.guild)
|
||||
|
|
0
botbotbot/voice.py
Normal file
0
botbotbot/voice.py
Normal file
81
botbotbot/wordlist.py
Normal file
81
botbotbot/wordlist.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
import logging
|
||||
import pathlib
|
||||
import pickle
|
||||
import random
|
||||
|
||||
import discord
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Wordlist:
|
||||
def __init__(
|
||||
self, bot: discord.Bot, path: pathlib.Path = pathlib.Path("wordlist.pickle")
|
||||
):
|
||||
self.path = path
|
||||
if self.path.exists():
|
||||
with self.path.open("rb") as w_file:
|
||||
self.word_list: list[str] = pickle.load(w_file)
|
||||
self.bot = bot
|
||||
|
||||
def init_events(self) -> None:
|
||||
self.bot.add_application_command(
|
||||
discord.SlashCommand(
|
||||
self.bibl, name="bibl", description="Ajouter une phrase"
|
||||
)
|
||||
)
|
||||
self.bot.add_application_command(
|
||||
discord.SlashCommand(
|
||||
self.tabl, name="tabl", description="Lister les phrases"
|
||||
)
|
||||
)
|
||||
self.bot.add_application_command(
|
||||
discord.SlashCommand(
|
||||
self.enle, name="enle", description="Enlever une phrase"
|
||||
)
|
||||
)
|
||||
|
||||
def random(self) -> str:
|
||||
return random.choice(self.word_list)
|
||||
|
||||
def save(self) -> None:
|
||||
logger.info("Saving updated wordlist")
|
||||
with open(self.path, "wb") as w_file:
|
||||
pickle.dump(self.word_list, w_file)
|
||||
|
||||
async def bibl(self, ctx: discord.ApplicationContext, phrase: str) -> None:
|
||||
logger.info(f"BIBL {ctx.author} {phrase}")
|
||||
self.word_list.append(phrase)
|
||||
embed = discord.Embed(
|
||||
title="BIBL", description=phrase, color=discord.Colour.green()
|
||||
)
|
||||
await ctx.respond(embed=embed)
|
||||
self.save()
|
||||
logger.info("FIN BIBL")
|
||||
|
||||
async def tabl(self, ctx: discord.ApplicationContext) -> None:
|
||||
logger.info(f"TABL {ctx.author}")
|
||||
embed = discord.Embed(
|
||||
title="TABL",
|
||||
description="\n".join(self.word_list),
|
||||
color=discord.Colour.green(),
|
||||
)
|
||||
await ctx.respond(embed=embed, ephemeral=True, delete_after=30)
|
||||
|
||||
async def enle(self, ctx: discord.ApplicationContext, phrase: str) -> None:
|
||||
logger.info(f"ENLE {ctx.author} {phrase}")
|
||||
try:
|
||||
self.word_list.remove(phrase)
|
||||
except ValueError:
|
||||
embed = discord.Embed(
|
||||
title="ERRE ENLE", description=phrase, color=discord.Colour.red()
|
||||
)
|
||||
await ctx.respond(embed=embed)
|
||||
logger.info("ERRE ENLE")
|
||||
else:
|
||||
embed = discord.Embed(
|
||||
title="ENLE", description=f"~~{phrase}~~", color=discord.Colour.green()
|
||||
)
|
||||
await ctx.respond(embed=embed, ephemeral=True, delete_after=30)
|
||||
self.save()
|
||||
logger.info("FIN ENLE")
|
Loading…
Add table
Reference in a new issue