Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions benchmarks/add-media-modal-upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { performance } from 'perf_hooks';

// Simulated delays
const FILE_TO_DATA_URL_DELAY = 10;
const UPLOAD_API_DELAY = 100;
const MEDIA_API_DELAY = 50;

// Mock functions
async function fileToDataUrl(f) {
await new Promise(resolve => setTimeout(resolve, FILE_TO_DATA_URL_DELAY));
return 'data:image/png;base64,mockbase64';
}

function parseDataUrl(dataUrl) {
return { mimeType: 'image/png', base64: 'mockbase64' };
}

async function adminApiRequest(url, options) {
const delay = url.includes('/storage/upload') ? UPLOAD_API_DELAY : MEDIA_API_DELAY;
await new Promise(resolve => setTimeout(resolve, delay));
return {
ok: true,
json: async () => ({
viewUrl: 'http://example.com/image.png',
id: 'mock-id'
})
};
}

// Current sequential implementation
async function uploadFileAndRecordSequential(files) {
const createdItems = [];
for (const f of files) {
const dataUrl = await fileToDataUrl(f);
const { mimeType, base64 } = parseDataUrl(dataUrl);
const uploadRes = await adminApiRequest('/api/admin/storage/upload', {
method: 'POST',
body: JSON.stringify({ mimeType, dataBase64: base64, filename: f.name || 'image.png' })
});
const uploaded = await uploadRes.json();

const mediaRes = await adminApiRequest('/api/admin/media', {
method: 'POST',
body: JSON.stringify({
url: uploaded.viewUrl || uploaded.downloadUrl,
source: 'storage',
filename: f.name || 'image',
mimeType: mimeType,
})
});
const saved = await mediaRes.json();
createdItems.push(saved);
}
return createdItems;
}

// Optimized parallel implementation
async function uploadFileAndRecordParallel(files) {
return Promise.all(files.map(async (f) => {
const dataUrl = await fileToDataUrl(f);
const { mimeType, base64 } = parseDataUrl(dataUrl);
const uploadRes = await adminApiRequest('/api/admin/storage/upload', {
method: 'POST',
body: JSON.stringify({ mimeType, dataBase64: base64, filename: f.name || 'image.png' })
});
const uploaded = await uploadRes.json();

const mediaRes = await adminApiRequest('/api/admin/media', {
method: 'POST',
body: JSON.stringify({
url: uploaded.viewUrl || uploaded.downloadUrl,
source: 'storage',
filename: f.name || 'image',
mimeType: mimeType,
})
});
return await mediaRes.json();
}));
}

async function runBenchmark() {
const files = [
{ name: 'file1.png' },
{ name: 'file2.png' },
{ name: 'file3.png' },
{ name: 'file4.png' },
{ name: 'file5.png' },
];

console.log(`Running benchmark with ${files.length} files...`);

const startSeq = performance.now();
await uploadFileAndRecordSequential(files);
const endSeq = performance.now();
const seqTime = endSeq - startSeq;
console.log(`Sequential implementation: ${seqTime.toFixed(2)}ms`);

const startPar = performance.now();
await uploadFileAndRecordParallel(files);
const endPar = performance.now();
const parTime = endPar - startPar;
console.log(`Parallel implementation: ${parTime.toFixed(2)}ms`);

const improvement = ((seqTime - parTime) / seqTime) * 100;
console.log(`Improvement: ${improvement.toFixed(2)}%`);

// Theoretical sequential time: 5 * (10 + 100 + 50) = 800ms
// Theoretical parallel time: 1 * (10 + 100 + 50) = 160ms
}

runBenchmark().catch(console.error);
20 changes: 10 additions & 10 deletions src/components/admin/AddMediaModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ export default function AddMediaModal({ open, onClose, onCreated }) {
setUploading(true)
setError('')
try {
const createdItems = []
for (const f of files) {
const createdItems = await Promise.all(files.map(async (f) => {
const dataUrl = await fileToDataUrl(f)
const { mimeType, base64 } = parseDataUrl(dataUrl)
const uploadRes = await adminApiRequest('/api/admin/storage/upload', {
Expand All @@ -83,8 +82,8 @@ export default function AddMediaModal({ open, onClose, onCreated }) {
})
const saved = await mediaRes.json()
if (!mediaRes.ok) throw new Error(saved.error || 'Failed to save media')
createdItems.push(saved)
}
return saved
}))
onCreated?.(createdItems)
onClose?.()
} catch (e) {
Expand Down Expand Up @@ -155,17 +154,18 @@ export default function AddMediaModal({ open, onClose, onCreated }) {
setError('')
try {
// Build inputs from selected reference images (up to 3)
const inputs = []
for (const url of refUrls.slice(0, 3)) {
const inputs = (await Promise.all(refUrls.slice(0, 3).map(async (url) => {
try {
const proxied = `/api/image-proxy?src=${encodeURIComponent(url)}`
const resp = await fetch(proxied)
if (!resp.ok) continue
if (!resp.ok) return null
const blob = await resp.blob()
const { mimeType, base64 } = await blobToBase64(blob)
if (base64) inputs.push({ mimeType, dataBase64: base64 })
} catch (_) {}
}
return base64 ? { mimeType, dataBase64: base64 } : null
} catch (_) {
return null
}
}))).filter(Boolean)

const res = await adminApiRequest('/api/admin/ai/generate-image', {
method: 'POST',
Expand Down
Loading