feat: optimize scan flow with WebP compression and fix admin metrics visibility
This commit is contained in:
80
src/utils/image-processing.ts
Normal file
80
src/utils/image-processing.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import imageCompression from 'browser-image-compression';
|
||||
|
||||
/**
|
||||
* Interface for the processed image result
|
||||
*/
|
||||
export interface ProcessedImage {
|
||||
file: File; // The compressed WebP file (ready for Supabase storage)
|
||||
base64: string; // The Base64 string (ready for LLM API calls)
|
||||
originalFile: File; // Pass through the original file
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a File or Blob object to a Base64 string.
|
||||
*
|
||||
* @param file - The file or blob to convert
|
||||
* @returns A promise that resolves to the Base64 string
|
||||
*/
|
||||
export function fileToBase64(file: File | Blob): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
if (typeof reader.result === 'string') {
|
||||
resolve(reader.result);
|
||||
} else {
|
||||
reject(new Error('Failed to convert file to Base64 string'));
|
||||
}
|
||||
};
|
||||
reader.onerror = (error) => reject(error);
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an image file for AI analysis and storage.
|
||||
*
|
||||
* Logic:
|
||||
* 1. Resize to max 1024x1024 (maintains aspect ratio)
|
||||
* 2. Convert to WebP format
|
||||
* 3. Limit file size to approx 0.4MB
|
||||
* 4. Uses WebWorker to prevent UI freezing
|
||||
*
|
||||
* @param file - The raw File object from an HTML input
|
||||
* @returns A promise that resolves to a ProcessedImage object
|
||||
*/
|
||||
export async function processImageForAI(file: File): Promise<ProcessedImage> {
|
||||
const options = {
|
||||
maxSizeMB: 0.4,
|
||||
maxWidthOrHeight: 1024,
|
||||
useWebWorker: true,
|
||||
fileType: 'image/webp'
|
||||
};
|
||||
|
||||
try {
|
||||
console.log(`[processImageForAI] Original size: ${(file.size / 1024 / 1024).toFixed(2)} MB`);
|
||||
|
||||
// Compress the image
|
||||
const compressedBlob = await imageCompression(file, options);
|
||||
|
||||
// Create a new File object from the compressed Blob with .webp extension
|
||||
const compressedFile = new File(
|
||||
[compressedBlob],
|
||||
file.name.replace(/\.[^/.]+$/, "") + ".webp",
|
||||
{ type: 'image/webp' }
|
||||
);
|
||||
|
||||
console.log(`[processImageForAI] Compressed size: ${(compressedFile.size / 1024 / 1024).toFixed(2)} MB`);
|
||||
|
||||
// Convert to Base64 for AI API calls
|
||||
const base64 = await fileToBase64(compressedFile);
|
||||
|
||||
return {
|
||||
file: compressedFile,
|
||||
base64,
|
||||
originalFile: file
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[processImageForAI] Error processing image:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user