fix: enhance image reference detection and optimize image processing
- Added support for detecting file URLs in prompts using fileURLToPath for accurate path resolution. - Updated image loading logic to default to JPEG format for optimized image processing. - Improved error handling in image optimization to continue processing on failures.
This commit is contained in:
committed by
Peter Steinberger
parent
7bfc77db25
commit
8c0e290db1
@@ -1,5 +1,6 @@
|
|||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
import type { ImageContent } from "@mariozechner/pi-ai";
|
import type { ImageContent } from "@mariozechner/pi-ai";
|
||||||
|
|
||||||
@@ -119,6 +120,18 @@ export function detectImageReferences(prompt: string): DetectedImageRef[] {
|
|||||||
refs.push({ raw, type: "url", resolved: raw });
|
refs.push({ raw, type: "url", resolved: raw });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pattern for file:// URLs - treat as paths since loadWebMedia handles them
|
||||||
|
const fileUrlPattern =
|
||||||
|
/file:\/\/[^\s<>"'`\]]+\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif)/gi;
|
||||||
|
while ((match = fileUrlPattern.exec(prompt)) !== null) {
|
||||||
|
const raw = match[0];
|
||||||
|
if (seen.has(raw.toLowerCase())) continue;
|
||||||
|
seen.add(raw.toLowerCase());
|
||||||
|
// Use fileURLToPath for proper handling (e.g., file://localhost/path)
|
||||||
|
const resolved = fileURLToPath(raw);
|
||||||
|
refs.push({ raw, type: "path", resolved });
|
||||||
|
}
|
||||||
|
|
||||||
// Pattern for file paths (absolute, relative, or home)
|
// Pattern for file paths (absolute, relative, or home)
|
||||||
// Matches:
|
// Matches:
|
||||||
// - /absolute/path/to/file.ext (including paths with special chars like Messages/Attachments)
|
// - /absolute/path/to/file.ext (including paths with special chars like Messages/Attachments)
|
||||||
@@ -127,8 +140,8 @@ export function detectImageReferences(prompt: string): DetectedImageRef[] {
|
|||||||
// - ~/home/path.ext
|
// - ~/home/path.ext
|
||||||
const pathPattern = /(?:^|\s|["'`(])((\.\.?\/|[~/])[^\s"'`()[\]]*\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif))/gi;
|
const pathPattern = /(?:^|\s|["'`(])((\.\.?\/|[~/])[^\s"'`()[\]]*\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif))/gi;
|
||||||
while ((match = pathPattern.exec(prompt)) !== null) {
|
while ((match = pathPattern.exec(prompt)) !== null) {
|
||||||
const raw = match[1] || match[0];
|
// Use capture group 1 (the path without delimiter prefix); skip if undefined
|
||||||
addPathRef(raw);
|
if (match[1]) addPathRef(match[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return refs;
|
return refs;
|
||||||
@@ -205,7 +218,8 @@ export async function loadImageFromRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXIF orientation is already normalized by loadWebMedia -> resizeToJpeg
|
// EXIF orientation is already normalized by loadWebMedia -> resizeToJpeg
|
||||||
const mimeType = media.contentType ?? "image/png";
|
// Default to JPEG since optimization converts images to JPEG format
|
||||||
|
const mimeType = media.contentType ?? "image/jpeg";
|
||||||
const data = media.buffer.toString("base64");
|
const data = media.buffer.toString("base64");
|
||||||
|
|
||||||
return { type: "image", data, mimeType };
|
return { type: "image", data, mimeType };
|
||||||
|
|||||||
@@ -161,23 +161,27 @@ export async function optimizeImageToJpeg(
|
|||||||
|
|
||||||
for (const side of sides) {
|
for (const side of sides) {
|
||||||
for (const quality of qualities) {
|
for (const quality of qualities) {
|
||||||
const out = await resizeToJpeg({
|
try {
|
||||||
buffer,
|
const out = await resizeToJpeg({
|
||||||
maxSide: side,
|
buffer,
|
||||||
quality,
|
maxSide: side,
|
||||||
withoutEnlargement: true,
|
|
||||||
});
|
|
||||||
const size = out.length;
|
|
||||||
if (!smallest || size < smallest.size) {
|
|
||||||
smallest = { buffer: out, size, resizeSide: side, quality };
|
|
||||||
}
|
|
||||||
if (size <= maxBytes) {
|
|
||||||
return {
|
|
||||||
buffer: out,
|
|
||||||
optimizedSize: size,
|
|
||||||
resizeSide: side,
|
|
||||||
quality,
|
quality,
|
||||||
};
|
withoutEnlargement: true,
|
||||||
|
});
|
||||||
|
const size = out.length;
|
||||||
|
if (!smallest || size < smallest.size) {
|
||||||
|
smallest = { buffer: out, size, resizeSide: side, quality };
|
||||||
|
}
|
||||||
|
if (size <= maxBytes) {
|
||||||
|
return {
|
||||||
|
buffer: out,
|
||||||
|
optimizedSize: size,
|
||||||
|
resizeSide: side,
|
||||||
|
quality,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Continue trying other size/quality combinations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user