-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbot.py
221 lines (171 loc) · 8.43 KB
/
bot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# bot.py
import discord
from discord.ext import commands
import asyncio
import random
import logging
from datetime import datetime, timedelta , timezone
from get_response import general, askl
from config import discord_token, help_txt
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class LBot(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.message_content = True
intents.messages = True
intents.members = True # Enable member intents
super().__init__(command_prefix="!L", intents=intents)
self.message_history = {}
self.user_states = {} # Track user interaction states
self.last_interaction = {} # Track timing of interactions
async def setup_hook(self):
# Add background task
self.bg_task = self.loop.create_task(self.periodic_presence_update())
async def periodic_presence_update(self):
"""Updates bot's presence with L-like status messages"""
await self.wait_until_ready()
presence_messages = [
"Calculating probabilities...",
"Observing human behavior",
"Analyzing patterns",
"Eating sweets",
f"Solving cases ({len(self.guilds)} servers)",
]
while not self.is_closed():
status = random.choice(presence_messages)
await self.change_presence(activity=discord.Game(name=status))
await asyncio.sleep(300) # Change every 5 minutes
def memory_management(self, author_id):
"""Enhanced memory management with time-based cleanup"""
if author_id not in self.message_history:
self.message_history[author_id] = []
# Keep only messages from last 24 hours and maximum 15 messages
current_time = datetime.now()
self.message_history[author_id] = [
msg for msg in self.message_history[author_id][-15:]
if current_time - msg.get('timestamp', current_time) < timedelta(hours=24)
]
async def get_typing_delay(self, message_length):
"""Simulate realistic typing delays based on message length"""
base_delay = 1
char_delay = message_length * 0.02 # 20ms per character
return min(base_delay + char_delay, 5) # Cap at 5 seconds
bot = LBot()
@bot.event
async def on_ready():
print(f'Detective L is online. Logged in as {bot.user}')
print(f'Connected to {len(bot.guilds)} servers')
@bot.event
async def on_message(message):
if message.author == bot.user:
return
# Add quirky reactions randomly (1% chance)
if random.random() < 0.01:
reactions = ['🍰', '🍬', '🔍', '🤔', '📝']
await message.add_reaction(random.choice(reactions))
if bot.user.mention in message.content or bot.user in message.mentions or message.guild is None:
# Add typing indicator
async with message.channel.typing():
if message.author.id not in bot.message_history:
bot.message_history[message.author.id] = []
# Store message with timestamp
bot.message_history[message.author.id].append({
'content': f'{message.author.global_name}: {message.content}',
'timestamp': datetime.now()
})
bot.memory_management(message.author.id)
# Get history content for AI
history_content = [msg['content'] for msg in bot.message_history[message.author.id]]
ai_reply = await general(history_content)
if ai_reply:
bot.message_history[message.author.id].append({
'content': f"L: {ai_reply}",
'timestamp': datetime.now()
})
# Add realistic typing delay
delay = await bot.get_typing_delay(len(ai_reply))
await asyncio.sleep(delay)
await message.reply(ai_reply)
await bot.process_commands(message)
@bot.command(name="analyze")
@commands.cooldown(1, 30, commands.BucketType.user) # Rate limit: 1 use per 30 seconds per user
async def analyze(ctx, *, question):
async with ctx.channel.typing():
messages = [message async for message in ctx.channel.history(limit=20)]
# Format history with timestamps
chat_history = []
for message in messages:
formatted_time = message.created_at.strftime("%H:%M:%S")
chat_history.append(f"[{formatted_time}] {message.author.name}: {message.content}")
prompt_with_history = (
f"Chat History:\n{'-' * 40}\n" +
"\n".join(reversed(chat_history)) +
f"\n{'-' * 40}\nQuestion for analysis: {question}\n\n"
)
ai_response = await askl(prompt_with_history)
# Add realistic typing delay
delay = await bot.get_typing_delay(len(ai_response))
await asyncio.sleep(delay)
await ctx.reply(ai_response)
@bot.command(name="deduce")
async def deduce(ctx, member: discord.Member = None):
"""L attempts to make deductions about a server member"""
logger.info(f"Deduce command called by {ctx.author} for target {'self' if member is None else member}")
try:
# If no member is specified or member lookup fails, use the author
target_member = member or ctx.author
logger.info(f"Analyzing member: {target_member}")
async with ctx.channel.typing():
# Basic user information we can access
created_at = target_member.created_at
account_age = (datetime.now(timezone.utc) - created_at).days
roles = [role.name for role in target_member.roles if role.name != "@everyone"]
logger.info(f"Collected data - Account age: {account_age}, Roles: {roles}")
# Craft the prompt
deduction_prompt = f"""
Subject Analysis Required:
Observable Data:
- Identity: {target_member.display_name}
- Account Age: {account_age} days
- Roles: {', '.join(roles)}
- Status: {str(target_member.status) if hasattr(target_member, 'status') else 'Unknown'}
As L, provide a short but insightful deduction about this user. Focus on subtle patterns and unexpected connections. Be mysterious and slightly unsettling, but avoid being hostile.
"""
logger.info("Sending prompt to AI")
try:
# Get AI response with timeout
ai_response = await askl(deduction_prompt)
logger.info("Received AI response")
# Add dramatic pause
await asyncio.sleep(1.5)
# Format and send response
formatted_response = f"I am going to adjust my siting position while analyzing {target_member.display_name}*\n\n{ai_response}"
await ctx.reply(formatted_response)
except Exception as e:
logger.error(f"Error in AI response generation: {str(e)}")
await ctx.reply("*stares at monitor* The probability of a successful analysis has decreased significantly...")
except discord.errors.Forbidden as e:
logger.error(f"Permission error: {str(e)}")
await ctx.reply("*frowns* I lack the necessary permissions to observe this subject.")
except Exception as e:
logger.error(f"Unexpected error in deduce command: {str(e)}")
await ctx.reply(f"*nibbles on candy* Something unexpected has occurred. This is... intriguing.")
@bot.event
async def on_command_error(ctx, error):
if isinstance(error, commands.CommandNotFound):
await ctx.reply(help_txt)
elif isinstance(error, commands.CommandOnCooldown):
remaining = round(error.retry_after)
await ctx.reply(f"Your eagerness is... interesting. Wait {remaining} seconds.")
@bot.command(name="clear_history")
async def clear_history(ctx):
user_id = ctx.author.id
if user_id in bot.message_history:
bot.message_history[user_id] = []
await ctx.send("*arranges sugar cubes while erasing our conversation history*")
@bot.command(name="helpme")
async def lhelp(ctx):
await ctx.reply(help_txt)
# Run the bot
bot.run(discord_token)