fix(moderation): fix image attachment pipeline causing PIL BadRequestError on NVIDIA inference

Three-layer defect chain causing 'cannot identify image file <_io.BytesIO object>':

1. attachmentUploader: hardcoded 'application/octet-stream' on Tele CDN upload
   regardless of actual file MIME type — CDN stored images under wrong type.

2. messageCapture: processAttachmentUpload call site never forwarded
   attachment.contentType into the options bag, so the fix in (1) would
   have received undefined and fallen back to octet-stream anyway.

3. llmModerationClient: blindly trusted att.type from the DB record
   (Discord-provided MIME) when constructing data: URLs, but validated
   neither the HTTP status of the CDN re-fetch nor the actual byte content.
   Stale/expired CDN URLs returning HTML error pages were base64-encoded
   and sent to the model as 'image/jpeg', causing PIL to reject the stream.

Fixes:
- uploadAttachmentToTele now accepts contentType param (defaults to
  application/octet-stream for non-image files)
- processAttachmentUpload options bag gains optional contentType field
- messageCapture forwards attachment.contentType at the call site
- Added sniffImageMimeType() using magic-byte probes for JPEG, PNG, GIF,
  WebP, AVIF/HEIF — runs on every downloaded attachment buffer before
  base64 encoding; skips the attachment (logs headerHex for diagnosis)
  if bytes don't match a known image format
- data: URL now uses the sniffed MIME type, not the DB record
This commit is contained in:
MythEclipse
2026-05-21 23:44:18 +07:00
parent d76549f94a
commit d0e906763e
3 changed files with 118 additions and 7 deletions
+1
View File
@@ -144,6 +144,7 @@ export async function captureMessage(
attachment.url,
attachment.name || "unknown",
{
contentType: attachment.contentType ?? undefined,
refreshDiscordUrl: async () => {
const freshMessage = await message.channel.messages.fetch(
message.id,