Colby commited on
Commit
08083cc
1 Parent(s): 0e36a1e

Deploy Discord Bot

Browse files
Files changed (2) hide show
  1. app.py +193 -0
  2. requirements.txt +1 -0
app.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import os
3
+ import threading
4
+ from threading import Event
5
+ from typing import Optional
6
+
7
+ import discord
8
+ import gradio as gr
9
+ from discord import Permissions
10
+ from discord.ext import commands
11
+ from discord.utils import oauth_url
12
+
13
+ import gradio_client as grc
14
+ from gradio_client.utils import QueueError
15
+
16
+ event = Event()
17
+
18
+ DISCORD_TOKEN = os.getenv("DISCORD_TOKEN")
19
+
20
+
21
+ async def wait(job):
22
+ while not job.done():
23
+ await asyncio.sleep(0.2)
24
+
25
+
26
+ def get_client(session: Optional[str] = None) -> grc.Client:
27
+ client = grc.Client("https://organika-merlin-chat-demo.hf.space", hf_token=os.getenv("HF_TOKEN"))
28
+ if session:
29
+ client.session_hash = session
30
+ return client
31
+
32
+
33
+ def truncate_response(response: str) -> str:
34
+ ending = "...\nTruncating response to 2000 characters due to discord api limits."
35
+ if len(response) > 2000:
36
+ return response[: 2000 - len(ending)] + ending
37
+ else:
38
+ return response
39
+
40
+
41
+ intents = discord.Intents.default()
42
+ intents.message_content = True
43
+ bot = commands.Bot(command_prefix="/", intents=intents)
44
+
45
+
46
+ @bot.event
47
+ async def on_ready():
48
+ print(f"Logged in as {bot.user} (ID: {bot.user.id})")
49
+ synced = await bot.tree.sync()
50
+ print(f"Synced commands: {', '.join([s.name for s in synced])}.")
51
+ event.set()
52
+ print("------")
53
+
54
+
55
+ thread_to_client = {}
56
+ thread_to_user = {}
57
+
58
+
59
+ @bot.hybrid_command(
60
+ name="chat",
61
+ description="Enter some text to chat with the bot! Like this: /chat Hello, how are you?",
62
+ )
63
+ async def chat(ctx, prompt: str):
64
+ if ctx.author.id == bot.user.id:
65
+ return
66
+ try:
67
+ message = await ctx.send("Creating thread...")
68
+
69
+ thread = await message.create_thread(name=prompt)
70
+ loop = asyncio.get_running_loop()
71
+ client = await loop.run_in_executor(None, get_client, None)
72
+ job = client.submit(prompt, api_name="/chat")
73
+ await wait(job)
74
+
75
+ try:
76
+ job.result()
77
+ response = job.outputs()[-1]
78
+ await thread.send(truncate_response(response))
79
+ thread_to_client[thread.id] = client
80
+ thread_to_user[thread.id] = ctx.author.id
81
+ except QueueError:
82
+ await thread.send(
83
+ "The gradio space powering this bot is really busy! Please try again later!"
84
+ )
85
+
86
+ except Exception as e:
87
+ print(f"{e}")
88
+
89
+
90
+ async def continue_chat(message):
91
+ """Continues a given conversation based on chathistory"""
92
+ try:
93
+ client = thread_to_client[message.channel.id]
94
+ prompt = message.content
95
+ job = client.submit(prompt, api_name="/chat")
96
+ await wait(job)
97
+ try:
98
+ job.result()
99
+ response = job.outputs()[-1]
100
+ await message.reply(truncate_response(response))
101
+ except QueueError:
102
+ await message.reply(
103
+ "The gradio space powering this bot is really busy! Please try again later!"
104
+ )
105
+
106
+ except Exception as e:
107
+ print(f"Error: {e}")
108
+
109
+
110
+ @bot.event
111
+ async def on_message(message):
112
+ """Continue the chat"""
113
+ try:
114
+ if not message.author.bot:
115
+ if message.channel.id in thread_to_user:
116
+ if thread_to_user[message.channel.id] == message.author.id:
117
+ await continue_chat(message)
118
+ else:
119
+ await bot.process_commands(message)
120
+
121
+ except Exception as e:
122
+ print(f"Error: {e}")
123
+
124
+
125
+ # running in thread
126
+ def run_bot():
127
+ if not DISCORD_TOKEN:
128
+ print("DISCORD_TOKEN NOT SET")
129
+ event.set()
130
+ else:
131
+ bot.run(DISCORD_TOKEN)
132
+
133
+
134
+ threading.Thread(target=run_bot).start()
135
+
136
+ event.wait()
137
+
138
+ if not DISCORD_TOKEN:
139
+ welcome_message = """
140
+
141
+ ## You have not specified a DISCORD_TOKEN, which means you have not created a bot account. Please follow these steps:
142
+
143
+ ### 1. Go to https://discord.com/developers/applications and click 'New Application'
144
+
145
+ ### 2. Give your bot a name 🤖
146
+
147
+ ![](https://gradio-builds.s3.amazonaws.com/demo-files/discordbots/BotName.png)
148
+
149
+ ## 3. In Settings > Bot, click the 'Reset Token' button to get a new token. Write it down and keep it safe 🔐
150
+
151
+ ![](https://gradio-builds.s3.amazonaws.com/demo-files/discordbots/ResetToken.png)
152
+
153
+ ## 4. Optionally make the bot public if you want anyone to be able to add it to their servers
154
+
155
+ ## 5. Scroll down and enable 'Message Content Intent' under 'Priviledged Gateway Intents'
156
+
157
+ ![](https://gradio-builds.s3.amazonaws.com/demo-files/discordbots/MessageContentIntent.png)
158
+
159
+ ## 6. Save your changes!
160
+
161
+ ## 7. The token from step 3 is the DISCORD_TOKEN. Rerun the deploy_discord command, e.g client.deploy_discord(discord_bot_token=DISCORD_TOKEN, ...), or add the token as a space secret manually.
162
+ """
163
+ else:
164
+ permissions = Permissions(326417525824)
165
+ url = oauth_url(bot.user.id, permissions=permissions)
166
+ welcome_message = f"""
167
+ ## Add this bot to your server by clicking this link:
168
+
169
+ {url}
170
+
171
+ ## How to use it?
172
+
173
+ The bot can be triggered via `/chat` followed by your text prompt.
174
+
175
+ This will create a thread with the bot's response to your text prompt.
176
+ You can reply in the thread (without `/chat`) to continue the conversation.
177
+ In the thread, the bot will only reply to the original author of the command.
178
+
179
+ ⚠️ Note ⚠️: Please make sure this bot's command does have the same name as another command in your server.
180
+
181
+ ⚠️ Note ⚠️: Bot commands do not work in DMs with the bot as of now.
182
+ """
183
+
184
+
185
+ with gr.Blocks() as demo:
186
+ gr.Markdown(
187
+ f"""
188
+ # Discord bot of https://organika-merlin-chat-demo.hf.space
189
+ {welcome_message}
190
+ """
191
+ )
192
+
193
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ discord.py==2.3.1