/** * @typedef {{ current: number, total: number, file: File }} BatchProgress */ /** * Run gallery identify sequentially over multiple files with progress, cancel, and per-file failure continuation. * * @param {File[] | FileList | Iterable} files * @param {(file: File) => Promise} identifyFn * @param {{ * onProgress?: (progress: BatchProgress) => void, * onFileSuccess?: (payload: { file: File, index: number }) => void, * onFileError?: (payload: { file: File, index: number, error: unknown }) => void, * cancelRef?: { current: boolean }, * }} [options] * @returns {Promise<{ results: Array<{ file: File, ok: true } | { file: File, ok: false, error: unknown }>, cancelled: boolean }>} */ export async function runSequentialGalleryIdentify(files, identifyFn, options = {}) { const { onProgress, onFileSuccess, onFileError, cancelRef = { current: false }, } = options; const list = Array.from(files || []); const total = list.length; const results = []; for (let i = 0; i < list.length; i++) { if (cancelRef.current) break; const file = list[i]; onProgress?.({ current: i + 1, total, file }); try { await identifyFn(file); results.push({ file, ok: true }); onFileSuccess?.({ file, index: i }); } catch (error) { results.push({ file, ok: false, error }); onFileError?.({ file, index: i, error }); } } return { results, cancelled: cancelRef.current }; }