mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Gemini: store compressed images. Save 80% at 98% quality (png -> webp)
This commit is contained in:
@@ -54,6 +54,8 @@ export async function getImageDimensions(base64DataUrl: string): Promise<{ width
|
||||
export async function convertBase64Image(base64DataUrl: string, destMimeType: string /*= 'image/webp'*/, destQuality: number /*= 0.90*/): Promise<{
|
||||
mimeType: string,
|
||||
base64: string,
|
||||
width: number,
|
||||
height: number,
|
||||
}> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new Image();
|
||||
@@ -75,6 +77,8 @@ export async function convertBase64Image(base64DataUrl: string, destMimeType: st
|
||||
resolve({
|
||||
mimeType: actualMimeType,
|
||||
base64: base64Data,
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn(`imageUtils: failed to convert image to ${destMimeType}.`, { error });
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { addDBImageAsset } from '~/modules/dblobs/dblobs.images';
|
||||
|
||||
import type { MaybePromise } from '~/common/types/useful.types';
|
||||
import { DEFAULT_ADRAFT_IMAGE_MIMETYPE } from '~/common/attachment-drafts/attachment.pipeline';
|
||||
import { convertBase64Image, getImageDimensions } from '~/common/util/imageUtils';
|
||||
import { create_CodeExecutionInvocation_ContentFragment, create_CodeExecutionResponse_ContentFragment, create_FunctionCallInvocation_ContentFragment, createAnnotationsVoidFragment, createDMessageDataRefDBlob, createDVoidWebCitation, createErrorContentFragment, createImageContentFragment, createModelAuxVoidFragment, createTextContentFragment, DVoidModelAuxPart, isContentFragment, isModelAuxPart, isTextContentFragment, isVoidAnnotationsFragment, isVoidFragment } from '~/common/stores/chat/chat.fragments';
|
||||
import { ellipsizeMiddle } from '~/common/util/textUtils';
|
||||
import { getImageDimensions } from '~/common/util/imageUtils';
|
||||
import { metricsFinishChatGenerateLg, metricsPendChatGenerateLg } from '~/common/stores/metrics/metrics.chatgenerate';
|
||||
import { presentErrorToHumans } from '~/common/util/errorUtils';
|
||||
|
||||
@@ -16,6 +17,8 @@ import { AixChatGenerateContent_LL, DEBUG_PARTICLES } from './aix.client';
|
||||
|
||||
|
||||
// configuration
|
||||
const GENERATED_IMAGES_CONVERT_TO_COMPRESSED = true; // converts PNG to WebP or JPEG to save IndexedDB space
|
||||
const GENERATED_IMAGES_COMPRESSION_QUALITY = 0.98;
|
||||
const ELLIPSIZE_DEV_ISSUE_MESSAGES = 4096;
|
||||
const MERGE_ISSUES_INTO_TEXT_PART_IF_OPEN = true;
|
||||
|
||||
@@ -373,15 +376,36 @@ export class ContentReassembler {
|
||||
// Break text accumulation, as we have a full image part in the middle
|
||||
this.currentTextFragmentIndex = null;
|
||||
|
||||
const { mimeType, i_b64: base64Data, label } = particle;
|
||||
let { mimeType, i_b64: base64Data, label, generator, prompt } = particle;
|
||||
const safeLabel = label || 'Generated Image';
|
||||
|
||||
try {
|
||||
|
||||
let safeWidth;
|
||||
let safeHeight;
|
||||
|
||||
// TODO: re-evaluate conversion-before-storage (quality is 0.98 and WebP is really optimized, but still, this is not the 'original' data)
|
||||
// PNG -> conversion to WebP or JPEG to save IndexedDB space - will
|
||||
if (GENERATED_IMAGES_CONVERT_TO_COMPRESSED && mimeType === 'image/png') {
|
||||
const preSize = base64Data.length;
|
||||
const convertedData = await convertBase64Image(`data:${mimeType};base64,${base64Data}`, DEFAULT_ADRAFT_IMAGE_MIMETYPE, GENERATED_IMAGES_COMPRESSION_QUALITY).catch(() => null);
|
||||
if (convertedData) {
|
||||
mimeType = convertedData.mimeType;
|
||||
base64Data = convertedData.base64;
|
||||
safeWidth = convertedData.width || 0;
|
||||
safeHeight = convertedData.height || 0;
|
||||
}
|
||||
const postSize = base64Data.length;
|
||||
const sizeDiffPerc = preSize ? Math.round(((postSize - preSize) / preSize) * 100) : 0;
|
||||
console.warn(`[image-pipeline] stored generated PNG as ${mimeType} (quality:${GENERATED_IMAGES_COMPRESSION_QUALITY}, ${sizeDiffPerc}% reduction, ${preSize?.toLocaleString()} -> ${postSize?.toLocaleString()})`);
|
||||
}
|
||||
|
||||
// find out the dimensions (frontend)
|
||||
const dimensions = await getImageDimensions(`data:${mimeType};base64,${base64Data}`).catch(() => null);
|
||||
const safeWidth = dimensions?.width || 0;
|
||||
const safeHeight = dimensions?.height || 0;
|
||||
if (!safeWidth || !safeHeight) {
|
||||
const dimensions = await getImageDimensions(`data:${mimeType};base64,${base64Data}`).catch(() => null);
|
||||
safeWidth = dimensions?.width || 0;
|
||||
safeHeight = dimensions?.height || 0;
|
||||
}
|
||||
|
||||
// add the image to the DBlobs DB
|
||||
const dblobAssetId = await addDBImageAsset('global', 'app-chat', {
|
||||
@@ -393,8 +417,8 @@ export class ContentReassembler {
|
||||
origin: {
|
||||
ot: 'generated',
|
||||
source: 'ai-text-to-image',
|
||||
generatorName: '', // ?
|
||||
prompt: '', // ?
|
||||
generatorName: generator ?? '',
|
||||
prompt: prompt ?? '',
|
||||
parameters: {}, // ?
|
||||
generatedAt: new Date().toISOString(),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user