Update .gitignore and pyproject.toml; streamline main entry point for BotBotBot
This commit is contained in:
parent
761111bb07
commit
bc9d5a8943
4 changed files with 356 additions and 350 deletions
19
.gitignore
vendored
19
.gitignore
vendored
|
@ -1,5 +1,14 @@
|
|||
/env
|
||||
/assets
|
||||
/config.toml
|
||||
/wordlist.pickle
|
||||
__pycache__
|
||||
# Python-generated files
|
||||
__pycache__/
|
||||
*.py[oc]
|
||||
build/
|
||||
dist/
|
||||
wheels/
|
||||
*.egg-info
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
|
||||
# BotBotBot
|
||||
config.toml
|
||||
wordlist.pickle
|
||||
|
|
|
@ -0,0 +1,337 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import pickle
|
||||
import random
|
||||
import tomllib
|
||||
|
||||
import discord
|
||||
|
||||
from botbotbot.ai import AIBot
|
||||
|
||||
|
||||
def main() -> None:
|
||||
description = """Discord Chaos Bot"""
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
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.
|
||||
Ta réponse doit être très courte.
|
||||
Ta réponse doit être une seule phrase.
|
||||
TA RÉPONSE DOIT ÊTRE EN FRANÇAIS !!!"""
|
||||
|
||||
aibot: AIBot | None = None
|
||||
|
||||
if isinstance(key := config.get("mistral_api_key"), str):
|
||||
aibot = AIBot(
|
||||
key,
|
||||
model="mistral-large-latest",
|
||||
system_message=system_prompt,
|
||||
)
|
||||
|
||||
intents = discord.Intents.default()
|
||||
intents.members = True
|
||||
intents.message_content = True
|
||||
intents.reactions = True
|
||||
intents.voice_states = True
|
||||
|
||||
bot = discord.Bot(description=description, intents=intents)
|
||||
|
||||
shuffle_tasks = set()
|
||||
|
||||
@bot.listen("on_ready")
|
||||
async def on_ready() -> None:
|
||||
logger.info(f"We have logged in as {bot.user}")
|
||||
|
||||
async def reply(message: discord.Message) -> None:
|
||||
logger.info(f"Reply to {message.author}")
|
||||
mention = random.choices(
|
||||
[f"<@{message.author.id}>", "@everyone", "@here"], weights=(98, 1, 1)
|
||||
)[0]
|
||||
content = random.choice(
|
||||
(
|
||||
f"{mention}, {random.choice(word_list)}",
|
||||
f"{random.choice(word_list)}",
|
||||
)
|
||||
)
|
||||
|
||||
if isinstance(message.channel, discord.TextChannel) and random.random() < 0.1:
|
||||
await send_as_webhook(
|
||||
message.channel,
|
||||
message.author.display_name,
|
||||
message.author.avatar.url if message.author.avatar else None,
|
||||
content,
|
||||
)
|
||||
else:
|
||||
fct = random.choice((message.reply, message.channel.send))
|
||||
|
||||
await fct(content)
|
||||
|
||||
async def ai_reply(message: discord.Message) -> None:
|
||||
if aibot is None:
|
||||
return
|
||||
|
||||
logger.info(f"AI Reply to {message.author}")
|
||||
prompt = message.clean_content
|
||||
if prompt == "" and message.embeds and message.embeds[0].description:
|
||||
prompt = message.embeds[0].description
|
||||
|
||||
answer = aibot.answer(prompt)
|
||||
if not isinstance(answer, str):
|
||||
return
|
||||
|
||||
if len(answer) > 2000:
|
||||
embed = discord.Embed(
|
||||
description=answer,
|
||||
thumbnail="https://mistral.ai/images/favicon/favicon-32x32.png",
|
||||
)
|
||||
await message.reply(embed=embed)
|
||||
else:
|
||||
await message.reply(answer)
|
||||
|
||||
async def react(message: discord.Message) -> None:
|
||||
if message.guild is None:
|
||||
return
|
||||
await message.add_reaction(random.choice(message.guild.emojis))
|
||||
|
||||
@bot.listen("on_message")
|
||||
async def on_message(message: discord.Message) -> None:
|
||||
if message.flags.ephemeral:
|
||||
return
|
||||
|
||||
if message.author != bot.user and bot.user in message.mentions:
|
||||
logger.info(f"{message.author} metion")
|
||||
await random.choice((reply, react))(message)
|
||||
return
|
||||
|
||||
probas = [10, 5, 10]
|
||||
|
||||
func = random.choices(
|
||||
(reply, ai_reply, react, None), weights=probas + [100 - sum(probas)]
|
||||
)[0]
|
||||
if func is not None:
|
||||
await func(message)
|
||||
|
||||
@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):
|
||||
embed = discord.Embed(title="ALEA", color=discord.Colour.green())
|
||||
await ctx.respond(embed=embed, ephemeral=True, delete_after=delay)
|
||||
logger.info("FIN ALEA")
|
||||
else:
|
||||
embed = discord.Embed(title="ERRE ALEA", color=discord.Colour.red())
|
||||
await ctx.respond(embed=embed)
|
||||
logger.info("ERRE ALEA")
|
||||
|
||||
@bot.listen("on_voice_state_update")
|
||||
async def voice_random_nicks(
|
||||
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)
|
||||
if after.channel:
|
||||
logger.debug(after.channel.members)
|
||||
if (
|
||||
before.channel is None
|
||||
and after.channel is not None
|
||||
and random.random() < 5 / 100
|
||||
and bot not in after.channel.members
|
||||
):
|
||||
logger.info(f"Voice connect from {member}")
|
||||
source = await discord.FFmpegOpusAudio.from_probe("assets/allo.ogg")
|
||||
|
||||
await asyncio.sleep(random.randrange(60))
|
||||
vo: discord.VoiceClient = await after.channel.connect()
|
||||
|
||||
await asyncio.sleep(random.randrange(10))
|
||||
await vo.play(source, wait_finish=True)
|
||||
|
||||
await asyncio.sleep(random.randrange(60))
|
||||
await vo.disconnect()
|
||||
logger.info("Voice disconnect")
|
||||
|
||||
@bot.slash_command(
|
||||
name="indu", guild_ids=guild_ids, description="Poser une question à MistralAI"
|
||||
)
|
||||
async def indu(ctx: discord.ApplicationContext, prompt: str) -> None:
|
||||
if aibot is None:
|
||||
return
|
||||
logger.info(f"INDU {ctx.author} {prompt}")
|
||||
await ctx.defer()
|
||||
res_stream = await aibot.get_response_stream(prompt)
|
||||
|
||||
embed = discord.Embed(
|
||||
title=prompt,
|
||||
description="",
|
||||
thumbnail="https://mistral.ai/images/favicon/favicon-32x32.png",
|
||||
color=discord.Colour.orange(),
|
||||
)
|
||||
message = await ctx.respond(embed=embed)
|
||||
|
||||
async for chunk in res_stream:
|
||||
if chunk.data.choices[0].delta.content is not None:
|
||||
embed.description += chunk.data.choices[0].delta.content
|
||||
await message.edit(embed=embed)
|
||||
|
||||
embed.colour = None
|
||||
await message.edit(embed=embed)
|
||||
logger.info("FIN INDU")
|
||||
|
||||
@bot.slash_command(
|
||||
name="chan", guild_ids=guild_ids, description="Donner de nouveaux pseudos"
|
||||
)
|
||||
async def chan(ctx: discord.ApplicationContext, file: discord.Attachment) -> None:
|
||||
logger.info(f"CHAN {ctx.author}")
|
||||
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
|
||||
|
||||
nicks = random.choices(nicks, k=len(members))
|
||||
for member, nick in zip(members, nicks):
|
||||
logger.info(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)
|
||||
logger.info("FIN CHAN")
|
||||
|
||||
async def send_as_webhook(
|
||||
channel: discord.TextChannel,
|
||||
name: str,
|
||||
avatar_url: str | None,
|
||||
content: str,
|
||||
) -> None:
|
||||
webhooks = await channel.webhooks()
|
||||
webhook = discord.utils.get(webhooks, name="BotbotbotHook")
|
||||
|
||||
if webhook is None:
|
||||
webhook = await channel.create_webhook(name="BotbotbotHook")
|
||||
|
||||
await webhook.send(content=content, username=name, avatar_url=avatar_url)
|
||||
|
||||
bot.run(config.get("token"))
|
|
@ -1,346 +1,3 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import pickle
|
||||
import random
|
||||
import tomllib
|
||||
from botbotbot import main
|
||||
|
||||
import discord
|
||||
|
||||
from botbotbot.ai import AIBot
|
||||
|
||||
description = """BotBotBot"""
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
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.
|
||||
Ta réponse doit être très courte.
|
||||
Ta réponse doit être une seule phrase.
|
||||
TA RÉPONSE DOIT ÊTRE EN FRANÇAIS !!!"""
|
||||
|
||||
aibot: AIBot | None = None
|
||||
|
||||
if isinstance(key := config.get("mistral_api_key"), str):
|
||||
aibot = AIBot(
|
||||
key,
|
||||
model="mistral-large-latest",
|
||||
system_message=system_prompt,
|
||||
)
|
||||
|
||||
intents = discord.Intents.default()
|
||||
intents.members = True
|
||||
intents.message_content = True
|
||||
intents.reactions = True
|
||||
intents.voice_states = True
|
||||
|
||||
bot = discord.Bot(description=description, intents=intents)
|
||||
|
||||
|
||||
shuffle_tasks = set()
|
||||
|
||||
|
||||
@bot.listen("on_ready")
|
||||
async def on_ready() -> None:
|
||||
logger.info(f"We have logged in as {bot.user}")
|
||||
|
||||
|
||||
async def reply(message: discord.Message) -> None:
|
||||
logger.info(f"Reply to {message.author}")
|
||||
mention = random.choices(
|
||||
[f"<@{message.author.id}>", "@everyone", "@here"], weights=(98, 1, 1)
|
||||
)[0]
|
||||
content = random.choice(
|
||||
(
|
||||
f"{mention}, {random.choice(word_list)}",
|
||||
f"{random.choice(word_list)}",
|
||||
)
|
||||
)
|
||||
|
||||
if isinstance(message.channel, discord.TextChannel) and random.random() < 0.1:
|
||||
await send_as_webhook(
|
||||
message.channel,
|
||||
message.author.display_name,
|
||||
message.author.avatar.url if message.author.avatar else None,
|
||||
content,
|
||||
)
|
||||
else:
|
||||
fct = random.choice((message.reply, message.channel.send))
|
||||
|
||||
await fct(content)
|
||||
|
||||
|
||||
async def ai_reply(message: discord.Message) -> None:
|
||||
if aibot is None:
|
||||
return
|
||||
|
||||
logger.info(f"AI Reply to {message.author}")
|
||||
prompt = message.clean_content
|
||||
if prompt == "" and message.embeds and message.embeds[0].description:
|
||||
prompt = message.embeds[0].description
|
||||
|
||||
answer = aibot.answer(prompt)
|
||||
if not isinstance(answer, str):
|
||||
return
|
||||
|
||||
if len(answer) > 2000:
|
||||
embed = discord.Embed(
|
||||
description=answer,
|
||||
thumbnail="https://mistral.ai/images/favicon/favicon-32x32.png",
|
||||
)
|
||||
await message.reply(embed=embed)
|
||||
else:
|
||||
await message.reply(answer)
|
||||
|
||||
|
||||
async def react(message: discord.Message) -> None:
|
||||
if message.guild is None:
|
||||
return
|
||||
await message.add_reaction(random.choice(message.guild.emojis))
|
||||
|
||||
|
||||
@bot.listen("on_message")
|
||||
async def on_message(message: discord.Message) -> None:
|
||||
if message.flags.ephemeral:
|
||||
return
|
||||
|
||||
if message.author != bot.user and bot.user in message.mentions:
|
||||
logger.info(f"{message.author} metion")
|
||||
await random.choice((reply, react))(message)
|
||||
return
|
||||
|
||||
probas = [10, 5, 10]
|
||||
|
||||
func = random.choices(
|
||||
(reply, ai_reply, react, None), weights=probas + [100 - sum(probas)]
|
||||
)[0]
|
||||
if func is not None:
|
||||
await func(message)
|
||||
|
||||
|
||||
@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):
|
||||
embed = discord.Embed(title="ALEA", color=discord.Colour.green())
|
||||
await ctx.respond(embed=embed, ephemeral=True, delete_after=delay)
|
||||
logger.info("FIN ALEA")
|
||||
else:
|
||||
embed = discord.Embed(title="ERRE ALEA", color=discord.Colour.red())
|
||||
await ctx.respond(embed=embed)
|
||||
logger.info("ERRE ALEA")
|
||||
|
||||
|
||||
@bot.listen("on_voice_state_update")
|
||||
async def voice_random_nicks(
|
||||
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)
|
||||
if after.channel:
|
||||
logger.debug(after.channel.members)
|
||||
if (
|
||||
before.channel is None
|
||||
and after.channel is not None
|
||||
and random.random() < 5 / 100
|
||||
and bot not in after.channel.members
|
||||
):
|
||||
logger.info(f"Voice connect from {member}")
|
||||
source = await discord.FFmpegOpusAudio.from_probe("assets/allo.ogg")
|
||||
|
||||
await asyncio.sleep(random.randrange(60))
|
||||
vo: discord.VoiceClient = await after.channel.connect()
|
||||
|
||||
await asyncio.sleep(random.randrange(10))
|
||||
await vo.play(source, wait_finish=True)
|
||||
|
||||
await asyncio.sleep(random.randrange(60))
|
||||
await vo.disconnect()
|
||||
logger.info("Voice disconnect")
|
||||
|
||||
|
||||
@bot.slash_command(
|
||||
name="indu", guild_ids=guild_ids, description="Poser une question à MistralAI"
|
||||
)
|
||||
async def indu(ctx: discord.ApplicationContext, prompt: str) -> None:
|
||||
if aibot is None:
|
||||
return
|
||||
logger.info(f"INDU {ctx.author} {prompt}")
|
||||
await ctx.defer()
|
||||
res_stream = await aibot.get_response_stream(prompt)
|
||||
|
||||
embed = discord.Embed(
|
||||
title=prompt,
|
||||
description="",
|
||||
thumbnail="https://mistral.ai/images/favicon/favicon-32x32.png",
|
||||
color=discord.Colour.orange(),
|
||||
)
|
||||
message = await ctx.respond(embed=embed)
|
||||
|
||||
async for chunk in res_stream:
|
||||
if chunk.data.choices[0].delta.content is not None:
|
||||
embed.description += chunk.data.choices[0].delta.content
|
||||
await message.edit(embed=embed)
|
||||
|
||||
embed.colour = None
|
||||
await message.edit(embed=embed)
|
||||
logger.info("FIN INDU")
|
||||
|
||||
|
||||
@bot.slash_command(
|
||||
name="chan", guild_ids=guild_ids, description="Donner de nouveaux pseudos"
|
||||
)
|
||||
async def chan(ctx: discord.ApplicationContext, file: discord.Attachment) -> None:
|
||||
logger.info(f"CHAN {ctx.author}")
|
||||
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
|
||||
|
||||
nicks = random.choices(nicks, k=len(members))
|
||||
for member, nick in zip(members, nicks):
|
||||
logger.info(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)
|
||||
logger.info("FIN CHAN")
|
||||
|
||||
|
||||
async def send_as_webhook(
|
||||
channel: discord.TextChannel,
|
||||
name: str,
|
||||
avatar_url: str | None,
|
||||
content: str,
|
||||
) -> None:
|
||||
webhooks = await channel.webhooks()
|
||||
webhook = discord.utils.get(webhooks, name="BotbotbotHook")
|
||||
|
||||
if webhook is None:
|
||||
webhook = await channel.create_webhook(name="BotbotbotHook")
|
||||
|
||||
await webhook.send(content=content, username=name, avatar_url=avatar_url)
|
||||
|
||||
|
||||
bot.run(config.get("token"))
|
||||
main()
|
||||
|
|
|
@ -11,6 +11,9 @@ dependencies = [
|
|||
"pynacl>=1.5.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
hasspy = "botbotbot:main"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"isort>=6.0.1",
|
||||
|
|
Loading…
Add table
Reference in a new issue