Add image/GIF sending support in bot responses
- Extract image URLs from AI responses - Send images as Discord embeds - Support standalone URLs and markdown image syntax - Clean image URLs from text to avoid duplication - Handle multiple images in a single response
This commit is contained in:
@@ -105,18 +105,99 @@ class AIChatCog(commands.Cog):
|
||||
try:
|
||||
response_text = await self._generate_response(message, content)
|
||||
|
||||
# Split and send response
|
||||
chunks = split_message(response_text)
|
||||
await message.reply(chunks[0])
|
||||
# Extract image URLs and clean response text
|
||||
text_content, image_urls = self._extract_image_urls(response_text)
|
||||
|
||||
# Split and send response
|
||||
chunks = split_message(text_content) if text_content.strip() else []
|
||||
|
||||
# Send first chunk as reply (or just images if no text)
|
||||
if chunks:
|
||||
first_embed = self._create_image_embed(image_urls[0]) if image_urls else None
|
||||
await message.reply(chunks[0], embed=first_embed)
|
||||
remaining_images = image_urls[1:] if image_urls else []
|
||||
elif image_urls:
|
||||
# Only images, no text
|
||||
await message.reply(embed=self._create_image_embed(image_urls[0]))
|
||||
remaining_images = image_urls[1:]
|
||||
else:
|
||||
await message.reply("I don't have a response for that.")
|
||||
return
|
||||
|
||||
# Send remaining text chunks
|
||||
for chunk in chunks[1:]:
|
||||
await message.channel.send(chunk)
|
||||
|
||||
# Send remaining images as separate embeds
|
||||
for img_url in remaining_images:
|
||||
await message.channel.send(embed=self._create_image_embed(img_url))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Mention response error: {e}", exc_info=True)
|
||||
error_message = self._get_error_message(e)
|
||||
await message.reply(error_message)
|
||||
|
||||
def _extract_image_urls(self, text: str) -> tuple[str, list[str]]:
|
||||
"""Extract image URLs from text and return cleaned text with URLs.
|
||||
|
||||
Args:
|
||||
text: The response text that may contain image URLs
|
||||
|
||||
Returns:
|
||||
Tuple of (cleaned text, list of image URLs)
|
||||
"""
|
||||
# Pattern to match image URLs (common formats)
|
||||
image_extensions = r"\.(png|jpg|jpeg|gif|webp|bmp)"
|
||||
url_pattern = rf"(https?://[^\s<>\"\')]+{image_extensions}(?:\?[^\s<>\"\')]*)?)"
|
||||
|
||||
# Find all image URLs
|
||||
image_urls = re.findall(url_pattern, text, re.IGNORECASE)
|
||||
# The findall returns tuples when there are groups, extract full URLs
|
||||
image_urls = re.findall(
|
||||
rf"https?://[^\s<>\"\')]+{image_extensions}(?:\?[^\s<>\"\')]*)?",
|
||||
text,
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
# Also check for markdown image syntax 
|
||||
markdown_images = re.findall(r"!\[[^\]]*\]\(([^)]+)\)", text)
|
||||
for url in markdown_images:
|
||||
if url not in image_urls:
|
||||
# Check if it looks like an image URL
|
||||
if re.search(image_extensions, url, re.IGNORECASE) or "image" in url.lower():
|
||||
image_urls.append(url)
|
||||
|
||||
# Clean the text by removing standalone image URLs (but keep them if part of markdown links)
|
||||
cleaned_text = text
|
||||
for url in image_urls:
|
||||
# Remove standalone URLs (not part of markdown)
|
||||
cleaned_text = re.sub(
|
||||
rf"(?<!\()(?<!\[){re.escape(url)}(?!\))",
|
||||
"",
|
||||
cleaned_text,
|
||||
)
|
||||
# Remove markdown image syntax
|
||||
cleaned_text = re.sub(rf"!\[[^\]]*\]\({re.escape(url)}\)", "", cleaned_text)
|
||||
|
||||
# Clean up extra whitespace
|
||||
cleaned_text = re.sub(r"\n{3,}", "\n\n", cleaned_text)
|
||||
cleaned_text = cleaned_text.strip()
|
||||
|
||||
return cleaned_text, image_urls
|
||||
|
||||
def _create_image_embed(self, image_url: str) -> discord.Embed:
|
||||
"""Create a Discord embed with an image.
|
||||
|
||||
Args:
|
||||
image_url: The URL of the image
|
||||
|
||||
Returns:
|
||||
Discord Embed object with the image
|
||||
"""
|
||||
embed = discord.Embed()
|
||||
embed.set_image(url=image_url)
|
||||
return embed
|
||||
|
||||
def _get_error_message(self, error: Exception) -> str:
|
||||
"""Get a user-friendly error message based on the exception type.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user