feat(message): add support for 2000+ charachter messages
This commit is contained in:
parent
135021a444
commit
8244ee95c9
@ -56,7 +56,7 @@ The bot can be configured by setting the following environment variables:
|
|||||||
- `ADMIN_ID`: The Discord ID of the admin user. This user will have the ability to reset the chat.
|
- `ADMIN_ID`: The Discord ID of the admin user. This user will have the ability to reset the chat.
|
||||||
- `CHAT_CHANNEL_ID`: The Discord ID of the specific channel where the bot will chat. Leave this empty to allow the bot to chat in all channels. (default is empty)
|
- `CHAT_CHANNEL_ID`: The Discord ID of the specific channel where the bot will chat. Leave this empty to allow the bot to chat in all channels. (default is empty)
|
||||||
- `BOT_NAME`: The name of the bot. This is used for the bot to recognize when it is mentioned in a message.
|
- `BOT_NAME`: The name of the bot. This is used for the bot to recognize when it is mentioned in a message.
|
||||||
- `CHAT_MAX_LENGTH`: The maximum length of the chat history to store in Redis. This is used to limit the amount of memory used by the bot.
|
- `CHAT_MAX_LENGTH`: The maximum length of the chat history to store in Redis. This is used to limit the amount of memory used by the bot. (default is 500 messages)
|
||||||
- `CTX`: The context length for the Ollama API. This determines how much of the chat history the bot will consider when generating a response.
|
- `CTX`: The context length for the Ollama API. This determines how much of the chat history the bot will consider when generating a response.
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|||||||
79
bot.py
79
bot.py
@ -21,28 +21,78 @@ class DiscordResponse:
|
|||||||
self.channel = message.channel
|
self.channel = message.channel
|
||||||
|
|
||||||
self.r = None
|
self.r = None
|
||||||
self.sb = io.StringIO()
|
|
||||||
|
|
||||||
async def write(self, message, s, end=''):
|
async def write(self, message, s, end=''):
|
||||||
if self.sb.seek(0, io.SEEK_END) + len(s) + len(end) > 2000:
|
|
||||||
self.r = None
|
|
||||||
self.sb.seek(0, io.SEEK_SET)
|
|
||||||
self.sb.truncate()
|
|
||||||
|
|
||||||
self.sb.write(s)
|
value = self.sanitize(s)
|
||||||
|
|
||||||
value = self.sb.getvalue().strip()
|
|
||||||
if not value:
|
if not value:
|
||||||
logging.info('Empty response, not sending')
|
logging.info('Empty response, not sending')
|
||||||
value = '*I don\'t have anything to say.*'
|
value = '*I don\'t have anything to say.*'
|
||||||
|
|
||||||
self.r = await self.channel.send(self.sanitize(value), reference=message)
|
# Reply with multiple messages if the response is too long. The first one should reference the original message.
|
||||||
|
i = 0
|
||||||
|
if len(value) >= 2000:
|
||||||
|
done = False
|
||||||
|
referenced = False
|
||||||
|
message_remaining = value
|
||||||
|
|
||||||
|
while not done:
|
||||||
|
i += 1
|
||||||
|
if i > 10:
|
||||||
|
logging.info('Too many chunks, stopping')
|
||||||
|
break
|
||||||
|
|
||||||
|
# Find the last newline before the 2000 character limit
|
||||||
|
split_index = message_remaining.rfind('\n', 0, 2000)
|
||||||
|
|
||||||
|
# If there's no newline, just split at the 2000 character limit
|
||||||
|
if split_index == -1:
|
||||||
|
split_index = 2000
|
||||||
|
logging.info('Splitting at 2000 characters - no newline found')
|
||||||
|
|
||||||
|
if len(message_remaining) <= 2000:
|
||||||
|
split_index = len(message_remaining)
|
||||||
|
|
||||||
|
# Get the chunk to send
|
||||||
|
logging.info('Sending chunk of length %s, of %s', len(message_remaining[:split_index]), len(message_remaining))
|
||||||
|
chunk_to_send = message_remaining[:split_index]
|
||||||
|
|
||||||
|
if len(chunk_to_send) == 0 and len(message_remaining) > 0 and len(message_remaining) <= 2000:
|
||||||
|
chunk_to_send = message_remaining
|
||||||
|
done = True
|
||||||
|
if len(chunk_to_send) == 0:
|
||||||
|
done = True
|
||||||
|
logging.info('Empty chunk, stopping')
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Send the chunk here
|
||||||
|
if not referenced:
|
||||||
|
self.r = await self.channel.send(chunk_to_send, reference=message)
|
||||||
|
referenced = True
|
||||||
|
else:
|
||||||
|
await self.channel.send(chunk_to_send)
|
||||||
|
|
||||||
|
# Update the remaining message
|
||||||
|
message_remaining = message_remaining[split_index:]
|
||||||
|
|
||||||
|
# If there's nothing left to send, we're done
|
||||||
|
if len(message_remaining) == 0:
|
||||||
|
done = True
|
||||||
|
logging.info('No more message to send')
|
||||||
|
break
|
||||||
|
|
||||||
|
# Wait a bit to avoid rate limiting
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
|
else:
|
||||||
|
await self.channel.send(value, reference=message)
|
||||||
|
|
||||||
def sanitize(self, s):
|
def sanitize(self, message):
|
||||||
step1 = s.replace('@everyone', '@\u200beveryone').replace('@here', '@\u200bhere')
|
stripped = message.strip()
|
||||||
step2 = discord.utils.escape_mentions(step1)
|
non_mentioned = stripped.replace('@everyone', '@\u200beveryone').replace('@here', '@\u200bhere')
|
||||||
|
escaped = discord.utils.escape_mentions(non_mentioned)
|
||||||
|
|
||||||
return step2
|
return escaped
|
||||||
|
|
||||||
|
|
||||||
class Bot:
|
class Bot:
|
||||||
@ -166,7 +216,8 @@ class Bot:
|
|||||||
|
|
||||||
# Write response
|
# Write response
|
||||||
# Truncate response if too long
|
# Truncate response if too long
|
||||||
await r.write(message, response[:2000])
|
await r.write(message, response)
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error('Error sending response: %s', e)
|
logging.error('Error sending response: %s', e)
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user