discord.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import argparse
  2. import logging
  3. import os
  4. from embedchain.helpers.json_serializable import register_deserializable
  5. from .base import BaseBot
  6. try:
  7. import discord
  8. from discord import app_commands
  9. from discord.ext import commands
  10. except ModuleNotFoundError:
  11. raise ModuleNotFoundError(
  12. "The required dependencies for Discord are not installed."
  13. 'Please install with `pip install "embedchain[discord]"`'
  14. ) from None
  15. logger = logging.getLogger(__name__)
  16. intents = discord.Intents.default()
  17. intents.message_content = True
  18. client = discord.Client(intents=intents)
  19. tree = app_commands.CommandTree(client)
  20. # Invite link example
  21. # https://discord.com/api/oauth2/authorize?client_id={DISCORD_CLIENT_ID}&permissions=2048&scope=bot
  22. @register_deserializable
  23. class DiscordBot(BaseBot):
  24. def __init__(self, *args, **kwargs):
  25. BaseBot.__init__(self, *args, **kwargs)
  26. def add_data(self, message):
  27. data = message.split(" ")[-1]
  28. try:
  29. self.add(data)
  30. response = f"Added data from: {data}"
  31. except Exception:
  32. logger.exception(f"Failed to add data {data}.")
  33. response = "Some error occurred while adding data."
  34. return response
  35. def ask_bot(self, message):
  36. try:
  37. response = self.query(message)
  38. except Exception:
  39. logger.exception(f"Failed to query {message}.")
  40. response = "An error occurred. Please try again!"
  41. return response
  42. def start(self):
  43. client.run(os.environ["DISCORD_BOT_TOKEN"])
  44. # @tree decorator cannot be used in a class. A global discord_bot is used as a workaround.
  45. @tree.command(name="question", description="ask embedchain")
  46. async def query_command(interaction: discord.Interaction, question: str):
  47. await interaction.response.defer()
  48. member = client.guilds[0].get_member(client.user.id)
  49. logger.info(f"User: {member}, Query: {question}")
  50. try:
  51. answer = discord_bot.ask_bot(question)
  52. if args.include_question:
  53. response = f"> {question}\n\n{answer}"
  54. else:
  55. response = answer
  56. await interaction.followup.send(response)
  57. except Exception as e:
  58. await interaction.followup.send("An error occurred. Please try again!")
  59. logger.error("Error occurred during 'query' command:", e)
  60. @tree.command(name="add", description="add new content to the embedchain database")
  61. async def add_command(interaction: discord.Interaction, url_or_text: str):
  62. await interaction.response.defer()
  63. member = client.guilds[0].get_member(client.user.id)
  64. logger.info(f"User: {member}, Add: {url_or_text}")
  65. try:
  66. response = discord_bot.add_data(url_or_text)
  67. await interaction.followup.send(response)
  68. except Exception as e:
  69. await interaction.followup.send("An error occurred. Please try again!")
  70. logger.error("Error occurred during 'add' command:", e)
  71. @tree.command(name="ping", description="Simple ping pong command")
  72. async def ping(interaction: discord.Interaction):
  73. await interaction.response.send_message("Pong", ephemeral=True)
  74. @tree.error
  75. async def on_app_command_error(interaction: discord.Interaction, error: discord.app_commands.AppCommandError) -> None:
  76. if isinstance(error, commands.CommandNotFound):
  77. await interaction.followup.send("Invalid command. Please refer to the documentation for correct syntax.")
  78. else:
  79. logger.error("Error occurred during command execution:", error)
  80. @client.event
  81. async def on_ready():
  82. # TODO: Sync in admin command, to not hit rate limits.
  83. # This might be overkill for most users, and it would require to set a guild or user id, where sync is allowed.
  84. await tree.sync()
  85. logger.debug("Command tree synced")
  86. logger.info(f"Logged in as {client.user.name}")
  87. def start_command():
  88. parser = argparse.ArgumentParser(description="EmbedChain DiscordBot command line interface")
  89. parser.add_argument(
  90. "--include-question",
  91. help="include question in query reply, otherwise it is hidden behind the slash command.",
  92. action="store_true",
  93. )
  94. global args
  95. args = parser.parse_args()
  96. global discord_bot
  97. discord_bot = DiscordBot()
  98. discord_bot.start()
  99. if __name__ == "__main__":
  100. start_command()