@manifest-editor/ocr-classification 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-CwtpxPp2.d.ts → index-BdkICeQa.d.cts} +1 -3
- package/dist/index-BdkICeQa.d.cts.map +1 -0
- package/dist/{index-MMJWr93c.d.cts → index-BdkICeQa.d.ts} +1 -3
- package/dist/index-BdkICeQa.d.ts.map +1 -0
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lazy.cjs +2 -1
- package/dist/lazy.cjs.map +1 -0
- package/dist/lazy.d.cts +1 -2
- package/dist/lazy.d.cts.map +1 -1
- package/dist/lazy.d.ts +1 -2
- package/dist/lazy.d.ts.map +1 -1
- package/dist/lazy.js +1 -1
- package/dist/lazy.js.map +1 -1
- package/dist/{ocr-difficulty-9L3ewI3P.cjs → ocr-difficulty-DGBSuuaz.cjs} +2 -1
- package/dist/ocr-difficulty-DGBSuuaz.cjs.map +1 -0
- package/dist/{ocr-difficulty-CjQvA3aZ.js → ocr-difficulty-DOYyPpGw.js} +1 -1
- package/dist/ocr-difficulty-DOYyPpGw.js.map +1 -0
- package/dist/{onnx-classifier-mb_6hJ1l.js → onnx-classifier-BRRrhiwP.js} +2 -2
- package/dist/onnx-classifier-BRRrhiwP.js.map +1 -0
- package/dist/onnx-classifier-DTT3FqmF.cjs +2 -0
- package/dist/onnx-classifier-DTT3FqmF.cjs.map +1 -0
- package/dist/{plugin-Bfd4lYW9.cjs → plugin-CEC3H4Xp.cjs} +2 -1
- package/dist/plugin-CEC3H4Xp.cjs.map +1 -0
- package/dist/{plugin-Cn1QgMZa.js → plugin-CsyG04LG.js} +1 -1
- package/dist/{plugin-Cn1QgMZa.js.map → plugin-CsyG04LG.js.map} +1 -1
- package/package.json +10 -11
- package/dist/index-CwtpxPp2.d.ts.map +0 -1
- package/dist/index-MMJWr93c.d.cts.map +0 -1
- package/dist/ocr-difficulty-CjQvA3aZ.js.map +0 -1
- package/dist/onnx-classifier-CDO8vcMl.cjs +0 -1
- package/dist/onnx-classifier-mb_6hJ1l.js.map +0 -1
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { BackgroundActionDefinition, BackgroundActionRunContext, ManifestEditorTag } from "@manifest-editor/shell";
|
|
2
|
-
|
|
3
|
-
//#region rolldown:runtime
|
|
4
2
|
//#endregion
|
|
5
3
|
//#region src/plugin.d.ts
|
|
6
4
|
declare const _default: {
|
|
@@ -82,4 +80,4 @@ declare namespace index_d_exports {
|
|
|
82
80
|
declare const backgroundActions: BackgroundActionDefinition[];
|
|
83
81
|
//#endregion
|
|
84
82
|
export { selectOcrDifficulty as _, OcrCanvasClassificationSkip as a, createOcrClassificationBackgroundAction as c, OcrClassifierRun as d, OcrDifficultyClass as f, formatOcrScore as g, createOcrDifficultyTag as h, OcrCanvasClassification as i, OCR_DIFFICULTY_CLASSES as l, OcrDifficultyPrediction as m, index_d_exports as n, OcrClassificationActionDependencies as o, OcrDifficultyId as p, OCR_CLASSIFICATION_ACTION_ID as r, OcrClassificationActionResult as s, backgroundActions as t, OCR_DIFFICULTY_TAG_TYPE as u, _default as v };
|
|
85
|
-
//# sourceMappingURL=index-
|
|
83
|
+
//# sourceMappingURL=index-BdkICeQa.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BdkICeQa.d.cts","names":[],"sources":["../src/plugin.ts","../src/canvas-image.ts","../src/ocr-difficulty.ts","../src/background-action.ts","../src/index.ts"],"mappings":";;;;;;;;;;;;IAWI;IACA;;;;;KCTQ;EACV;EACA,MAAM;;;;cCHK;KAED;KAEA;EACV,IAAI;EACJ;EACA;EACA;EACA;;KAGU,0BAA0B;EACpC;;KAGU;EACV;EACA,YAAY;EACZ;;cAGW,wBAAwB;iBAwBrB,oBAAoB,QAAQ,oBAAoB;iBAwBhD,uBAAuB,YAAY,0BAA0B;iBAU7D,eAAe;;;cClElB;KAED;EACV;EACA;EACA;EACA;EACA;EACA;EACA;;KAGU;EACV;EACA;EACA;;KAGU;EACV;EACA;EACA;EACA,QAAQ;EACR,iBAAiB;EACjB,iBAAiB;;KAaP;EACV,0BAA0B;EAC1B,kBAAkB,KAAK,4BAA4B,gBAAgB,QAAQ;EAC3E,iBAAiB,OAAO,SAAS,QAAQ;;iBAG3B,wCACd,eAAc,sCACb;;;;cCzDU,mBAAmB"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { BackgroundActionDefinition, BackgroundActionRunContext, ManifestEditorTag } from "@manifest-editor/shell";
|
|
2
|
-
|
|
3
|
-
//#region rolldown:runtime
|
|
4
2
|
//#endregion
|
|
5
3
|
//#region src/plugin.d.ts
|
|
6
4
|
declare const _default: {
|
|
@@ -82,4 +80,4 @@ declare namespace index_d_exports {
|
|
|
82
80
|
declare const backgroundActions: BackgroundActionDefinition[];
|
|
83
81
|
//#endregion
|
|
84
82
|
export { selectOcrDifficulty as _, OcrCanvasClassificationSkip as a, createOcrClassificationBackgroundAction as c, OcrClassifierRun as d, OcrDifficultyClass as f, formatOcrScore as g, createOcrDifficultyTag as h, OcrCanvasClassification as i, OCR_DIFFICULTY_CLASSES as l, OcrDifficultyPrediction as m, index_d_exports as n, OcrClassificationActionDependencies as o, OcrDifficultyId as p, OCR_CLASSIFICATION_ACTION_ID as r, OcrClassificationActionResult as s, backgroundActions as t, OCR_DIFFICULTY_TAG_TYPE as u, _default as v };
|
|
85
|
-
//# sourceMappingURL=index-
|
|
83
|
+
//# sourceMappingURL=index-BdkICeQa.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BdkICeQa.d.ts","names":[],"sources":["../src/plugin.ts","../src/canvas-image.ts","../src/ocr-difficulty.ts","../src/background-action.ts","../src/index.ts"],"mappings":";;;;;;;;;;;;IAWI;IACA;;;;;KCTQ;EACV;EACA,MAAM;;;;cCHK;KAED;KAEA;EACV,IAAI;EACJ;EACA;EACA;EACA;;KAGU,0BAA0B;EACpC;;KAGU;EACV;EACA,YAAY;EACZ;;cAGW,wBAAwB;iBAwBrB,oBAAoB,QAAQ,oBAAoB;iBAwBhD,uBAAuB,YAAY,0BAA0B;iBAU7D,eAAe;;;cClElB;KAED;EACV;EACA;EACA;EACA;EACA;EACA;EACA;;KAGU;EACV;EACA;EACA;;KAGU;EACV;EACA;EACA;EACA,QAAQ;EACR,iBAAiB;EACjB,iBAAiB;;KAaP;EACV,0BAA0B;EAC1B,kBAAkB,KAAK,4BAA4B,gBAAgB,QAAQ;EAC3E,iBAAiB,OAAO,SAAS,QAAQ;;iBAG3B,wCACd,eAAc,sCACb;;;;cCzDU,mBAAmB"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,`__esModule`,{value:!0});const e=require(`./ocr-difficulty-9L3ewI3P.cjs`),t=require(`./plugin-Bfd4lYW9.cjs`),n=require(`./onnx-classifier-CDO8vcMl.cjs`);let r=require(`@iiif/helpers`),i=require(`@manifest-editor/components`),a=require(`react`),o=require(`react/jsx-runtime`);async function s(e,t){let n=c(e,t);if(!n)return null;let i=(await(0,r.createThumbnailHelper)(e.vault).getBestThumbnailAtSize(n,{width:512,height:512,maxWidth:512,maxHeight:512,unsafeImageService:!0,allowUnsafe:!0,preferFixedSize:!0},!1)).best?.id;if(!i)return null;let a=await fetch(i,{signal:e.signal});if(!a.ok)throw Error(`Unable to fetch canvas image (${a.status}).`);return{url:i,blob:await a.blob()}}function c(e,t){let n=t?.items&&e.vault.get(t.items)||[];for(let t of n){let n=t?.items&&e.vault.get(t.items)||[];for(let t of n){if(!l(t))continue;let n=u(t?.body);if(n)return e.vault.get(n)||n}}return null}function l(e){return(Array.isArray(e?.motivation)?e.motivation:[e?.motivation]).includes(`painting`)}function u(e){return Array.isArray(e)?e[0]??null:e??null}const d=`@manifest-editor/ocr-classification:results`;function f(e,t){typeof window>`u`||window.dispatchEvent(new CustomEvent(d,{detail:{actionId:e,result:x(t)?t:void 0}}))}function p(e){return(0,o.jsx)(m,{actionId:e})}function m({actionId:t}){let[n,r]=(0,a.useState)(null);(0,a.useEffect)(()=>{let e=e=>{let n=e.detail;n?.actionId===t&&r(n)};return window.addEventListener(d,e),()=>window.removeEventListener(d,e)},[t]);let s=n?.result,c=(0,a.useMemo)(()=>s?.classifications||[],[s]),l=(0,a.useMemo)(()=>s?e.t.map(e=>({...e,count:s.counts?.[e.id]||0})):[],[s]);return n?(0,o.jsx)(i.Modal,{title:`OCR classification results`,onClose:()=>r(null),className:`max-w-6xl`,children:(0,o.jsx)(`div`,{className:`flex min-h-0 flex-col gap-4 p-4 text-sm text-zinc-700`,children:s?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)(`div`,{className:`rounded border border-zinc-200 bg-white p-4`,children:[(0,o.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[(0,o.jsxs)(`div`,{className:`min-w-0`,children:[(0,o.jsx)(`div`,{className:`text-xs font-semibold uppercase text-zinc-500`,children:`Task complete`}),(0,o.jsxs)(`div`,{className:`mt-1 text-lg font-semibold text-zinc-950`,children:[`Classified `,y(s.classified),` of `,y(s.total),` canvases`]}),(0,o.jsx)(`div`,{className:`mt-1 text-sm text-zinc-500`,children:s.skipped?`${y(s.skipped)} ${s.skipped===1?`canvas was`:`canvases were`} skipped. Review the skipped list below before rerunning.`:`Every canvas was classified and tagged.`})]}),(0,o.jsxs)(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 px-3 py-2 text-right`,children:[(0,o.jsx)(`div`,{className:`text-2xl font-semibold text-zinc-950`,children:b(s.classified,s.total)}),(0,o.jsx)(`div`,{className:`text-xs uppercase text-zinc-500`,children:`Coverage`})]})]}),(0,o.jsx)(`div`,{className:`mt-4 flex h-2 overflow-hidden rounded-full bg-zinc-100`,children:s.classified?l.map(e=>e.count?(0,o.jsx)(`div`,{className:`h-full`,style:{width:`${e.count/s.classified*100}%`,backgroundColor:e.backgroundColor}},e.id):null):(0,o.jsx)(`div`,{className:`h-full w-full bg-zinc-200`})}),(0,o.jsx)(`div`,{className:`mt-3 flex flex-wrap gap-2`,children:l.map(e=>(0,o.jsxs)(`div`,{className:`inline-flex items-center gap-2 rounded border border-zinc-200 bg-zinc-50 px-2 py-1`,children:[(0,o.jsx)(`span`,{className:`h-2.5 w-2.5 rounded-full`,style:{backgroundColor:e.backgroundColor},"aria-hidden":`true`}),(0,o.jsx)(`span`,{className:`font-medium text-zinc-900`,children:e.label}),(0,o.jsxs)(`span`,{className:`text-zinc-500`,children:[y(e.count),` (`,b(e.count,s.classified),`)`]})]},e.id))})]}),(0,o.jsxs)(`div`,{className:`grid gap-2 sm:grid-cols-4`,children:[(0,o.jsx)(_,{label:`Total canvases`,value:y(s.total)}),(0,o.jsx)(_,{label:`Classified`,value:y(s.classified)}),(0,o.jsx)(_,{label:`Skipped`,value:y(s.skipped)}),(0,o.jsx)(_,{label:`Tags applied`,value:y(s.classifications.length)})]}),(0,o.jsx)(`div`,{className:`grid gap-2 sm:grid-cols-3`,children:l.map(e=>(0,o.jsxs)(`div`,{className:`rounded border border-zinc-200 bg-white p-3`,children:[(0,o.jsx)(`div`,{className:`inline-flex rounded px-2 py-1 text-xs font-medium`,style:{backgroundColor:e.backgroundColor,color:e.textColor},children:e.label}),(0,o.jsx)(`div`,{className:`mt-2 text-xl font-semibold text-zinc-950`,children:y(e.count)}),(0,o.jsxs)(`div`,{className:`mt-1 text-xs text-zinc-500`,children:[b(e.count,s.classified),` of classified canvases`]})]},e.id))}),c.length?(0,o.jsxs)(`div`,{className:`min-h-0 overflow-hidden rounded border border-zinc-200`,children:[(0,o.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2 border-b border-zinc-200 bg-zinc-50 px-3 py-2`,children:[(0,o.jsx)(`div`,{className:`font-medium text-zinc-900`,children:`Classified canvases`}),(0,o.jsxs)(`div`,{className:`text-xs text-zinc-500`,children:[`Showing all `,y(c.length),` classified results`]})]}),(0,o.jsx)(`div`,{className:`max-h-[55vh] overflow-auto`,children:(0,o.jsxs)(`table`,{className:`w-full min-w-[820px] border-collapse text-left`,children:[(0,o.jsx)(`thead`,{className:`sticky top-0 bg-white text-xs uppercase text-zinc-500`,children:(0,o.jsxs)(`tr`,{children:[(0,o.jsx)(`th`,{className:`w-14 border-b border-zinc-200 px-3 py-2 font-medium`,children:`#`}),(0,o.jsx)(`th`,{className:`border-b border-zinc-200 px-3 py-2 font-medium`,children:`Canvas`}),(0,o.jsx)(`th`,{className:`w-44 border-b border-zinc-200 px-3 py-2 font-medium`,children:`Result`}),(0,o.jsx)(`th`,{className:`w-28 border-b border-zinc-200 px-3 py-2 font-medium`,children:`Confidence`}),(0,o.jsx)(`th`,{className:`border-b border-zinc-200 px-3 py-2 font-medium`,children:`Scores`})]})}),(0,o.jsx)(`tbody`,{children:c.map((t,n)=>{let r=t.canvasLabel||t.canvasId;return(0,o.jsxs)(`tr`,{className:`border-b border-zinc-100 last:border-0`,children:[(0,o.jsx)(`td`,{className:`px-3 py-2 align-top text-xs text-zinc-400`,children:n+1}),(0,o.jsxs)(`td`,{className:`px-3 py-2 align-top`,title:t.canvasId,children:[(0,o.jsx)(`div`,{className:`font-medium text-zinc-900`,children:r}),r===t.canvasId?null:(0,o.jsx)(`div`,{className:`mt-0.5 break-all text-xs text-zinc-500`,children:t.canvasId})]}),(0,o.jsx)(`td`,{className:`px-3 py-2 align-top`,children:(0,o.jsx)(h,{tagId:t.tagId,label:t.label})}),(0,o.jsx)(`td`,{className:`px-3 py-2 align-top font-medium text-zinc-900`,children:e.i(t.score)}),(0,o.jsx)(`td`,{className:`px-3 py-2 align-top text-xs text-zinc-500`,children:(0,o.jsx)(g,{scores:t.scores})})]},t.canvasId)})})]})})]}):(0,o.jsx)(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 p-3`,children:`No canvases were classified. Check the skipped canvases and task logs for details.`}),s.skippedCanvases.length?(0,o.jsxs)(`details`,{open:!0,className:`rounded border border-zinc-200 bg-zinc-50`,children:[(0,o.jsxs)(`summary`,{className:`cursor-pointer px-3 py-2 font-medium text-zinc-900`,children:[`Skipped canvases (`,s.skippedCanvases.length,`)`]}),(0,o.jsx)(`div`,{className:`max-h-52 overflow-auto border-t border-zinc-200 bg-white`,children:s.skippedCanvases.map(e=>(0,o.jsxs)(`div`,{className:`grid gap-1 border-b border-zinc-100 px-3 py-2 last:border-0`,children:[(0,o.jsx)(`div`,{className:`font-medium text-zinc-900`,children:e.canvasLabel||e.canvasId}),e.canvasLabel&&e.canvasLabel!==e.canvasId?(0,o.jsx)(`div`,{className:`break-all text-xs text-zinc-500`,children:e.canvasId}):null,(0,o.jsx)(`div`,{className:`text-xs text-zinc-500`,children:e.reason})]},e.canvasId))})]}):null]}):(0,o.jsx)(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 p-3`,children:`No result data is available for this run.`})})}):null}function h({tagId:e,label:t}){let n=v(e);return(0,o.jsx)(`span`,{className:`inline-flex rounded px-2 py-1 text-xs font-medium`,style:{backgroundColor:n?.backgroundColor||`#f4f4f5`,color:n?.textColor||`#18181b`},children:t})}function g({scores:t}){return(0,o.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.map((t,n)=>(0,o.jsxs)(`span`,{className:`whitespace-nowrap rounded bg-zinc-100 px-1.5 py-0.5`,children:[e.t[n]?.id||`class-${n}`,`: `,e.i(t)]},n))})}function _({label:e,value:t}){return(0,o.jsxs)(`div`,{className:`rounded border border-zinc-200 bg-white p-3`,children:[(0,o.jsx)(`div`,{className:`text-xs uppercase text-zinc-500`,children:e}),(0,o.jsx)(`div`,{className:`mt-1 text-xl font-semibold text-zinc-950`,children:t})]})}function v(t){return e.t.find(e=>e.id===t)}function y(e){return new Intl.NumberFormat().format(e)}function b(t,n){return n?e.i(t/n):`0%`}function x(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.total==`number`&&typeof t.classified==`number`&&typeof t.skipped==`number`&&!!t.counts&&typeof t.counts==`object`&&Array.isArray(t.classifications)&&Array.isArray(t.skippedCanvases)}const S=`@manifest-editor/ocr-classification/classify-canvases`;function C(t={}){let n=t.prepareClassifier||D,r=t.getCanvasImage||s,i=t.classifyImage||O;return{id:S,label:`Classify OCR difficulty`,summary:`Tag each canvas by OCR difficulty`,section:`OCR`,order:10,resourceTypes:[`Manifest`],resumable:!0,render:()=>p(S),onResults:e=>f(e.definition.id,e.instance?.result),supports:e=>!!e.vault.get(e.target)?.items?.length,prepare:e=>w(j(e)),run:async t=>{let a=t.plan||w(j(t)),o=t.tasks.getAll(),s=t.tasks.getPending();if(t.setActionLabel(`Classifying OCR difficulty`),!o.length)return t.setActionStatus(`running`,`No canvases to classify`),T(0);s.length&&(t.canvasProgress.setStatuses(s.map(e=>e.target).filter(e=>!!e&&e.type===`Canvas`),`queued`),t.setActionStatus(`running`,`Loading OCR classifier`),await n(),await t.tasks.runEach(async(n,{index:a,total:o})=>{k(t.signal);let s=n.target?.id||n.input?.canvasId||n.id,c=M(t,s),l=N(c,s),u=`Classifying ${a+1}/${o}`;t.appendActionLog(u,`info`,{canvasId:s,current:a+1,total:o});try{let n=c?await r(t,c):null;if(!n){let e={canvasId:s,canvasLabel:l,reason:`No painting image found`};return t.appendActionLog(`Skipped canvas classification`,`warn`,{canvasId:s,reason:e.reason}),{taskStatus:`skipped`,result:{type:`skipped`,skip:e}}}let a=await i(n.blob),o=e.r(a.prediction);t.tags.upsertTag({id:s,type:`Canvas`},o);let u={canvasId:s,canvasLabel:l,tagId:o.id,label:o.label,score:a.prediction.score,scores:a.scores,imageUrl:n.url};return t.appendActionLog(`Classified canvas`,`info`,{canvasId:s,label:o.label,score:a.prediction.score}),{taskStatus:`complete`,result:{type:`classified`,classification:u}}}catch(e){if(t.signal.aborted)throw e;let n={canvasId:s,canvasLabel:l,reason:A(e)};return t.appendActionLog(`Skipped canvas classification`,`warn`,{canvasId:s,reason:n.reason}),{taskStatus:`skipped`,result:{type:`skipped`,skip:n}}}},{progressLabel:(e,t,n)=>`Classifying ${t+1}/${n}`}));let c=E(t.tasks.getAll().length?t.tasks.getAll():a.tasks);return t.setActionStatus(`running`,`Classified ${c.classified}/${c.total}`),t.setActionProgress({current:c.total,total:c.total,label:`Classification complete`}),t.appendActionLog(`Classification complete`,`info`,{total:c.total,classified:c.classified,skipped:c.skipped,counts:c.counts}),c}}}function w(e){return{version:1,tasks:e.map((e,t)=>{let n=e?.id||`canvas-${t+1}`,r=N(e,n);return{id:`canvas:${n}`,label:r,target:{id:n,type:`Canvas`,label:r,scope:`canvas`},input:{canvasId:n,canvasLabel:r},status:`queued`}})}}function T(t){return{total:t,classified:0,skipped:0,counts:Object.fromEntries(e.t.map(e=>[e.id,0])),classifications:[],skippedCanvases:[]}}function E(e){let t=T(e.length);for(let n of e){let e=n.result;if(e?.type===`classified`){t.classifications.push(e.classification),t.counts[e.classification.tagId]=(t.counts[e.classification.tagId]||0)+1;continue}if(e?.type===`skipped`){t.skippedCanvases.push(e.skip);continue}if(n.status===`error`&&n.error){let e=n.target?.id||n.id;t.skippedCanvases.push({canvasId:e,canvasLabel:n.label||e,reason:n.error.message})}}return t.classified=t.classifications.length,t.skipped=t.skippedCanvases.length,t}async function D(){let{loadOcrClassifier:e}=await Promise.resolve().then(()=>require(`./onnx-classifier-CDO8vcMl.cjs`));await e()}async function O(e){let{runOcrClassifier:t}=await Promise.resolve().then(()=>require(`./onnx-classifier-CDO8vcMl.cjs`));return t(e)}function k(e){if(e.aborted)throw Error(`OCR classification cancelled.`)}function A(e){return e instanceof Error?e.message:`Canvas classification failed`}function j(e){let t=e.vault.get(e.target);return t?.items?(e.vault.get(t.items)||[]).filter(Boolean):[]}function M(e,t){return e.vault.get({id:t,type:`Canvas`})}function N(e,t){let n=e?.label;if(!n)return t;if(typeof n==`string`)return n;let r=Array.isArray(n.en)?n.en[0]:void 0;if(r)return r;let i=Object.keys(n)[0];return(i&&Array.isArray(n[i])?n[i][0]:void 0)||t}const P=[C()];exports.OCR_CLASSIFICATION_ACTION_ID=S,exports.OCR_DIFFICULTY_CLASSES=e.t,exports.OCR_DIFFICULTY_TAG_TYPE=e.n,exports.backgroundActions=P,exports.createOcrClassificationBackgroundAction=C,exports.createOcrDifficultyTag=e.r,exports.default=t.t,exports.formatOcrScore=e.i,exports.selectOcrDifficulty=e.a;
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("./ocr-difficulty-DGBSuuaz.cjs"),t=require("./plugin-CEC3H4Xp.cjs");let n=require("@iiif/helpers"),r=require("@manifest-editor/components"),i=require("react"),a=require("react/jsx-runtime");async function o(e,t){let r=s(e,t);if(!r)return null;let i=(await(0,n.createThumbnailHelper)(e.vault).getBestThumbnailAtSize(r,{width:512,height:512,maxWidth:512,maxHeight:512,unsafeImageService:!0,allowUnsafe:!0,preferFixedSize:!0},!1)).best?.id;if(!i)return null;let a=await fetch(i,{signal:e.signal});if(!a.ok)throw Error(`Unable to fetch canvas image (${a.status}).`);return{url:i,blob:await a.blob()}}function s(e,t){let n=t?.items&&e.vault.get(t.items)||[];for(let t of n){let n=t?.items&&e.vault.get(t.items)||[];for(let t of n){if(!c(t))continue;let n=l(t?.body);if(n)return e.vault.get(n)||n}}return null}function c(e){return(Array.isArray(e?.motivation)?e.motivation:[e?.motivation]).includes(`painting`)}function l(e){return Array.isArray(e)?e[0]??null:e??null}const u=`@manifest-editor/ocr-classification:results`;function d(e,t){typeof window>`u`||window.dispatchEvent(new CustomEvent(u,{detail:{actionId:e,result:b(t)?t:void 0}}))}function f(e){return(0,a.jsx)(p,{actionId:e})}function p({actionId:t}){let[n,o]=(0,i.useState)(null);(0,i.useEffect)(()=>{let e=e=>{let n=e.detail;n?.actionId===t&&o(n)};return window.addEventListener(u,e),()=>window.removeEventListener(u,e)},[t]);let s=n?.result,c=(0,i.useMemo)(()=>s?.classifications||[],[s]),l=(0,i.useMemo)(()=>s?e.t.map(e=>({...e,count:s.counts?.[e.id]||0})):[],[s]);return n?(0,a.jsx)(r.Modal,{title:`OCR classification results`,onClose:()=>o(null),className:`max-w-6xl`,children:(0,a.jsx)(`div`,{className:`flex min-h-0 flex-col gap-4 p-4 text-sm text-zinc-700`,children:s?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(`div`,{className:`rounded border border-zinc-200 bg-white p-4`,children:[(0,a.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[(0,a.jsxs)(`div`,{className:`min-w-0`,children:[(0,a.jsx)(`div`,{className:`text-xs font-semibold uppercase text-zinc-500`,children:`Task complete`}),(0,a.jsxs)(`div`,{className:`mt-1 text-lg font-semibold text-zinc-950`,children:[`Classified `,v(s.classified),` of `,v(s.total),` canvases`]}),(0,a.jsx)(`div`,{className:`mt-1 text-sm text-zinc-500`,children:s.skipped?`${v(s.skipped)} ${s.skipped===1?`canvas was`:`canvases were`} skipped. Review the skipped list below before rerunning.`:`Every canvas was classified and tagged.`})]}),(0,a.jsxs)(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 px-3 py-2 text-right`,children:[(0,a.jsx)(`div`,{className:`text-2xl font-semibold text-zinc-950`,children:y(s.classified,s.total)}),(0,a.jsx)(`div`,{className:`text-xs uppercase text-zinc-500`,children:`Coverage`})]})]}),(0,a.jsx)(`div`,{className:`mt-4 flex h-2 overflow-hidden rounded-full bg-zinc-100`,children:s.classified?l.map(e=>e.count?(0,a.jsx)(`div`,{className:`h-full`,style:{width:`${e.count/s.classified*100}%`,backgroundColor:e.backgroundColor}},e.id):null):(0,a.jsx)(`div`,{className:`h-full w-full bg-zinc-200`})}),(0,a.jsx)(`div`,{className:`mt-3 flex flex-wrap gap-2`,children:l.map(e=>(0,a.jsxs)(`div`,{className:`inline-flex items-center gap-2 rounded border border-zinc-200 bg-zinc-50 px-2 py-1`,children:[(0,a.jsx)(`span`,{className:`h-2.5 w-2.5 rounded-full`,style:{backgroundColor:e.backgroundColor},"aria-hidden":`true`}),(0,a.jsx)(`span`,{className:`font-medium text-zinc-900`,children:e.label}),(0,a.jsxs)(`span`,{className:`text-zinc-500`,children:[v(e.count),` (`,y(e.count,s.classified),`)`]})]},e.id))})]}),(0,a.jsxs)(`div`,{className:`grid gap-2 sm:grid-cols-4`,children:[(0,a.jsx)(g,{label:`Total canvases`,value:v(s.total)}),(0,a.jsx)(g,{label:`Classified`,value:v(s.classified)}),(0,a.jsx)(g,{label:`Skipped`,value:v(s.skipped)}),(0,a.jsx)(g,{label:`Tags applied`,value:v(s.classifications.length)})]}),(0,a.jsx)(`div`,{className:`grid gap-2 sm:grid-cols-3`,children:l.map(e=>(0,a.jsxs)(`div`,{className:`rounded border border-zinc-200 bg-white p-3`,children:[(0,a.jsx)(`div`,{className:`inline-flex rounded px-2 py-1 text-xs font-medium`,style:{backgroundColor:e.backgroundColor,color:e.textColor},children:e.label}),(0,a.jsx)(`div`,{className:`mt-2 text-xl font-semibold text-zinc-950`,children:v(e.count)}),(0,a.jsxs)(`div`,{className:`mt-1 text-xs text-zinc-500`,children:[y(e.count,s.classified),` of classified canvases`]})]},e.id))}),c.length?(0,a.jsxs)(`div`,{className:`min-h-0 overflow-hidden rounded border border-zinc-200`,children:[(0,a.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2 border-b border-zinc-200 bg-zinc-50 px-3 py-2`,children:[(0,a.jsx)(`div`,{className:`font-medium text-zinc-900`,children:`Classified canvases`}),(0,a.jsxs)(`div`,{className:`text-xs text-zinc-500`,children:[`Showing all `,v(c.length),` classified results`]})]}),(0,a.jsx)(`div`,{className:`max-h-[55vh] overflow-auto`,children:(0,a.jsxs)(`table`,{className:`w-full min-w-[820px] border-collapse text-left`,children:[(0,a.jsx)(`thead`,{className:`sticky top-0 bg-white text-xs uppercase text-zinc-500`,children:(0,a.jsxs)(`tr`,{children:[(0,a.jsx)(`th`,{className:`w-14 border-b border-zinc-200 px-3 py-2 font-medium`,children:`#`}),(0,a.jsx)(`th`,{className:`border-b border-zinc-200 px-3 py-2 font-medium`,children:`Canvas`}),(0,a.jsx)(`th`,{className:`w-44 border-b border-zinc-200 px-3 py-2 font-medium`,children:`Result`}),(0,a.jsx)(`th`,{className:`w-28 border-b border-zinc-200 px-3 py-2 font-medium`,children:`Confidence`}),(0,a.jsx)(`th`,{className:`border-b border-zinc-200 px-3 py-2 font-medium`,children:`Scores`})]})}),(0,a.jsx)(`tbody`,{children:c.map((t,n)=>{let r=t.canvasLabel||t.canvasId;return(0,a.jsxs)(`tr`,{className:`border-b border-zinc-100 last:border-0`,children:[(0,a.jsx)(`td`,{className:`px-3 py-2 align-top text-xs text-zinc-400`,children:n+1}),(0,a.jsxs)(`td`,{className:`px-3 py-2 align-top`,title:t.canvasId,children:[(0,a.jsx)(`div`,{className:`font-medium text-zinc-900`,children:r}),r===t.canvasId?null:(0,a.jsx)(`div`,{className:`mt-0.5 break-all text-xs text-zinc-500`,children:t.canvasId})]}),(0,a.jsx)(`td`,{className:`px-3 py-2 align-top`,children:(0,a.jsx)(m,{tagId:t.tagId,label:t.label})}),(0,a.jsx)(`td`,{className:`px-3 py-2 align-top font-medium text-zinc-900`,children:e.i(t.score)}),(0,a.jsx)(`td`,{className:`px-3 py-2 align-top text-xs text-zinc-500`,children:(0,a.jsx)(h,{scores:t.scores})})]},t.canvasId)})})]})})]}):(0,a.jsx)(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 p-3`,children:`No canvases were classified. Check the skipped canvases and task logs for details.`}),s.skippedCanvases.length?(0,a.jsxs)(`details`,{open:!0,className:`rounded border border-zinc-200 bg-zinc-50`,children:[(0,a.jsxs)(`summary`,{className:`cursor-pointer px-3 py-2 font-medium text-zinc-900`,children:[`Skipped canvases (`,s.skippedCanvases.length,`)`]}),(0,a.jsx)(`div`,{className:`max-h-52 overflow-auto border-t border-zinc-200 bg-white`,children:s.skippedCanvases.map(e=>(0,a.jsxs)(`div`,{className:`grid gap-1 border-b border-zinc-100 px-3 py-2 last:border-0`,children:[(0,a.jsx)(`div`,{className:`font-medium text-zinc-900`,children:e.canvasLabel||e.canvasId}),e.canvasLabel&&e.canvasLabel!==e.canvasId?(0,a.jsx)(`div`,{className:`break-all text-xs text-zinc-500`,children:e.canvasId}):null,(0,a.jsx)(`div`,{className:`text-xs text-zinc-500`,children:e.reason})]},e.canvasId))})]}):null]}):(0,a.jsx)(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 p-3`,children:`No result data is available for this run.`})})}):null}function m({tagId:e,label:t}){let n=_(e);return(0,a.jsx)(`span`,{className:`inline-flex rounded px-2 py-1 text-xs font-medium`,style:{backgroundColor:n?.backgroundColor||`#f4f4f5`,color:n?.textColor||`#18181b`},children:t})}function h({scores:t}){return(0,a.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.map((t,n)=>(0,a.jsxs)(`span`,{className:`whitespace-nowrap rounded bg-zinc-100 px-1.5 py-0.5`,children:[e.t[n]?.id||`class-${n}`,`: `,e.i(t)]},n))})}function g({label:e,value:t}){return(0,a.jsxs)(`div`,{className:`rounded border border-zinc-200 bg-white p-3`,children:[(0,a.jsx)(`div`,{className:`text-xs uppercase text-zinc-500`,children:e}),(0,a.jsx)(`div`,{className:`mt-1 text-xl font-semibold text-zinc-950`,children:t})]})}function _(t){return e.t.find(e=>e.id===t)}function v(e){return new Intl.NumberFormat().format(e)}function y(t,n){return n?e.i(t/n):`0%`}function b(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.total==`number`&&typeof t.classified==`number`&&typeof t.skipped==`number`&&!!t.counts&&typeof t.counts==`object`&&Array.isArray(t.classifications)&&Array.isArray(t.skippedCanvases)}const x=`@manifest-editor/ocr-classification/classify-canvases`;function S(t={}){let n=t.prepareClassifier||E,r=t.getCanvasImage||o,i=t.classifyImage||D;return{id:x,label:`Classify OCR difficulty`,summary:`Tag each canvas by OCR difficulty`,section:`OCR`,order:10,resourceTypes:[`Manifest`],resumable:!0,render:()=>f(x),onResults:e=>d(e.definition.id,e.instance?.result),supports:e=>!!e.vault.get(e.target)?.items?.length,prepare:e=>C(A(e)),run:async t=>{let a=t.plan||C(A(t)),o=t.tasks.getAll(),s=t.tasks.getPending();if(t.setActionLabel(`Classifying OCR difficulty`),!o.length)return t.setActionStatus(`running`,`No canvases to classify`),w(0);s.length&&(t.canvasProgress.setStatuses(s.map(e=>e.target).filter(e=>!!e&&e.type===`Canvas`),`queued`),t.setActionStatus(`running`,`Loading OCR classifier`),await n(),await t.tasks.runEach(async(n,{index:a,total:o})=>{O(t.signal);let s=n.target?.id||n.input?.canvasId||n.id,c=j(t,s),l=M(c,s),u=`Classifying ${a+1}/${o}`;t.appendActionLog(u,`info`,{canvasId:s,current:a+1,total:o});try{let n=c?await r(t,c):null;if(!n){let e={canvasId:s,canvasLabel:l,reason:`No painting image found`};return t.appendActionLog(`Skipped canvas classification`,`warn`,{canvasId:s,reason:e.reason}),{taskStatus:`skipped`,result:{type:`skipped`,skip:e}}}let a=await i(n.blob),o=e.r(a.prediction);t.tags.upsertTag({id:s,type:`Canvas`},o);let u={canvasId:s,canvasLabel:l,tagId:o.id,label:o.label,score:a.prediction.score,scores:a.scores,imageUrl:n.url};return t.appendActionLog(`Classified canvas`,`info`,{canvasId:s,label:o.label,score:a.prediction.score}),{taskStatus:`complete`,result:{type:`classified`,classification:u}}}catch(e){if(t.signal.aborted)throw e;let n={canvasId:s,canvasLabel:l,reason:k(e)};return t.appendActionLog(`Skipped canvas classification`,`warn`,{canvasId:s,reason:n.reason}),{taskStatus:`skipped`,result:{type:`skipped`,skip:n}}}},{progressLabel:(e,t,n)=>`Classifying ${t+1}/${n}`}));let c=T(t.tasks.getAll().length?t.tasks.getAll():a.tasks);return t.setActionStatus(`running`,`Classified ${c.classified}/${c.total}`),t.setActionProgress({current:c.total,total:c.total,label:`Classification complete`}),t.appendActionLog(`Classification complete`,`info`,{total:c.total,classified:c.classified,skipped:c.skipped,counts:c.counts}),c}}}function C(e){return{version:1,tasks:e.map((e,t)=>{let n=e?.id||`canvas-${t+1}`,r=M(e,n);return{id:`canvas:${n}`,label:r,target:{id:n,type:`Canvas`,label:r,scope:`canvas`},input:{canvasId:n,canvasLabel:r},status:`queued`}})}}function w(t){return{total:t,classified:0,skipped:0,counts:Object.fromEntries(e.t.map(e=>[e.id,0])),classifications:[],skippedCanvases:[]}}function T(e){let t=w(e.length);for(let n of e){let e=n.result;if(e?.type===`classified`){t.classifications.push(e.classification),t.counts[e.classification.tagId]=(t.counts[e.classification.tagId]||0)+1;continue}if(e?.type===`skipped`){t.skippedCanvases.push(e.skip);continue}if(n.status===`error`&&n.error){let e=n.target?.id||n.id;t.skippedCanvases.push({canvasId:e,canvasLabel:n.label||e,reason:n.error.message})}}return t.classified=t.classifications.length,t.skipped=t.skippedCanvases.length,t}async function E(){let{loadOcrClassifier:e}=await Promise.resolve().then(()=>require("./onnx-classifier-DTT3FqmF.cjs"));await e()}async function D(e){let{runOcrClassifier:t}=await Promise.resolve().then(()=>require("./onnx-classifier-DTT3FqmF.cjs"));return t(e)}function O(e){if(e.aborted)throw Error(`OCR classification cancelled.`)}function k(e){return e instanceof Error?e.message:`Canvas classification failed`}function A(e){let t=e.vault.get(e.target);return t?.items?(e.vault.get(t.items)||[]).filter(Boolean):[]}function j(e,t){return e.vault.get({id:t,type:`Canvas`})}function M(e,t){let n=e?.label;if(!n)return t;if(typeof n==`string`)return n;let r=Array.isArray(n.en)?n.en[0]:void 0;if(r)return r;let i=Object.keys(n)[0];return(i&&Array.isArray(n[i])?n[i][0]:void 0)||t}const N=[S()];exports.OCR_CLASSIFICATION_ACTION_ID=x,exports.OCR_DIFFICULTY_CLASSES=e.t,exports.OCR_DIFFICULTY_TAG_TYPE=e.n,exports.backgroundActions=N,exports.createOcrClassificationBackgroundAction=S,exports.createOcrDifficultyTag=e.r,exports.default=t.t,exports.formatOcrScore=e.i,exports.selectOcrDifficulty=e.a;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["createThumbnailHelper","useState","useMemo","OCR_DIFFICULTY_CLASSES","Modal","formatOcrScore","createOcrDifficultyTag","OCR_DIFFICULTY_CLASSES"],"sources":["../src/canvas-image.ts","../src/results.tsx","../src/background-action.ts","../src/index.ts"],"sourcesContent":["import { createThumbnailHelper } from \"@iiif/helpers\";\nimport type { BackgroundActionRunContext } from \"@manifest-editor/shell\";\n\nexport type CanvasImageForClassification = {\n url: string;\n blob: Blob;\n};\n\nexport async function getCanvasImageForClassification(\n ctx: BackgroundActionRunContext,\n canvas: any,\n): Promise<CanvasImageForClassification | null> {\n const paintingBody = getFirstPaintingBody(ctx, canvas);\n if (!paintingBody) {\n return null;\n }\n\n const thumbnailHelper = createThumbnailHelper(ctx.vault);\n const thumbnail = await thumbnailHelper.getBestThumbnailAtSize(\n paintingBody,\n {\n width: 512,\n height: 512,\n maxWidth: 512,\n maxHeight: 512,\n unsafeImageService: true,\n allowUnsafe: true,\n preferFixedSize: true,\n },\n false,\n );\n const url = thumbnail.best?.id;\n\n if (!url) {\n return null;\n }\n\n const response = await fetch(url, { signal: ctx.signal });\n if (!response.ok) {\n throw new Error(`Unable to fetch canvas image (${response.status}).`);\n }\n\n return {\n url,\n blob: await response.blob(),\n };\n}\n\nfunction getFirstPaintingBody(ctx: BackgroundActionRunContext, canvas: any) {\n const pages = canvas?.items ? ctx.vault.get(canvas.items) || [] : [];\n\n for (const page of pages) {\n const annotations = page?.items ? ctx.vault.get(page.items) || [] : [];\n for (const annotation of annotations) {\n if (!isPaintingAnnotation(annotation)) {\n continue;\n }\n\n const body = first(annotation?.body);\n if (!body) {\n continue;\n }\n\n return ctx.vault.get(body) || body;\n }\n }\n\n return null;\n}\n\nfunction isPaintingAnnotation(annotation: any) {\n const motivation = Array.isArray(annotation?.motivation) ? annotation.motivation : [annotation?.motivation];\n return motivation.includes(\"painting\");\n}\n\nfunction first<T>(value: T | T[] | null | undefined): T | null {\n if (Array.isArray(value)) {\n return value[0] ?? null;\n }\n\n return value ?? null;\n}\n","import { Modal } from \"@manifest-editor/components\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { OcrClassificationActionResult } from \"./background-action\";\nimport { formatOcrScore, OCR_DIFFICULTY_CLASSES } from \"./ocr-difficulty\";\n\nconst resultsEventName = \"@manifest-editor/ocr-classification:results\";\n\ntype OcrClassificationResultsEvent = {\n actionId: string;\n result?: OcrClassificationActionResult;\n};\n\nexport function openOcrClassificationResults(actionId: string, result: unknown) {\n if (typeof window === \"undefined\") {\n return;\n }\n\n window.dispatchEvent(\n new CustomEvent<OcrClassificationResultsEvent>(resultsEventName, {\n detail: {\n actionId,\n result: isOcrClassificationActionResult(result) ? result : undefined,\n },\n }),\n );\n}\n\nexport function renderOcrClassificationResults(actionId: string) {\n return <OcrClassificationResultsModal actionId={actionId} />;\n}\n\nfunction OcrClassificationResultsModal({ actionId }: { actionId: string }) {\n const [activeResult, setActiveResult] = useState<OcrClassificationResultsEvent | null>(null);\n\n useEffect(() => {\n const listener = (event: Event) => {\n const detail = (event as CustomEvent<OcrClassificationResultsEvent>).detail;\n if (detail?.actionId === actionId) {\n setActiveResult(detail);\n }\n };\n\n window.addEventListener(resultsEventName, listener);\n return () => window.removeEventListener(resultsEventName, listener);\n }, [actionId]);\n\n const result = activeResult?.result;\n const classifiedRows = useMemo(() => result?.classifications || [], [result]);\n const difficultyRows = useMemo(\n () =>\n result\n ? OCR_DIFFICULTY_CLASSES.map((item) => ({\n ...item,\n count: result.counts?.[item.id] || 0,\n }))\n : [],\n [result],\n );\n\n if (!activeResult) {\n return null;\n }\n\n return (\n <Modal title=\"OCR classification results\" onClose={() => setActiveResult(null)} className=\"max-w-6xl\">\n <div className=\"flex min-h-0 flex-col gap-4 p-4 text-sm text-zinc-700\">\n {!result ? (\n <div className=\"rounded border border-zinc-200 bg-zinc-50 p-3\">No result data is available for this run.</div>\n ) : (\n <>\n <div className=\"rounded border border-zinc-200 bg-white p-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"text-xs font-semibold uppercase text-zinc-500\">Task complete</div>\n <div className=\"mt-1 text-lg font-semibold text-zinc-950\">\n Classified {formatNumber(result.classified)} of {formatNumber(result.total)} canvases\n </div>\n <div className=\"mt-1 text-sm text-zinc-500\">\n {result.skipped\n ? `${formatNumber(result.skipped)} ${result.skipped === 1 ? \"canvas was\" : \"canvases were\"} skipped. Review the skipped list below before rerunning.`\n : \"Every canvas was classified and tagged.\"}\n </div>\n </div>\n <div className=\"rounded border border-zinc-200 bg-zinc-50 px-3 py-2 text-right\">\n <div className=\"text-2xl font-semibold text-zinc-950\">\n {formatRatio(result.classified, result.total)}\n </div>\n <div className=\"text-xs uppercase text-zinc-500\">Coverage</div>\n </div>\n </div>\n\n <div className=\"mt-4 flex h-2 overflow-hidden rounded-full bg-zinc-100\">\n {result.classified ? (\n difficultyRows.map((item) =>\n item.count ? (\n <div\n key={item.id}\n className=\"h-full\"\n style={{\n width: `${(item.count / result.classified) * 100}%`,\n backgroundColor: item.backgroundColor,\n }}\n />\n ) : null,\n )\n ) : (\n <div className=\"h-full w-full bg-zinc-200\" />\n )}\n </div>\n\n <div className=\"mt-3 flex flex-wrap gap-2\">\n {difficultyRows.map((item) => (\n <div\n key={item.id}\n className=\"inline-flex items-center gap-2 rounded border border-zinc-200 bg-zinc-50 px-2 py-1\"\n >\n <span\n className=\"h-2.5 w-2.5 rounded-full\"\n style={{ backgroundColor: item.backgroundColor }}\n aria-hidden=\"true\"\n />\n <span className=\"font-medium text-zinc-900\">{item.label}</span>\n <span className=\"text-zinc-500\">\n {formatNumber(item.count)} ({formatRatio(item.count, result.classified)})\n </span>\n </div>\n ))}\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-4\">\n <SummaryStat label=\"Total canvases\" value={formatNumber(result.total)} />\n <SummaryStat label=\"Classified\" value={formatNumber(result.classified)} />\n <SummaryStat label=\"Skipped\" value={formatNumber(result.skipped)} />\n <SummaryStat label=\"Tags applied\" value={formatNumber(result.classifications.length)} />\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3\">\n {difficultyRows.map((item) => (\n <div key={item.id} className=\"rounded border border-zinc-200 bg-white p-3\">\n <div\n className=\"inline-flex rounded px-2 py-1 text-xs font-medium\"\n style={{ backgroundColor: item.backgroundColor, color: item.textColor }}\n >\n {item.label}\n </div>\n <div className=\"mt-2 text-xl font-semibold text-zinc-950\">{formatNumber(item.count)}</div>\n <div className=\"mt-1 text-xs text-zinc-500\">\n {formatRatio(item.count, result.classified)} of classified canvases\n </div>\n </div>\n ))}\n </div>\n\n {classifiedRows.length ? (\n <div className=\"min-h-0 overflow-hidden rounded border border-zinc-200\">\n <div className=\"flex flex-wrap items-center justify-between gap-2 border-b border-zinc-200 bg-zinc-50 px-3 py-2\">\n <div className=\"font-medium text-zinc-900\">Classified canvases</div>\n <div className=\"text-xs text-zinc-500\">\n Showing all {formatNumber(classifiedRows.length)} classified results\n </div>\n </div>\n <div className=\"max-h-[55vh] overflow-auto\">\n <table className=\"w-full min-w-[820px] border-collapse text-left\">\n <thead className=\"sticky top-0 bg-white text-xs uppercase text-zinc-500\">\n <tr>\n <th className=\"w-14 border-b border-zinc-200 px-3 py-2 font-medium\">#</th>\n <th className=\"border-b border-zinc-200 px-3 py-2 font-medium\">Canvas</th>\n <th className=\"w-44 border-b border-zinc-200 px-3 py-2 font-medium\">Result</th>\n <th className=\"w-28 border-b border-zinc-200 px-3 py-2 font-medium\">Confidence</th>\n <th className=\"border-b border-zinc-200 px-3 py-2 font-medium\">Scores</th>\n </tr>\n </thead>\n <tbody>\n {classifiedRows.map((item, index) => {\n const canvasLabel = item.canvasLabel || item.canvasId;\n return (\n <tr key={item.canvasId} className=\"border-b border-zinc-100 last:border-0\">\n <td className=\"px-3 py-2 align-top text-xs text-zinc-400\">{index + 1}</td>\n <td className=\"px-3 py-2 align-top\" title={item.canvasId}>\n <div className=\"font-medium text-zinc-900\">{canvasLabel}</div>\n {canvasLabel !== item.canvasId ? (\n <div className=\"mt-0.5 break-all text-xs text-zinc-500\">{item.canvasId}</div>\n ) : null}\n </td>\n <td className=\"px-3 py-2 align-top\">\n <DifficultyBadge tagId={item.tagId} label={item.label} />\n </td>\n <td className=\"px-3 py-2 align-top font-medium text-zinc-900\">\n {formatOcrScore(item.score)}\n </td>\n <td className=\"px-3 py-2 align-top text-xs text-zinc-500\">\n <ScoreList scores={item.scores} />\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n </div>\n ) : (\n <div className=\"rounded border border-zinc-200 bg-zinc-50 p-3\">\n No canvases were classified. Check the skipped canvases and task logs for details.\n </div>\n )}\n\n {result.skippedCanvases.length ? (\n <details open className=\"rounded border border-zinc-200 bg-zinc-50\">\n <summary className=\"cursor-pointer px-3 py-2 font-medium text-zinc-900\">\n Skipped canvases ({result.skippedCanvases.length})\n </summary>\n <div className=\"max-h-52 overflow-auto border-t border-zinc-200 bg-white\">\n {result.skippedCanvases.map((item) => (\n <div key={item.canvasId} className=\"grid gap-1 border-b border-zinc-100 px-3 py-2 last:border-0\">\n <div className=\"font-medium text-zinc-900\">{item.canvasLabel || item.canvasId}</div>\n {item.canvasLabel && item.canvasLabel !== item.canvasId ? (\n <div className=\"break-all text-xs text-zinc-500\">{item.canvasId}</div>\n ) : null}\n <div className=\"text-xs text-zinc-500\">{item.reason}</div>\n </div>\n ))}\n </div>\n </details>\n ) : null}\n </>\n )}\n </div>\n </Modal>\n );\n}\n\nfunction DifficultyBadge({ tagId, label }: { tagId: string; label: string }) {\n const difficultyClass = getDifficultyClass(tagId);\n\n return (\n <span\n className=\"inline-flex rounded px-2 py-1 text-xs font-medium\"\n style={{\n backgroundColor: difficultyClass?.backgroundColor || \"#f4f4f5\",\n color: difficultyClass?.textColor || \"#18181b\",\n }}\n >\n {label}\n </span>\n );\n}\n\nfunction ScoreList({ scores }: { scores: number[] }) {\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {scores.map((score, index) => (\n <span key={index} className=\"whitespace-nowrap rounded bg-zinc-100 px-1.5 py-0.5\">\n {OCR_DIFFICULTY_CLASSES[index]?.id || `class-${index}`}: {formatOcrScore(score)}\n </span>\n ))}\n </div>\n );\n}\n\nfunction SummaryStat({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"rounded border border-zinc-200 bg-white p-3\">\n <div className=\"text-xs uppercase text-zinc-500\">{label}</div>\n <div className=\"mt-1 text-xl font-semibold text-zinc-950\">{value}</div>\n </div>\n );\n}\n\nfunction getDifficultyClass(tagId: string) {\n return OCR_DIFFICULTY_CLASSES.find((item) => item.id === tagId);\n}\n\nfunction formatNumber(value: number) {\n return new Intl.NumberFormat().format(value);\n}\n\nfunction formatRatio(value: number, total: number) {\n return total ? formatOcrScore(value / total) : \"0%\";\n}\n\nfunction isOcrClassificationActionResult(result: unknown): result is OcrClassificationActionResult {\n if (!result || typeof result !== \"object\") {\n return false;\n }\n\n const candidate = result as Partial<OcrClassificationActionResult>;\n return (\n typeof candidate.total === \"number\" &&\n typeof candidate.classified === \"number\" &&\n typeof candidate.skipped === \"number\" &&\n !!candidate.counts &&\n typeof candidate.counts === \"object\" &&\n Array.isArray(candidate.classifications) &&\n Array.isArray(candidate.skippedCanvases)\n );\n}\n","import type {\n BackgroundActionDefinition,\n BackgroundActionPlan,\n BackgroundActionRunContext,\n BackgroundActionTask,\n} from \"@manifest-editor/shell\";\nimport { type CanvasImageForClassification, getCanvasImageForClassification } from \"./canvas-image\";\nimport {\n createOcrDifficultyTag,\n formatOcrScore,\n OCR_DIFFICULTY_CLASSES,\n OCR_DIFFICULTY_TAG_TYPE,\n type OcrClassifierRun,\n} from \"./ocr-difficulty\";\nimport { openOcrClassificationResults, renderOcrClassificationResults } from \"./results\";\n\nexport const OCR_CLASSIFICATION_ACTION_ID = \"@manifest-editor/ocr-classification/classify-canvases\";\n\nexport type OcrCanvasClassification = {\n canvasId: string;\n canvasLabel: string;\n tagId: string;\n label: string;\n score: number;\n scores: number[];\n imageUrl: string;\n};\n\nexport type OcrCanvasClassificationSkip = {\n canvasId: string;\n canvasLabel: string;\n reason: string;\n};\n\nexport type OcrClassificationActionResult = {\n total: number;\n classified: number;\n skipped: number;\n counts: Record<string, number>;\n classifications: OcrCanvasClassification[];\n skippedCanvases: OcrCanvasClassificationSkip[];\n};\n\ntype OcrClassificationTaskResult =\n | {\n type: \"classified\";\n classification: OcrCanvasClassification;\n }\n | {\n type: \"skipped\";\n skip: OcrCanvasClassificationSkip;\n };\n\nexport type OcrClassificationActionDependencies = {\n prepareClassifier?: () => Promise<void>;\n getCanvasImage?: (ctx: BackgroundActionRunContext, canvas: any) => Promise<CanvasImageForClassification | null>;\n classifyImage?: (image: Blob) => Promise<OcrClassifierRun>;\n};\n\nexport function createOcrClassificationBackgroundAction(\n dependencies: OcrClassificationActionDependencies = {},\n): BackgroundActionDefinition {\n const prepareClassifier = dependencies.prepareClassifier || defaultPrepareClassifier;\n const getCanvasImage = dependencies.getCanvasImage || getCanvasImageForClassification;\n const classifyImage = dependencies.classifyImage || defaultClassifyImage;\n\n return {\n id: OCR_CLASSIFICATION_ACTION_ID,\n label: \"Classify OCR difficulty\",\n summary: \"Tag each canvas by OCR difficulty\",\n section: \"OCR\",\n order: 10,\n resourceTypes: [\"Manifest\"],\n resumable: true,\n render: () => renderOcrClassificationResults(OCR_CLASSIFICATION_ACTION_ID),\n onResults: (ctx) => openOcrClassificationResults(ctx.definition.id, ctx.instance?.result),\n supports: (ctx) => {\n const manifest = ctx.vault.get(ctx.target as any) as any;\n return !!manifest?.items?.length;\n },\n prepare: (ctx) => {\n return createClassificationPlan(getManifestCanvases(ctx));\n },\n run: async (ctx) => {\n const plan = ctx.plan || createClassificationPlan(getManifestCanvases(ctx));\n const tasks = ctx.tasks.getAll();\n const pendingTasks = ctx.tasks.getPending();\n\n ctx.setActionLabel(\"Classifying OCR difficulty\");\n\n if (!tasks.length) {\n ctx.setActionStatus(\"running\", \"No canvases to classify\");\n return createEmptyResult(0);\n }\n\n if (pendingTasks.length) {\n ctx.canvasProgress.setStatuses(\n pendingTasks\n .map((task) => task.target)\n .filter((target): target is NonNullable<BackgroundActionTask[\"target\"]> => !!target && target.type === \"Canvas\"),\n \"queued\",\n );\n ctx.setActionStatus(\"running\", \"Loading OCR classifier\");\n await prepareClassifier();\n\n await ctx.tasks.runEach(\n async (task, { index, total }) => {\n throwIfAborted(ctx.signal);\n const canvasId = task.target?.id || (task.input as { canvasId?: string } | undefined)?.canvasId || task.id;\n const canvas = getCanvasById(ctx, canvasId);\n const canvasLabel = getCanvasLabel(canvas, canvasId);\n const label = `Classifying ${index + 1}/${total}`;\n\n ctx.appendActionLog(label, \"info\", { canvasId, current: index + 1, total });\n\n try {\n const image = canvas ? await getCanvasImage(ctx, canvas) : null;\n if (!image) {\n const skip = {\n canvasId,\n canvasLabel,\n reason: \"No painting image found\",\n };\n ctx.appendActionLog(\"Skipped canvas classification\", \"warn\", {\n canvasId,\n reason: skip.reason,\n });\n return {\n taskStatus: \"skipped\",\n result: {\n type: \"skipped\",\n skip,\n } satisfies OcrClassificationTaskResult,\n };\n }\n\n const classification = await classifyImage(image.blob);\n const tag = createOcrDifficultyTag(classification.prediction);\n ctx.tags.upsertTag({ id: canvasId, type: \"Canvas\" }, tag);\n\n const result = {\n canvasId,\n canvasLabel,\n tagId: tag.id,\n label: tag.label,\n score: classification.prediction.score,\n scores: classification.scores,\n imageUrl: image.url,\n };\n ctx.appendActionLog(\"Classified canvas\", \"info\", {\n canvasId,\n label: tag.label,\n score: classification.prediction.score,\n });\n return {\n taskStatus: \"complete\",\n result: {\n type: \"classified\",\n classification: result,\n } satisfies OcrClassificationTaskResult,\n };\n } catch (error) {\n if (ctx.signal.aborted) {\n throw error;\n }\n\n const skip = {\n canvasId,\n canvasLabel,\n reason: getErrorMessage(error),\n };\n ctx.appendActionLog(\"Skipped canvas classification\", \"warn\", {\n canvasId,\n reason: skip.reason,\n });\n return {\n taskStatus: \"skipped\",\n result: {\n type: \"skipped\",\n skip,\n } satisfies OcrClassificationTaskResult,\n };\n }\n },\n {\n progressLabel: (_task, index, total) => `Classifying ${index + 1}/${total}`,\n },\n );\n }\n\n const result = aggregateClassificationResult(ctx.tasks.getAll().length ? ctx.tasks.getAll() : plan.tasks);\n ctx.setActionStatus(\"running\", `Classified ${result.classified}/${result.total}`);\n ctx.setActionProgress({ current: result.total, total: result.total, label: \"Classification complete\" });\n ctx.appendActionLog(\"Classification complete\", \"info\", {\n total: result.total,\n classified: result.classified,\n skipped: result.skipped,\n counts: result.counts,\n });\n\n return result;\n },\n };\n}\n\nfunction createClassificationPlan(canvases: any[]): BackgroundActionPlan {\n return {\n version: 1,\n tasks: canvases.map((canvas, index) => {\n const canvasId = canvas?.id || `canvas-${index + 1}`;\n const canvasLabel = getCanvasLabel(canvas, canvasId);\n return {\n id: `canvas:${canvasId}`,\n label: canvasLabel,\n target: {\n id: canvasId,\n type: \"Canvas\",\n label: canvasLabel,\n scope: \"canvas\",\n },\n input: {\n canvasId,\n canvasLabel,\n },\n status: \"queued\",\n };\n }),\n };\n}\n\nfunction createEmptyResult(total: number): OcrClassificationActionResult {\n return {\n total,\n classified: 0,\n skipped: 0,\n counts: Object.fromEntries(OCR_DIFFICULTY_CLASSES.map((item) => [item.id, 0])),\n classifications: [],\n skippedCanvases: [],\n };\n}\n\nfunction aggregateClassificationResult(tasks: BackgroundActionTask[]): OcrClassificationActionResult {\n const result = createEmptyResult(tasks.length);\n\n for (const task of tasks) {\n const taskResult = task.result as OcrClassificationTaskResult | undefined;\n if (taskResult?.type === \"classified\") {\n result.classifications.push(taskResult.classification);\n result.counts[taskResult.classification.tagId] = (result.counts[taskResult.classification.tagId] || 0) + 1;\n continue;\n }\n\n if (taskResult?.type === \"skipped\") {\n result.skippedCanvases.push(taskResult.skip);\n continue;\n }\n\n if (task.status === \"error\" && task.error) {\n const canvasId = task.target?.id || task.id;\n result.skippedCanvases.push({\n canvasId,\n canvasLabel: task.label || canvasId,\n reason: task.error.message,\n });\n }\n }\n\n result.classified = result.classifications.length;\n result.skipped = result.skippedCanvases.length;\n return result;\n}\n\nasync function defaultPrepareClassifier() {\n const { loadOcrClassifier } = await import(\"./onnx-classifier\");\n await loadOcrClassifier();\n}\n\nasync function defaultClassifyImage(image: Blob) {\n const { runOcrClassifier } = await import(\"./onnx-classifier\");\n return runOcrClassifier(image);\n}\n\nfunction throwIfAborted(signal: AbortSignal) {\n if (signal.aborted) {\n throw new Error(\"OCR classification cancelled.\");\n }\n}\n\nfunction getErrorMessage(error: unknown) {\n return error instanceof Error ? error.message : \"Canvas classification failed\";\n}\n\nfunction getManifestCanvases(ctx: BackgroundActionRunContext) {\n const manifest = ctx.vault.get(ctx.target as any) as any;\n return manifest?.items ? (ctx.vault.get(manifest.items) || []).filter(Boolean) : [];\n}\n\nfunction getCanvasById(ctx: BackgroundActionRunContext, canvasId: string) {\n return ctx.vault.get({ id: canvasId, type: \"Canvas\" } as any) as any;\n}\n\nfunction getCanvasLabel(canvas: any, fallback: string) {\n const label = canvas?.label;\n if (!label) {\n return fallback;\n }\n\n if (typeof label === \"string\") {\n return label;\n }\n\n const englishLabel = Array.isArray(label.en) ? label.en[0] : undefined;\n if (englishLabel) {\n return englishLabel;\n }\n\n const firstLanguage = Object.keys(label)[0];\n const firstValue = firstLanguage && Array.isArray(label[firstLanguage]) ? label[firstLanguage][0] : undefined;\n return firstValue || fallback;\n}\n\nexport { OCR_DIFFICULTY_TAG_TYPE, formatOcrScore };\n","import type { BackgroundActionDefinition } from \"@manifest-editor/shell\";\nimport { createOcrClassificationBackgroundAction } from \"./background-action\";\nexport { default } from \"./plugin\";\n\nexport const backgroundActions: BackgroundActionDefinition[] = [createOcrClassificationBackgroundAction()];\n\nexport * from \"./background-action\";\nexport * from \"./ocr-difficulty\";\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as selectOcrDifficulty, a as OcrCanvasClassificationSkip, c as createOcrClassificationBackgroundAction, d as OcrClassifierRun, f as OcrDifficultyClass, g as formatOcrScore, h as createOcrDifficultyTag, i as OcrCanvasClassification, l as OCR_DIFFICULTY_CLASSES, m as OcrDifficultyPrediction, o as OcrClassificationActionDependencies, p as OcrDifficultyId, r as OCR_CLASSIFICATION_ACTION_ID, s as OcrClassificationActionResult, t as backgroundActions, u as OCR_DIFFICULTY_TAG_TYPE, v as _default } from "./index-
|
|
1
|
+
import { _ as selectOcrDifficulty, a as OcrCanvasClassificationSkip, c as createOcrClassificationBackgroundAction, d as OcrClassifierRun, f as OcrDifficultyClass, g as formatOcrScore, h as createOcrDifficultyTag, i as OcrCanvasClassification, l as OCR_DIFFICULTY_CLASSES, m as OcrDifficultyPrediction, o as OcrClassificationActionDependencies, p as OcrDifficultyId, r as OCR_CLASSIFICATION_ACTION_ID, s as OcrClassificationActionResult, t as backgroundActions, u as OCR_DIFFICULTY_TAG_TYPE, v as _default } from "./index-BdkICeQa.cjs";
|
|
2
2
|
export { OCR_CLASSIFICATION_ACTION_ID, OCR_DIFFICULTY_CLASSES, OCR_DIFFICULTY_TAG_TYPE, OcrCanvasClassification, OcrCanvasClassificationSkip, OcrClassificationActionDependencies, OcrClassificationActionResult, OcrClassifierRun, OcrDifficultyClass, OcrDifficultyId, OcrDifficultyPrediction, backgroundActions, createOcrClassificationBackgroundAction, createOcrDifficultyTag, _default as default, formatOcrScore, selectOcrDifficulty };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as selectOcrDifficulty, a as OcrCanvasClassificationSkip, c as createOcrClassificationBackgroundAction, d as OcrClassifierRun, f as OcrDifficultyClass, g as formatOcrScore, h as createOcrDifficultyTag, i as OcrCanvasClassification, l as OCR_DIFFICULTY_CLASSES, m as OcrDifficultyPrediction, o as OcrClassificationActionDependencies, p as OcrDifficultyId, r as OCR_CLASSIFICATION_ACTION_ID, s as OcrClassificationActionResult, t as backgroundActions, u as OCR_DIFFICULTY_TAG_TYPE, v as _default } from "./index-
|
|
1
|
+
import { _ as selectOcrDifficulty, a as OcrCanvasClassificationSkip, c as createOcrClassificationBackgroundAction, d as OcrClassifierRun, f as OcrDifficultyClass, g as formatOcrScore, h as createOcrDifficultyTag, i as OcrCanvasClassification, l as OCR_DIFFICULTY_CLASSES, m as OcrDifficultyPrediction, o as OcrClassificationActionDependencies, p as OcrDifficultyId, r as OCR_CLASSIFICATION_ACTION_ID, s as OcrClassificationActionResult, t as backgroundActions, u as OCR_DIFFICULTY_TAG_TYPE, v as _default } from "./index-BdkICeQa.js";
|
|
2
2
|
export { OCR_CLASSIFICATION_ACTION_ID, OCR_DIFFICULTY_CLASSES, OCR_DIFFICULTY_TAG_TYPE, OcrCanvasClassification, OcrCanvasClassificationSkip, OcrClassificationActionDependencies, OcrClassificationActionResult, OcrClassifierRun, OcrDifficultyClass, OcrDifficultyId, OcrDifficultyPrediction, backgroundActions, createOcrClassificationBackgroundAction, createOcrDifficultyTag, _default as default, formatOcrScore, selectOcrDifficulty };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,i as t,n,r,t as i}from"./ocr-difficulty-CjQvA3aZ.js";import{t as a}from"./plugin-Cn1QgMZa.js";import{createThumbnailHelper as o}from"@iiif/helpers";import{Modal as s}from"@manifest-editor/components";import{useEffect as c,useMemo as l,useState as u}from"react";import{Fragment as d,jsx as f,jsxs as p}from"react/jsx-runtime";async function m(e,t){let n=h(e,t);if(!n)return null;let r=(await o(e.vault).getBestThumbnailAtSize(n,{width:512,height:512,maxWidth:512,maxHeight:512,unsafeImageService:!0,allowUnsafe:!0,preferFixedSize:!0},!1)).best?.id;if(!r)return null;let i=await fetch(r,{signal:e.signal});if(!i.ok)throw Error(`Unable to fetch canvas image (${i.status}).`);return{url:r,blob:await i.blob()}}function h(e,t){let n=t?.items&&e.vault.get(t.items)||[];for(let t of n){let n=t?.items&&e.vault.get(t.items)||[];for(let t of n){if(!g(t))continue;let n=_(t?.body);if(n)return e.vault.get(n)||n}}return null}function g(e){return(Array.isArray(e?.motivation)?e.motivation:[e?.motivation]).includes(`painting`)}function _(e){return Array.isArray(e)?e[0]??null:e??null}const v=`@manifest-editor/ocr-classification:results`;function y(e,t){typeof window>`u`||window.dispatchEvent(new CustomEvent(v,{detail:{actionId:e,result:O(t)?t:void 0}}))}function b(e){return f(x,{actionId:e})}function x({actionId:e}){let[n,r]=u(null);c(()=>{let t=t=>{let n=t.detail;n?.actionId===e&&r(n)};return window.addEventListener(v,t),()=>window.removeEventListener(v,t)},[e]);let a=n?.result,o=l(()=>a?.classifications||[],[a]),m=l(()=>a?i.map(e=>({...e,count:a.counts?.[e.id]||0})):[],[a]);return n?f(s,{title:`OCR classification results`,onClose:()=>r(null),className:`max-w-6xl`,children:f(`div`,{className:`flex min-h-0 flex-col gap-4 p-4 text-sm text-zinc-700`,children:a?p(d,{children:[p(`div`,{className:`rounded border border-zinc-200 bg-white p-4`,children:[p(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[p(`div`,{className:`min-w-0`,children:[f(`div`,{className:`text-xs font-semibold uppercase text-zinc-500`,children:`Task complete`}),p(`div`,{className:`mt-1 text-lg font-semibold text-zinc-950`,children:[`Classified `,E(a.classified),` of `,E(a.total),` canvases`]}),f(`div`,{className:`mt-1 text-sm text-zinc-500`,children:a.skipped?`${E(a.skipped)} ${a.skipped===1?`canvas was`:`canvases were`} skipped. Review the skipped list below before rerunning.`:`Every canvas was classified and tagged.`})]}),p(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 px-3 py-2 text-right`,children:[f(`div`,{className:`text-2xl font-semibold text-zinc-950`,children:D(a.classified,a.total)}),f(`div`,{className:`text-xs uppercase text-zinc-500`,children:`Coverage`})]})]}),f(`div`,{className:`mt-4 flex h-2 overflow-hidden rounded-full bg-zinc-100`,children:a.classified?m.map(e=>e.count?f(`div`,{className:`h-full`,style:{width:`${e.count/a.classified*100}%`,backgroundColor:e.backgroundColor}},e.id):null):f(`div`,{className:`h-full w-full bg-zinc-200`})}),f(`div`,{className:`mt-3 flex flex-wrap gap-2`,children:m.map(e=>p(`div`,{className:`inline-flex items-center gap-2 rounded border border-zinc-200 bg-zinc-50 px-2 py-1`,children:[f(`span`,{className:`h-2.5 w-2.5 rounded-full`,style:{backgroundColor:e.backgroundColor},"aria-hidden":`true`}),f(`span`,{className:`font-medium text-zinc-900`,children:e.label}),p(`span`,{className:`text-zinc-500`,children:[E(e.count),` (`,D(e.count,a.classified),`)`]})]},e.id))})]}),p(`div`,{className:`grid gap-2 sm:grid-cols-4`,children:[f(w,{label:`Total canvases`,value:E(a.total)}),f(w,{label:`Classified`,value:E(a.classified)}),f(w,{label:`Skipped`,value:E(a.skipped)}),f(w,{label:`Tags applied`,value:E(a.classifications.length)})]}),f(`div`,{className:`grid gap-2 sm:grid-cols-3`,children:m.map(e=>p(`div`,{className:`rounded border border-zinc-200 bg-white p-3`,children:[f(`div`,{className:`inline-flex rounded px-2 py-1 text-xs font-medium`,style:{backgroundColor:e.backgroundColor,color:e.textColor},children:e.label}),f(`div`,{className:`mt-2 text-xl font-semibold text-zinc-950`,children:E(e.count)}),p(`div`,{className:`mt-1 text-xs text-zinc-500`,children:[D(e.count,a.classified),` of classified canvases`]})]},e.id))}),o.length?p(`div`,{className:`min-h-0 overflow-hidden rounded border border-zinc-200`,children:[p(`div`,{className:`flex flex-wrap items-center justify-between gap-2 border-b border-zinc-200 bg-zinc-50 px-3 py-2`,children:[f(`div`,{className:`font-medium text-zinc-900`,children:`Classified canvases`}),p(`div`,{className:`text-xs text-zinc-500`,children:[`Showing all `,E(o.length),` classified results`]})]}),f(`div`,{className:`max-h-[55vh] overflow-auto`,children:p(`table`,{className:`w-full min-w-[820px] border-collapse text-left`,children:[f(`thead`,{className:`sticky top-0 bg-white text-xs uppercase text-zinc-500`,children:p(`tr`,{children:[f(`th`,{className:`w-14 border-b border-zinc-200 px-3 py-2 font-medium`,children:`#`}),f(`th`,{className:`border-b border-zinc-200 px-3 py-2 font-medium`,children:`Canvas`}),f(`th`,{className:`w-44 border-b border-zinc-200 px-3 py-2 font-medium`,children:`Result`}),f(`th`,{className:`w-28 border-b border-zinc-200 px-3 py-2 font-medium`,children:`Confidence`}),f(`th`,{className:`border-b border-zinc-200 px-3 py-2 font-medium`,children:`Scores`})]})}),f(`tbody`,{children:o.map((e,n)=>{let r=e.canvasLabel||e.canvasId;return p(`tr`,{className:`border-b border-zinc-100 last:border-0`,children:[f(`td`,{className:`px-3 py-2 align-top text-xs text-zinc-400`,children:n+1}),p(`td`,{className:`px-3 py-2 align-top`,title:e.canvasId,children:[f(`div`,{className:`font-medium text-zinc-900`,children:r}),r===e.canvasId?null:f(`div`,{className:`mt-0.5 break-all text-xs text-zinc-500`,children:e.canvasId})]}),f(`td`,{className:`px-3 py-2 align-top`,children:f(S,{tagId:e.tagId,label:e.label})}),f(`td`,{className:`px-3 py-2 align-top font-medium text-zinc-900`,children:t(e.score)}),f(`td`,{className:`px-3 py-2 align-top text-xs text-zinc-500`,children:f(C,{scores:e.scores})})]},e.canvasId)})})]})})]}):f(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 p-3`,children:`No canvases were classified. Check the skipped canvases and task logs for details.`}),a.skippedCanvases.length?p(`details`,{open:!0,className:`rounded border border-zinc-200 bg-zinc-50`,children:[p(`summary`,{className:`cursor-pointer px-3 py-2 font-medium text-zinc-900`,children:[`Skipped canvases (`,a.skippedCanvases.length,`)`]}),f(`div`,{className:`max-h-52 overflow-auto border-t border-zinc-200 bg-white`,children:a.skippedCanvases.map(e=>p(`div`,{className:`grid gap-1 border-b border-zinc-100 px-3 py-2 last:border-0`,children:[f(`div`,{className:`font-medium text-zinc-900`,children:e.canvasLabel||e.canvasId}),e.canvasLabel&&e.canvasLabel!==e.canvasId?f(`div`,{className:`break-all text-xs text-zinc-500`,children:e.canvasId}):null,f(`div`,{className:`text-xs text-zinc-500`,children:e.reason})]},e.canvasId))})]}):null]}):f(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 p-3`,children:`No result data is available for this run.`})})}):null}function S({tagId:e,label:t}){let n=T(e);return f(`span`,{className:`inline-flex rounded px-2 py-1 text-xs font-medium`,style:{backgroundColor:n?.backgroundColor||`#f4f4f5`,color:n?.textColor||`#18181b`},children:t})}function C({scores:e}){return f(`div`,{className:`flex flex-wrap gap-1.5`,children:e.map((e,n)=>p(`span`,{className:`whitespace-nowrap rounded bg-zinc-100 px-1.5 py-0.5`,children:[i[n]?.id||`class-${n}`,`: `,t(e)]},n))})}function w({label:e,value:t}){return p(`div`,{className:`rounded border border-zinc-200 bg-white p-3`,children:[f(`div`,{className:`text-xs uppercase text-zinc-500`,children:e}),f(`div`,{className:`mt-1 text-xl font-semibold text-zinc-950`,children:t})]})}function T(e){return i.find(t=>t.id===e)}function E(e){return new Intl.NumberFormat().format(e)}function D(e,n){return n?t(e/n):`0%`}function O(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.total==`number`&&typeof t.classified==`number`&&typeof t.skipped==`number`&&!!t.counts&&typeof t.counts==`object`&&Array.isArray(t.classifications)&&Array.isArray(t.skippedCanvases)}const k=`@manifest-editor/ocr-classification/classify-canvases`;function A(e={}){let t=e.prepareClassifier||P,n=e.getCanvasImage||m,i=e.classifyImage||F;return{id:k,label:`Classify OCR difficulty`,summary:`Tag each canvas by OCR difficulty`,section:`OCR`,order:10,resourceTypes:[`Manifest`],resumable:!0,render:()=>b(k),onResults:e=>y(e.definition.id,e.instance?.result),supports:e=>!!e.vault.get(e.target)?.items?.length,prepare:e=>j(R(e)),run:async e=>{let a=e.plan||j(R(e)),o=e.tasks.getAll(),s=e.tasks.getPending();if(e.setActionLabel(`Classifying OCR difficulty`),!o.length)return e.setActionStatus(`running`,`No canvases to classify`),M(0);s.length&&(e.canvasProgress.setStatuses(s.map(e=>e.target).filter(e=>!!e&&e.type===`Canvas`),`queued`),e.setActionStatus(`running`,`Loading OCR classifier`),await t(),await e.tasks.runEach(async(t,{index:a,total:o})=>{I(e.signal);let s=t.target?.id||t.input?.canvasId||t.id,c=z(e,s),l=B(c,s),u=`Classifying ${a+1}/${o}`;e.appendActionLog(u,`info`,{canvasId:s,current:a+1,total:o});try{let t=c?await n(e,c):null;if(!t){let t={canvasId:s,canvasLabel:l,reason:`No painting image found`};return e.appendActionLog(`Skipped canvas classification`,`warn`,{canvasId:s,reason:t.reason}),{taskStatus:`skipped`,result:{type:`skipped`,skip:t}}}let a=await i(t.blob),o=r(a.prediction);e.tags.upsertTag({id:s,type:`Canvas`},o);let u={canvasId:s,canvasLabel:l,tagId:o.id,label:o.label,score:a.prediction.score,scores:a.scores,imageUrl:t.url};return e.appendActionLog(`Classified canvas`,`info`,{canvasId:s,label:o.label,score:a.prediction.score}),{taskStatus:`complete`,result:{type:`classified`,classification:u}}}catch(t){if(e.signal.aborted)throw t;let n={canvasId:s,canvasLabel:l,reason:L(t)};return e.appendActionLog(`Skipped canvas classification`,`warn`,{canvasId:s,reason:n.reason}),{taskStatus:`skipped`,result:{type:`skipped`,skip:n}}}},{progressLabel:(e,t,n)=>`Classifying ${t+1}/${n}`}));let c=N(e.tasks.getAll().length?e.tasks.getAll():a.tasks);return e.setActionStatus(`running`,`Classified ${c.classified}/${c.total}`),e.setActionProgress({current:c.total,total:c.total,label:`Classification complete`}),e.appendActionLog(`Classification complete`,`info`,{total:c.total,classified:c.classified,skipped:c.skipped,counts:c.counts}),c}}}function j(e){return{version:1,tasks:e.map((e,t)=>{let n=e?.id||`canvas-${t+1}`,r=B(e,n);return{id:`canvas:${n}`,label:r,target:{id:n,type:`Canvas`,label:r,scope:`canvas`},input:{canvasId:n,canvasLabel:r},status:`queued`}})}}function M(e){return{total:e,classified:0,skipped:0,counts:Object.fromEntries(i.map(e=>[e.id,0])),classifications:[],skippedCanvases:[]}}function N(e){let t=M(e.length);for(let n of e){let e=n.result;if(e?.type===`classified`){t.classifications.push(e.classification),t.counts[e.classification.tagId]=(t.counts[e.classification.tagId]||0)+1;continue}if(e?.type===`skipped`){t.skippedCanvases.push(e.skip);continue}if(n.status===`error`&&n.error){let e=n.target?.id||n.id;t.skippedCanvases.push({canvasId:e,canvasLabel:n.label||e,reason:n.error.message})}}return t.classified=t.classifications.length,t.skipped=t.skippedCanvases.length,t}async function P(){let{loadOcrClassifier:e}=await import(`./onnx-classifier-mb_6hJ1l.js`);await e()}async function F(e){let{runOcrClassifier:t}=await import(`./onnx-classifier-mb_6hJ1l.js`);return t(e)}function I(e){if(e.aborted)throw Error(`OCR classification cancelled.`)}function L(e){return e instanceof Error?e.message:`Canvas classification failed`}function R(e){let t=e.vault.get(e.target);return t?.items?(e.vault.get(t.items)||[]).filter(Boolean):[]}function z(e,t){return e.vault.get({id:t,type:`Canvas`})}function B(e,t){let n=e?.label;if(!n)return t;if(typeof n==`string`)return n;let r=Array.isArray(n.en)?n.en[0]:void 0;if(r)return r;let i=Object.keys(n)[0];return(i&&Array.isArray(n[i])?n[i][0]:void 0)||t}const V=[A()];export{k as OCR_CLASSIFICATION_ACTION_ID,i as OCR_DIFFICULTY_CLASSES,n as OCR_DIFFICULTY_TAG_TYPE,V as backgroundActions,A as createOcrClassificationBackgroundAction,r as createOcrDifficultyTag,a as default,t as formatOcrScore,e as selectOcrDifficulty};
|
|
1
|
+
import{a as e,i as t,n,r,t as i}from"./ocr-difficulty-DOYyPpGw.js";import{t as a}from"./plugin-CsyG04LG.js";import{createThumbnailHelper as o}from"@iiif/helpers";import{Modal as s}from"@manifest-editor/components";import{useEffect as c,useMemo as l,useState as u}from"react";import{Fragment as d,jsx as f,jsxs as p}from"react/jsx-runtime";async function m(e,t){let n=h(e,t);if(!n)return null;let r=(await o(e.vault).getBestThumbnailAtSize(n,{width:512,height:512,maxWidth:512,maxHeight:512,unsafeImageService:!0,allowUnsafe:!0,preferFixedSize:!0},!1)).best?.id;if(!r)return null;let i=await fetch(r,{signal:e.signal});if(!i.ok)throw Error(`Unable to fetch canvas image (${i.status}).`);return{url:r,blob:await i.blob()}}function h(e,t){let n=t?.items&&e.vault.get(t.items)||[];for(let t of n){let n=t?.items&&e.vault.get(t.items)||[];for(let t of n){if(!g(t))continue;let n=_(t?.body);if(n)return e.vault.get(n)||n}}return null}function g(e){return(Array.isArray(e?.motivation)?e.motivation:[e?.motivation]).includes(`painting`)}function _(e){return Array.isArray(e)?e[0]??null:e??null}const v=`@manifest-editor/ocr-classification:results`;function y(e,t){typeof window>`u`||window.dispatchEvent(new CustomEvent(v,{detail:{actionId:e,result:O(t)?t:void 0}}))}function b(e){return f(x,{actionId:e})}function x({actionId:e}){let[n,r]=u(null);c(()=>{let t=t=>{let n=t.detail;n?.actionId===e&&r(n)};return window.addEventListener(v,t),()=>window.removeEventListener(v,t)},[e]);let a=n?.result,o=l(()=>a?.classifications||[],[a]),m=l(()=>a?i.map(e=>({...e,count:a.counts?.[e.id]||0})):[],[a]);return n?f(s,{title:`OCR classification results`,onClose:()=>r(null),className:`max-w-6xl`,children:f(`div`,{className:`flex min-h-0 flex-col gap-4 p-4 text-sm text-zinc-700`,children:a?p(d,{children:[p(`div`,{className:`rounded border border-zinc-200 bg-white p-4`,children:[p(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[p(`div`,{className:`min-w-0`,children:[f(`div`,{className:`text-xs font-semibold uppercase text-zinc-500`,children:`Task complete`}),p(`div`,{className:`mt-1 text-lg font-semibold text-zinc-950`,children:[`Classified `,E(a.classified),` of `,E(a.total),` canvases`]}),f(`div`,{className:`mt-1 text-sm text-zinc-500`,children:a.skipped?`${E(a.skipped)} ${a.skipped===1?`canvas was`:`canvases were`} skipped. Review the skipped list below before rerunning.`:`Every canvas was classified and tagged.`})]}),p(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 px-3 py-2 text-right`,children:[f(`div`,{className:`text-2xl font-semibold text-zinc-950`,children:D(a.classified,a.total)}),f(`div`,{className:`text-xs uppercase text-zinc-500`,children:`Coverage`})]})]}),f(`div`,{className:`mt-4 flex h-2 overflow-hidden rounded-full bg-zinc-100`,children:a.classified?m.map(e=>e.count?f(`div`,{className:`h-full`,style:{width:`${e.count/a.classified*100}%`,backgroundColor:e.backgroundColor}},e.id):null):f(`div`,{className:`h-full w-full bg-zinc-200`})}),f(`div`,{className:`mt-3 flex flex-wrap gap-2`,children:m.map(e=>p(`div`,{className:`inline-flex items-center gap-2 rounded border border-zinc-200 bg-zinc-50 px-2 py-1`,children:[f(`span`,{className:`h-2.5 w-2.5 rounded-full`,style:{backgroundColor:e.backgroundColor},"aria-hidden":`true`}),f(`span`,{className:`font-medium text-zinc-900`,children:e.label}),p(`span`,{className:`text-zinc-500`,children:[E(e.count),` (`,D(e.count,a.classified),`)`]})]},e.id))})]}),p(`div`,{className:`grid gap-2 sm:grid-cols-4`,children:[f(w,{label:`Total canvases`,value:E(a.total)}),f(w,{label:`Classified`,value:E(a.classified)}),f(w,{label:`Skipped`,value:E(a.skipped)}),f(w,{label:`Tags applied`,value:E(a.classifications.length)})]}),f(`div`,{className:`grid gap-2 sm:grid-cols-3`,children:m.map(e=>p(`div`,{className:`rounded border border-zinc-200 bg-white p-3`,children:[f(`div`,{className:`inline-flex rounded px-2 py-1 text-xs font-medium`,style:{backgroundColor:e.backgroundColor,color:e.textColor},children:e.label}),f(`div`,{className:`mt-2 text-xl font-semibold text-zinc-950`,children:E(e.count)}),p(`div`,{className:`mt-1 text-xs text-zinc-500`,children:[D(e.count,a.classified),` of classified canvases`]})]},e.id))}),o.length?p(`div`,{className:`min-h-0 overflow-hidden rounded border border-zinc-200`,children:[p(`div`,{className:`flex flex-wrap items-center justify-between gap-2 border-b border-zinc-200 bg-zinc-50 px-3 py-2`,children:[f(`div`,{className:`font-medium text-zinc-900`,children:`Classified canvases`}),p(`div`,{className:`text-xs text-zinc-500`,children:[`Showing all `,E(o.length),` classified results`]})]}),f(`div`,{className:`max-h-[55vh] overflow-auto`,children:p(`table`,{className:`w-full min-w-[820px] border-collapse text-left`,children:[f(`thead`,{className:`sticky top-0 bg-white text-xs uppercase text-zinc-500`,children:p(`tr`,{children:[f(`th`,{className:`w-14 border-b border-zinc-200 px-3 py-2 font-medium`,children:`#`}),f(`th`,{className:`border-b border-zinc-200 px-3 py-2 font-medium`,children:`Canvas`}),f(`th`,{className:`w-44 border-b border-zinc-200 px-3 py-2 font-medium`,children:`Result`}),f(`th`,{className:`w-28 border-b border-zinc-200 px-3 py-2 font-medium`,children:`Confidence`}),f(`th`,{className:`border-b border-zinc-200 px-3 py-2 font-medium`,children:`Scores`})]})}),f(`tbody`,{children:o.map((e,n)=>{let r=e.canvasLabel||e.canvasId;return p(`tr`,{className:`border-b border-zinc-100 last:border-0`,children:[f(`td`,{className:`px-3 py-2 align-top text-xs text-zinc-400`,children:n+1}),p(`td`,{className:`px-3 py-2 align-top`,title:e.canvasId,children:[f(`div`,{className:`font-medium text-zinc-900`,children:r}),r===e.canvasId?null:f(`div`,{className:`mt-0.5 break-all text-xs text-zinc-500`,children:e.canvasId})]}),f(`td`,{className:`px-3 py-2 align-top`,children:f(S,{tagId:e.tagId,label:e.label})}),f(`td`,{className:`px-3 py-2 align-top font-medium text-zinc-900`,children:t(e.score)}),f(`td`,{className:`px-3 py-2 align-top text-xs text-zinc-500`,children:f(C,{scores:e.scores})})]},e.canvasId)})})]})})]}):f(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 p-3`,children:`No canvases were classified. Check the skipped canvases and task logs for details.`}),a.skippedCanvases.length?p(`details`,{open:!0,className:`rounded border border-zinc-200 bg-zinc-50`,children:[p(`summary`,{className:`cursor-pointer px-3 py-2 font-medium text-zinc-900`,children:[`Skipped canvases (`,a.skippedCanvases.length,`)`]}),f(`div`,{className:`max-h-52 overflow-auto border-t border-zinc-200 bg-white`,children:a.skippedCanvases.map(e=>p(`div`,{className:`grid gap-1 border-b border-zinc-100 px-3 py-2 last:border-0`,children:[f(`div`,{className:`font-medium text-zinc-900`,children:e.canvasLabel||e.canvasId}),e.canvasLabel&&e.canvasLabel!==e.canvasId?f(`div`,{className:`break-all text-xs text-zinc-500`,children:e.canvasId}):null,f(`div`,{className:`text-xs text-zinc-500`,children:e.reason})]},e.canvasId))})]}):null]}):f(`div`,{className:`rounded border border-zinc-200 bg-zinc-50 p-3`,children:`No result data is available for this run.`})})}):null}function S({tagId:e,label:t}){let n=T(e);return f(`span`,{className:`inline-flex rounded px-2 py-1 text-xs font-medium`,style:{backgroundColor:n?.backgroundColor||`#f4f4f5`,color:n?.textColor||`#18181b`},children:t})}function C({scores:e}){return f(`div`,{className:`flex flex-wrap gap-1.5`,children:e.map((e,n)=>p(`span`,{className:`whitespace-nowrap rounded bg-zinc-100 px-1.5 py-0.5`,children:[i[n]?.id||`class-${n}`,`: `,t(e)]},n))})}function w({label:e,value:t}){return p(`div`,{className:`rounded border border-zinc-200 bg-white p-3`,children:[f(`div`,{className:`text-xs uppercase text-zinc-500`,children:e}),f(`div`,{className:`mt-1 text-xl font-semibold text-zinc-950`,children:t})]})}function T(e){return i.find(t=>t.id===e)}function E(e){return new Intl.NumberFormat().format(e)}function D(e,n){return n?t(e/n):`0%`}function O(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.total==`number`&&typeof t.classified==`number`&&typeof t.skipped==`number`&&!!t.counts&&typeof t.counts==`object`&&Array.isArray(t.classifications)&&Array.isArray(t.skippedCanvases)}const k=`@manifest-editor/ocr-classification/classify-canvases`;function A(e={}){let t=e.prepareClassifier||P,n=e.getCanvasImage||m,i=e.classifyImage||F;return{id:k,label:`Classify OCR difficulty`,summary:`Tag each canvas by OCR difficulty`,section:`OCR`,order:10,resourceTypes:[`Manifest`],resumable:!0,render:()=>b(k),onResults:e=>y(e.definition.id,e.instance?.result),supports:e=>!!e.vault.get(e.target)?.items?.length,prepare:e=>j(R(e)),run:async e=>{let a=e.plan||j(R(e)),o=e.tasks.getAll(),s=e.tasks.getPending();if(e.setActionLabel(`Classifying OCR difficulty`),!o.length)return e.setActionStatus(`running`,`No canvases to classify`),M(0);s.length&&(e.canvasProgress.setStatuses(s.map(e=>e.target).filter(e=>!!e&&e.type===`Canvas`),`queued`),e.setActionStatus(`running`,`Loading OCR classifier`),await t(),await e.tasks.runEach(async(t,{index:a,total:o})=>{I(e.signal);let s=t.target?.id||t.input?.canvasId||t.id,c=z(e,s),l=B(c,s),u=`Classifying ${a+1}/${o}`;e.appendActionLog(u,`info`,{canvasId:s,current:a+1,total:o});try{let t=c?await n(e,c):null;if(!t){let t={canvasId:s,canvasLabel:l,reason:`No painting image found`};return e.appendActionLog(`Skipped canvas classification`,`warn`,{canvasId:s,reason:t.reason}),{taskStatus:`skipped`,result:{type:`skipped`,skip:t}}}let a=await i(t.blob),o=r(a.prediction);e.tags.upsertTag({id:s,type:`Canvas`},o);let u={canvasId:s,canvasLabel:l,tagId:o.id,label:o.label,score:a.prediction.score,scores:a.scores,imageUrl:t.url};return e.appendActionLog(`Classified canvas`,`info`,{canvasId:s,label:o.label,score:a.prediction.score}),{taskStatus:`complete`,result:{type:`classified`,classification:u}}}catch(t){if(e.signal.aborted)throw t;let n={canvasId:s,canvasLabel:l,reason:L(t)};return e.appendActionLog(`Skipped canvas classification`,`warn`,{canvasId:s,reason:n.reason}),{taskStatus:`skipped`,result:{type:`skipped`,skip:n}}}},{progressLabel:(e,t,n)=>`Classifying ${t+1}/${n}`}));let c=N(e.tasks.getAll().length?e.tasks.getAll():a.tasks);return e.setActionStatus(`running`,`Classified ${c.classified}/${c.total}`),e.setActionProgress({current:c.total,total:c.total,label:`Classification complete`}),e.appendActionLog(`Classification complete`,`info`,{total:c.total,classified:c.classified,skipped:c.skipped,counts:c.counts}),c}}}function j(e){return{version:1,tasks:e.map((e,t)=>{let n=e?.id||`canvas-${t+1}`,r=B(e,n);return{id:`canvas:${n}`,label:r,target:{id:n,type:`Canvas`,label:r,scope:`canvas`},input:{canvasId:n,canvasLabel:r},status:`queued`}})}}function M(e){return{total:e,classified:0,skipped:0,counts:Object.fromEntries(i.map(e=>[e.id,0])),classifications:[],skippedCanvases:[]}}function N(e){let t=M(e.length);for(let n of e){let e=n.result;if(e?.type===`classified`){t.classifications.push(e.classification),t.counts[e.classification.tagId]=(t.counts[e.classification.tagId]||0)+1;continue}if(e?.type===`skipped`){t.skippedCanvases.push(e.skip);continue}if(n.status===`error`&&n.error){let e=n.target?.id||n.id;t.skippedCanvases.push({canvasId:e,canvasLabel:n.label||e,reason:n.error.message})}}return t.classified=t.classifications.length,t.skipped=t.skippedCanvases.length,t}async function P(){let{loadOcrClassifier:e}=await import(`./onnx-classifier-BRRrhiwP.js`);await e()}async function F(e){let{runOcrClassifier:t}=await import(`./onnx-classifier-BRRrhiwP.js`);return t(e)}function I(e){if(e.aborted)throw Error(`OCR classification cancelled.`)}function L(e){return e instanceof Error?e.message:`Canvas classification failed`}function R(e){let t=e.vault.get(e.target);return t?.items?(e.vault.get(t.items)||[]).filter(Boolean):[]}function z(e,t){return e.vault.get({id:t,type:`Canvas`})}function B(e,t){let n=e?.label;if(!n)return t;if(typeof n==`string`)return n;let r=Array.isArray(n.en)?n.en[0]:void 0;if(r)return r;let i=Object.keys(n)[0];return(i&&Array.isArray(n[i])?n[i][0]:void 0)||t}const V=[A()];export{k as OCR_CLASSIFICATION_ACTION_ID,i as OCR_DIFFICULTY_CLASSES,n as OCR_DIFFICULTY_TAG_TYPE,V as backgroundActions,A as createOcrClassificationBackgroundAction,r as createOcrDifficultyTag,a as default,t as formatOcrScore,e as selectOcrDifficulty};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["result","backgroundActions: BackgroundActionDefinition[]"],"sources":["../src/canvas-image.ts","../src/results.tsx","../src/background-action.ts","../src/index.ts"],"sourcesContent":["import { createThumbnailHelper } from \"@iiif/helpers\";\nimport type { BackgroundActionRunContext } from \"@manifest-editor/shell\";\n\nexport type CanvasImageForClassification = {\n url: string;\n blob: Blob;\n};\n\nexport async function getCanvasImageForClassification(\n ctx: BackgroundActionRunContext,\n canvas: any,\n): Promise<CanvasImageForClassification | null> {\n const paintingBody = getFirstPaintingBody(ctx, canvas);\n if (!paintingBody) {\n return null;\n }\n\n const thumbnailHelper = createThumbnailHelper(ctx.vault);\n const thumbnail = await thumbnailHelper.getBestThumbnailAtSize(\n paintingBody,\n {\n width: 512,\n height: 512,\n maxWidth: 512,\n maxHeight: 512,\n unsafeImageService: true,\n allowUnsafe: true,\n preferFixedSize: true,\n },\n false,\n );\n const url = thumbnail.best?.id;\n\n if (!url) {\n return null;\n }\n\n const response = await fetch(url, { signal: ctx.signal });\n if (!response.ok) {\n throw new Error(`Unable to fetch canvas image (${response.status}).`);\n }\n\n return {\n url,\n blob: await response.blob(),\n };\n}\n\nfunction getFirstPaintingBody(ctx: BackgroundActionRunContext, canvas: any) {\n const pages = canvas?.items ? ctx.vault.get(canvas.items) || [] : [];\n\n for (const page of pages) {\n const annotations = page?.items ? ctx.vault.get(page.items) || [] : [];\n for (const annotation of annotations) {\n if (!isPaintingAnnotation(annotation)) {\n continue;\n }\n\n const body = first(annotation?.body);\n if (!body) {\n continue;\n }\n\n return ctx.vault.get(body) || body;\n }\n }\n\n return null;\n}\n\nfunction isPaintingAnnotation(annotation: any) {\n const motivation = Array.isArray(annotation?.motivation) ? annotation.motivation : [annotation?.motivation];\n return motivation.includes(\"painting\");\n}\n\nfunction first<T>(value: T | T[] | null | undefined): T | null {\n if (Array.isArray(value)) {\n return value[0] ?? null;\n }\n\n return value ?? null;\n}\n","import { Modal } from \"@manifest-editor/components\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { OcrClassificationActionResult } from \"./background-action\";\nimport { formatOcrScore, OCR_DIFFICULTY_CLASSES } from \"./ocr-difficulty\";\n\nconst resultsEventName = \"@manifest-editor/ocr-classification:results\";\n\ntype OcrClassificationResultsEvent = {\n actionId: string;\n result?: OcrClassificationActionResult;\n};\n\nexport function openOcrClassificationResults(actionId: string, result: unknown) {\n if (typeof window === \"undefined\") {\n return;\n }\n\n window.dispatchEvent(\n new CustomEvent<OcrClassificationResultsEvent>(resultsEventName, {\n detail: {\n actionId,\n result: isOcrClassificationActionResult(result) ? result : undefined,\n },\n }),\n );\n}\n\nexport function renderOcrClassificationResults(actionId: string) {\n return <OcrClassificationResultsModal actionId={actionId} />;\n}\n\nfunction OcrClassificationResultsModal({ actionId }: { actionId: string }) {\n const [activeResult, setActiveResult] = useState<OcrClassificationResultsEvent | null>(null);\n\n useEffect(() => {\n const listener = (event: Event) => {\n const detail = (event as CustomEvent<OcrClassificationResultsEvent>).detail;\n if (detail?.actionId === actionId) {\n setActiveResult(detail);\n }\n };\n\n window.addEventListener(resultsEventName, listener);\n return () => window.removeEventListener(resultsEventName, listener);\n }, [actionId]);\n\n const result = activeResult?.result;\n const classifiedRows = useMemo(() => result?.classifications || [], [result]);\n const difficultyRows = useMemo(\n () =>\n result\n ? OCR_DIFFICULTY_CLASSES.map((item) => ({\n ...item,\n count: result.counts?.[item.id] || 0,\n }))\n : [],\n [result],\n );\n\n if (!activeResult) {\n return null;\n }\n\n return (\n <Modal title=\"OCR classification results\" onClose={() => setActiveResult(null)} className=\"max-w-6xl\">\n <div className=\"flex min-h-0 flex-col gap-4 p-4 text-sm text-zinc-700\">\n {!result ? (\n <div className=\"rounded border border-zinc-200 bg-zinc-50 p-3\">No result data is available for this run.</div>\n ) : (\n <>\n <div className=\"rounded border border-zinc-200 bg-white p-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"text-xs font-semibold uppercase text-zinc-500\">Task complete</div>\n <div className=\"mt-1 text-lg font-semibold text-zinc-950\">\n Classified {formatNumber(result.classified)} of {formatNumber(result.total)} canvases\n </div>\n <div className=\"mt-1 text-sm text-zinc-500\">\n {result.skipped\n ? `${formatNumber(result.skipped)} ${result.skipped === 1 ? \"canvas was\" : \"canvases were\"} skipped. Review the skipped list below before rerunning.`\n : \"Every canvas was classified and tagged.\"}\n </div>\n </div>\n <div className=\"rounded border border-zinc-200 bg-zinc-50 px-3 py-2 text-right\">\n <div className=\"text-2xl font-semibold text-zinc-950\">\n {formatRatio(result.classified, result.total)}\n </div>\n <div className=\"text-xs uppercase text-zinc-500\">Coverage</div>\n </div>\n </div>\n\n <div className=\"mt-4 flex h-2 overflow-hidden rounded-full bg-zinc-100\">\n {result.classified ? (\n difficultyRows.map((item) =>\n item.count ? (\n <div\n key={item.id}\n className=\"h-full\"\n style={{\n width: `${(item.count / result.classified) * 100}%`,\n backgroundColor: item.backgroundColor,\n }}\n />\n ) : null,\n )\n ) : (\n <div className=\"h-full w-full bg-zinc-200\" />\n )}\n </div>\n\n <div className=\"mt-3 flex flex-wrap gap-2\">\n {difficultyRows.map((item) => (\n <div\n key={item.id}\n className=\"inline-flex items-center gap-2 rounded border border-zinc-200 bg-zinc-50 px-2 py-1\"\n >\n <span\n className=\"h-2.5 w-2.5 rounded-full\"\n style={{ backgroundColor: item.backgroundColor }}\n aria-hidden=\"true\"\n />\n <span className=\"font-medium text-zinc-900\">{item.label}</span>\n <span className=\"text-zinc-500\">\n {formatNumber(item.count)} ({formatRatio(item.count, result.classified)})\n </span>\n </div>\n ))}\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-4\">\n <SummaryStat label=\"Total canvases\" value={formatNumber(result.total)} />\n <SummaryStat label=\"Classified\" value={formatNumber(result.classified)} />\n <SummaryStat label=\"Skipped\" value={formatNumber(result.skipped)} />\n <SummaryStat label=\"Tags applied\" value={formatNumber(result.classifications.length)} />\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3\">\n {difficultyRows.map((item) => (\n <div key={item.id} className=\"rounded border border-zinc-200 bg-white p-3\">\n <div\n className=\"inline-flex rounded px-2 py-1 text-xs font-medium\"\n style={{ backgroundColor: item.backgroundColor, color: item.textColor }}\n >\n {item.label}\n </div>\n <div className=\"mt-2 text-xl font-semibold text-zinc-950\">{formatNumber(item.count)}</div>\n <div className=\"mt-1 text-xs text-zinc-500\">\n {formatRatio(item.count, result.classified)} of classified canvases\n </div>\n </div>\n ))}\n </div>\n\n {classifiedRows.length ? (\n <div className=\"min-h-0 overflow-hidden rounded border border-zinc-200\">\n <div className=\"flex flex-wrap items-center justify-between gap-2 border-b border-zinc-200 bg-zinc-50 px-3 py-2\">\n <div className=\"font-medium text-zinc-900\">Classified canvases</div>\n <div className=\"text-xs text-zinc-500\">\n Showing all {formatNumber(classifiedRows.length)} classified results\n </div>\n </div>\n <div className=\"max-h-[55vh] overflow-auto\">\n <table className=\"w-full min-w-[820px] border-collapse text-left\">\n <thead className=\"sticky top-0 bg-white text-xs uppercase text-zinc-500\">\n <tr>\n <th className=\"w-14 border-b border-zinc-200 px-3 py-2 font-medium\">#</th>\n <th className=\"border-b border-zinc-200 px-3 py-2 font-medium\">Canvas</th>\n <th className=\"w-44 border-b border-zinc-200 px-3 py-2 font-medium\">Result</th>\n <th className=\"w-28 border-b border-zinc-200 px-3 py-2 font-medium\">Confidence</th>\n <th className=\"border-b border-zinc-200 px-3 py-2 font-medium\">Scores</th>\n </tr>\n </thead>\n <tbody>\n {classifiedRows.map((item, index) => {\n const canvasLabel = item.canvasLabel || item.canvasId;\n return (\n <tr key={item.canvasId} className=\"border-b border-zinc-100 last:border-0\">\n <td className=\"px-3 py-2 align-top text-xs text-zinc-400\">{index + 1}</td>\n <td className=\"px-3 py-2 align-top\" title={item.canvasId}>\n <div className=\"font-medium text-zinc-900\">{canvasLabel}</div>\n {canvasLabel !== item.canvasId ? (\n <div className=\"mt-0.5 break-all text-xs text-zinc-500\">{item.canvasId}</div>\n ) : null}\n </td>\n <td className=\"px-3 py-2 align-top\">\n <DifficultyBadge tagId={item.tagId} label={item.label} />\n </td>\n <td className=\"px-3 py-2 align-top font-medium text-zinc-900\">\n {formatOcrScore(item.score)}\n </td>\n <td className=\"px-3 py-2 align-top text-xs text-zinc-500\">\n <ScoreList scores={item.scores} />\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n </div>\n ) : (\n <div className=\"rounded border border-zinc-200 bg-zinc-50 p-3\">\n No canvases were classified. Check the skipped canvases and task logs for details.\n </div>\n )}\n\n {result.skippedCanvases.length ? (\n <details open className=\"rounded border border-zinc-200 bg-zinc-50\">\n <summary className=\"cursor-pointer px-3 py-2 font-medium text-zinc-900\">\n Skipped canvases ({result.skippedCanvases.length})\n </summary>\n <div className=\"max-h-52 overflow-auto border-t border-zinc-200 bg-white\">\n {result.skippedCanvases.map((item) => (\n <div key={item.canvasId} className=\"grid gap-1 border-b border-zinc-100 px-3 py-2 last:border-0\">\n <div className=\"font-medium text-zinc-900\">{item.canvasLabel || item.canvasId}</div>\n {item.canvasLabel && item.canvasLabel !== item.canvasId ? (\n <div className=\"break-all text-xs text-zinc-500\">{item.canvasId}</div>\n ) : null}\n <div className=\"text-xs text-zinc-500\">{item.reason}</div>\n </div>\n ))}\n </div>\n </details>\n ) : null}\n </>\n )}\n </div>\n </Modal>\n );\n}\n\nfunction DifficultyBadge({ tagId, label }: { tagId: string; label: string }) {\n const difficultyClass = getDifficultyClass(tagId);\n\n return (\n <span\n className=\"inline-flex rounded px-2 py-1 text-xs font-medium\"\n style={{\n backgroundColor: difficultyClass?.backgroundColor || \"#f4f4f5\",\n color: difficultyClass?.textColor || \"#18181b\",\n }}\n >\n {label}\n </span>\n );\n}\n\nfunction ScoreList({ scores }: { scores: number[] }) {\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {scores.map((score, index) => (\n <span key={index} className=\"whitespace-nowrap rounded bg-zinc-100 px-1.5 py-0.5\">\n {OCR_DIFFICULTY_CLASSES[index]?.id || `class-${index}`}: {formatOcrScore(score)}\n </span>\n ))}\n </div>\n );\n}\n\nfunction SummaryStat({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"rounded border border-zinc-200 bg-white p-3\">\n <div className=\"text-xs uppercase text-zinc-500\">{label}</div>\n <div className=\"mt-1 text-xl font-semibold text-zinc-950\">{value}</div>\n </div>\n );\n}\n\nfunction getDifficultyClass(tagId: string) {\n return OCR_DIFFICULTY_CLASSES.find((item) => item.id === tagId);\n}\n\nfunction formatNumber(value: number) {\n return new Intl.NumberFormat().format(value);\n}\n\nfunction formatRatio(value: number, total: number) {\n return total ? formatOcrScore(value / total) : \"0%\";\n}\n\nfunction isOcrClassificationActionResult(result: unknown): result is OcrClassificationActionResult {\n if (!result || typeof result !== \"object\") {\n return false;\n }\n\n const candidate = result as Partial<OcrClassificationActionResult>;\n return (\n typeof candidate.total === \"number\" &&\n typeof candidate.classified === \"number\" &&\n typeof candidate.skipped === \"number\" &&\n !!candidate.counts &&\n typeof candidate.counts === \"object\" &&\n Array.isArray(candidate.classifications) &&\n Array.isArray(candidate.skippedCanvases)\n );\n}\n","import type {\n BackgroundActionDefinition,\n BackgroundActionPlan,\n BackgroundActionRunContext,\n BackgroundActionTask,\n} from \"@manifest-editor/shell\";\nimport { type CanvasImageForClassification, getCanvasImageForClassification } from \"./canvas-image\";\nimport {\n createOcrDifficultyTag,\n formatOcrScore,\n OCR_DIFFICULTY_CLASSES,\n OCR_DIFFICULTY_TAG_TYPE,\n type OcrClassifierRun,\n} from \"./ocr-difficulty\";\nimport { openOcrClassificationResults, renderOcrClassificationResults } from \"./results\";\n\nexport const OCR_CLASSIFICATION_ACTION_ID = \"@manifest-editor/ocr-classification/classify-canvases\";\n\nexport type OcrCanvasClassification = {\n canvasId: string;\n canvasLabel: string;\n tagId: string;\n label: string;\n score: number;\n scores: number[];\n imageUrl: string;\n};\n\nexport type OcrCanvasClassificationSkip = {\n canvasId: string;\n canvasLabel: string;\n reason: string;\n};\n\nexport type OcrClassificationActionResult = {\n total: number;\n classified: number;\n skipped: number;\n counts: Record<string, number>;\n classifications: OcrCanvasClassification[];\n skippedCanvases: OcrCanvasClassificationSkip[];\n};\n\ntype OcrClassificationTaskResult =\n | {\n type: \"classified\";\n classification: OcrCanvasClassification;\n }\n | {\n type: \"skipped\";\n skip: OcrCanvasClassificationSkip;\n };\n\nexport type OcrClassificationActionDependencies = {\n prepareClassifier?: () => Promise<void>;\n getCanvasImage?: (ctx: BackgroundActionRunContext, canvas: any) => Promise<CanvasImageForClassification | null>;\n classifyImage?: (image: Blob) => Promise<OcrClassifierRun>;\n};\n\nexport function createOcrClassificationBackgroundAction(\n dependencies: OcrClassificationActionDependencies = {},\n): BackgroundActionDefinition {\n const prepareClassifier = dependencies.prepareClassifier || defaultPrepareClassifier;\n const getCanvasImage = dependencies.getCanvasImage || getCanvasImageForClassification;\n const classifyImage = dependencies.classifyImage || defaultClassifyImage;\n\n return {\n id: OCR_CLASSIFICATION_ACTION_ID,\n label: \"Classify OCR difficulty\",\n summary: \"Tag each canvas by OCR difficulty\",\n section: \"OCR\",\n order: 10,\n resourceTypes: [\"Manifest\"],\n resumable: true,\n render: () => renderOcrClassificationResults(OCR_CLASSIFICATION_ACTION_ID),\n onResults: (ctx) => openOcrClassificationResults(ctx.definition.id, ctx.instance?.result),\n supports: (ctx) => {\n const manifest = ctx.vault.get(ctx.target as any) as any;\n return !!manifest?.items?.length;\n },\n prepare: (ctx) => {\n return createClassificationPlan(getManifestCanvases(ctx));\n },\n run: async (ctx) => {\n const plan = ctx.plan || createClassificationPlan(getManifestCanvases(ctx));\n const tasks = ctx.tasks.getAll();\n const pendingTasks = ctx.tasks.getPending();\n\n ctx.setActionLabel(\"Classifying OCR difficulty\");\n\n if (!tasks.length) {\n ctx.setActionStatus(\"running\", \"No canvases to classify\");\n return createEmptyResult(0);\n }\n\n if (pendingTasks.length) {\n ctx.canvasProgress.setStatuses(\n pendingTasks\n .map((task) => task.target)\n .filter((target): target is NonNullable<BackgroundActionTask[\"target\"]> => !!target && target.type === \"Canvas\"),\n \"queued\",\n );\n ctx.setActionStatus(\"running\", \"Loading OCR classifier\");\n await prepareClassifier();\n\n await ctx.tasks.runEach(\n async (task, { index, total }) => {\n throwIfAborted(ctx.signal);\n const canvasId = task.target?.id || (task.input as { canvasId?: string } | undefined)?.canvasId || task.id;\n const canvas = getCanvasById(ctx, canvasId);\n const canvasLabel = getCanvasLabel(canvas, canvasId);\n const label = `Classifying ${index + 1}/${total}`;\n\n ctx.appendActionLog(label, \"info\", { canvasId, current: index + 1, total });\n\n try {\n const image = canvas ? await getCanvasImage(ctx, canvas) : null;\n if (!image) {\n const skip = {\n canvasId,\n canvasLabel,\n reason: \"No painting image found\",\n };\n ctx.appendActionLog(\"Skipped canvas classification\", \"warn\", {\n canvasId,\n reason: skip.reason,\n });\n return {\n taskStatus: \"skipped\",\n result: {\n type: \"skipped\",\n skip,\n } satisfies OcrClassificationTaskResult,\n };\n }\n\n const classification = await classifyImage(image.blob);\n const tag = createOcrDifficultyTag(classification.prediction);\n ctx.tags.upsertTag({ id: canvasId, type: \"Canvas\" }, tag);\n\n const result = {\n canvasId,\n canvasLabel,\n tagId: tag.id,\n label: tag.label,\n score: classification.prediction.score,\n scores: classification.scores,\n imageUrl: image.url,\n };\n ctx.appendActionLog(\"Classified canvas\", \"info\", {\n canvasId,\n label: tag.label,\n score: classification.prediction.score,\n });\n return {\n taskStatus: \"complete\",\n result: {\n type: \"classified\",\n classification: result,\n } satisfies OcrClassificationTaskResult,\n };\n } catch (error) {\n if (ctx.signal.aborted) {\n throw error;\n }\n\n const skip = {\n canvasId,\n canvasLabel,\n reason: getErrorMessage(error),\n };\n ctx.appendActionLog(\"Skipped canvas classification\", \"warn\", {\n canvasId,\n reason: skip.reason,\n });\n return {\n taskStatus: \"skipped\",\n result: {\n type: \"skipped\",\n skip,\n } satisfies OcrClassificationTaskResult,\n };\n }\n },\n {\n progressLabel: (_task, index, total) => `Classifying ${index + 1}/${total}`,\n },\n );\n }\n\n const result = aggregateClassificationResult(ctx.tasks.getAll().length ? ctx.tasks.getAll() : plan.tasks);\n ctx.setActionStatus(\"running\", `Classified ${result.classified}/${result.total}`);\n ctx.setActionProgress({ current: result.total, total: result.total, label: \"Classification complete\" });\n ctx.appendActionLog(\"Classification complete\", \"info\", {\n total: result.total,\n classified: result.classified,\n skipped: result.skipped,\n counts: result.counts,\n });\n\n return result;\n },\n };\n}\n\nfunction createClassificationPlan(canvases: any[]): BackgroundActionPlan {\n return {\n version: 1,\n tasks: canvases.map((canvas, index) => {\n const canvasId = canvas?.id || `canvas-${index + 1}`;\n const canvasLabel = getCanvasLabel(canvas, canvasId);\n return {\n id: `canvas:${canvasId}`,\n label: canvasLabel,\n target: {\n id: canvasId,\n type: \"Canvas\",\n label: canvasLabel,\n scope: \"canvas\",\n },\n input: {\n canvasId,\n canvasLabel,\n },\n status: \"queued\",\n };\n }),\n };\n}\n\nfunction createEmptyResult(total: number): OcrClassificationActionResult {\n return {\n total,\n classified: 0,\n skipped: 0,\n counts: Object.fromEntries(OCR_DIFFICULTY_CLASSES.map((item) => [item.id, 0])),\n classifications: [],\n skippedCanvases: [],\n };\n}\n\nfunction aggregateClassificationResult(tasks: BackgroundActionTask[]): OcrClassificationActionResult {\n const result = createEmptyResult(tasks.length);\n\n for (const task of tasks) {\n const taskResult = task.result as OcrClassificationTaskResult | undefined;\n if (taskResult?.type === \"classified\") {\n result.classifications.push(taskResult.classification);\n result.counts[taskResult.classification.tagId] = (result.counts[taskResult.classification.tagId] || 0) + 1;\n continue;\n }\n\n if (taskResult?.type === \"skipped\") {\n result.skippedCanvases.push(taskResult.skip);\n continue;\n }\n\n if (task.status === \"error\" && task.error) {\n const canvasId = task.target?.id || task.id;\n result.skippedCanvases.push({\n canvasId,\n canvasLabel: task.label || canvasId,\n reason: task.error.message,\n });\n }\n }\n\n result.classified = result.classifications.length;\n result.skipped = result.skippedCanvases.length;\n return result;\n}\n\nasync function defaultPrepareClassifier() {\n const { loadOcrClassifier } = await import(\"./onnx-classifier\");\n await loadOcrClassifier();\n}\n\nasync function defaultClassifyImage(image: Blob) {\n const { runOcrClassifier } = await import(\"./onnx-classifier\");\n return runOcrClassifier(image);\n}\n\nfunction throwIfAborted(signal: AbortSignal) {\n if (signal.aborted) {\n throw new Error(\"OCR classification cancelled.\");\n }\n}\n\nfunction getErrorMessage(error: unknown) {\n return error instanceof Error ? error.message : \"Canvas classification failed\";\n}\n\nfunction getManifestCanvases(ctx: BackgroundActionRunContext) {\n const manifest = ctx.vault.get(ctx.target as any) as any;\n return manifest?.items ? (ctx.vault.get(manifest.items) || []).filter(Boolean) : [];\n}\n\nfunction getCanvasById(ctx: BackgroundActionRunContext, canvasId: string) {\n return ctx.vault.get({ id: canvasId, type: \"Canvas\" } as any) as any;\n}\n\nfunction getCanvasLabel(canvas: any, fallback: string) {\n const label = canvas?.label;\n if (!label) {\n return fallback;\n }\n\n if (typeof label === \"string\") {\n return label;\n }\n\n const englishLabel = Array.isArray(label.en) ? label.en[0] : undefined;\n if (englishLabel) {\n return englishLabel;\n }\n\n const firstLanguage = Object.keys(label)[0];\n const firstValue = firstLanguage && Array.isArray(label[firstLanguage]) ? label[firstLanguage][0] : undefined;\n return firstValue || fallback;\n}\n\nexport { OCR_DIFFICULTY_TAG_TYPE, formatOcrScore };\n","import type { BackgroundActionDefinition } from \"@manifest-editor/shell\";\nimport { createOcrClassificationBackgroundAction } from \"./background-action\";\nexport { default } from \"./plugin\";\n\nexport const backgroundActions: BackgroundActionDefinition[] = [createOcrClassificationBackgroundAction()];\n\nexport * from \"./background-action\";\nexport * from \"./ocr-difficulty\";\n"],"mappings":"mVAQA,eAAsB,EACpB,EACA,EAC8C,CAC9C,IAAM,EAAe,EAAqB,EAAK,EAAO,CACtD,GAAI,CAAC,EACH,OAAO,KAiBT,IAAM,GAbY,MADM,EAAsB,EAAI,MAAM,CAChB,uBACtC,EACA,CACE,MAAO,IACP,OAAQ,IACR,SAAU,IACV,UAAW,IACX,mBAAoB,GACpB,YAAa,GACb,gBAAiB,GAClB,CACD,GACD,EACqB,MAAM,GAE5B,GAAI,CAAC,EACH,OAAO,KAGT,IAAM,EAAW,MAAM,MAAM,EAAK,CAAE,OAAQ,EAAI,OAAQ,CAAC,CACzD,GAAI,CAAC,EAAS,GACZ,MAAU,MAAM,iCAAiC,EAAS,OAAO,IAAI,CAGvE,MAAO,CACL,MACA,KAAM,MAAM,EAAS,MAAM,CAC5B,CAGH,SAAS,EAAqB,EAAiC,EAAa,CAC1E,IAAM,EAAQ,GAAQ,OAAQ,EAAI,MAAM,IAAI,EAAO,MAAM,EAAS,EAAE,CAEpE,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAc,GAAM,OAAQ,EAAI,MAAM,IAAI,EAAK,MAAM,EAAS,EAAE,CACtE,IAAK,IAAM,KAAc,EAAa,CACpC,GAAI,CAAC,EAAqB,EAAW,CACnC,SAGF,IAAM,EAAO,EAAM,GAAY,KAAK,CAC/B,KAIL,OAAO,EAAI,MAAM,IAAI,EAAK,EAAI,GAIlC,OAAO,KAGT,SAAS,EAAqB,EAAiB,CAE7C,OADmB,MAAM,QAAQ,GAAY,WAAW,CAAG,EAAW,WAAa,CAAC,GAAY,WAAW,EACzF,SAAS,WAAW,CAGxC,SAAS,EAAS,EAA6C,CAK7D,OAJI,MAAM,QAAQ,EAAM,CACf,EAAM,IAAM,KAGd,GAAS,KC3ElB,MAAM,EAAmB,8CAOzB,SAAgB,EAA6B,EAAkB,EAAiB,CAC1E,OAAO,OAAW,KAItB,OAAO,cACL,IAAI,YAA2C,EAAkB,CAC/D,OAAQ,CACN,WACA,OAAQ,EAAgC,EAAO,CAAG,EAAS,IAAA,GAC5D,CACF,CAAC,CACH,CAGH,SAAgB,EAA+B,EAAkB,CAC/D,OAAO,EAAC,EAAA,CAAwC,WAAA,CAAY,CAG9D,SAAS,EAA8B,CAAE,YAAkC,CACzE,GAAM,CAAC,EAAc,GAAmB,EAA+C,KAAK,CAE5F,MAAgB,CACd,IAAM,EAAY,GAAiB,CACjC,IAAM,EAAU,EAAqD,OACjE,GAAQ,WAAa,GACvB,EAAgB,EAAO,EAK3B,OADA,OAAO,iBAAiB,EAAkB,EAAS,KACtC,OAAO,oBAAoB,EAAkB,EAAS,EAClE,CAAC,EAAS,CAAC,CAEd,IAAM,EAAS,GAAc,OACvB,EAAiB,MAAc,GAAQ,iBAAmB,EAAE,CAAE,CAAC,EAAO,CAAC,CACvE,EAAiB,MAEnB,EACI,EAAuB,IAAK,IAAU,CACpC,GAAG,EACH,MAAO,EAAO,SAAS,EAAK,KAAO,EACpC,EAAE,CACH,EAAE,CACR,CAAC,EAAO,CACT,CAMD,OAJK,EAKH,EAAC,EAAA,CAAM,MAAM,6BAA6B,YAAe,EAAgB,KAAK,CAAE,UAAU,qBACxF,EAAC,MAAA,CAAI,UAAU,iEACX,EAGA,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,MAAA,CAAI,UAAU,wDACb,EAAC,MAAA,CAAI,UAAU,6DACb,EAAC,MAAA,CAAI,UAAU,oBACb,EAAC,MAAA,CAAI,UAAU,yDAAgD,iBAAmB,CAClF,EAAC,MAAA,CAAI,UAAU,qDAA2C,cAC5C,EAAa,EAAO,WAAW,CAAC,OAAK,EAAa,EAAO,MAAM,CAAC,cACxE,CACN,EAAC,MAAA,CAAI,UAAU,sCACZ,EAAO,QACJ,GAAG,EAAa,EAAO,QAAQ,CAAC,GAAG,EAAO,UAAY,EAAI,aAAe,gBAAgB,2DACzF,2CACA,GACF,CACN,EAAC,MAAA,CAAI,UAAU,2EACb,EAAC,MAAA,CAAI,UAAU,gDACZ,EAAY,EAAO,WAAY,EAAO,MAAM,EACzC,CACN,EAAC,MAAA,CAAI,UAAU,2CAAkC,YAAc,CAAA,EAC3D,CAAA,EACF,CAEN,EAAC,MAAA,CAAI,UAAU,kEACZ,EAAO,WACN,EAAe,IAAK,GAClB,EAAK,MACH,EAAC,MAAA,CAEC,UAAU,SACV,MAAO,CACL,MAAO,GAAI,EAAK,MAAQ,EAAO,WAAc,IAAI,GACjD,gBAAiB,EAAK,gBACvB,EALI,EAAK,GAMV,CACA,KACL,CAED,EAAC,MAAA,CAAI,UAAU,4BAAA,CAA8B,EAE3C,CAEN,EAAC,MAAA,CAAI,UAAU,qCACZ,EAAe,IAAK,GACnB,EAAC,MAAA,CAEC,UAAU,+FAEV,EAAC,OAAA,CACC,UAAU,2BACV,MAAO,CAAE,gBAAiB,EAAK,gBAAiB,CAChD,cAAY,QACZ,CACF,EAAC,OAAA,CAAK,UAAU,qCAA6B,EAAK,OAAa,CAC/D,EAAC,OAAA,CAAK,UAAU,0BACb,EAAa,EAAK,MAAM,CAAC,KAAG,EAAY,EAAK,MAAO,EAAO,WAAW,CAAC,MACnE,GAXF,EAAK,GAYN,CACN,EACE,GACF,CAEN,EAAC,MAAA,CAAI,UAAU,sCACb,EAAC,EAAA,CAAY,MAAM,iBAAiB,MAAO,EAAa,EAAO,MAAM,EAAI,CACzE,EAAC,EAAA,CAAY,MAAM,aAAa,MAAO,EAAa,EAAO,WAAW,EAAI,CAC1E,EAAC,EAAA,CAAY,MAAM,UAAU,MAAO,EAAa,EAAO,QAAQ,EAAI,CACpE,EAAC,EAAA,CAAY,MAAM,eAAe,MAAO,EAAa,EAAO,gBAAgB,OAAO,EAAI,GACpF,CAEN,EAAC,MAAA,CAAI,UAAU,qCACZ,EAAe,IAAK,GACnB,EAAC,MAAA,CAAkB,UAAU,wDAC3B,EAAC,MAAA,CACC,UAAU,oDACV,MAAO,CAAE,gBAAiB,EAAK,gBAAiB,MAAO,EAAK,UAAW,UAEtE,EAAK,OACF,CACN,EAAC,MAAA,CAAI,UAAU,oDAA4C,EAAa,EAAK,MAAM,EAAO,CAC1F,EAAC,MAAA,CAAI,UAAU,uCACZ,EAAY,EAAK,MAAO,EAAO,WAAW,CAAC,0BAAA,EACxC,GAVE,EAAK,GAWT,CACN,EACE,CAEL,EAAe,OACd,EAAC,MAAA,CAAI,UAAU,mEACb,EAAC,MAAA,CAAI,UAAU,4GACb,EAAC,MAAA,CAAI,UAAU,qCAA4B,uBAAyB,CACpE,EAAC,MAAA,CAAI,UAAU,kCAAwB,eACxB,EAAa,EAAe,OAAO,CAAC,wBAC7C,CAAA,EACF,CACN,EAAC,MAAA,CAAI,UAAU,sCACb,EAAC,QAAA,CAAM,UAAU,2DACf,EAAC,QAAA,CAAM,UAAU,iEACf,EAAC,KAAA,CAAA,SAAA,CACC,EAAC,KAAA,CAAG,UAAU,+DAAsD,KAAM,CAC1E,EAAC,KAAA,CAAG,UAAU,0DAAiD,UAAW,CAC1E,EAAC,KAAA,CAAG,UAAU,+DAAsD,UAAW,CAC/E,EAAC,KAAA,CAAG,UAAU,+DAAsD,cAAe,CACnF,EAAC,KAAA,CAAG,UAAU,0DAAiD,UAAW,GACvE,EACC,CACR,EAAC,QAAA,CAAA,SACE,EAAe,KAAK,EAAM,IAAU,CACnC,IAAM,EAAc,EAAK,aAAe,EAAK,SAC7C,OACE,EAAC,KAAA,CAAuB,UAAU,mDAChC,EAAC,KAAA,CAAG,UAAU,qDAA6C,EAAQ,GAAO,CAC1E,EAAC,KAAA,CAAG,UAAU,sBAAsB,MAAO,EAAK,mBAC9C,EAAC,MAAA,CAAI,UAAU,qCAA6B,GAAkB,CAC7D,IAAgB,EAAK,SAElB,KADF,EAAC,MAAA,CAAI,UAAU,kDAA0C,EAAK,UAAe,CAC3E,EACD,CACL,EAAC,KAAA,CAAG,UAAU,+BACZ,EAAC,EAAA,CAAgB,MAAO,EAAK,MAAO,MAAO,EAAK,OAAS,EACtD,CACL,EAAC,KAAA,CAAG,UAAU,yDACX,EAAe,EAAK,MAAM,EACxB,CACL,EAAC,KAAA,CAAG,UAAU,qDACZ,EAAC,EAAA,CAAU,OAAQ,EAAK,OAAA,CAAU,EAC/B,GAhBE,EAAK,SAiBT,EAEP,CAAA,CACI,CAAA,EACF,EACJ,CAAA,EACF,CAEN,EAAC,MAAA,CAAI,UAAU,yDAAgD,sFAEzD,CAGP,EAAO,gBAAgB,OACtB,EAAC,UAAA,CAAQ,KAAA,GAAK,UAAU,sDACtB,EAAC,UAAA,CAAQ,UAAU,+DAAqD,qBACnD,EAAO,gBAAgB,OAAO,MACzC,CACV,EAAC,MAAA,CAAI,UAAU,oEACZ,EAAO,gBAAgB,IAAK,GAC3B,EAAC,MAAA,CAAwB,UAAU,wEACjC,EAAC,MAAA,CAAI,UAAU,qCAA6B,EAAK,aAAe,EAAK,UAAe,CACnF,EAAK,aAAe,EAAK,cAAgB,EAAK,SAC7C,EAAC,MAAA,CAAI,UAAU,2CAAmC,EAAK,UAAe,CACpE,KACJ,EAAC,MAAA,CAAI,UAAU,iCAAyB,EAAK,QAAa,GALlD,EAAK,SAMT,CACN,EACE,CAAA,EACE,CACR,OACH,CA9JH,EAAC,MAAA,CAAI,UAAU,yDAAgD,6CAA+C,EAgK5G,EACA,CAxKD,KA4KX,SAAS,EAAgB,CAAE,QAAO,SAA2C,CAC3E,IAAM,EAAkB,EAAmB,EAAM,CAEjD,OACE,EAAC,OAAA,CACC,UAAU,oDACV,MAAO,CACL,gBAAiB,GAAiB,iBAAmB,UACrD,MAAO,GAAiB,WAAa,UACtC,UAEA,GACI,CAIX,SAAS,EAAU,CAAE,UAAgC,CACnD,OACE,EAAC,MAAA,CAAI,UAAU,kCACZ,EAAO,KAAK,EAAO,IAClB,EAAC,OAAA,CAAiB,UAAU,gEACzB,EAAuB,IAAQ,IAAM,SAAS,IAAQ,KAAG,EAAe,EAAM,GADtE,EAEJ,CACP,EACE,CAIV,SAAS,EAAY,CAAE,QAAO,SAA2C,CACvE,OACE,EAAC,MAAA,CAAI,UAAU,wDACb,EAAC,MAAA,CAAI,UAAU,2CAAmC,GAAY,CAC9D,EAAC,MAAA,CAAI,UAAU,oDAA4C,GAAY,CAAA,EACnE,CAIV,SAAS,EAAmB,EAAe,CACzC,OAAO,EAAuB,KAAM,GAAS,EAAK,KAAO,EAAM,CAGjE,SAAS,EAAa,EAAe,CACnC,OAAO,IAAI,KAAK,cAAc,CAAC,OAAO,EAAM,CAG9C,SAAS,EAAY,EAAe,EAAe,CACjD,OAAO,EAAQ,EAAe,EAAQ,EAAM,CAAG,KAGjD,SAAS,EAAgC,EAA0D,CACjG,GAAI,CAAC,GAAU,OAAO,GAAW,SAC/B,MAAO,GAGT,IAAM,EAAY,EAClB,OACE,OAAO,EAAU,OAAU,UAC3B,OAAO,EAAU,YAAe,UAChC,OAAO,EAAU,SAAY,UAC7B,CAAC,CAAC,EAAU,QACZ,OAAO,EAAU,QAAW,UAC5B,MAAM,QAAQ,EAAU,gBAAgB,EACxC,MAAM,QAAQ,EAAU,gBAAgB,CCtR5C,MAAa,EAA+B,wDA2C5C,SAAgB,EACd,EAAoD,EAAE,CAC1B,CAC5B,IAAM,EAAoB,EAAa,mBAAqB,EACtD,EAAiB,EAAa,gBAAkB,EAChD,EAAgB,EAAa,eAAiB,EAEpD,MAAO,CACL,GAAI,EACJ,MAAO,0BACP,QAAS,oCACT,QAAS,MACT,MAAO,GACP,cAAe,CAAC,WAAW,CAC3B,UAAW,GACX,WAAc,EAA+B,EAA6B,CAC1E,UAAY,GAAQ,EAA6B,EAAI,WAAW,GAAI,EAAI,UAAU,OAAO,CACzF,SAAW,GAEF,CAAC,CADS,EAAI,MAAM,IAAI,EAAI,OAAc,EAC9B,OAAO,OAE5B,QAAU,GACD,EAAyB,EAAoB,EAAI,CAAC,CAE3D,IAAK,KAAO,IAAQ,CAClB,IAAM,EAAO,EAAI,MAAQ,EAAyB,EAAoB,EAAI,CAAC,CACrE,EAAQ,EAAI,MAAM,QAAQ,CAC1B,EAAe,EAAI,MAAM,YAAY,CAI3C,GAFA,EAAI,eAAe,6BAA6B,CAE5C,CAAC,EAAM,OAET,OADA,EAAI,gBAAgB,UAAW,0BAA0B,CAClD,EAAkB,EAAE,CAGzB,EAAa,SACf,EAAI,eAAe,YACjB,EACG,IAAK,GAAS,EAAK,OAAO,CAC1B,OAAQ,GAAkE,CAAC,CAAC,GAAU,EAAO,OAAS,SAAS,CAClH,SACD,CACD,EAAI,gBAAgB,UAAW,yBAAyB,CACxD,MAAM,GAAmB,CAEzB,MAAM,EAAI,MAAM,QACd,MAAO,EAAM,CAAE,QAAO,WAAY,CAChC,EAAe,EAAI,OAAO,CAC1B,IAAM,EAAW,EAAK,QAAQ,IAAO,EAAK,OAA6C,UAAY,EAAK,GAClG,EAAS,EAAc,EAAK,EAAS,CACrC,EAAc,EAAe,EAAQ,EAAS,CAC9C,EAAQ,eAAe,EAAQ,EAAE,GAAG,IAE1C,EAAI,gBAAgB,EAAO,OAAQ,CAAE,WAAU,QAAS,EAAQ,EAAG,QAAO,CAAC,CAE3E,GAAI,CACF,IAAM,EAAQ,EAAS,MAAM,EAAe,EAAK,EAAO,CAAG,KAC3D,GAAI,CAAC,EAAO,CACV,IAAM,EAAO,CACX,WACA,cACA,OAAQ,0BACT,CAKD,OAJA,EAAI,gBAAgB,gCAAiC,OAAQ,CAC3D,WACA,OAAQ,EAAK,OACd,CAAC,CACK,CACL,WAAY,UACZ,OAAQ,CACN,KAAM,UACN,OACD,CACF,CAGH,IAAM,EAAiB,MAAM,EAAc,EAAM,KAAK,CAChD,EAAM,EAAuB,EAAe,WAAW,CAC7D,EAAI,KAAK,UAAU,CAAE,GAAI,EAAU,KAAM,SAAU,CAAE,EAAI,CAEzD,IAAMA,EAAS,CACb,WACA,cACA,MAAO,EAAI,GACX,MAAO,EAAI,MACX,MAAO,EAAe,WAAW,MACjC,OAAQ,EAAe,OACvB,SAAU,EAAM,IACjB,CAMD,OALA,EAAI,gBAAgB,oBAAqB,OAAQ,CAC/C,WACA,MAAO,EAAI,MACX,MAAO,EAAe,WAAW,MAClC,CAAC,CACK,CACL,WAAY,WACZ,OAAQ,CACN,KAAM,aACN,eAAgBA,EACjB,CACF,OACM,EAAO,CACd,GAAI,EAAI,OAAO,QACb,MAAM,EAGR,IAAM,EAAO,CACX,WACA,cACA,OAAQ,EAAgB,EAAM,CAC/B,CAKD,OAJA,EAAI,gBAAgB,gCAAiC,OAAQ,CAC3D,WACA,OAAQ,EAAK,OACd,CAAC,CACK,CACL,WAAY,UACZ,OAAQ,CACN,KAAM,UACN,OACD,CACF,GAGL,CACE,eAAgB,EAAO,EAAO,IAAU,eAAe,EAAQ,EAAE,GAAG,IACrE,CACF,EAGH,IAAM,EAAS,EAA8B,EAAI,MAAM,QAAQ,CAAC,OAAS,EAAI,MAAM,QAAQ,CAAG,EAAK,MAAM,CAUzG,OATA,EAAI,gBAAgB,UAAW,cAAc,EAAO,WAAW,GAAG,EAAO,QAAQ,CACjF,EAAI,kBAAkB,CAAE,QAAS,EAAO,MAAO,MAAO,EAAO,MAAO,MAAO,0BAA2B,CAAC,CACvG,EAAI,gBAAgB,0BAA2B,OAAQ,CACrD,MAAO,EAAO,MACd,WAAY,EAAO,WACnB,QAAS,EAAO,QAChB,OAAQ,EAAO,OAChB,CAAC,CAEK,GAEV,CAGH,SAAS,EAAyB,EAAuC,CACvE,MAAO,CACL,QAAS,EACT,MAAO,EAAS,KAAK,EAAQ,IAAU,CACrC,IAAM,EAAW,GAAQ,IAAM,UAAU,EAAQ,IAC3C,EAAc,EAAe,EAAQ,EAAS,CACpD,MAAO,CACL,GAAI,UAAU,IACd,MAAO,EACP,OAAQ,CACN,GAAI,EACJ,KAAM,SACN,MAAO,EACP,MAAO,SACR,CACD,MAAO,CACL,WACA,cACD,CACD,OAAQ,SACT,EACD,CACH,CAGH,SAAS,EAAkB,EAA8C,CACvE,MAAO,CACL,QACA,WAAY,EACZ,QAAS,EACT,OAAQ,OAAO,YAAY,EAAuB,IAAK,GAAS,CAAC,EAAK,GAAI,EAAE,CAAC,CAAC,CAC9E,gBAAiB,EAAE,CACnB,gBAAiB,EAAE,CACpB,CAGH,SAAS,EAA8B,EAA8D,CACnG,IAAM,EAAS,EAAkB,EAAM,OAAO,CAE9C,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAa,EAAK,OACxB,GAAI,GAAY,OAAS,aAAc,CACrC,EAAO,gBAAgB,KAAK,EAAW,eAAe,CACtD,EAAO,OAAO,EAAW,eAAe,QAAU,EAAO,OAAO,EAAW,eAAe,QAAU,GAAK,EACzG,SAGF,GAAI,GAAY,OAAS,UAAW,CAClC,EAAO,gBAAgB,KAAK,EAAW,KAAK,CAC5C,SAGF,GAAI,EAAK,SAAW,SAAW,EAAK,MAAO,CACzC,IAAM,EAAW,EAAK,QAAQ,IAAM,EAAK,GACzC,EAAO,gBAAgB,KAAK,CAC1B,WACA,YAAa,EAAK,OAAS,EAC3B,OAAQ,EAAK,MAAM,QACpB,CAAC,EAMN,MAFA,GAAO,WAAa,EAAO,gBAAgB,OAC3C,EAAO,QAAU,EAAO,gBAAgB,OACjC,EAGT,eAAe,GAA2B,CACxC,GAAM,CAAE,qBAAsB,MAAM,OAAO,iCAC3C,MAAM,GAAmB,CAG3B,eAAe,EAAqB,EAAa,CAC/C,GAAM,CAAE,oBAAqB,MAAM,OAAO,iCAC1C,OAAO,EAAiB,EAAM,CAGhC,SAAS,EAAe,EAAqB,CAC3C,GAAI,EAAO,QACT,MAAU,MAAM,gCAAgC,CAIpD,SAAS,EAAgB,EAAgB,CACvC,OAAO,aAAiB,MAAQ,EAAM,QAAU,+BAGlD,SAAS,EAAoB,EAAiC,CAC5D,IAAM,EAAW,EAAI,MAAM,IAAI,EAAI,OAAc,CACjD,OAAO,GAAU,OAAS,EAAI,MAAM,IAAI,EAAS,MAAM,EAAI,EAAE,EAAE,OAAO,QAAQ,CAAG,EAAE,CAGrF,SAAS,EAAc,EAAiC,EAAkB,CACxE,OAAO,EAAI,MAAM,IAAI,CAAE,GAAI,EAAU,KAAM,SAAU,CAAQ,CAG/D,SAAS,EAAe,EAAa,EAAkB,CACrD,IAAM,EAAQ,GAAQ,MACtB,GAAI,CAAC,EACH,OAAO,EAGT,GAAI,OAAO,GAAU,SACnB,OAAO,EAGT,IAAM,EAAe,MAAM,QAAQ,EAAM,GAAG,CAAG,EAAM,GAAG,GAAK,IAAA,GAC7D,GAAI,EACF,OAAO,EAGT,IAAM,EAAgB,OAAO,KAAK,EAAM,CAAC,GAEzC,OADmB,GAAiB,MAAM,QAAQ,EAAM,GAAe,CAAG,EAAM,GAAe,GAAK,IAAA,KAC/E,EC1TvB,MAAaC,EAAkD,CAAC,GAAyC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/canvas-image.ts","../src/results.tsx","../src/background-action.ts","../src/index.ts"],"sourcesContent":["import { createThumbnailHelper } from \"@iiif/helpers\";\nimport type { BackgroundActionRunContext } from \"@manifest-editor/shell\";\n\nexport type CanvasImageForClassification = {\n url: string;\n blob: Blob;\n};\n\nexport async function getCanvasImageForClassification(\n ctx: BackgroundActionRunContext,\n canvas: any,\n): Promise<CanvasImageForClassification | null> {\n const paintingBody = getFirstPaintingBody(ctx, canvas);\n if (!paintingBody) {\n return null;\n }\n\n const thumbnailHelper = createThumbnailHelper(ctx.vault);\n const thumbnail = await thumbnailHelper.getBestThumbnailAtSize(\n paintingBody,\n {\n width: 512,\n height: 512,\n maxWidth: 512,\n maxHeight: 512,\n unsafeImageService: true,\n allowUnsafe: true,\n preferFixedSize: true,\n },\n false,\n );\n const url = thumbnail.best?.id;\n\n if (!url) {\n return null;\n }\n\n const response = await fetch(url, { signal: ctx.signal });\n if (!response.ok) {\n throw new Error(`Unable to fetch canvas image (${response.status}).`);\n }\n\n return {\n url,\n blob: await response.blob(),\n };\n}\n\nfunction getFirstPaintingBody(ctx: BackgroundActionRunContext, canvas: any) {\n const pages = canvas?.items ? ctx.vault.get(canvas.items) || [] : [];\n\n for (const page of pages) {\n const annotations = page?.items ? ctx.vault.get(page.items) || [] : [];\n for (const annotation of annotations) {\n if (!isPaintingAnnotation(annotation)) {\n continue;\n }\n\n const body = first(annotation?.body);\n if (!body) {\n continue;\n }\n\n return ctx.vault.get(body) || body;\n }\n }\n\n return null;\n}\n\nfunction isPaintingAnnotation(annotation: any) {\n const motivation = Array.isArray(annotation?.motivation) ? annotation.motivation : [annotation?.motivation];\n return motivation.includes(\"painting\");\n}\n\nfunction first<T>(value: T | T[] | null | undefined): T | null {\n if (Array.isArray(value)) {\n return value[0] ?? null;\n }\n\n return value ?? null;\n}\n","import { Modal } from \"@manifest-editor/components\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { OcrClassificationActionResult } from \"./background-action\";\nimport { formatOcrScore, OCR_DIFFICULTY_CLASSES } from \"./ocr-difficulty\";\n\nconst resultsEventName = \"@manifest-editor/ocr-classification:results\";\n\ntype OcrClassificationResultsEvent = {\n actionId: string;\n result?: OcrClassificationActionResult;\n};\n\nexport function openOcrClassificationResults(actionId: string, result: unknown) {\n if (typeof window === \"undefined\") {\n return;\n }\n\n window.dispatchEvent(\n new CustomEvent<OcrClassificationResultsEvent>(resultsEventName, {\n detail: {\n actionId,\n result: isOcrClassificationActionResult(result) ? result : undefined,\n },\n }),\n );\n}\n\nexport function renderOcrClassificationResults(actionId: string) {\n return <OcrClassificationResultsModal actionId={actionId} />;\n}\n\nfunction OcrClassificationResultsModal({ actionId }: { actionId: string }) {\n const [activeResult, setActiveResult] = useState<OcrClassificationResultsEvent | null>(null);\n\n useEffect(() => {\n const listener = (event: Event) => {\n const detail = (event as CustomEvent<OcrClassificationResultsEvent>).detail;\n if (detail?.actionId === actionId) {\n setActiveResult(detail);\n }\n };\n\n window.addEventListener(resultsEventName, listener);\n return () => window.removeEventListener(resultsEventName, listener);\n }, [actionId]);\n\n const result = activeResult?.result;\n const classifiedRows = useMemo(() => result?.classifications || [], [result]);\n const difficultyRows = useMemo(\n () =>\n result\n ? OCR_DIFFICULTY_CLASSES.map((item) => ({\n ...item,\n count: result.counts?.[item.id] || 0,\n }))\n : [],\n [result],\n );\n\n if (!activeResult) {\n return null;\n }\n\n return (\n <Modal title=\"OCR classification results\" onClose={() => setActiveResult(null)} className=\"max-w-6xl\">\n <div className=\"flex min-h-0 flex-col gap-4 p-4 text-sm text-zinc-700\">\n {!result ? (\n <div className=\"rounded border border-zinc-200 bg-zinc-50 p-3\">No result data is available for this run.</div>\n ) : (\n <>\n <div className=\"rounded border border-zinc-200 bg-white p-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"text-xs font-semibold uppercase text-zinc-500\">Task complete</div>\n <div className=\"mt-1 text-lg font-semibold text-zinc-950\">\n Classified {formatNumber(result.classified)} of {formatNumber(result.total)} canvases\n </div>\n <div className=\"mt-1 text-sm text-zinc-500\">\n {result.skipped\n ? `${formatNumber(result.skipped)} ${result.skipped === 1 ? \"canvas was\" : \"canvases were\"} skipped. Review the skipped list below before rerunning.`\n : \"Every canvas was classified and tagged.\"}\n </div>\n </div>\n <div className=\"rounded border border-zinc-200 bg-zinc-50 px-3 py-2 text-right\">\n <div className=\"text-2xl font-semibold text-zinc-950\">\n {formatRatio(result.classified, result.total)}\n </div>\n <div className=\"text-xs uppercase text-zinc-500\">Coverage</div>\n </div>\n </div>\n\n <div className=\"mt-4 flex h-2 overflow-hidden rounded-full bg-zinc-100\">\n {result.classified ? (\n difficultyRows.map((item) =>\n item.count ? (\n <div\n key={item.id}\n className=\"h-full\"\n style={{\n width: `${(item.count / result.classified) * 100}%`,\n backgroundColor: item.backgroundColor,\n }}\n />\n ) : null,\n )\n ) : (\n <div className=\"h-full w-full bg-zinc-200\" />\n )}\n </div>\n\n <div className=\"mt-3 flex flex-wrap gap-2\">\n {difficultyRows.map((item) => (\n <div\n key={item.id}\n className=\"inline-flex items-center gap-2 rounded border border-zinc-200 bg-zinc-50 px-2 py-1\"\n >\n <span\n className=\"h-2.5 w-2.5 rounded-full\"\n style={{ backgroundColor: item.backgroundColor }}\n aria-hidden=\"true\"\n />\n <span className=\"font-medium text-zinc-900\">{item.label}</span>\n <span className=\"text-zinc-500\">\n {formatNumber(item.count)} ({formatRatio(item.count, result.classified)})\n </span>\n </div>\n ))}\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-4\">\n <SummaryStat label=\"Total canvases\" value={formatNumber(result.total)} />\n <SummaryStat label=\"Classified\" value={formatNumber(result.classified)} />\n <SummaryStat label=\"Skipped\" value={formatNumber(result.skipped)} />\n <SummaryStat label=\"Tags applied\" value={formatNumber(result.classifications.length)} />\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3\">\n {difficultyRows.map((item) => (\n <div key={item.id} className=\"rounded border border-zinc-200 bg-white p-3\">\n <div\n className=\"inline-flex rounded px-2 py-1 text-xs font-medium\"\n style={{ backgroundColor: item.backgroundColor, color: item.textColor }}\n >\n {item.label}\n </div>\n <div className=\"mt-2 text-xl font-semibold text-zinc-950\">{formatNumber(item.count)}</div>\n <div className=\"mt-1 text-xs text-zinc-500\">\n {formatRatio(item.count, result.classified)} of classified canvases\n </div>\n </div>\n ))}\n </div>\n\n {classifiedRows.length ? (\n <div className=\"min-h-0 overflow-hidden rounded border border-zinc-200\">\n <div className=\"flex flex-wrap items-center justify-between gap-2 border-b border-zinc-200 bg-zinc-50 px-3 py-2\">\n <div className=\"font-medium text-zinc-900\">Classified canvases</div>\n <div className=\"text-xs text-zinc-500\">\n Showing all {formatNumber(classifiedRows.length)} classified results\n </div>\n </div>\n <div className=\"max-h-[55vh] overflow-auto\">\n <table className=\"w-full min-w-[820px] border-collapse text-left\">\n <thead className=\"sticky top-0 bg-white text-xs uppercase text-zinc-500\">\n <tr>\n <th className=\"w-14 border-b border-zinc-200 px-3 py-2 font-medium\">#</th>\n <th className=\"border-b border-zinc-200 px-3 py-2 font-medium\">Canvas</th>\n <th className=\"w-44 border-b border-zinc-200 px-3 py-2 font-medium\">Result</th>\n <th className=\"w-28 border-b border-zinc-200 px-3 py-2 font-medium\">Confidence</th>\n <th className=\"border-b border-zinc-200 px-3 py-2 font-medium\">Scores</th>\n </tr>\n </thead>\n <tbody>\n {classifiedRows.map((item, index) => {\n const canvasLabel = item.canvasLabel || item.canvasId;\n return (\n <tr key={item.canvasId} className=\"border-b border-zinc-100 last:border-0\">\n <td className=\"px-3 py-2 align-top text-xs text-zinc-400\">{index + 1}</td>\n <td className=\"px-3 py-2 align-top\" title={item.canvasId}>\n <div className=\"font-medium text-zinc-900\">{canvasLabel}</div>\n {canvasLabel !== item.canvasId ? (\n <div className=\"mt-0.5 break-all text-xs text-zinc-500\">{item.canvasId}</div>\n ) : null}\n </td>\n <td className=\"px-3 py-2 align-top\">\n <DifficultyBadge tagId={item.tagId} label={item.label} />\n </td>\n <td className=\"px-3 py-2 align-top font-medium text-zinc-900\">\n {formatOcrScore(item.score)}\n </td>\n <td className=\"px-3 py-2 align-top text-xs text-zinc-500\">\n <ScoreList scores={item.scores} />\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n </div>\n ) : (\n <div className=\"rounded border border-zinc-200 bg-zinc-50 p-3\">\n No canvases were classified. Check the skipped canvases and task logs for details.\n </div>\n )}\n\n {result.skippedCanvases.length ? (\n <details open className=\"rounded border border-zinc-200 bg-zinc-50\">\n <summary className=\"cursor-pointer px-3 py-2 font-medium text-zinc-900\">\n Skipped canvases ({result.skippedCanvases.length})\n </summary>\n <div className=\"max-h-52 overflow-auto border-t border-zinc-200 bg-white\">\n {result.skippedCanvases.map((item) => (\n <div key={item.canvasId} className=\"grid gap-1 border-b border-zinc-100 px-3 py-2 last:border-0\">\n <div className=\"font-medium text-zinc-900\">{item.canvasLabel || item.canvasId}</div>\n {item.canvasLabel && item.canvasLabel !== item.canvasId ? (\n <div className=\"break-all text-xs text-zinc-500\">{item.canvasId}</div>\n ) : null}\n <div className=\"text-xs text-zinc-500\">{item.reason}</div>\n </div>\n ))}\n </div>\n </details>\n ) : null}\n </>\n )}\n </div>\n </Modal>\n );\n}\n\nfunction DifficultyBadge({ tagId, label }: { tagId: string; label: string }) {\n const difficultyClass = getDifficultyClass(tagId);\n\n return (\n <span\n className=\"inline-flex rounded px-2 py-1 text-xs font-medium\"\n style={{\n backgroundColor: difficultyClass?.backgroundColor || \"#f4f4f5\",\n color: difficultyClass?.textColor || \"#18181b\",\n }}\n >\n {label}\n </span>\n );\n}\n\nfunction ScoreList({ scores }: { scores: number[] }) {\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {scores.map((score, index) => (\n <span key={index} className=\"whitespace-nowrap rounded bg-zinc-100 px-1.5 py-0.5\">\n {OCR_DIFFICULTY_CLASSES[index]?.id || `class-${index}`}: {formatOcrScore(score)}\n </span>\n ))}\n </div>\n );\n}\n\nfunction SummaryStat({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"rounded border border-zinc-200 bg-white p-3\">\n <div className=\"text-xs uppercase text-zinc-500\">{label}</div>\n <div className=\"mt-1 text-xl font-semibold text-zinc-950\">{value}</div>\n </div>\n );\n}\n\nfunction getDifficultyClass(tagId: string) {\n return OCR_DIFFICULTY_CLASSES.find((item) => item.id === tagId);\n}\n\nfunction formatNumber(value: number) {\n return new Intl.NumberFormat().format(value);\n}\n\nfunction formatRatio(value: number, total: number) {\n return total ? formatOcrScore(value / total) : \"0%\";\n}\n\nfunction isOcrClassificationActionResult(result: unknown): result is OcrClassificationActionResult {\n if (!result || typeof result !== \"object\") {\n return false;\n }\n\n const candidate = result as Partial<OcrClassificationActionResult>;\n return (\n typeof candidate.total === \"number\" &&\n typeof candidate.classified === \"number\" &&\n typeof candidate.skipped === \"number\" &&\n !!candidate.counts &&\n typeof candidate.counts === \"object\" &&\n Array.isArray(candidate.classifications) &&\n Array.isArray(candidate.skippedCanvases)\n );\n}\n","import type {\n BackgroundActionDefinition,\n BackgroundActionPlan,\n BackgroundActionRunContext,\n BackgroundActionTask,\n} from \"@manifest-editor/shell\";\nimport { type CanvasImageForClassification, getCanvasImageForClassification } from \"./canvas-image\";\nimport {\n createOcrDifficultyTag,\n formatOcrScore,\n OCR_DIFFICULTY_CLASSES,\n OCR_DIFFICULTY_TAG_TYPE,\n type OcrClassifierRun,\n} from \"./ocr-difficulty\";\nimport { openOcrClassificationResults, renderOcrClassificationResults } from \"./results\";\n\nexport const OCR_CLASSIFICATION_ACTION_ID = \"@manifest-editor/ocr-classification/classify-canvases\";\n\nexport type OcrCanvasClassification = {\n canvasId: string;\n canvasLabel: string;\n tagId: string;\n label: string;\n score: number;\n scores: number[];\n imageUrl: string;\n};\n\nexport type OcrCanvasClassificationSkip = {\n canvasId: string;\n canvasLabel: string;\n reason: string;\n};\n\nexport type OcrClassificationActionResult = {\n total: number;\n classified: number;\n skipped: number;\n counts: Record<string, number>;\n classifications: OcrCanvasClassification[];\n skippedCanvases: OcrCanvasClassificationSkip[];\n};\n\ntype OcrClassificationTaskResult =\n | {\n type: \"classified\";\n classification: OcrCanvasClassification;\n }\n | {\n type: \"skipped\";\n skip: OcrCanvasClassificationSkip;\n };\n\nexport type OcrClassificationActionDependencies = {\n prepareClassifier?: () => Promise<void>;\n getCanvasImage?: (ctx: BackgroundActionRunContext, canvas: any) => Promise<CanvasImageForClassification | null>;\n classifyImage?: (image: Blob) => Promise<OcrClassifierRun>;\n};\n\nexport function createOcrClassificationBackgroundAction(\n dependencies: OcrClassificationActionDependencies = {},\n): BackgroundActionDefinition {\n const prepareClassifier = dependencies.prepareClassifier || defaultPrepareClassifier;\n const getCanvasImage = dependencies.getCanvasImage || getCanvasImageForClassification;\n const classifyImage = dependencies.classifyImage || defaultClassifyImage;\n\n return {\n id: OCR_CLASSIFICATION_ACTION_ID,\n label: \"Classify OCR difficulty\",\n summary: \"Tag each canvas by OCR difficulty\",\n section: \"OCR\",\n order: 10,\n resourceTypes: [\"Manifest\"],\n resumable: true,\n render: () => renderOcrClassificationResults(OCR_CLASSIFICATION_ACTION_ID),\n onResults: (ctx) => openOcrClassificationResults(ctx.definition.id, ctx.instance?.result),\n supports: (ctx) => {\n const manifest = ctx.vault.get(ctx.target as any) as any;\n return !!manifest?.items?.length;\n },\n prepare: (ctx) => {\n return createClassificationPlan(getManifestCanvases(ctx));\n },\n run: async (ctx) => {\n const plan = ctx.plan || createClassificationPlan(getManifestCanvases(ctx));\n const tasks = ctx.tasks.getAll();\n const pendingTasks = ctx.tasks.getPending();\n\n ctx.setActionLabel(\"Classifying OCR difficulty\");\n\n if (!tasks.length) {\n ctx.setActionStatus(\"running\", \"No canvases to classify\");\n return createEmptyResult(0);\n }\n\n if (pendingTasks.length) {\n ctx.canvasProgress.setStatuses(\n pendingTasks\n .map((task) => task.target)\n .filter((target): target is NonNullable<BackgroundActionTask[\"target\"]> => !!target && target.type === \"Canvas\"),\n \"queued\",\n );\n ctx.setActionStatus(\"running\", \"Loading OCR classifier\");\n await prepareClassifier();\n\n await ctx.tasks.runEach(\n async (task, { index, total }) => {\n throwIfAborted(ctx.signal);\n const canvasId = task.target?.id || (task.input as { canvasId?: string } | undefined)?.canvasId || task.id;\n const canvas = getCanvasById(ctx, canvasId);\n const canvasLabel = getCanvasLabel(canvas, canvasId);\n const label = `Classifying ${index + 1}/${total}`;\n\n ctx.appendActionLog(label, \"info\", { canvasId, current: index + 1, total });\n\n try {\n const image = canvas ? await getCanvasImage(ctx, canvas) : null;\n if (!image) {\n const skip = {\n canvasId,\n canvasLabel,\n reason: \"No painting image found\",\n };\n ctx.appendActionLog(\"Skipped canvas classification\", \"warn\", {\n canvasId,\n reason: skip.reason,\n });\n return {\n taskStatus: \"skipped\",\n result: {\n type: \"skipped\",\n skip,\n } satisfies OcrClassificationTaskResult,\n };\n }\n\n const classification = await classifyImage(image.blob);\n const tag = createOcrDifficultyTag(classification.prediction);\n ctx.tags.upsertTag({ id: canvasId, type: \"Canvas\" }, tag);\n\n const result = {\n canvasId,\n canvasLabel,\n tagId: tag.id,\n label: tag.label,\n score: classification.prediction.score,\n scores: classification.scores,\n imageUrl: image.url,\n };\n ctx.appendActionLog(\"Classified canvas\", \"info\", {\n canvasId,\n label: tag.label,\n score: classification.prediction.score,\n });\n return {\n taskStatus: \"complete\",\n result: {\n type: \"classified\",\n classification: result,\n } satisfies OcrClassificationTaskResult,\n };\n } catch (error) {\n if (ctx.signal.aborted) {\n throw error;\n }\n\n const skip = {\n canvasId,\n canvasLabel,\n reason: getErrorMessage(error),\n };\n ctx.appendActionLog(\"Skipped canvas classification\", \"warn\", {\n canvasId,\n reason: skip.reason,\n });\n return {\n taskStatus: \"skipped\",\n result: {\n type: \"skipped\",\n skip,\n } satisfies OcrClassificationTaskResult,\n };\n }\n },\n {\n progressLabel: (_task, index, total) => `Classifying ${index + 1}/${total}`,\n },\n );\n }\n\n const result = aggregateClassificationResult(ctx.tasks.getAll().length ? ctx.tasks.getAll() : plan.tasks);\n ctx.setActionStatus(\"running\", `Classified ${result.classified}/${result.total}`);\n ctx.setActionProgress({ current: result.total, total: result.total, label: \"Classification complete\" });\n ctx.appendActionLog(\"Classification complete\", \"info\", {\n total: result.total,\n classified: result.classified,\n skipped: result.skipped,\n counts: result.counts,\n });\n\n return result;\n },\n };\n}\n\nfunction createClassificationPlan(canvases: any[]): BackgroundActionPlan {\n return {\n version: 1,\n tasks: canvases.map((canvas, index) => {\n const canvasId = canvas?.id || `canvas-${index + 1}`;\n const canvasLabel = getCanvasLabel(canvas, canvasId);\n return {\n id: `canvas:${canvasId}`,\n label: canvasLabel,\n target: {\n id: canvasId,\n type: \"Canvas\",\n label: canvasLabel,\n scope: \"canvas\",\n },\n input: {\n canvasId,\n canvasLabel,\n },\n status: \"queued\",\n };\n }),\n };\n}\n\nfunction createEmptyResult(total: number): OcrClassificationActionResult {\n return {\n total,\n classified: 0,\n skipped: 0,\n counts: Object.fromEntries(OCR_DIFFICULTY_CLASSES.map((item) => [item.id, 0])),\n classifications: [],\n skippedCanvases: [],\n };\n}\n\nfunction aggregateClassificationResult(tasks: BackgroundActionTask[]): OcrClassificationActionResult {\n const result = createEmptyResult(tasks.length);\n\n for (const task of tasks) {\n const taskResult = task.result as OcrClassificationTaskResult | undefined;\n if (taskResult?.type === \"classified\") {\n result.classifications.push(taskResult.classification);\n result.counts[taskResult.classification.tagId] = (result.counts[taskResult.classification.tagId] || 0) + 1;\n continue;\n }\n\n if (taskResult?.type === \"skipped\") {\n result.skippedCanvases.push(taskResult.skip);\n continue;\n }\n\n if (task.status === \"error\" && task.error) {\n const canvasId = task.target?.id || task.id;\n result.skippedCanvases.push({\n canvasId,\n canvasLabel: task.label || canvasId,\n reason: task.error.message,\n });\n }\n }\n\n result.classified = result.classifications.length;\n result.skipped = result.skippedCanvases.length;\n return result;\n}\n\nasync function defaultPrepareClassifier() {\n const { loadOcrClassifier } = await import(\"./onnx-classifier\");\n await loadOcrClassifier();\n}\n\nasync function defaultClassifyImage(image: Blob) {\n const { runOcrClassifier } = await import(\"./onnx-classifier\");\n return runOcrClassifier(image);\n}\n\nfunction throwIfAborted(signal: AbortSignal) {\n if (signal.aborted) {\n throw new Error(\"OCR classification cancelled.\");\n }\n}\n\nfunction getErrorMessage(error: unknown) {\n return error instanceof Error ? error.message : \"Canvas classification failed\";\n}\n\nfunction getManifestCanvases(ctx: BackgroundActionRunContext) {\n const manifest = ctx.vault.get(ctx.target as any) as any;\n return manifest?.items ? (ctx.vault.get(manifest.items) || []).filter(Boolean) : [];\n}\n\nfunction getCanvasById(ctx: BackgroundActionRunContext, canvasId: string) {\n return ctx.vault.get({ id: canvasId, type: \"Canvas\" } as any) as any;\n}\n\nfunction getCanvasLabel(canvas: any, fallback: string) {\n const label = canvas?.label;\n if (!label) {\n return fallback;\n }\n\n if (typeof label === \"string\") {\n return label;\n }\n\n const englishLabel = Array.isArray(label.en) ? label.en[0] : undefined;\n if (englishLabel) {\n return englishLabel;\n }\n\n const firstLanguage = Object.keys(label)[0];\n const firstValue = firstLanguage && Array.isArray(label[firstLanguage]) ? label[firstLanguage][0] : undefined;\n return firstValue || fallback;\n}\n\nexport { OCR_DIFFICULTY_TAG_TYPE, formatOcrScore };\n","import type { BackgroundActionDefinition } from \"@manifest-editor/shell\";\nimport { createOcrClassificationBackgroundAction } from \"./background-action\";\nexport { default } from \"./plugin\";\n\nexport const backgroundActions: BackgroundActionDefinition[] = [createOcrClassificationBackgroundAction()];\n\nexport * from \"./background-action\";\nexport * from \"./ocr-difficulty\";\n"],"mappings":"mVAQA,eAAsB,EACpB,EACA,EAC8C,CAC9C,IAAM,EAAe,EAAqB,EAAK,CAAM,EACrD,GAAI,CAAC,EACH,OAAO,KAiBT,IAAM,GAAM,MAdY,EAAsB,EAAI,KACZ,CAAC,CAAC,uBACtC,EACA,CACE,MAAO,IACP,OAAQ,IACR,SAAU,IACV,UAAW,IACX,mBAAoB,GACpB,YAAa,GACb,gBAAiB,EACnB,EACA,EACF,EAAA,CACsB,MAAM,GAE5B,GAAI,CAAC,EACH,OAAO,KAGT,IAAM,EAAW,MAAM,MAAM,EAAK,CAAE,OAAQ,EAAI,MAAO,CAAC,EACxD,GAAI,CAAC,EAAS,GACZ,MAAU,MAAM,iCAAiC,EAAS,OAAO,GAAG,EAGtE,MAAO,CACL,MACA,KAAM,MAAM,EAAS,KAAK,CAC5B,CACF,CAEA,SAAS,EAAqB,EAAiC,EAAa,CAC1E,IAAM,EAAQ,GAAQ,OAAQ,EAAI,MAAM,IAAI,EAAO,KAAK,GAAU,CAAC,EAEnE,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAc,GAAM,OAAQ,EAAI,MAAM,IAAI,EAAK,KAAK,GAAU,CAAC,EACrE,IAAK,IAAM,KAAc,EAAa,CACpC,GAAI,CAAC,EAAqB,CAAU,EAClC,SAGF,IAAM,EAAO,EAAM,GAAY,IAAI,EAC9B,KAIL,OAAO,EAAI,MAAM,IAAI,CAAI,GAAK,CAChC,CACF,CAEA,OAAO,IACT,CAEA,SAAS,EAAqB,EAAiB,CAE7C,OADmB,MAAM,QAAQ,GAAY,UAAU,EAAI,EAAW,WAAa,CAAC,GAAY,UAAU,EAAA,CACxF,SAAS,UAAU,CACvC,CAEA,SAAS,EAAS,EAA6C,CAK7D,OAJI,MAAM,QAAQ,CAAK,EACd,EAAM,IAAM,KAGd,GAAS,IAClB,CC5EA,MAAM,EAAmB,8CAOzB,SAAgB,EAA6B,EAAkB,EAAiB,CAC1E,OAAO,OAAW,KAItB,OAAO,cACL,IAAI,YAA2C,EAAkB,CAC/D,OAAQ,CACN,WACA,OAAQ,EAAgC,CAAM,EAAI,EAAS,IAAA,EAC7D,CACF,CAAC,CACH,CACF,CAEA,SAAgB,EAA+B,EAAkB,CAC/D,OAAO,EAAC,EAAD,CAAyC,UAAW,CAAA,CAC7D,CAEA,SAAS,EAA8B,CAAE,YAAkC,CACzE,GAAM,CAAC,EAAc,GAAmB,EAA+C,IAAI,EAE3F,MAAgB,CACd,IAAM,EAAY,GAAiB,CACjC,IAAM,EAAU,EAAqD,OACjE,GAAQ,WAAa,GACvB,EAAgB,CAAM,CAE1B,EAGA,OADA,OAAO,iBAAiB,EAAkB,CAAQ,MACrC,OAAO,oBAAoB,EAAkB,CAAQ,CACpE,EAAG,CAAC,CAAQ,CAAC,EAEb,IAAM,EAAS,GAAc,OACvB,EAAiB,MAAc,GAAQ,iBAAmB,CAAC,EAAG,CAAC,CAAM,CAAC,EACtE,EAAiB,MAEnB,EACI,EAAuB,IAAK,IAAU,CACpC,GAAG,EACH,MAAO,EAAO,SAAS,EAAK,KAAO,CACrC,EAAE,EACF,CAAC,EACP,CAAC,CAAM,CACT,EAMA,OAJK,EAKH,EAAC,EAAD,CAAO,MAAM,6BAA6B,YAAe,EAAgB,IAAI,EAAG,UAAU,YACxF,SAAA,EAAC,MAAD,CAAK,UAAU,wDACZ,SAAC,EAGA,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,8CAAf,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,mDAAf,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,UAAf,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,gDAAgD,SAAA,eAAkB,CAAA,EACjF,EAAC,MAAD,CAAK,UAAU,2CAAf,SAAA,CAA0D,cAC5C,EAAa,EAAO,UAAU,EAAE,OAAK,EAAa,EAAO,KAAK,EAAE,WACzE,IACL,EAAC,MAAD,CAAK,UAAU,6BACZ,SAAA,EAAO,QACJ,GAAG,EAAa,EAAO,OAAO,EAAE,GAAG,EAAO,UAAY,EAAI,aAAe,gBAAgB,2DACzF,yCACD,CAAA,CACF,CACL,CAAA,EAAA,EAAC,MAAD,CAAK,UAAU,iEAAf,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,uCACZ,SAAA,EAAY,EAAO,WAAY,EAAO,KAAK,CACzC,CAAA,EACL,EAAC,MAAD,CAAK,UAAU,kCAAkC,SAAA,UAAa,CAAA,CAC3D,CACF,CAAA,CAAA,IAEL,EAAC,MAAD,CAAK,UAAU,yDACZ,SAAA,EAAO,WACN,EAAe,IAAK,GAClB,EAAK,MACH,EAAC,MAAD,CAEE,UAAU,SACV,MAAO,CACL,MAAO,GAAI,EAAK,MAAQ,EAAO,WAAc,IAAI,GACjD,gBAAiB,EAAK,eACxB,CACD,EANM,EAAK,EAMX,EACC,IACN,EAEA,EAAC,MAAD,CAAK,UAAU,2BAA6B,CAAA,CAE3C,CAAA,EAEL,EAAC,MAAD,CAAK,UAAU,4BACZ,SAAA,EAAe,IAAK,GACnB,EAAC,MAAD,CAEE,UAAU,qFAFZ,SAAA,CAIE,EAAC,OAAD,CACE,UAAU,2BACV,MAAO,CAAE,gBAAiB,EAAK,eAAgB,EAC/C,cAAY,MACb,CAAA,EACD,EAAC,OAAD,CAAM,UAAU,4BAA6B,SAAA,EAAK,KAAY,CAAA,EAC9D,EAAC,OAAD,CAAM,UAAU,gBAAhB,SAAA,CACG,EAAa,EAAK,KAAK,EAAE,KAAG,EAAY,EAAK,MAAO,EAAO,UAAU,EAAE,GACpE,GACH,CAZE,EAAA,EAAK,EAYP,CACN,CACE,CAAA,CACF,IAEL,EAAC,MAAD,CAAK,UAAU,4BAAf,SAAA,CACE,EAAC,EAAD,CAAa,MAAM,iBAAiB,MAAO,EAAa,EAAO,KAAK,CAAI,CAAA,EACxE,EAAC,EAAD,CAAa,MAAM,aAAa,MAAO,EAAa,EAAO,UAAU,CAAI,CAAA,EACzE,EAAC,EAAD,CAAa,MAAM,UAAU,MAAO,EAAa,EAAO,OAAO,CAAI,CAAA,EACnE,EAAC,EAAD,CAAa,MAAM,eAAe,MAAO,EAAa,EAAO,gBAAgB,MAAM,CAAI,CAAA,CACpF,IAEL,EAAC,MAAD,CAAK,UAAU,4BACZ,SAAA,EAAe,IAAK,GACnB,EAAC,MAAD,CAAmB,UAAU,8CAA7B,SAAA,CACE,EAAC,MAAD,CACE,UAAU,oDACV,MAAO,CAAE,gBAAiB,EAAK,gBAAiB,MAAO,EAAK,SAAU,EAErE,SAAA,EAAK,KACH,CAAA,EACL,EAAC,MAAD,CAAK,UAAU,2CAA4C,SAAA,EAAa,EAAK,KAAK,CAAO,CAAA,EACzF,EAAC,MAAD,CAAK,UAAU,6BAAf,SAAA,CACG,EAAY,EAAK,MAAO,EAAO,UAAU,EAAE,yBACzC,GACF,CAXK,EAAA,EAAK,EAWV,CACN,CACE,CAAA,EAEJ,EAAe,OACd,EAAC,MAAD,CAAK,UAAU,yDAAf,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,kGAAf,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,4BAA4B,SAAA,qBAAwB,CAAA,EACnE,EAAC,MAAD,CAAK,UAAU,wBAAf,SAAA,CAAuC,eACxB,EAAa,EAAe,MAAM,EAAE,qBAC9C,CACF,CAAA,CAAA,CACL,CAAA,EAAA,EAAC,MAAD,CAAK,UAAU,6BACb,SAAA,EAAC,QAAD,CAAO,UAAU,iDAAjB,SAAA,CACE,EAAC,QAAD,CAAO,UAAU,wDACf,SAAA,EAAC,KAAD,CAAA,SAAA,CACE,EAAC,KAAD,CAAI,UAAU,sDAAsD,SAAA,GAAK,CAAA,EACzE,EAAC,KAAD,CAAI,UAAU,iDAAiD,SAAA,QAAU,CAAA,EACzE,EAAC,KAAD,CAAI,UAAU,sDAAsD,SAAA,QAAU,CAAA,EAC9E,EAAC,KAAD,CAAI,UAAU,sDAAsD,SAAA,YAAc,CAAA,EAClF,EAAC,KAAD,CAAI,UAAU,iDAAiD,SAAA,QAAU,CAAA,CACvE,CAAA,CAAA,CACC,CAAA,EACP,EAAC,QAAD,CAAA,SACG,EAAe,KAAK,EAAM,IAAU,CACnC,IAAM,EAAc,EAAK,aAAe,EAAK,SAC7C,OACE,EAAC,KAAD,CAAwB,UAAU,yCAAlC,SAAA,CACE,EAAC,KAAD,CAAI,UAAU,4CAA6C,SAAA,EAAQ,CAAM,CAAA,EACzE,EAAC,KAAD,CAAI,UAAU,sBAAsB,MAAO,EAAK,SAAhD,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,4BAA6B,SAAA,CAAiB,CAAA,EAC5D,IAAgB,EAAK,SAElB,KADF,EAAC,MAAD,CAAK,UAAU,yCAA0C,SAAA,EAAK,QAAc,CAAA,CAE5E,IACJ,EAAC,KAAD,CAAI,UAAU,sBACZ,SAAA,EAAC,EAAD,CAAiB,MAAO,EAAK,MAAO,MAAO,EAAK,KAAQ,CAAA,CACtD,CAAA,EACJ,EAAC,KAAD,CAAI,UAAU,gDACX,SAAA,EAAe,EAAK,KAAK,CACxB,CAAA,EACJ,EAAC,KAAD,CAAI,UAAU,4CACZ,SAAA,EAAC,EAAD,CAAW,OAAQ,EAAK,MAAS,CAAA,CAC/B,CAAA,CACF,CAjBK,EAAA,EAAK,QAiBV,CAER,CAAC,CACI,CAAA,CACF,GACJ,CAAA,CACF,CAEL,CAAA,EAAA,EAAC,MAAD,CAAK,UAAU,gDAAgD,SAAA,oFAE1D,CAAA,EAGN,EAAO,gBAAgB,OACtB,EAAC,UAAD,CAAS,KAAA,GAAK,UAAU,4CAAxB,SAAA,CACE,EAAC,UAAD,CAAS,UAAU,qDAAnB,SAAA,CAAwE,qBACnD,EAAO,gBAAgB,OAAO,GAC1C,CACT,CAAA,EAAA,EAAC,MAAD,CAAK,UAAU,2DACZ,SAAA,EAAO,gBAAgB,IAAK,GAC3B,EAAC,MAAD,CAAyB,UAAU,8DAAnC,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,4BAA6B,SAAA,EAAK,aAAe,EAAK,QAAc,CAAA,EAClF,EAAK,aAAe,EAAK,cAAgB,EAAK,SAC7C,EAAC,MAAD,CAAK,UAAU,kCAAmC,SAAA,EAAK,QAAc,CAAA,EACnE,KACJ,EAAC,MAAD,CAAK,UAAU,wBAAyB,SAAA,EAAK,MAAY,CAAA,CACtD,CANK,EAAA,EAAK,QAMV,CACN,CACE,CAAA,CACE,CACP,CAAA,EAAA,IACJ,CAAA,CAAA,EA9JF,EAAC,MAAD,CAAK,UAAU,gDAAgD,SAAA,2CAA8C,CAAA,CAgK5G,CAAA,CACA,CAAA,EAxKA,IA0KX,CAEA,SAAS,EAAgB,CAAE,QAAO,SAA2C,CAC3E,IAAM,EAAkB,EAAmB,CAAK,EAEhD,OACE,EAAC,OAAD,CACE,UAAU,oDACV,MAAO,CACL,gBAAiB,GAAiB,iBAAmB,UACrD,MAAO,GAAiB,WAAa,SACvC,EAEC,SAAA,CACG,CAAA,CAEV,CAEA,SAAS,EAAU,CAAE,UAAgC,CACnD,OACE,EAAC,MAAD,CAAK,UAAU,yBACZ,SAAA,EAAO,KAAK,EAAO,IAClB,EAAC,OAAD,CAAkB,UAAU,sDAA5B,SAAA,CACG,EAAuB,EAAM,EAAE,IAAM,SAAS,IAAQ,KAAG,EAAe,CAAK,CAC1E,CAFK,EAAA,CAEL,CACP,CACE,CAAA,CAET,CAEA,SAAS,EAAY,CAAE,QAAO,SAA2C,CACvE,OACE,EAAC,MAAD,CAAK,UAAU,8CAAf,SAAA,CACE,EAAC,MAAD,CAAK,UAAU,kCAAmC,SAAA,CAAW,CAAA,EAC7D,EAAC,MAAD,CAAK,UAAU,2CAA4C,SAAA,CAAW,CAAA,CACnE,GAET,CAEA,SAAS,EAAmB,EAAe,CACzC,OAAO,EAAuB,KAAM,GAAS,EAAK,KAAO,CAAK,CAChE,CAEA,SAAS,EAAa,EAAe,CACnC,OAAO,IAAI,KAAK,aAAa,CAAC,CAAC,OAAO,CAAK,CAC7C,CAEA,SAAS,EAAY,EAAe,EAAe,CACjD,OAAO,EAAQ,EAAe,EAAQ,CAAK,EAAI,IACjD,CAEA,SAAS,EAAgC,EAA0D,CACjG,GAAI,CAAC,GAAU,OAAO,GAAW,SAC/B,MAAO,GAGT,IAAM,EAAY,EAClB,OACE,OAAO,EAAU,OAAU,UAC3B,OAAO,EAAU,YAAe,UAChC,OAAO,EAAU,SAAY,UAC7B,CAAC,CAAC,EAAU,QACZ,OAAO,EAAU,QAAW,UAC5B,MAAM,QAAQ,EAAU,eAAe,GACvC,MAAM,QAAQ,EAAU,eAAe,CAE3C,CCxRA,MAAa,EAA+B,wDA2C5C,SAAgB,EACd,EAAoD,CAAC,EACzB,CAC5B,IAAM,EAAoB,EAAa,mBAAqB,EACtD,EAAiB,EAAa,gBAAkB,EAChD,EAAgB,EAAa,eAAiB,EAEpD,MAAO,CACL,GAAI,EACJ,MAAO,0BACP,QAAS,oCACT,QAAS,MACT,MAAO,GACP,cAAe,CAAC,UAAU,EAC1B,UAAW,GACX,WAAc,EAA+B,CAA4B,EACzE,UAAY,GAAQ,EAA6B,EAAI,WAAW,GAAI,EAAI,UAAU,MAAM,EACxF,SAAW,GAEF,CAAC,CADS,EAAI,MAAM,IAAI,EAAI,MACnB,CAAC,EAAE,OAAO,OAE5B,QAAU,GACD,EAAyB,EAAoB,CAAG,CAAC,EAE1D,IAAK,KAAO,IAAQ,CAClB,IAAM,EAAO,EAAI,MAAQ,EAAyB,EAAoB,CAAG,CAAC,EACpE,EAAQ,EAAI,MAAM,OAAO,EACzB,EAAe,EAAI,MAAM,WAAW,EAI1C,GAFA,EAAI,eAAe,4BAA4B,EAE3C,CAAC,EAAM,OAET,OADA,EAAI,gBAAgB,UAAW,yBAAyB,EACjD,EAAkB,CAAC,EAGxB,EAAa,SACf,EAAI,eAAe,YACjB,EACG,IAAK,GAAS,EAAK,MAAM,CAAC,CAC1B,OAAQ,GAAkE,CAAC,CAAC,GAAU,EAAO,OAAS,QAAQ,EACjH,QACF,EACA,EAAI,gBAAgB,UAAW,wBAAwB,EACvD,MAAM,EAAkB,EAExB,MAAM,EAAI,MAAM,QACd,MAAO,EAAM,CAAE,QAAO,WAAY,CAChC,EAAe,EAAI,MAAM,EACzB,IAAM,EAAW,EAAK,QAAQ,IAAO,EAAK,OAA6C,UAAY,EAAK,GAClG,EAAS,EAAc,EAAK,CAAQ,EACpC,EAAc,EAAe,EAAQ,CAAQ,EAC7C,EAAQ,eAAe,EAAQ,EAAE,GAAG,IAE1C,EAAI,gBAAgB,EAAO,OAAQ,CAAE,WAAU,QAAS,EAAQ,EAAG,OAAM,CAAC,EAE1E,GAAI,CACF,IAAM,EAAQ,EAAS,MAAM,EAAe,EAAK,CAAM,EAAI,KAC3D,GAAI,CAAC,EAAO,CACV,IAAM,EAAO,CACX,WACA,cACA,OAAQ,yBACV,EAKA,OAJA,EAAI,gBAAgB,gCAAiC,OAAQ,CAC3D,WACA,OAAQ,EAAK,MACf,CAAC,EACM,CACL,WAAY,UACZ,OAAQ,CACN,KAAM,UACN,MACF,CACF,CACF,CAEA,IAAM,EAAiB,MAAM,EAAc,EAAM,IAAI,EAC/C,EAAM,EAAuB,EAAe,UAAU,EAC5D,EAAI,KAAK,UAAU,CAAE,GAAI,EAAU,KAAM,QAAS,EAAG,CAAG,EAExD,IAAM,EAAS,CACb,WACA,cACA,MAAO,EAAI,GACX,MAAO,EAAI,MACX,MAAO,EAAe,WAAW,MACjC,OAAQ,EAAe,OACvB,SAAU,EAAM,GAClB,EAMA,OALA,EAAI,gBAAgB,oBAAqB,OAAQ,CAC/C,WACA,MAAO,EAAI,MACX,MAAO,EAAe,WAAW,KACnC,CAAC,EACM,CACL,WAAY,WACZ,OAAQ,CACN,KAAM,aACN,eAAgB,CAClB,CACF,CACF,OAAS,EAAO,CACd,GAAI,EAAI,OAAO,QACb,MAAM,EAGR,IAAM,EAAO,CACX,WACA,cACA,OAAQ,EAAgB,CAAK,CAC/B,EAKA,OAJA,EAAI,gBAAgB,gCAAiC,OAAQ,CAC3D,WACA,OAAQ,EAAK,MACf,CAAC,EACM,CACL,WAAY,UACZ,OAAQ,CACN,KAAM,UACN,MACF,CACF,CACF,CACF,EACA,CACE,eAAgB,EAAO,EAAO,IAAU,eAAe,EAAQ,EAAE,GAAG,GACtE,CACF,GAGF,IAAM,EAAS,EAA8B,EAAI,MAAM,OAAO,CAAC,CAAC,OAAS,EAAI,MAAM,OAAO,EAAI,EAAK,KAAK,EAUxG,OATA,EAAI,gBAAgB,UAAW,cAAc,EAAO,WAAW,GAAG,EAAO,OAAO,EAChF,EAAI,kBAAkB,CAAE,QAAS,EAAO,MAAO,MAAO,EAAO,MAAO,MAAO,yBAA0B,CAAC,EACtG,EAAI,gBAAgB,0BAA2B,OAAQ,CACrD,MAAO,EAAO,MACd,WAAY,EAAO,WACnB,QAAS,EAAO,QAChB,OAAQ,EAAO,MACjB,CAAC,EAEM,CACT,CACF,CACF,CAEA,SAAS,EAAyB,EAAuC,CACvE,MAAO,CACL,QAAS,EACT,MAAO,EAAS,KAAK,EAAQ,IAAU,CACrC,IAAM,EAAW,GAAQ,IAAM,UAAU,EAAQ,IAC3C,EAAc,EAAe,EAAQ,CAAQ,EACnD,MAAO,CACL,GAAI,UAAU,IACd,MAAO,EACP,OAAQ,CACN,GAAI,EACJ,KAAM,SACN,MAAO,EACP,MAAO,QACT,EACA,MAAO,CACL,WACA,aACF,EACA,OAAQ,QACV,CACF,CAAC,CACH,CACF,CAEA,SAAS,EAAkB,EAA8C,CACvE,MAAO,CACL,QACA,WAAY,EACZ,QAAS,EACT,OAAQ,OAAO,YAAY,EAAuB,IAAK,GAAS,CAAC,EAAK,GAAI,CAAC,CAAC,CAAC,EAC7E,gBAAiB,CAAC,EAClB,gBAAiB,CAAC,CACpB,CACF,CAEA,SAAS,EAA8B,EAA8D,CACnG,IAAM,EAAS,EAAkB,EAAM,MAAM,EAE7C,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAa,EAAK,OACxB,GAAI,GAAY,OAAS,aAAc,CACrC,EAAO,gBAAgB,KAAK,EAAW,cAAc,EACrD,EAAO,OAAO,EAAW,eAAe,QAAU,EAAO,OAAO,EAAW,eAAe,QAAU,GAAK,EACzG,QACF,CAEA,GAAI,GAAY,OAAS,UAAW,CAClC,EAAO,gBAAgB,KAAK,EAAW,IAAI,EAC3C,QACF,CAEA,GAAI,EAAK,SAAW,SAAW,EAAK,MAAO,CACzC,IAAM,EAAW,EAAK,QAAQ,IAAM,EAAK,GACzC,EAAO,gBAAgB,KAAK,CAC1B,WACA,YAAa,EAAK,OAAS,EAC3B,OAAQ,EAAK,MAAM,OACrB,CAAC,CACH,CACF,CAIA,MAFA,GAAO,WAAa,EAAO,gBAAgB,OAC3C,EAAO,QAAU,EAAO,gBAAgB,OACjC,CACT,CAEA,eAAe,GAA2B,CACxC,GAAM,CAAE,qBAAsB,MAAM,OAAO,iCAC3C,MAAM,EAAkB,CAC1B,CAEA,eAAe,EAAqB,EAAa,CAC/C,GAAM,CAAE,oBAAqB,MAAM,OAAO,iCAC1C,OAAO,EAAiB,CAAK,CAC/B,CAEA,SAAS,EAAe,EAAqB,CAC3C,GAAI,EAAO,QACT,MAAU,MAAM,+BAA+B,CAEnD,CAEA,SAAS,EAAgB,EAAgB,CACvC,OAAO,aAAiB,MAAQ,EAAM,QAAU,8BAClD,CAEA,SAAS,EAAoB,EAAiC,CAC5D,IAAM,EAAW,EAAI,MAAM,IAAI,EAAI,MAAa,EAChD,OAAO,GAAU,OAAS,EAAI,MAAM,IAAI,EAAS,KAAK,GAAK,CAAC,EAAA,CAAG,OAAO,OAAO,EAAI,CAAC,CACpF,CAEA,SAAS,EAAc,EAAiC,EAAkB,CACxE,OAAO,EAAI,MAAM,IAAI,CAAE,GAAI,EAAU,KAAM,QAAS,CAAQ,CAC9D,CAEA,SAAS,EAAe,EAAa,EAAkB,CACrD,IAAM,EAAQ,GAAQ,MACtB,GAAI,CAAC,EACH,OAAO,EAGT,GAAI,OAAO,GAAU,SACnB,OAAO,EAGT,IAAM,EAAe,MAAM,QAAQ,EAAM,EAAE,EAAI,EAAM,GAAG,GAAK,IAAA,GAC7D,GAAI,EACF,OAAO,EAGT,IAAM,EAAgB,OAAO,KAAK,CAAK,CAAC,CAAC,GAEzC,OADmB,GAAiB,MAAM,QAAQ,EAAM,EAAc,EAAI,EAAM,EAAc,CAAC,GAAK,IAAA,KAC/E,CACvB,CC3TA,MAAa,EAAkD,CAAC,EAAwC,CAAC"}
|
package/dist/lazy.cjs
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
var e={default:require("./plugin-CEC3H4Xp.cjs").t,load:()=>Promise.resolve().then(()=>require("./index.cjs"))};module.exports=e;
|
|
2
|
+
//# sourceMappingURL=lazy.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy.cjs","names":["metadata"],"sources":["../src/lazy.ts"],"sourcesContent":["import type { LazyPluginModule } from \"@manifest-editor/shell\";\nimport metadata from \"./plugin\";\n\nexport default {\n default: metadata,\n load: () => import(\"./index\"),\n} satisfies LazyPluginModule;\n"],"mappings":"AAGA,IAAA,EAAe,CACb,uCAASA,CAAAA,CAAAA,EACT,SAAA,QAAA,QAAA,CAAA,CAAA,SAAA,QAAY,aAAA,CAAA,CACd"}
|
package/dist/lazy.d.cts
CHANGED
package/dist/lazy.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy.d.cts","names":[],"sources":["../src/lazy.ts"],"
|
|
1
|
+
{"version":3,"file":"lazy.d.cts","names":[],"sources":["../src/lazy.ts"],"mappings":""}
|
package/dist/lazy.d.ts
CHANGED
package/dist/lazy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy.d.ts","names":[],"sources":["../src/lazy.ts"],"
|
|
1
|
+
{"version":3,"file":"lazy.d.ts","names":[],"sources":["../src/lazy.ts"],"mappings":""}
|
package/dist/lazy.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./plugin-
|
|
1
|
+
import{t as e}from"./plugin-CsyG04LG.js";var t={default:e,load:()=>import(`./index.js`)};export{t as default};
|
|
2
2
|
//# sourceMappingURL=lazy.js.map
|
package/dist/lazy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy.js","names":["metadata"],"sources":["../src/lazy.ts"],"sourcesContent":["import type { LazyPluginModule } from \"@manifest-editor/shell\";\nimport metadata from \"./plugin\";\n\nexport default {\n default: metadata,\n load: () => import(\"./index\"),\n} satisfies LazyPluginModule;\n"],"mappings":"yCAGA,IAAA,EAAe,CACb,QAASA,EACT,SAAY,OAAO,
|
|
1
|
+
{"version":3,"file":"lazy.js","names":["metadata"],"sources":["../src/lazy.ts"],"sourcesContent":["import type { LazyPluginModule } from \"@manifest-editor/shell\";\nimport metadata from \"./plugin\";\n\nexport default {\n default: metadata,\n load: () => import(\"./index\"),\n} satisfies LazyPluginModule;\n"],"mappings":"yCAGA,IAAA,EAAe,CACb,QAASA,EACT,SAAY,OAAO,aACrB"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
const e=`ocr-difficulty`,t=[{id:`easy`,index:0,label:`OCR Easy`,backgroundColor:`#047857`,textColor:`#ffffff`},{id:`medium`,index:1,label:`OCR Medium`,backgroundColor:`#b45309`,textColor:`#ffffff`},{id:`difficult`,index:2,label:`OCR Difficult`,backgroundColor:`#991b1b`,textColor:`#ffffff`}];function n(e){if(!e.length)throw Error(`OCR classifier returned no scores.`);let n=0,r=Number(e[0]??0);for(let t=1;t<e.length;t+=1){let i=Number(e[t]);i>r&&(n=t,r=i)}return{...t[n]??t[2],score:r}}function r(t){return{type:e,id:t.id,label:t.label,backgroundColor:t.backgroundColor,textColor:t.textColor}}function i(e){return`${Math.round(e*1e3)/10}%`}Object.defineProperty(exports
|
|
1
|
+
const e=`ocr-difficulty`,t=[{id:`easy`,index:0,label:`OCR Easy`,backgroundColor:`#047857`,textColor:`#ffffff`},{id:`medium`,index:1,label:`OCR Medium`,backgroundColor:`#b45309`,textColor:`#ffffff`},{id:`difficult`,index:2,label:`OCR Difficult`,backgroundColor:`#991b1b`,textColor:`#ffffff`}];function n(e){if(!e.length)throw Error(`OCR classifier returned no scores.`);let n=0,r=Number(e[0]??0);for(let t=1;t<e.length;t+=1){let i=Number(e[t]);i>r&&(n=t,r=i)}return{...t[n]??t[2],score:r}}function r(t){return{type:e,id:t.id,label:t.label,backgroundColor:t.backgroundColor,textColor:t.textColor}}function i(e){return`${Math.round(e*1e3)/10}%`}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return t}});
|
|
2
|
+
//# sourceMappingURL=ocr-difficulty-DGBSuuaz.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ocr-difficulty-DGBSuuaz.cjs","names":[],"sources":["../src/ocr-difficulty.ts"],"sourcesContent":["import type { ManifestEditorTag } from \"@manifest-editor/shell\";\n\nexport const OCR_DIFFICULTY_TAG_TYPE = \"ocr-difficulty\";\n\nexport type OcrDifficultyId = \"easy\" | \"medium\" | \"difficult\";\n\nexport type OcrDifficultyClass = {\n id: OcrDifficultyId;\n index: number;\n label: string;\n backgroundColor: string;\n textColor: string;\n};\n\nexport type OcrDifficultyPrediction = OcrDifficultyClass & {\n score: number;\n};\n\nexport type OcrClassifierRun = {\n scores: number[];\n prediction: OcrDifficultyPrediction;\n inferenceMs: number;\n};\n\nexport const OCR_DIFFICULTY_CLASSES: OcrDifficultyClass[] = [\n {\n id: \"easy\",\n index: 0,\n label: \"OCR Easy\",\n backgroundColor: \"#047857\",\n textColor: \"#ffffff\",\n },\n {\n id: \"medium\",\n index: 1,\n label: \"OCR Medium\",\n backgroundColor: \"#b45309\",\n textColor: \"#ffffff\",\n },\n {\n id: \"difficult\",\n index: 2,\n label: \"OCR Difficult\",\n backgroundColor: \"#991b1b\",\n textColor: \"#ffffff\",\n },\n];\n\nexport function selectOcrDifficulty(scores: ArrayLike<number>): OcrDifficultyPrediction {\n if (!scores.length) {\n throw new Error(\"OCR classifier returned no scores.\");\n }\n\n let bestIndex = 0;\n let bestScore = Number(scores[0] ?? 0);\n\n for (let index = 1; index < scores.length; index += 1) {\n const score = Number(scores[index]);\n if (score > bestScore) {\n bestIndex = index;\n bestScore = score;\n }\n }\n\n const difficultyClass = OCR_DIFFICULTY_CLASSES[bestIndex] ?? OCR_DIFFICULTY_CLASSES[2]!;\n\n return {\n ...difficultyClass,\n score: bestScore,\n };\n}\n\nexport function createOcrDifficultyTag(prediction: OcrDifficultyPrediction): ManifestEditorTag {\n return {\n type: OCR_DIFFICULTY_TAG_TYPE,\n id: prediction.id,\n label: prediction.label,\n backgroundColor: prediction.backgroundColor,\n textColor: prediction.textColor,\n };\n}\n\nexport function formatOcrScore(score: number) {\n return `${Math.round(score * 1000) / 10}%`;\n}\n"],"mappings":"AAEA,MAAa,EAA0B,iBAsB1B,EAA+C,CAC1D,CACE,GAAI,OACJ,MAAO,EACP,MAAO,WACP,gBAAiB,UACjB,UAAW,SACb,EACA,CACE,GAAI,SACJ,MAAO,EACP,MAAO,aACP,gBAAiB,UACjB,UAAW,SACb,EACA,CACE,GAAI,YACJ,MAAO,EACP,MAAO,gBACP,gBAAiB,UACjB,UAAW,SACb,CACF,EAEA,SAAgB,EAAoB,EAAoD,CACtF,GAAI,CAAC,EAAO,OACV,MAAU,MAAM,oCAAoC,EAGtD,IAAI,EAAY,EACZ,EAAY,OAAO,EAAO,IAAM,CAAC,EAErC,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAO,OAAQ,GAAS,EAAG,CACrD,IAAM,EAAQ,OAAO,EAAO,EAAM,EAC9B,EAAQ,IACV,EAAY,EACZ,EAAY,EAEhB,CAIA,MAAO,CACL,GAHsB,EAAuB,IAAc,EAAuB,GAIlF,MAAO,CACT,CACF,CAEA,SAAgB,EAAuB,EAAwD,CAC7F,MAAO,CACL,KAAM,EACN,GAAI,EAAW,GACf,MAAO,EAAW,MAClB,gBAAiB,EAAW,gBAC5B,UAAW,EAAW,SACxB,CACF,CAEA,SAAgB,EAAe,EAAe,CAC5C,MAAO,GAAG,KAAK,MAAM,EAAQ,GAAI,EAAI,GAAG,EAC1C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
const e=`ocr-difficulty`,t=[{id:`easy`,index:0,label:`OCR Easy`,backgroundColor:`#047857`,textColor:`#ffffff`},{id:`medium`,index:1,label:`OCR Medium`,backgroundColor:`#b45309`,textColor:`#ffffff`},{id:`difficult`,index:2,label:`OCR Difficult`,backgroundColor:`#991b1b`,textColor:`#ffffff`}];function n(e){if(!e.length)throw Error(`OCR classifier returned no scores.`);let n=0,r=Number(e[0]??0);for(let t=1;t<e.length;t+=1){let i=Number(e[t]);i>r&&(n=t,r=i)}return{...t[n]??t[2],score:r}}function r(t){return{type:e,id:t.id,label:t.label,backgroundColor:t.backgroundColor,textColor:t.textColor}}function i(e){return`${Math.round(e*1e3)/10}%`}export{n as a,i,e as n,r,t};
|
|
2
|
-
//# sourceMappingURL=ocr-difficulty-
|
|
2
|
+
//# sourceMappingURL=ocr-difficulty-DOYyPpGw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ocr-difficulty-DOYyPpGw.js","names":[],"sources":["../src/ocr-difficulty.ts"],"sourcesContent":["import type { ManifestEditorTag } from \"@manifest-editor/shell\";\n\nexport const OCR_DIFFICULTY_TAG_TYPE = \"ocr-difficulty\";\n\nexport type OcrDifficultyId = \"easy\" | \"medium\" | \"difficult\";\n\nexport type OcrDifficultyClass = {\n id: OcrDifficultyId;\n index: number;\n label: string;\n backgroundColor: string;\n textColor: string;\n};\n\nexport type OcrDifficultyPrediction = OcrDifficultyClass & {\n score: number;\n};\n\nexport type OcrClassifierRun = {\n scores: number[];\n prediction: OcrDifficultyPrediction;\n inferenceMs: number;\n};\n\nexport const OCR_DIFFICULTY_CLASSES: OcrDifficultyClass[] = [\n {\n id: \"easy\",\n index: 0,\n label: \"OCR Easy\",\n backgroundColor: \"#047857\",\n textColor: \"#ffffff\",\n },\n {\n id: \"medium\",\n index: 1,\n label: \"OCR Medium\",\n backgroundColor: \"#b45309\",\n textColor: \"#ffffff\",\n },\n {\n id: \"difficult\",\n index: 2,\n label: \"OCR Difficult\",\n backgroundColor: \"#991b1b\",\n textColor: \"#ffffff\",\n },\n];\n\nexport function selectOcrDifficulty(scores: ArrayLike<number>): OcrDifficultyPrediction {\n if (!scores.length) {\n throw new Error(\"OCR classifier returned no scores.\");\n }\n\n let bestIndex = 0;\n let bestScore = Number(scores[0] ?? 0);\n\n for (let index = 1; index < scores.length; index += 1) {\n const score = Number(scores[index]);\n if (score > bestScore) {\n bestIndex = index;\n bestScore = score;\n }\n }\n\n const difficultyClass = OCR_DIFFICULTY_CLASSES[bestIndex] ?? OCR_DIFFICULTY_CLASSES[2]!;\n\n return {\n ...difficultyClass,\n score: bestScore,\n };\n}\n\nexport function createOcrDifficultyTag(prediction: OcrDifficultyPrediction): ManifestEditorTag {\n return {\n type: OCR_DIFFICULTY_TAG_TYPE,\n id: prediction.id,\n label: prediction.label,\n backgroundColor: prediction.backgroundColor,\n textColor: prediction.textColor,\n };\n}\n\nexport function formatOcrScore(score: number) {\n return `${Math.round(score * 1000) / 10}%`;\n}\n"],"mappings":"AAEA,MAAa,EAA0B,iBAsB1B,EAA+C,CAC1D,CACE,GAAI,OACJ,MAAO,EACP,MAAO,WACP,gBAAiB,UACjB,UAAW,SACb,EACA,CACE,GAAI,SACJ,MAAO,EACP,MAAO,aACP,gBAAiB,UACjB,UAAW,SACb,EACA,CACE,GAAI,YACJ,MAAO,EACP,MAAO,gBACP,gBAAiB,UACjB,UAAW,SACb,CACF,EAEA,SAAgB,EAAoB,EAAoD,CACtF,GAAI,CAAC,EAAO,OACV,MAAU,MAAM,oCAAoC,EAGtD,IAAI,EAAY,EACZ,EAAY,OAAO,EAAO,IAAM,CAAC,EAErC,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAO,OAAQ,GAAS,EAAG,CACrD,IAAM,EAAQ,OAAO,EAAO,EAAM,EAC9B,EAAQ,IACV,EAAY,EACZ,EAAY,EAEhB,CAIA,MAAO,CACL,GAHsB,EAAuB,IAAc,EAAuB,GAIlF,MAAO,CACT,CACF,CAEA,SAAgB,EAAuB,EAAwD,CAC7F,MAAO,CACL,KAAM,EACN,GAAI,EAAW,GACf,MAAO,EAAW,MAClB,gBAAiB,EAAW,gBAC5B,UAAW,EAAW,SACxB,CACF,CAEA,SAAgB,EAAe,EAAe,CAC5C,MAAO,GAAG,KAAK,MAAM,EAAQ,GAAI,EAAI,GAAG,EAC1C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e}from"./ocr-difficulty-
|
|
2
|
-
//# sourceMappingURL=onnx-classifier-
|
|
1
|
+
import{a as e}from"./ocr-difficulty-DOYyPpGw.js";import*as t from"onnxruntime-web/wasm";const n=new URL(`./assets/ocr_router_efficientnet_b0_threshold_0.15.onnx`,import.meta.url).href,r=new URL(`./assets/ort-wasm-simd-threaded.mjs`,import.meta.url).href,i=new URL(`./assets/ort-wasm-simd-threaded.wasm`,import.meta.url).href,a=[1,3,224,224],o=[.485,.456,.406],s=[.229,.224,.225];let c=null;async function l(){return c||(t.env.wasm.wasmPaths={mjs:r,wasm:i},t.env.wasm.numThreads=1,c=t.InferenceSession.create(n,{executionProviders:[`wasm`],graphOptimizationLevel:`all`}).catch(e=>{throw c=null,e})),c}async function u(t){let n=await l(),r=await f(t);try{let t=m(r),i=n.inputNames[0]??`x`,a=n.outputNames[0]??`linear`,o=performance.now(),s=await n.run({[i]:t}),c=performance.now()-o,l=s[a];if(!l)throw Error(`Model output "${a}" was not returned.`);let u=Array.from(l.data).map(d);return{scores:u,prediction:e(u),inferenceMs:c}}finally{r.dispose()}}function d(e){return 1/(1+Math.exp(-e))}async function f(e){if(typeof createImageBitmap==`function`){let t=await createImageBitmap(e,{imageOrientation:`from-image`});return{source:t,width:t.width,height:t.height,dispose:()=>t.close()}}let t=URL.createObjectURL(e);try{let e=await p(t);return{source:e,width:e.naturalWidth,height:e.naturalHeight,dispose:()=>URL.revokeObjectURL(t)}}catch(e){throw URL.revokeObjectURL(t),e}}function p(e){return new Promise((t,n)=>{let r=new Image;r.decoding=`async`,r.onload=()=>t(r),r.onerror=()=>n(Error(`Unable to decode the canvas image.`)),r.src=e})}function m(e){let[,n,r,i]=a,c=256/Math.min(e.width,e.height),l=Math.round(e.width*c),u=Math.round(e.height*c),d=h(l,u);g(d).drawImage(e.source,0,0,l,u);let f=Math.max(0,Math.floor((l-i)/2)),p=Math.max(0,Math.floor((u-r)/2)),m=g(h(i,r));m.drawImage(d,f,p,i,r,0,0,i,r);let _=m.getImageData(0,0,i,r).data,v=i*r,y=new Float32Array(n*v);for(let e=0;e<v;e+=1){let t=e*4,n=(_[t]??0)/255,r=(_[t+1]??0)/255,i=(_[t+2]??0)/255;y[e]=(n-o[0])/s[0],y[v+e]=(r-o[1])/s[1],y[v*2+e]=(i-o[2])/s[2]}return new t.Tensor(`float32`,y,Array.from(a))}function h(e,t){let n=document.createElement(`canvas`);return n.width=e,n.height=t,n}function g(e){let t=e.getContext(`2d`,{willReadFrequently:!0});if(!t)throw Error(`Could not acquire a 2D canvas context for image preprocessing.`);return t}export{l as loadOcrClassifier,u as runOcrClassifier};
|
|
2
|
+
//# sourceMappingURL=onnx-classifier-BRRrhiwP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onnx-classifier-BRRrhiwP.js","names":[],"sources":["../src/onnx-classifier.ts"],"sourcesContent":["import * as ort from \"onnxruntime-web/wasm\";\nimport { type OcrClassifierRun, selectOcrDifficulty } from \"./ocr-difficulty\";\n\nconst MODEL_URL = new URL(\"./assets/ocr_router_efficientnet_b0_threshold_0.15.onnx\", import.meta.url).href;\nconst ORT_WASM_MODULE_URL = new URL(\"./assets/ort-wasm-simd-threaded.mjs\", import.meta.url).href;\nconst ORT_WASM_BINARY_URL = new URL(\"./assets/ort-wasm-simd-threaded.wasm\", import.meta.url).href;\n\nexport const MODEL_INPUT_SHAPE = [1, 3, 224, 224] as const;\nexport const MODEL_OUTPUT_SHAPE = [1, 3] as const;\n\nconst RESIZE_SHORT_SIDE = 256;\nconst IMAGE_MEAN = [0.485, 0.456, 0.406] as const;\nconst IMAGE_STD = [0.229, 0.224, 0.225] as const;\n\ntype LoadedImageSource = {\n source: CanvasImageSource;\n width: number;\n height: number;\n dispose: () => void;\n};\n\nlet sessionPromise: Promise<ort.InferenceSession> | null = null;\n\nexport async function loadOcrClassifier() {\n if (!sessionPromise) {\n ort.env.wasm.wasmPaths = {\n mjs: ORT_WASM_MODULE_URL,\n wasm: ORT_WASM_BINARY_URL,\n };\n ort.env.wasm.numThreads = 1;\n\n sessionPromise = ort.InferenceSession.create(MODEL_URL, {\n executionProviders: [\"wasm\"],\n graphOptimizationLevel: \"all\",\n }).catch((error: unknown) => {\n sessionPromise = null;\n throw error;\n });\n }\n\n return sessionPromise;\n}\n\nexport async function runOcrClassifier(imageBlob: Blob): Promise<OcrClassifierRun> {\n const session = await loadOcrClassifier();\n const image = await loadImageSource(imageBlob);\n\n try {\n const tensor = imageToTensor(image);\n const inputName = session.inputNames[0] ?? \"x\";\n const outputName = session.outputNames[0] ?? \"linear\";\n const startedAt = performance.now();\n const outputMap = await session.run({ [inputName]: tensor });\n const inferenceMs = performance.now() - startedAt;\n const outputTensor = outputMap[outputName];\n\n if (!outputTensor) {\n throw new Error(`Model output \"${outputName}\" was not returned.`);\n }\n\n const scores = Array.from(outputTensor.data as ArrayLike<number>).map(sigmoid);\n\n return {\n scores,\n prediction: selectOcrDifficulty(scores),\n inferenceMs,\n };\n } finally {\n image.dispose();\n }\n}\n\nfunction sigmoid(value: number) {\n return 1 / (1 + Math.exp(-value));\n}\n\nasync function loadImageSource(blob: Blob): Promise<LoadedImageSource> {\n if (typeof createImageBitmap === \"function\") {\n const bitmap = await createImageBitmap(blob, { imageOrientation: \"from-image\" });\n\n return {\n source: bitmap,\n width: bitmap.width,\n height: bitmap.height,\n dispose: () => bitmap.close(),\n };\n }\n\n const objectUrl = URL.createObjectURL(blob);\n\n try {\n const image = await loadHtmlImage(objectUrl);\n\n return {\n source: image,\n width: image.naturalWidth,\n height: image.naturalHeight,\n dispose: () => URL.revokeObjectURL(objectUrl),\n };\n } catch (error) {\n URL.revokeObjectURL(objectUrl);\n throw error;\n }\n}\n\nfunction loadHtmlImage(source: string) {\n return new Promise<HTMLImageElement>((resolve, reject) => {\n const image = new Image();\n image.decoding = \"async\";\n image.onload = () => resolve(image);\n image.onerror = () => reject(new Error(\"Unable to decode the canvas image.\"));\n image.src = source;\n });\n}\n\nfunction imageToTensor(image: LoadedImageSource) {\n const [, channels, croppedHeight, croppedWidth] = MODEL_INPUT_SHAPE;\n const resizeScale = RESIZE_SHORT_SIDE / Math.min(image.width, image.height);\n const resizedWidth = Math.round(image.width * resizeScale);\n const resizedHeight = Math.round(image.height * resizeScale);\n const resizeCanvas = createCanvas(resizedWidth, resizedHeight);\n const resizeContext = getCanvasContext(resizeCanvas);\n\n resizeContext.drawImage(image.source, 0, 0, resizedWidth, resizedHeight);\n\n const cropX = Math.max(0, Math.floor((resizedWidth - croppedWidth) / 2));\n const cropY = Math.max(0, Math.floor((resizedHeight - croppedHeight) / 2));\n const cropCanvas = createCanvas(croppedWidth, croppedHeight);\n const cropContext = getCanvasContext(cropCanvas);\n\n cropContext.drawImage(resizeCanvas, cropX, cropY, croppedWidth, croppedHeight, 0, 0, croppedWidth, croppedHeight);\n\n const imageData = cropContext.getImageData(0, 0, croppedWidth, croppedHeight).data;\n const pixelCount = croppedWidth * croppedHeight;\n const tensorData = new Float32Array(channels * pixelCount);\n\n for (let pixelIndex = 0; pixelIndex < pixelCount; pixelIndex += 1) {\n const dataOffset = pixelIndex * 4;\n const red = (imageData[dataOffset] ?? 0) / 255;\n const green = (imageData[dataOffset + 1] ?? 0) / 255;\n const blue = (imageData[dataOffset + 2] ?? 0) / 255;\n\n tensorData[pixelIndex] = (red - IMAGE_MEAN[0]) / IMAGE_STD[0];\n tensorData[pixelCount + pixelIndex] = (green - IMAGE_MEAN[1]) / IMAGE_STD[1];\n tensorData[pixelCount * 2 + pixelIndex] = (blue - IMAGE_MEAN[2]) / IMAGE_STD[2];\n }\n\n return new ort.Tensor(\"float32\", tensorData, Array.from(MODEL_INPUT_SHAPE));\n}\n\nfunction createCanvas(width: number, height: number) {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\nfunction getCanvasContext(canvas: HTMLCanvasElement) {\n const context = canvas.getContext(\"2d\", { willReadFrequently: true });\n\n if (!context) {\n throw new Error(\"Could not acquire a 2D canvas context for image preprocessing.\");\n }\n\n return context;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));const c=require("./ocr-difficulty-DGBSuuaz.cjs");let l=require("onnxruntime-web/wasm");l=s(l,1);const u=new URL(`./assets/ocr_router_efficientnet_b0_threshold_0.15.onnx`,require("url").pathToFileURL(__filename).href).href,d=new URL(`./assets/ort-wasm-simd-threaded.mjs`,require("url").pathToFileURL(__filename).href).href,f=new URL(`./assets/ort-wasm-simd-threaded.wasm`,require("url").pathToFileURL(__filename).href).href,p=[1,3,224,224],m=[.485,.456,.406],h=[.229,.224,.225];let g=null;async function _(){return g||(l.env.wasm.wasmPaths={mjs:d,wasm:f},l.env.wasm.numThreads=1,g=l.InferenceSession.create(u,{executionProviders:[`wasm`],graphOptimizationLevel:`all`}).catch(e=>{throw g=null,e})),g}async function v(e){let t=await _(),n=await b(e);try{let e=S(n),r=t.inputNames[0]??`x`,i=t.outputNames[0]??`linear`,a=performance.now(),o=await t.run({[r]:e}),s=performance.now()-a,l=o[i];if(!l)throw Error(`Model output "${i}" was not returned.`);let u=Array.from(l.data).map(y);return{scores:u,prediction:c.a(u),inferenceMs:s}}finally{n.dispose()}}function y(e){return 1/(1+Math.exp(-e))}async function b(e){if(typeof createImageBitmap==`function`){let t=await createImageBitmap(e,{imageOrientation:`from-image`});return{source:t,width:t.width,height:t.height,dispose:()=>t.close()}}let t=URL.createObjectURL(e);try{let e=await x(t);return{source:e,width:e.naturalWidth,height:e.naturalHeight,dispose:()=>URL.revokeObjectURL(t)}}catch(e){throw URL.revokeObjectURL(t),e}}function x(e){return new Promise((t,n)=>{let r=new Image;r.decoding=`async`,r.onload=()=>t(r),r.onerror=()=>n(Error(`Unable to decode the canvas image.`)),r.src=e})}function S(e){let[,t,n,r]=p,i=256/Math.min(e.width,e.height),a=Math.round(e.width*i),o=Math.round(e.height*i),s=C(a,o);w(s).drawImage(e.source,0,0,a,o);let c=Math.max(0,Math.floor((a-r)/2)),u=Math.max(0,Math.floor((o-n)/2)),d=w(C(r,n));d.drawImage(s,c,u,r,n,0,0,r,n);let f=d.getImageData(0,0,r,n).data,g=r*n,_=new Float32Array(t*g);for(let e=0;e<g;e+=1){let t=e*4,n=(f[t]??0)/255,r=(f[t+1]??0)/255,i=(f[t+2]??0)/255;_[e]=(n-m[0])/h[0],_[g+e]=(r-m[1])/h[1],_[g*2+e]=(i-m[2])/h[2]}return new l.Tensor(`float32`,_,Array.from(p))}function C(e,t){let n=document.createElement(`canvas`);return n.width=e,n.height=t,n}function w(e){let t=e.getContext(`2d`,{willReadFrequently:!0});if(!t)throw Error(`Could not acquire a 2D canvas context for image preprocessing.`);return t}exports.loadOcrClassifier=_,exports.runOcrClassifier=v;
|
|
2
|
+
//# sourceMappingURL=onnx-classifier-DTT3FqmF.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onnx-classifier-DTT3FqmF.cjs","names":["ort","selectOcrDifficulty"],"sources":["../src/onnx-classifier.ts"],"sourcesContent":["import * as ort from \"onnxruntime-web/wasm\";\nimport { type OcrClassifierRun, selectOcrDifficulty } from \"./ocr-difficulty\";\n\nconst MODEL_URL = new URL(\"./assets/ocr_router_efficientnet_b0_threshold_0.15.onnx\", import.meta.url).href;\nconst ORT_WASM_MODULE_URL = new URL(\"./assets/ort-wasm-simd-threaded.mjs\", import.meta.url).href;\nconst ORT_WASM_BINARY_URL = new URL(\"./assets/ort-wasm-simd-threaded.wasm\", import.meta.url).href;\n\nexport const MODEL_INPUT_SHAPE = [1, 3, 224, 224] as const;\nexport const MODEL_OUTPUT_SHAPE = [1, 3] as const;\n\nconst RESIZE_SHORT_SIDE = 256;\nconst IMAGE_MEAN = [0.485, 0.456, 0.406] as const;\nconst IMAGE_STD = [0.229, 0.224, 0.225] as const;\n\ntype LoadedImageSource = {\n source: CanvasImageSource;\n width: number;\n height: number;\n dispose: () => void;\n};\n\nlet sessionPromise: Promise<ort.InferenceSession> | null = null;\n\nexport async function loadOcrClassifier() {\n if (!sessionPromise) {\n ort.env.wasm.wasmPaths = {\n mjs: ORT_WASM_MODULE_URL,\n wasm: ORT_WASM_BINARY_URL,\n };\n ort.env.wasm.numThreads = 1;\n\n sessionPromise = ort.InferenceSession.create(MODEL_URL, {\n executionProviders: [\"wasm\"],\n graphOptimizationLevel: \"all\",\n }).catch((error: unknown) => {\n sessionPromise = null;\n throw error;\n });\n }\n\n return sessionPromise;\n}\n\nexport async function runOcrClassifier(imageBlob: Blob): Promise<OcrClassifierRun> {\n const session = await loadOcrClassifier();\n const image = await loadImageSource(imageBlob);\n\n try {\n const tensor = imageToTensor(image);\n const inputName = session.inputNames[0] ?? \"x\";\n const outputName = session.outputNames[0] ?? \"linear\";\n const startedAt = performance.now();\n const outputMap = await session.run({ [inputName]: tensor });\n const inferenceMs = performance.now() - startedAt;\n const outputTensor = outputMap[outputName];\n\n if (!outputTensor) {\n throw new Error(`Model output \"${outputName}\" was not returned.`);\n }\n\n const scores = Array.from(outputTensor.data as ArrayLike<number>).map(sigmoid);\n\n return {\n scores,\n prediction: selectOcrDifficulty(scores),\n inferenceMs,\n };\n } finally {\n image.dispose();\n }\n}\n\nfunction sigmoid(value: number) {\n return 1 / (1 + Math.exp(-value));\n}\n\nasync function loadImageSource(blob: Blob): Promise<LoadedImageSource> {\n if (typeof createImageBitmap === \"function\") {\n const bitmap = await createImageBitmap(blob, { imageOrientation: \"from-image\" });\n\n return {\n source: bitmap,\n width: bitmap.width,\n height: bitmap.height,\n dispose: () => bitmap.close(),\n };\n }\n\n const objectUrl = URL.createObjectURL(blob);\n\n try {\n const image = await loadHtmlImage(objectUrl);\n\n return {\n source: image,\n width: image.naturalWidth,\n height: image.naturalHeight,\n dispose: () => URL.revokeObjectURL(objectUrl),\n };\n } catch (error) {\n URL.revokeObjectURL(objectUrl);\n throw error;\n }\n}\n\nfunction loadHtmlImage(source: string) {\n return new Promise<HTMLImageElement>((resolve, reject) => {\n const image = new Image();\n image.decoding = \"async\";\n image.onload = () => resolve(image);\n image.onerror = () => reject(new Error(\"Unable to decode the canvas image.\"));\n image.src = source;\n });\n}\n\nfunction imageToTensor(image: LoadedImageSource) {\n const [, channels, croppedHeight, croppedWidth] = MODEL_INPUT_SHAPE;\n const resizeScale = RESIZE_SHORT_SIDE / Math.min(image.width, image.height);\n const resizedWidth = Math.round(image.width * resizeScale);\n const resizedHeight = Math.round(image.height * resizeScale);\n const resizeCanvas = createCanvas(resizedWidth, resizedHeight);\n const resizeContext = getCanvasContext(resizeCanvas);\n\n resizeContext.drawImage(image.source, 0, 0, resizedWidth, resizedHeight);\n\n const cropX = Math.max(0, Math.floor((resizedWidth - croppedWidth) / 2));\n const cropY = Math.max(0, Math.floor((resizedHeight - croppedHeight) / 2));\n const cropCanvas = createCanvas(croppedWidth, croppedHeight);\n const cropContext = getCanvasContext(cropCanvas);\n\n cropContext.drawImage(resizeCanvas, cropX, cropY, croppedWidth, croppedHeight, 0, 0, croppedWidth, croppedHeight);\n\n const imageData = cropContext.getImageData(0, 0, croppedWidth, croppedHeight).data;\n const pixelCount = croppedWidth * croppedHeight;\n const tensorData = new Float32Array(channels * pixelCount);\n\n for (let pixelIndex = 0; pixelIndex < pixelCount; pixelIndex += 1) {\n const dataOffset = pixelIndex * 4;\n const red = (imageData[dataOffset] ?? 0) / 255;\n const green = (imageData[dataOffset + 1] ?? 0) / 255;\n const blue = (imageData[dataOffset + 2] ?? 0) / 255;\n\n tensorData[pixelIndex] = (red - IMAGE_MEAN[0]) / IMAGE_STD[0];\n tensorData[pixelCount + pixelIndex] = (green - IMAGE_MEAN[1]) / IMAGE_STD[1];\n tensorData[pixelCount * 2 + pixelIndex] = (blue - IMAGE_MEAN[2]) / IMAGE_STD[2];\n }\n\n return new ort.Tensor(\"float32\", tensorData, Array.from(MODEL_INPUT_SHAPE));\n}\n\nfunction createCanvas(width: number, height: number) {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\nfunction getCanvasContext(canvas: HTMLCanvasElement) {\n const context = canvas.getContext(\"2d\", { willReadFrequently: true });\n\n if (!context) {\n throw new Error(\"Could not acquire a 2D canvas context for image preprocessing.\");\n }\n\n return context;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
var e={id:`@manifest-editor/ocr-classification`,label:`OCR Classification`,description:`Classify canvases by OCR difficulty and apply canvas tags.`,author:`Digirati`,official:!0,defaultEnabled:!1,tags:[`ocr`,`classification`,`automation`],supports:{apps:[`manifest-editor`],projectTypes:[`Manifest`]}};Object.defineProperty(exports
|
|
1
|
+
var e={id:`@manifest-editor/ocr-classification`,label:`OCR Classification`,description:`Classify canvases by OCR difficulty and apply canvas tags.`,author:`Digirati`,official:!0,defaultEnabled:!1,tags:[`ocr`,`classification`,`automation`],supports:{apps:[`manifest-editor`],projectTypes:[`Manifest`]}};Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return e}});
|
|
2
|
+
//# sourceMappingURL=plugin-CEC3H4Xp.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-CEC3H4Xp.cjs","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import type { PluginMetadata } from \"@manifest-editor/shell\";\n\nexport default {\n id: \"@manifest-editor/ocr-classification\",\n label: \"OCR Classification\",\n description: \"Classify canvases by OCR difficulty and apply canvas tags.\",\n author: \"Digirati\",\n official: true,\n defaultEnabled: false,\n tags: [\"ocr\", \"classification\", \"automation\"],\n supports: {\n apps: [\"manifest-editor\"],\n projectTypes: [\"Manifest\"],\n },\n} satisfies PluginMetadata;\n"],"mappings":"AAEA,IAAA,EAAe,CACb,GAAI,sCACJ,MAAO,qBACP,YAAa,6DACb,OAAQ,WACR,SAAU,GACV,eAAgB,GAChB,KAAM,CAAC,MAAO,iBAAkB,YAAY,EAC5C,SAAU,CACR,KAAM,CAAC,iBAAiB,EACxB,aAAc,CAAC,UAAU,CAC3B,CACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
var e={id:`@manifest-editor/ocr-classification`,label:`OCR Classification`,description:`Classify canvases by OCR difficulty and apply canvas tags.`,author:`Digirati`,official:!0,defaultEnabled:!1,tags:[`ocr`,`classification`,`automation`],supports:{apps:[`manifest-editor`],projectTypes:[`Manifest`]}};export{e as t};
|
|
2
|
-
//# sourceMappingURL=plugin-
|
|
2
|
+
//# sourceMappingURL=plugin-CsyG04LG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-
|
|
1
|
+
{"version":3,"file":"plugin-CsyG04LG.js","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import type { PluginMetadata } from \"@manifest-editor/shell\";\n\nexport default {\n id: \"@manifest-editor/ocr-classification\",\n label: \"OCR Classification\",\n description: \"Classify canvases by OCR difficulty and apply canvas tags.\",\n author: \"Digirati\",\n official: true,\n defaultEnabled: false,\n tags: [\"ocr\", \"classification\", \"automation\"],\n supports: {\n apps: [\"manifest-editor\"],\n projectTypes: [\"Manifest\"],\n },\n} satisfies PluginMetadata;\n"],"mappings":"AAEA,IAAA,EAAe,CACb,GAAI,sCACJ,MAAO,qBACP,YAAa,6DACb,OAAQ,WACR,SAAU,GACV,eAAgB,GAChB,KAAM,CAAC,MAAO,iBAAkB,YAAY,EAC5C,SAAU,CACR,KAAM,CAAC,iBAAiB,EACxB,aAAc,CAAC,UAAU,CAC3B,CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manifest-editor/ocr-classification",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bugs": "https://github.com/digirati-co-uk/iiif-manifest-editor/issues",
|
|
6
6
|
"repository": {
|
|
@@ -37,25 +37,24 @@
|
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "tsdown",
|
|
39
39
|
"dev": "tsdown --watch",
|
|
40
|
-
"test": "vitest run",
|
|
40
|
+
"test": "vitest run --config ../../vitest.config.cjs",
|
|
41
41
|
"typecheck": "tsc --noEmit",
|
|
42
42
|
"prepack": "tsdown --clean"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@iiif/helpers": "1.
|
|
46
|
-
"@manifest-editor/components": "2.
|
|
47
|
-
"@manifest-editor/shell": "2.
|
|
45
|
+
"@iiif/helpers": "1.6.1",
|
|
46
|
+
"@manifest-editor/components": "2.2.0",
|
|
47
|
+
"@manifest-editor/shell": "2.2.0",
|
|
48
48
|
"onnxruntime-web": "^1.24.3",
|
|
49
|
-
"react": "19.2.
|
|
49
|
+
"react": "19.2.8"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"vitest": "v3.0.9"
|
|
52
|
+
"@types/react": "19.2.18",
|
|
53
|
+
"tsdown": "0.22.14",
|
|
54
|
+
"vitest": "4.1.10"
|
|
56
55
|
},
|
|
57
56
|
"publishConfig": {
|
|
58
57
|
"access": "public"
|
|
59
58
|
},
|
|
60
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "9ee7ce32bf7728205e22d852fb80061b86067471"
|
|
61
60
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-CwtpxPp2.d.ts","names":[],"sources":["../src/plugin.ts","../src/canvas-image.ts","../src/ocr-difficulty.ts","../src/background-action.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;KCGY,4BAAA;;QAEJ;;;;cCHK,uBAAA;KAED,eAAA;KAEA,kBAAA;MACN;;;;;;KAOM,uBAAA,GAA0B;;;KAI1B,gBAAA;;cAEE;;;cAID,wBAAwB;ADrBzB,iBC6CI,mBAAA,CD7CwB,MAEhC,EC2CoC,SD3ChC,CAAA,MAAA,CAAA,CAAA,EC2CoD,uBD3CpD;iBCmEI,sBAAA,aAAmC,0BAA0B;iBAU7D,cAAA;;;cClEH,4BAAA;KAED,uBAAA;;;;;;;;;KAUA,2BAAA;;;;;KAMA,6BAAA;EF/BA,KAAA,EAAA,MAAA;;;UEmCF;EDpCG,eAAA,ECqCM,uBDrCiB,EAAA;EAExB,eAAA,ECoCO,2BDpCQ,EAAA;AAE3B,CAAA;AAQY,KCuCA,mCAAA,GDvC0B;EAI1B,iBAAA,CAAA,EAAgB,GAAA,GCoCA,ODlCd,CAAA,IAAA,CAAA;EAID,cAAA,CAAA,EAAA,CAAA,GAAA,EC+BY,0BD/BY,EAAA,MAAkB,EAAA,GAAA,EAAA,GC+Bc,OD/Bd,CC+BsB,4BD/BtB,GAAA,IAAA,CAAA;EAwBvC,aAAA,CAAA,EAAA,CAAA,KAAmB,ECQT,IDRS,EAAA,GCQA,ODRS,CCQD,gBDRqB,CAAA;AAwBhE,CAAA;AAUgB,iBCvBA,uCAAA,CDuBc,YAAA,CAAA,ECtBd,mCDsBc,CAAA,ECrB3B,0BDqB2B;AAAA;;;cE9EjB,mBAAmB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-MMJWr93c.d.cts","names":[],"sources":["../src/plugin.ts","../src/canvas-image.ts","../src/ocr-difficulty.ts","../src/background-action.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;KCGY,4BAAA;;QAEJ;;;;cCHK,uBAAA;KAED,eAAA;KAEA,kBAAA;MACN;;;;;;KAOM,uBAAA,GAA0B;;;KAI1B,gBAAA;;cAEE;;;cAID,wBAAwB;ADrBzB,iBC6CI,mBAAA,CD7CwB,MAEhC,EC2CoC,SD3ChC,CAAA,MAAA,CAAA,CAAA,EC2CoD,uBD3CpD;iBCmEI,sBAAA,aAAmC,0BAA0B;iBAU7D,cAAA;;;cClEH,4BAAA;KAED,uBAAA;;;;;;;;;KAUA,2BAAA;;;;;KAMA,6BAAA;EF/BA,KAAA,EAAA,MAAA;;;UEmCF;EDpCG,eAAA,ECqCM,uBDrCiB,EAAA;EAExB,eAAA,ECoCO,2BDpCQ,EAAA;AAE3B,CAAA;AAQY,KCuCA,mCAAA,GDvC0B;EAI1B,iBAAA,CAAA,EAAgB,GAAA,GCoCA,ODlCd,CAAA,IAAA,CAAA;EAID,cAAA,CAAA,EAAA,CAAA,GAAA,EC+BY,0BD/BY,EAAA,MAAkB,EAAA,GAAA,EAAA,GC+Bc,OD/Bd,CC+BsB,4BD/BtB,GAAA,IAAA,CAAA;EAwBvC,aAAA,CAAA,EAAA,CAAA,KAAmB,ECQT,IDRS,EAAA,GCQA,ODRS,CCQD,gBDRqB,CAAA;AAwBhE,CAAA;AAUgB,iBCvBA,uCAAA,CDuBc,YAAA,CAAA,ECtBd,mCDsBc,CAAA,ECrB3B,0BDqB2B;AAAA;;;cE9EjB,mBAAmB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ocr-difficulty-CjQvA3aZ.js","names":["OCR_DIFFICULTY_CLASSES: OcrDifficultyClass[]"],"sources":["../src/ocr-difficulty.ts"],"sourcesContent":["import type { ManifestEditorTag } from \"@manifest-editor/shell\";\n\nexport const OCR_DIFFICULTY_TAG_TYPE = \"ocr-difficulty\";\n\nexport type OcrDifficultyId = \"easy\" | \"medium\" | \"difficult\";\n\nexport type OcrDifficultyClass = {\n id: OcrDifficultyId;\n index: number;\n label: string;\n backgroundColor: string;\n textColor: string;\n};\n\nexport type OcrDifficultyPrediction = OcrDifficultyClass & {\n score: number;\n};\n\nexport type OcrClassifierRun = {\n scores: number[];\n prediction: OcrDifficultyPrediction;\n inferenceMs: number;\n};\n\nexport const OCR_DIFFICULTY_CLASSES: OcrDifficultyClass[] = [\n {\n id: \"easy\",\n index: 0,\n label: \"OCR Easy\",\n backgroundColor: \"#047857\",\n textColor: \"#ffffff\",\n },\n {\n id: \"medium\",\n index: 1,\n label: \"OCR Medium\",\n backgroundColor: \"#b45309\",\n textColor: \"#ffffff\",\n },\n {\n id: \"difficult\",\n index: 2,\n label: \"OCR Difficult\",\n backgroundColor: \"#991b1b\",\n textColor: \"#ffffff\",\n },\n];\n\nexport function selectOcrDifficulty(scores: ArrayLike<number>): OcrDifficultyPrediction {\n if (!scores.length) {\n throw new Error(\"OCR classifier returned no scores.\");\n }\n\n let bestIndex = 0;\n let bestScore = Number(scores[0] ?? 0);\n\n for (let index = 1; index < scores.length; index += 1) {\n const score = Number(scores[index]);\n if (score > bestScore) {\n bestIndex = index;\n bestScore = score;\n }\n }\n\n const difficultyClass = OCR_DIFFICULTY_CLASSES[bestIndex] ?? OCR_DIFFICULTY_CLASSES[2]!;\n\n return {\n ...difficultyClass,\n score: bestScore,\n };\n}\n\nexport function createOcrDifficultyTag(prediction: OcrDifficultyPrediction): ManifestEditorTag {\n return {\n type: OCR_DIFFICULTY_TAG_TYPE,\n id: prediction.id,\n label: prediction.label,\n backgroundColor: prediction.backgroundColor,\n textColor: prediction.textColor,\n };\n}\n\nexport function formatOcrScore(score: number) {\n return `${Math.round(score * 1000) / 10}%`;\n}\n"],"mappings":"AAEA,MAAa,EAA0B,iBAsB1BA,EAA+C,CAC1D,CACE,GAAI,OACJ,MAAO,EACP,MAAO,WACP,gBAAiB,UACjB,UAAW,UACZ,CACD,CACE,GAAI,SACJ,MAAO,EACP,MAAO,aACP,gBAAiB,UACjB,UAAW,UACZ,CACD,CACE,GAAI,YACJ,MAAO,EACP,MAAO,gBACP,gBAAiB,UACjB,UAAW,UACZ,CACF,CAED,SAAgB,EAAoB,EAAoD,CACtF,GAAI,CAAC,EAAO,OACV,MAAU,MAAM,qCAAqC,CAGvD,IAAI,EAAY,EACZ,EAAY,OAAO,EAAO,IAAM,EAAE,CAEtC,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAO,OAAQ,GAAS,EAAG,CACrD,IAAM,EAAQ,OAAO,EAAO,GAAO,CAC/B,EAAQ,IACV,EAAY,EACZ,EAAY,GAMhB,MAAO,CACL,GAHsB,EAAuB,IAAc,EAAuB,GAIlF,MAAO,EACR,CAGH,SAAgB,EAAuB,EAAwD,CAC7F,MAAO,CACL,KAAM,EACN,GAAI,EAAW,GACf,MAAO,EAAW,MAClB,gBAAiB,EAAW,gBAC5B,UAAW,EAAW,UACvB,CAGH,SAAgB,EAAe,EAAe,CAC5C,MAAO,GAAG,KAAK,MAAM,EAAQ,IAAK,CAAG,GAAG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./ocr-difficulty-9L3ewI3P.cjs`);let l=require(`onnxruntime-web/wasm`);l=s(l);const u=new URL(`./assets/ocr_router_efficientnet_b0_threshold_0.15.onnx`,require(`url`).pathToFileURL(__filename).href).href,d=new URL(`./assets/ort-wasm-simd-threaded.mjs`,require(`url`).pathToFileURL(__filename).href).href,f=new URL(`./assets/ort-wasm-simd-threaded.wasm`,require(`url`).pathToFileURL(__filename).href).href,p=[1,3,224,224],m=256,h=[.485,.456,.406],g=[.229,.224,.225];let _=null;async function v(){return _||(l.env.wasm.wasmPaths={mjs:d,wasm:f},l.env.wasm.numThreads=1,_=l.InferenceSession.create(u,{executionProviders:[`wasm`],graphOptimizationLevel:`all`}).catch(e=>{throw _=null,e})),_}async function y(e){let t=await v(),n=await x(e);try{let e=C(n),r=t.inputNames[0]??`x`,i=t.outputNames[0]??`linear`,a=performance.now(),o=await t.run({[r]:e}),s=performance.now()-a,l=o[i];if(!l)throw Error(`Model output "${i}" was not returned.`);let u=Array.from(l.data).map(b);return{scores:u,prediction:c.a(u),inferenceMs:s}}finally{n.dispose()}}function b(e){return 1/(1+Math.exp(-e))}async function x(e){if(typeof createImageBitmap==`function`){let t=await createImageBitmap(e,{imageOrientation:`from-image`});return{source:t,width:t.width,height:t.height,dispose:()=>t.close()}}let t=URL.createObjectURL(e);try{let e=await S(t);return{source:e,width:e.naturalWidth,height:e.naturalHeight,dispose:()=>URL.revokeObjectURL(t)}}catch(e){throw URL.revokeObjectURL(t),e}}function S(e){return new Promise((t,n)=>{let r=new Image;r.decoding=`async`,r.onload=()=>t(r),r.onerror=()=>n(Error(`Unable to decode the canvas image.`)),r.src=e})}function C(e){let[,t,n,r]=p,i=256/Math.min(e.width,e.height),a=Math.round(e.width*i),o=Math.round(e.height*i),s=w(a,o);T(s).drawImage(e.source,0,0,a,o);let c=Math.max(0,Math.floor((a-r)/2)),u=Math.max(0,Math.floor((o-n)/2)),d=T(w(r,n));d.drawImage(s,c,u,r,n,0,0,r,n);let f=d.getImageData(0,0,r,n).data,m=r*n,_=new Float32Array(t*m);for(let e=0;e<m;e+=1){let t=e*4,n=(f[t]??0)/255,r=(f[t+1]??0)/255,i=(f[t+2]??0)/255;_[e]=(n-h[0])/g[0],_[m+e]=(r-h[1])/g[1],_[m*2+e]=(i-h[2])/g[2]}return new l.Tensor(`float32`,_,Array.from(p))}function w(e,t){let n=document.createElement(`canvas`);return n.width=e,n.height=t,n}function T(e){let t=e.getContext(`2d`,{willReadFrequently:!0});if(!t)throw Error(`Could not acquire a 2D canvas context for image preprocessing.`);return t}exports.loadOcrClassifier=v,exports.runOcrClassifier=y,exports.t=s;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"onnx-classifier-mb_6hJ1l.js","names":["sessionPromise: Promise<ort.InferenceSession> | null"],"sources":["../src/onnx-classifier.ts"],"sourcesContent":["import * as ort from \"onnxruntime-web/wasm\";\nimport { type OcrClassifierRun, selectOcrDifficulty } from \"./ocr-difficulty\";\n\nconst MODEL_URL = new URL(\"./assets/ocr_router_efficientnet_b0_threshold_0.15.onnx\", import.meta.url).href;\nconst ORT_WASM_MODULE_URL = new URL(\"./assets/ort-wasm-simd-threaded.mjs\", import.meta.url).href;\nconst ORT_WASM_BINARY_URL = new URL(\"./assets/ort-wasm-simd-threaded.wasm\", import.meta.url).href;\n\nexport const MODEL_INPUT_SHAPE = [1, 3, 224, 224] as const;\nexport const MODEL_OUTPUT_SHAPE = [1, 3] as const;\n\nconst RESIZE_SHORT_SIDE = 256;\nconst IMAGE_MEAN = [0.485, 0.456, 0.406] as const;\nconst IMAGE_STD = [0.229, 0.224, 0.225] as const;\n\ntype LoadedImageSource = {\n source: CanvasImageSource;\n width: number;\n height: number;\n dispose: () => void;\n};\n\nlet sessionPromise: Promise<ort.InferenceSession> | null = null;\n\nexport async function loadOcrClassifier() {\n if (!sessionPromise) {\n ort.env.wasm.wasmPaths = {\n mjs: ORT_WASM_MODULE_URL,\n wasm: ORT_WASM_BINARY_URL,\n };\n ort.env.wasm.numThreads = 1;\n\n sessionPromise = ort.InferenceSession.create(MODEL_URL, {\n executionProviders: [\"wasm\"],\n graphOptimizationLevel: \"all\",\n }).catch((error: unknown) => {\n sessionPromise = null;\n throw error;\n });\n }\n\n return sessionPromise;\n}\n\nexport async function runOcrClassifier(imageBlob: Blob): Promise<OcrClassifierRun> {\n const session = await loadOcrClassifier();\n const image = await loadImageSource(imageBlob);\n\n try {\n const tensor = imageToTensor(image);\n const inputName = session.inputNames[0] ?? \"x\";\n const outputName = session.outputNames[0] ?? \"linear\";\n const startedAt = performance.now();\n const outputMap = await session.run({ [inputName]: tensor });\n const inferenceMs = performance.now() - startedAt;\n const outputTensor = outputMap[outputName];\n\n if (!outputTensor) {\n throw new Error(`Model output \"${outputName}\" was not returned.`);\n }\n\n const scores = Array.from(outputTensor.data as ArrayLike<number>).map(sigmoid);\n\n return {\n scores,\n prediction: selectOcrDifficulty(scores),\n inferenceMs,\n };\n } finally {\n image.dispose();\n }\n}\n\nfunction sigmoid(value: number) {\n return 1 / (1 + Math.exp(-value));\n}\n\nasync function loadImageSource(blob: Blob): Promise<LoadedImageSource> {\n if (typeof createImageBitmap === \"function\") {\n const bitmap = await createImageBitmap(blob, { imageOrientation: \"from-image\" });\n\n return {\n source: bitmap,\n width: bitmap.width,\n height: bitmap.height,\n dispose: () => bitmap.close(),\n };\n }\n\n const objectUrl = URL.createObjectURL(blob);\n\n try {\n const image = await loadHtmlImage(objectUrl);\n\n return {\n source: image,\n width: image.naturalWidth,\n height: image.naturalHeight,\n dispose: () => URL.revokeObjectURL(objectUrl),\n };\n } catch (error) {\n URL.revokeObjectURL(objectUrl);\n throw error;\n }\n}\n\nfunction loadHtmlImage(source: string) {\n return new Promise<HTMLImageElement>((resolve, reject) => {\n const image = new Image();\n image.decoding = \"async\";\n image.onload = () => resolve(image);\n image.onerror = () => reject(new Error(\"Unable to decode the canvas image.\"));\n image.src = source;\n });\n}\n\nfunction imageToTensor(image: LoadedImageSource) {\n const [, channels, croppedHeight, croppedWidth] = MODEL_INPUT_SHAPE;\n const resizeScale = RESIZE_SHORT_SIDE / Math.min(image.width, image.height);\n const resizedWidth = Math.round(image.width * resizeScale);\n const resizedHeight = Math.round(image.height * resizeScale);\n const resizeCanvas = createCanvas(resizedWidth, resizedHeight);\n const resizeContext = getCanvasContext(resizeCanvas);\n\n resizeContext.drawImage(image.source, 0, 0, resizedWidth, resizedHeight);\n\n const cropX = Math.max(0, Math.floor((resizedWidth - croppedWidth) / 2));\n const cropY = Math.max(0, Math.floor((resizedHeight - croppedHeight) / 2));\n const cropCanvas = createCanvas(croppedWidth, croppedHeight);\n const cropContext = getCanvasContext(cropCanvas);\n\n cropContext.drawImage(resizeCanvas, cropX, cropY, croppedWidth, croppedHeight, 0, 0, croppedWidth, croppedHeight);\n\n const imageData = cropContext.getImageData(0, 0, croppedWidth, croppedHeight).data;\n const pixelCount = croppedWidth * croppedHeight;\n const tensorData = new Float32Array(channels * pixelCount);\n\n for (let pixelIndex = 0; pixelIndex < pixelCount; pixelIndex += 1) {\n const dataOffset = pixelIndex * 4;\n const red = (imageData[dataOffset] ?? 0) / 255;\n const green = (imageData[dataOffset + 1] ?? 0) / 255;\n const blue = (imageData[dataOffset + 2] ?? 0) / 255;\n\n tensorData[pixelIndex] = (red - IMAGE_MEAN[0]) / IMAGE_STD[0];\n tensorData[pixelCount + pixelIndex] = (green - IMAGE_MEAN[1]) / IMAGE_STD[1];\n tensorData[pixelCount * 2 + pixelIndex] = (blue - IMAGE_MEAN[2]) / IMAGE_STD[2];\n }\n\n return new ort.Tensor(\"float32\", tensorData, Array.from(MODEL_INPUT_SHAPE));\n}\n\nfunction createCanvas(width: number, height: number) {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\nfunction getCanvasContext(canvas: HTMLCanvasElement) {\n const context = canvas.getContext(\"2d\", { willReadFrequently: true });\n\n if (!context) {\n throw new Error(\"Could not acquire a 2D canvas context for image preprocessing.\");\n }\n\n return context;\n}\n"],"mappings":"wFAGA,MAAM,EAAY,IAAI,IAAI,0DAA2D,OAAO,KAAK,IAAI,CAAC,KAChG,EAAsB,IAAI,IAAI,sCAAuC,OAAO,KAAK,IAAI,CAAC,KACtF,EAAsB,IAAI,IAAI,uCAAwC,OAAO,KAAK,IAAI,CAAC,KAEhF,EAAoB,CAAC,EAAG,EAAG,IAAK,IAAI,CAI3C,EAAa,CAAC,KAAO,KAAO,KAAM,CAClC,EAAY,CAAC,KAAO,KAAO,KAAM,CASvC,IAAIA,EAAuD,KAE3D,eAAsB,GAAoB,CAiBxC,OAhBK,IACH,EAAI,IAAI,KAAK,UAAY,CACvB,IAAK,EACL,KAAM,EACP,CACD,EAAI,IAAI,KAAK,WAAa,EAE1B,EAAiB,EAAI,iBAAiB,OAAO,EAAW,CACtD,mBAAoB,CAAC,OAAO,CAC5B,uBAAwB,MACzB,CAAC,CAAC,MAAO,GAAmB,CAE3B,KADA,GAAiB,KACX,GACN,EAGG,EAGT,eAAsB,EAAiB,EAA4C,CACjF,IAAM,EAAU,MAAM,GAAmB,CACnC,EAAQ,MAAM,EAAgB,EAAU,CAE9C,GAAI,CACF,IAAM,EAAS,EAAc,EAAM,CAC7B,EAAY,EAAQ,WAAW,IAAM,IACrC,EAAa,EAAQ,YAAY,IAAM,SACvC,EAAY,YAAY,KAAK,CAC7B,EAAY,MAAM,EAAQ,IAAI,EAAG,GAAY,EAAQ,CAAC,CACtD,EAAc,YAAY,KAAK,CAAG,EAClC,EAAe,EAAU,GAE/B,GAAI,CAAC,EACH,MAAU,MAAM,iBAAiB,EAAW,qBAAqB,CAGnE,IAAM,EAAS,MAAM,KAAK,EAAa,KAA0B,CAAC,IAAI,EAAQ,CAE9E,MAAO,CACL,SACA,WAAY,EAAoB,EAAO,CACvC,cACD,QACO,CACR,EAAM,SAAS,EAInB,SAAS,EAAQ,EAAe,CAC9B,MAAO,IAAK,EAAI,KAAK,IAAI,CAAC,EAAM,EAGlC,eAAe,EAAgB,EAAwC,CACrE,GAAI,OAAO,mBAAsB,WAAY,CAC3C,IAAM,EAAS,MAAM,kBAAkB,EAAM,CAAE,iBAAkB,aAAc,CAAC,CAEhF,MAAO,CACL,OAAQ,EACR,MAAO,EAAO,MACd,OAAQ,EAAO,OACf,YAAe,EAAO,OAAO,CAC9B,CAGH,IAAM,EAAY,IAAI,gBAAgB,EAAK,CAE3C,GAAI,CACF,IAAM,EAAQ,MAAM,EAAc,EAAU,CAE5C,MAAO,CACL,OAAQ,EACR,MAAO,EAAM,aACb,OAAQ,EAAM,cACd,YAAe,IAAI,gBAAgB,EAAU,CAC9C,OACM,EAAO,CAEd,MADA,IAAI,gBAAgB,EAAU,CACxB,GAIV,SAAS,EAAc,EAAgB,CACrC,OAAO,IAAI,SAA2B,EAAS,IAAW,CACxD,IAAM,EAAQ,IAAI,MAClB,EAAM,SAAW,QACjB,EAAM,WAAe,EAAQ,EAAM,CACnC,EAAM,YAAgB,EAAW,MAAM,qCAAqC,CAAC,CAC7E,EAAM,IAAM,GACZ,CAGJ,SAAS,EAAc,EAA0B,CAC/C,GAAM,EAAG,EAAU,EAAe,GAAgB,EAC5C,EAAc,IAAoB,KAAK,IAAI,EAAM,MAAO,EAAM,OAAO,CACrE,EAAe,KAAK,MAAM,EAAM,MAAQ,EAAY,CACpD,EAAgB,KAAK,MAAM,EAAM,OAAS,EAAY,CACtD,EAAe,EAAa,EAAc,EAAc,CACxC,EAAiB,EAAa,CAEtC,UAAU,EAAM,OAAQ,EAAG,EAAG,EAAc,EAAc,CAExE,IAAM,EAAQ,KAAK,IAAI,EAAG,KAAK,OAAO,EAAe,GAAgB,EAAE,CAAC,CAClE,EAAQ,KAAK,IAAI,EAAG,KAAK,OAAO,EAAgB,GAAiB,EAAE,CAAC,CAEpE,EAAc,EADD,EAAa,EAAc,EAAc,CACZ,CAEhD,EAAY,UAAU,EAAc,EAAO,EAAO,EAAc,EAAe,EAAG,EAAG,EAAc,EAAc,CAEjH,IAAM,EAAY,EAAY,aAAa,EAAG,EAAG,EAAc,EAAc,CAAC,KACxE,EAAa,EAAe,EAC5B,EAAa,IAAI,aAAa,EAAW,EAAW,CAE1D,IAAK,IAAI,EAAa,EAAG,EAAa,EAAY,GAAc,EAAG,CACjE,IAAM,EAAa,EAAa,EAC1B,GAAO,EAAU,IAAe,GAAK,IACrC,GAAS,EAAU,EAAa,IAAM,GAAK,IAC3C,GAAQ,EAAU,EAAa,IAAM,GAAK,IAEhD,EAAW,IAAe,EAAM,EAAW,IAAM,EAAU,GAC3D,EAAW,EAAa,IAAe,EAAQ,EAAW,IAAM,EAAU,GAC1E,EAAW,EAAa,EAAI,IAAe,EAAO,EAAW,IAAM,EAAU,GAG/E,OAAO,IAAI,EAAI,OAAO,UAAW,EAAY,MAAM,KAAK,EAAkB,CAAC,CAG7E,SAAS,EAAa,EAAe,EAAgB,CACnD,IAAM,EAAS,SAAS,cAAc,SAAS,CAG/C,MAFA,GAAO,MAAQ,EACf,EAAO,OAAS,EACT,EAGT,SAAS,EAAiB,EAA2B,CACnD,IAAM,EAAU,EAAO,WAAW,KAAM,CAAE,mBAAoB,GAAM,CAAC,CAErE,GAAI,CAAC,EACH,MAAU,MAAM,iEAAiE,CAGnF,OAAO"}
|