@cerebriline/core 4.100.241 → 4.100.243
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/document-reader-child.js +23 -0
- package/dist/extensions/tools/executors/document/ocr.d.ts +5 -0
- package/dist/extensions/tools/executors/document/read-job.d.ts +68 -0
- package/dist/extensions/tools/executors/document/read-process.d.ts +52 -0
- package/dist/extensions/tools/executors/document/read-protocol.d.ts +65 -0
- package/dist/extensions/tools/executors/document/recognition.d.ts +2 -9
- package/dist/extensions/tools/executors/document-extract.d.ts +33 -5
- package/dist/extensions/tools/librarian-tools.d.ts +2 -5
- package/dist/hub/daemon/entry.js +582 -580
- package/dist/hub/index.js +567 -565
- package/dist/index.js +711 -707
- package/dist/runtime/orchestration/runtime-builder.d.ts +13 -0
- package/dist/runtime/orchestration/session-runtime.d.ts +2 -0
- package/dist/runtime/safety/loop-detection.d.ts +13 -0
- package/dist/services/retrieval/catalogue.d.ts +29 -2
- package/dist/services/retrieval/running-heads.d.ts +38 -0
- package/package.json +4 -4
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import{createRequire as F$}from"node:module";var D=F$(import.meta.url);import{mkdir as wJ,writeFile as yJ}from"node:fs/promises";import{join as W$}from"node:path";import xJ from"node:fs/promises";import{existsSync as PQ,readdirSync as v$,readFileSync as AQ,statSync as S$}from"node:fs";import*as u from"node:path";import{createHash as C$}from"node:crypto";import{inflateSync as R$}from"node:zlib";var N$=new Set(["image/png","image/jpeg","image/gif","image/webp"]),L$={"image/png":"png","image/jpeg":"jpg","image/gif":"gif","image/webp":"webp","image/bmp":"bmp","image/tiff":"tif","image/svg+xml":"svg","image/emf":"emf","image/wmf":"wmf","image/x-pict":"pict"};function j$(Q){let $=(q,...Z)=>Z.every((K,H)=>Q[q+H]===K);if($(0,137,80,78,71))return"image/png";if($(0,255,216,255))return"image/jpeg";if($(0,71,73,70,56))return"image/gif";if($(0,82,73,70,70)&&$(8,87,69,66,80))return"image/webp";if($(0,66,77))return"image/bmp";if($(0,73,73,42,0)||$(0,77,77,0,42))return"image/tiff";if($(40,32,69,77,70))return"image/emf";if($(0,215,205,198,154)||$(0,1,0,9,0))return"image/wmf";if($(10,0,17,2,255))return"image/x-pict";let J=Buffer.from(Q.subarray(0,256)).toString("utf8").trimStart();if(J.startsWith("<svg")||J.startsWith("<?xml")&&J.includes("<svg"))return"image/svg+xml";return}function T$(Q){if(Q[0]!==120||![1,94,156,218].includes(Q[1]??0))return Q;try{return new Uint8Array(R$(Q))}catch{return Q}}class BQ{linkDir;byHash=new Map;names=new Set;pending=[];constructor(Q="images"){this.linkDir=Q}add(Q){if(Q.data.byteLength===0)return;let $=T$(Q.data),J=C$("sha1").update($).digest("hex"),q=this.byHash.get(J);if(q)return q;let Z=j$($)??Q.mediaType??"application/octet-stream",K=L$[Z]??"bin",H=this.uniqueName(O$(Q.stem),K),Y={file:H,link:`${this.linkDir}/${H}`,mediaType:Z,bytes:$.byteLength,...Q.width?{width:Q.width}:{},...Q.height?{height:Q.height}:{},...Q.source?{source:Q.source}:{},...Q.alt?.trim()?{alt:Q.alt.trim()}:{},...N$.has(Z)||Z==="image/svg+xml"?{}:{notViewable:!0},sha1:J};return this.byHash.set(J,Y),this.pending.push({image:Y,data:$}),Y}get images(){return this.pending.map((Q)=>Q.image)}entries(){return this.pending}uniqueName(Q,$){let J=`${Q}.${$}`;for(let q=2;this.names.has(J);q++)J=`${Q}-${q}.${$}`;return this.names.add(J),J}}function O$(Q){return Q.replace(/\.[a-z0-9]{2,4}$/i,"").replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)||"image"}function x(Q){return`![${(Q.alt??"").replace(/[[\]\n]/g," ").trim()}](${Q.link})`}var P$=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?)$/i;function A$(Q){if(Q.length<90)return 0;let $=new DataView(Q.buffer,Q.byteOffset,Q.byteLength),J=$.getUint32(78);if(J+14>Q.length)return 0;return $.getUint16(J+12)}function I$(Q){let $=Buffer.from(Q.buffer,Q.byteOffset,Q.byteLength);return $.includes("META-INF/rights.xml")||$.includes("META-INF/license.lcpl")}function k$(Q){let $=Buffer.from(Q.buffer,Q.byteOffset,Q.byteLength);if($.length<22||$.readUInt32LE(0)!==67324752)return"it does not start as a ZIP archive, which every EPUB is";let J=$.lastIndexOf(Buffer.from([80,75,5,6]),$.length-22);if(J<0||J<$.length-22-65535)return`it ends before its index (${$.length.toLocaleString("en-US")} bytes), so it was cut short when it was copied, downloaded or unpacked`;let q=$.readUInt32LE(J+12),Z=$.readUInt32LE(J+16);if(Z!==4294967295&&q!==4294967295&&Z+q>J)return"its index points past the end of the file, so part of it is missing";return}var IQ=120000;async function $Q(Q){let $;try{return await Promise.race([Q,new Promise((J,q)=>{$=setTimeout(()=>q(Error(`The book could not be opened: the reader gave no answer in ${IQ/1000}s, which is what it does with a damaged file. Check that the file is complete.`)),IQ)})])}finally{clearTimeout($)}}function kQ(Q,$=0,J=[]){for(let q of Q){if(J.length>=200)break;let Z=String(q.label??"").trim();if(Z)J.push(`${" ".repeat($)}${Z}`);if(Array.isArray(q.children))kQ(q.children,$+1,J)}return J}function JQ(Q){if(typeof Q==="string")return Q.trim()||void 0;if(Array.isArray(Q))for(let $ of Q){let J=JQ(typeof $==="object"&&$!==null?$.contributor??$.name:$);if(J)return J}if(typeof Q==="object"&&Q!==null){let $=Q;return JQ($.contributor??$.name??$.value)}return}async function D$(Q){let{default:$}=await import("turndown"),{gfm:J}=await import("@joplin/turndown-plugin-gfm"),q=new $({headingStyle:"atx",codeBlockStyle:"fenced",bulletListMarker:"-"});return q.use(J),q.remove(["script","style","head"]),q.addRule("image",{filter:"img",replacement:(Z,K)=>{let H=K,Y=H.getAttribute("src")??"";return Q(Y,H.getAttribute("alt")??"")??""}}),q.addRule("svgImage",{filter:(Z)=>Z.nodeName.toLowerCase()==="image",replacement:(Z,K)=>{let H=K,Y=H.getAttribute("xlink:href")??H.getAttribute("href")??"";return Q(Y,"")??""}}),q}async function DQ(Q,$,J,q){if((J==="mobi"||J==="azw3")&&A$($)>1)throw Error("This Kindle book is DRM-protected. It can be read only in a Kindle app; nothing here can remove the protection.");if(J==="epub"&&I$($))throw Error("This EPUB is DRM-protected (Adobe ADEPT or Readium LCP). It can be read only in a reader app licensed for it.");if(J==="epub"){let U=k$($);if(U)throw Error(`This EPUB is damaged: ${U}. Nothing can be read from it; get the file again.`)}let Z=q.scratchDir,{initEpubFile:K}=await import("@lingo-reader/epub-parser"),{initFb2File:H}=await import("@lingo-reader/fb2-parser"),{initKf8File:Y,initMobiFile:X}=await import("@lingo-reader/mobi-parser"),B,F;if(J==="epub")B=await $Q(K(Q,Z)),F="lingo-reader (EPUB)";else if(J==="fb2")B=await $Q(H(Q,Z)),F="lingo-reader (FB2)";else{let[U,V]=J==="azw3"?[Y,X]:[X,Y];try{B=await $Q(U(Q,Z)),F=`lingo-reader (${U===Y?"KF8":"MOBI"})`}catch{B=await $Q(V(Q,Z)),F=`lingo-reader (${V===Y?"KF8":"MOBI"})`}}try{let U=new Map,V=0,G=await D$((L,T)=>{if(!q.wantImages||!L||/^(data:|https?:)/i.test(L))return;let S=L;try{S=decodeURI(L.replace(/^file:\/\//,""))}catch{}if(!u.isAbsolute(S)||!PQ(S))return;if(!U.has(S))U.set(S,q.images.add({data:AQ(S),stem:u.basename(S),source:`chapter ${V}`,...T?{alt:T}:{}}));let w=U.get(S);return w?x(w):void 0}),z=B.getSpine(),C=[],I=[];for(let L=0;L<z.length;L++){let T=L+1;if(q.selects&&!q.selects(T))continue;q.signal?.throwIfAborted(),V=T,q.onProgress?.({unit:"chapter",at:T,total:z.length,pictures:U.size}),C.push(T);let w=(await B.loadChapter(z[L].id))?.html??"",i=w?G.turndown(w).trim():"";if(i)I.push(i)}if(q.wantImages&&PQ(Z))for(let L of v$(Z,{recursive:!0})){let T=u.join(Z,L);if(!P$.test(L)||U.has(T)||!S$(T).isFile())continue;U.set(T,q.images.add({data:AQ(T),stem:u.basename(L)}))}let P=B.getMetadata()??{},v=JQ(P.title),b=JQ(P.creator??P.author),d=kQ(B.getToc()??[]);return{markdown:I.join(`
|
|
2
|
+
|
|
3
|
+
`),reader:F,...v&&v!=="Unknown"?{title:v}:{},...b&&b!=="Unknown"?{author:b}:{},units:{name:"chapter",total:z.length,read:C},...d.length?{contents:d}:{}}}finally{B.destroy()}}import*as WQ from"node:path";var M$={pdf:"PDF",docx:"Word document (DOCX)",pptx:"PowerPoint presentation (PPTX)",xlsx:"Excel workbook (XLSX)",odt:"OpenDocument text (ODT)",odp:"OpenDocument presentation (ODP)",ods:"OpenDocument spreadsheet (ODS)",odg:"OpenDocument drawing (ODG)",rtf:"Rich Text (RTF)",csv:"CSV",html:"HTML",epub:"EPUB ebook",mobi:"Mobipocket / Kindle ebook (MOBI)",azw3:"Kindle KF8 ebook (AZW3)",fb2:"FictionBook (FB2)",doc:"Word 97-2003 document (DOC)",xls:"Excel 97-2003 workbook (XLS)",ppt:"PowerPoint 97-2003 presentation (PPT)"},MQ={".pdf":"pdf",".docx":"docx",".docm":"docx",".dotx":"docx",".pptx":"pptx",".pptm":"pptx",".ppsx":"pptx",".xlsx":"xlsx",".xlsm":"xlsx",".odt":"odt",".odp":"odp",".ods":"ods",".odg":"odg",".rtf":"rtf",".csv":"csv",".html":"html",".htm":"html",".xhtml":"html",".epub":"epub",".mobi":"mobi",".prc":"mobi",".azw":"mobi",".azw3":"azw3",".kf8":"azw3",".fb2":"fb2",".doc":"doc",".dot":"doc",".xls":"xls",".ppt":"ppt",".pps":"ppt"},E$={".djvu":"DjVu has no JavaScript reader.",".djv":"DjVu has no JavaScript reader.",".chm":"Compiled HTML Help (CHM) has no JavaScript reader.",".lit":"Microsoft Reader (LIT) has no JavaScript reader.",".lrf":"Sony BBeB (LRF) has no JavaScript reader.",".kfx":"KFX is Amazon's DRM-bound format and cannot be read.",".pages":"Apple Pages files have no JavaScript reader; export them as DOCX or PDF.",".key":"Apple Keynote files have no JavaScript reader; export them as PPTX or PDF.",".numbers":"Apple Numbers files have no JavaScript reader; export them as XLSX or CSV.",".xlsb":"Binary Excel workbooks (XLSB) are not read; save the workbook as XLSX.",".wps":"Microsoft Works documents are not read; save them as DOCX.",".cbz":"Comic archives are not read yet.",".cbr":"Comic archives are not read yet."},oJ=Object.keys(MQ);function EQ(Q,$){let J=WQ.extname(Q).toLowerCase(),q=E$[J];if(q)return{unsupported:q};let Z=Buffer.from($.subarray(0,512)).toString("latin1"),K=MQ[J];if(Z.startsWith("%PDF"))return{format:"pdf"};if(Z.startsWith("{\\rtf"))return{format:"rtf"};if(Z.slice(60,68)==="BOOKMOBI")return{format:K==="azw3"?"azw3":"mobi"};let H=Z.startsWith("PK\x03\x04"),Y=Z.startsWith("ÐÏ\x11ࡱ\x1Aá");if(H){if(Z.includes("mimetypeapplication/epub+zip"))return{format:"epub"};let X=/mimetypeapplication\/vnd\.oasis\.opendocument\.(text|presentation|spreadsheet|graphics)/.exec(Z);if(X)return{format:{text:"odt",presentation:"odp",spreadsheet:"ods",graphics:"odg"}[X[1]]};if(K&&["docx","pptx","xlsx","epub","odt","odp","ods","odg"].includes(K))return{format:K};if(K==="doc")return{format:"docx"};if(K==="xls")return{format:"xlsx"};if(K==="ppt")return{format:"pptx"}}if(Y){if(K==="doc"||K==="xls"||K==="ppt")return{format:K};if(K==="docx")return{format:"doc"};if(K==="xlsx")return{format:"xls"};if(K==="pptx")return{format:"ppt"};return{unsupported:"This is an OLE compound file, but its extension does not say which Office program wrote it; rename it to .doc, .xls or .ppt."}}if(K==="fb2"||/<FictionBook[\s>]/.test(Z))return{format:"fb2"};if(K==="html"||K==="csv")return{format:K};if(K)return{unsupported:`The file is named as ${M$[K]} but its contents are not; it may be damaged or a different format.`};return{unsupported:`No reader for ${J||"files without an extension"}. Readable: PDF, DOCX/DOC, PPTX/PPT, XLSX/XLS, ODT/ODP/ODS/ODG, RTF, CSV, HTML, EPUB, MOBI/AZW/AZW3, FB2.`}}import{existsSync as hQ,readFileSync as c$}from"node:fs";import{dirname as cQ,join as bQ}from"node:path";import{fileURLToPath as g$}from"node:url";class t{__destroy_into_raw(){let Q=this.__wbg_ptr;return this.__wbg_ptr=0,xQ.unregister(this),Q}free(){let Q=this.__destroy_into_raw();W.__wbg_wasmdocument_free(Q,0)}formatName(){let Q,$;try{let Z=W.__wbindgen_add_to_stack_pointer(-16);W.wasmdocument_formatName(Z,this.__wbg_ptr);var J=R().getInt32(Z+0,!0),q=R().getInt32(Z+4,!0);return Q=J,$=q,h(J,q)}finally{W.__wbindgen_add_to_stack_pointer(16),W.__wbindgen_export3(Q,$,1)}}constructor(Q,$){try{let K=W.__wbindgen_add_to_stack_pointer(-16),H=wQ(Q,W.__wbindgen_export),Y=E,X=r($,W.__wbindgen_export,W.__wbindgen_export2),B=E;W.wasmdocument_new(K,H,Y,X,B);var J=R().getInt32(K+0,!0),q=R().getInt32(K+4,!0),Z=R().getInt32(K+8,!0);if(Z)throw M(q);return this.__wbg_ptr=J,xQ.register(this,this.__wbg_ptr,this),this}finally{W.__wbindgen_add_to_stack_pointer(16)}}plainText(){let Q,$;try{let Z=W.__wbindgen_add_to_stack_pointer(-16);W.wasmdocument_plainText(Z,this.__wbg_ptr);var J=R().getInt32(Z+0,!0),q=R().getInt32(Z+4,!0);return Q=J,$=q,h(J,q)}finally{W.__wbindgen_add_to_stack_pointer(16),W.__wbindgen_export3(Q,$,1)}}toHtml(){let Q,$;try{let Z=W.__wbindgen_add_to_stack_pointer(-16);W.wasmdocument_toHtml(Z,this.__wbg_ptr);var J=R().getInt32(Z+0,!0),q=R().getInt32(Z+4,!0);return Q=J,$=q,h(J,q)}finally{W.__wbindgen_add_to_stack_pointer(16),W.__wbindgen_export3(Q,$,1)}}toIr(){try{let q=W.__wbindgen_add_to_stack_pointer(-16);W.wasmdocument_toIr(q,this.__wbg_ptr);var Q=R().getInt32(q+0,!0),$=R().getInt32(q+4,!0),J=R().getInt32(q+8,!0);if(J)throw M($);return M(Q)}finally{W.__wbindgen_add_to_stack_pointer(16)}}toMarkdownWithImages(){let Q,$;try{let Z=W.__wbindgen_add_to_stack_pointer(-16);W.wasmdocument_toMarkdownWithImages(Z,this.__wbg_ptr);var J=R().getInt32(Z+0,!0),q=R().getInt32(Z+4,!0);return Q=J,$=q,h(J,q)}finally{W.__wbindgen_add_to_stack_pointer(16),W.__wbindgen_export3(Q,$,1)}}toMarkdown(){let Q,$;try{let Z=W.__wbindgen_add_to_stack_pointer(-16);W.wasmdocument_toMarkdown(Z,this.__wbg_ptr);var J=R().getInt32(Z+0,!0),q=R().getInt32(Z+4,!0);return Q=J,$=q,h(J,q)}finally{W.__wbindgen_add_to_stack_pointer(16),W.__wbindgen_export3(Q,$,1)}}}if(Symbol.dispose)t.prototype[Symbol.dispose]=t.prototype.free;class UQ{__destroy_into_raw(){let Q=this.__wbg_ptr;return this.__wbg_ptr=0,_Q.unregister(this),Q}free(){let Q=this.__destroy_into_raw();W.__wbg_wasmeditabledocument_free(Q,0)}constructor(Q,$){try{let K=W.__wbindgen_add_to_stack_pointer(-16),H=wQ(Q,W.__wbindgen_export),Y=E,X=r($,W.__wbindgen_export,W.__wbindgen_export2),B=E;W.wasmeditabledocument_new(K,H,Y,X,B);var J=R().getInt32(K+0,!0),q=R().getInt32(K+4,!0),Z=R().getInt32(K+8,!0);if(Z)throw M(q);return this.__wbg_ptr=J,_Q.register(this,this.__wbg_ptr,this),this}finally{W.__wbindgen_add_to_stack_pointer(16)}}replaceText(Q,$){try{let K=W.__wbindgen_add_to_stack_pointer(-16),H=r(Q,W.__wbindgen_export,W.__wbindgen_export2),Y=E,X=r($,W.__wbindgen_export,W.__wbindgen_export2),B=E;W.wasmeditabledocument_replaceText(K,this.__wbg_ptr,H,Y,X,B);var J=R().getInt32(K+0,!0),q=R().getInt32(K+4,!0),Z=R().getInt32(K+8,!0);if(Z)throw M(q);return J>>>0}finally{W.__wbindgen_add_to_stack_pointer(16)}}toBytes(){try{let K=W.__wbindgen_add_to_stack_pointer(-16);W.wasmeditabledocument_toBytes(K,this.__wbg_ptr);var Q=R().getInt32(K+0,!0),$=R().getInt32(K+4,!0),J=R().getInt32(K+8,!0),q=R().getInt32(K+12,!0);if(q)throw M(J);var Z=w$(Q,$).slice();return W.__wbindgen_export3(Q,$*1,1),Z}finally{W.__wbindgen_add_to_stack_pointer(16)}}}if(Symbol.dispose)UQ.prototype[Symbol.dispose]=UQ.prototype.free;function x$(){return{__proto__:null,"./office_oxide_bg.js":{__proto__:null,__wbg_Error_67e7344beaa85059:function($,J){let q=Error(h($,J));return y(q)},__wbg_String_8564e559799eccda:function($,J){let q=String(s(J)),Z=r(q,W.__wbindgen_export,W.__wbindgen_export2),K=E;R().setInt32($+4,K,!0),R().setInt32($+0,Z,!0)},__wbg___wbindgen_throw_5d9e815e6fdf150f:function($,J){throw Error(h($,J))},__wbg_new_bebc3f4757acf305:function(){return y({})},__wbg_new_ffa92086ea89f79c:function(){return y([])},__wbg_set_13d25b81ab403f5e:function($,J,q){s($)[J>>>0]=M(q)},__wbg_set_6be42768c690e380:function($,J,q){s($)[M(J)]=M(q)},__wbindgen_generic_0000000000000001:function($){return y($)},__wbindgen_generic_0000000000000002:function($){return y($)},__wbindgen_generic_0000000000000003:function($,J){let q=h($,J);return y(q)},__wbindgen_generic_0000000000000004:function($){let J=BigInt.asUintN(64,$);return y(J)},__wbindgen_object_clone_ref:function($){let J=s($);return y(J)},__wbindgen_object_drop_ref:function($){M($)}}}}var xQ=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry((Q)=>W.__wbg_wasmdocument_free(Q,1)),_Q=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry((Q)=>W.__wbg_wasmeditabledocument_free(Q,1));function y(Q){if(o===_.length)_.push(_.length+1);let $=o;return o=_[$],_[$]=Q,$}function _$(Q){if(Q<1028)return;_[Q]=o,o=Q}function w$(Q,$){return Q=Q>>>0,g().subarray(Q/1,Q/1+$)}var c=null;function R(){if(c===null||c.buffer.detached===!0||c.buffer.detached===void 0&&c.buffer!==W.memory.buffer)c=new DataView(W.memory.buffer);return c}function h(Q,$){return h$(Q>>>0,$)}var n=null;function g(){if(n===null||n.byteLength===0)n=new Uint8Array(W.memory.buffer);return n}function s(Q){return _[Q]}var _=Array(1024).fill(void 0);_.push(void 0,null,!0,!1);var o=_.length;function wQ(Q,$){let J=$(Q.length*1,1)>>>0;return g().set(Q,J/1),E=Q.length,J}function r(Q,$,J){if(J===void 0){let Y=a.encode(Q),X=$(Y.length,1)>>>0;return g().subarray(X,X+Y.length).set(Y),E=Y.length,X}let q=Q.length,Z=$(q,1)>>>0,K=g(),H=0;for(;H<q;H++){let Y=Q.charCodeAt(H);if(Y>127)break;K[Z+H]=Y}if(H!==q){if(H!==0)Q=Q.slice(H);Z=J(Z,q,q=H+Q.length*3,1)>>>0;let Y=g().subarray(Z+H,Z+q),X=a.encodeInto(Q,Y);H+=X.written,Z=J(Z,q,H,1)>>>0}return E=H,Z}function M(Q){let $=s(Q);return _$(Q),$}var qQ=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});qQ.decode();var y$=2146435072,GQ=0;function h$(Q,$){if(GQ+=$,GQ>=y$)qQ=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0}),qQ.decode(),GQ=$;return qQ.decode(g().subarray(Q,Q+$))}var a=new TextEncoder;if(!("encodeInto"in a))a.encodeInto=function(Q,$){let J=a.encode(Q);return $.set(J),{read:Q.length,written:J.length}};var E=0,b$,f$,W;function u$(Q,$){return f$=Q,W=Q.exports,b$=$,c=null,n=null,W}function yQ(Q){if(W!==void 0)return W;if(Q!==void 0)if(Object.getPrototypeOf(Q)===Object.prototype)({module:Q}=Q);else console.warn("using deprecated parameters for `initSync()`; pass a single object instead");let $=x$();if(!(Q instanceof WebAssembly.Module))Q=new WebAssembly.Module(Q);let J=new WebAssembly.Instance(Q,$);return u$(J,Q)}var fQ="office_oxide_bg.wasm",uQ=!1;function l$(Q=m$()){let $=bQ(Q,"office-oxide",fQ);if(hQ($))return $;let J=Q;for(let q=0;q<7;q++){let Z=bQ(J,"assets","office-oxide",fQ);if(hQ(Z))return Z;let K=cQ(J);if(K===J)break;J=K}return}function m$(){try{return cQ(g$(import.meta.url))}catch{return"."}}function gQ(Q,$){if(!uQ){let J=l$();if(!J)throw Error("The reader for Word, Excel and PowerPoint 97-2003 files is missing from this installation (office_oxide_bg.wasm was not found).");yQ({module:c$(J)}),uQ=!0}return new t(Q,$)}var p$=/\[image-base64:([A-Za-z0-9+/=\s]+)\]/g;function d$(Q){return Q.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F]/g,"")}function i$(Q,$){let J=new DataView(Q.buffer,Q.byteOffset,Q.byteLength),q=$+8;while(q+12<=Q.length){let Z=J.getUint32(q),K=String.fromCharCode(...Q.subarray(q+4,q+8));if(q+=12+Z,K==="IEND")return q-$;if(Z>Q.length)return}return}function n$(Q,$){let J=$+2;while(J+4<=Q.length){if(Q[J]!==255)return;let q=Q[J+1];if(q===217)return J+2-$;if(q===218){J+=2+(Q[J+2]<<8|Q[J+3]);while(J+1<Q.length){if(Q[J]===255){let Z=Q[J+1];if(Z===217)return J+2-$;if(Z!==0&&(Z<208||Z>215))break}J++}continue}J+=2+(Q[J+2]<<8|Q[J+3])}return}async function s$(Q){let $=await import("cfb"),J=$.default??$,q;try{q=J.read(Buffer.from(Q),{type:"buffer"})}catch{return[]}let Z=[];for(let K of q.FileIndex){let H=K.content;if(K.type!==2||!H||H.length<64)continue;let Y=H instanceof Uint8Array?H:new Uint8Array(H);for(let X=0;X+8<Y.length;X++){let B;if(Y[X]===137&&Y[X+1]===80&&Y[X+2]===78&&Y[X+3]===71)B=i$(Y,X);else if(Y[X]===255&&Y[X+1]===216&&Y[X+2]===255)B=n$(Y,X);if(B&&B>64&&X+B<=Y.length)Z.push(Y.slice(X,X+B)),X+=B-1}}return Z}async function lQ(Q,$,J){let q=gQ(Q,$),Z;try{Z=q.toMarkdownWithImages()}finally{q.free()}let K=0;Z=Z.replace(p$,(Y,X)=>{if(!J.wantImages)return"";K++;let B=J.images.add({data:Buffer.from(X.replace(/\s/g,""),"base64"),stem:`${$}-image-${K}`});return B?x(B):""}),Z=d$(Z).replace(/\n{3,}/g,`
|
|
4
|
+
|
|
5
|
+
`).trim();let H=[];if(J.wantImages&&$==="doc"){let Y=[];for(let X of await s$(Q)){let B=J.images.images.length;K++;let F=J.images.add({data:X,stem:`${$}-image-${K}`});if(F&&J.images.images.length>B)Y.push(x(F))}if(Y.length)Z+=`
|
|
6
|
+
|
|
7
|
+
## Pictures not placed in the text
|
|
8
|
+
|
|
9
|
+
${Y.join(`
|
|
10
|
+
|
|
11
|
+
`)}`,H.push(`${Y.length} picture(s) were found in the file but not at a place in its text; they are listed at the end.`)}return{markdown:Z,reader:"office_oxide",...H.length?{notes:H}:{}}}var o$={maxUncompressedBytes:268435456,maxZipEntries:20000},r$={pptx:{node:"slide",unit:"slide"},odp:{node:"slide",unit:"slide"},xlsx:{node:"sheet",unit:"sheet"},ods:{node:"sheet",unit:"sheet"}};async function a$(){let Q=await import("officeparser");return Q.OfficeParser??Q.default}function t$(Q,$){let J=Q?.message??"";if(!/password|encrypt/i.test(J))return;return Error($?"The document's password is not the one given in `password`.":"The document is password-protected. Ask the user for the password and call again with `password`.")}function e$(Q){return Q.replace(/^\s*---\n[\s\S]*?\n---\n/,"").trim()}async function mQ(Q,$,J){let q=await a$(),Z;try{Z=await q.parseOffice(Buffer.from(Q),{fileType:$,extractAttachments:J.wantImages,decompressionLimits:o$,...J.password?{password:J.password}:{}})}catch(V){throw t$(V,J.password)??V}let K=r$[$],H;if(K){let V=Z.content.filter((z)=>z.type===K.node),N=[],G=new Set;V.forEach((z,C)=>{if(!J.selects||J.selects(C+1))N.push(C+1),G.add(z)}),Z.content=Z.content.filter((z)=>z.type!==K.node||G.has(z)),H={name:K.unit,total:V.length,read:N}}let Y=new Map,X=(V,N)=>{if(Y.has(V))return Y.get(V);let G=Z.attachments?.find((C)=>C.name===V),z=G?J.images.add({data:Buffer.from(G.data,"base64"),stem:V,mediaType:G.mimeType,...N?{alt:N}:{}}):void 0;return Y.set(V,z),z},B=await Z.to("md",{mdConfig:{dialect:"github",fallbackToHtml:{textFormatting:!1,alignment:!1,anchors:!1,tables:!0,embeds:!1,cellLineBreaks:!0}},onNode:(V)=>{if(V.type!=="image")return;if(!J.wantImages)return!1;let N=V.metadata??{},G=N.attachmentName?X(N.attachmentName,N.altText):void 0;return G?x(G):!1}}),F=e$(String(B.value??""));if($==="rtf")F=F.replace(/^[ ]*\t[ \t]*(?![-*+] |\d+[.)] )/gm,"");if(J.wantImages){for(let V of Z.attachments??[])if(V.type==="image")X(V.name)}let U=Z.metadata??{};return{markdown:F,reader:"officeparser",...U.title?.trim()?{title:U.title.trim()}:{},...U.author?.trim()?{author:U.author.trim()}:{},...H?{units:H}:{}}}import{existsSync as VQ}from"node:fs";import{createRequire as QJ}from"node:module";import{dirname as pQ,join as l}from"node:path";import{fileURLToPath as $J}from"node:url";function FQ(){try{return pQ($J(import.meta.url))}catch{return"."}}function JJ(Q){try{let $=QJ(l(FQ(),"noop.js"));return pQ($.resolve(`${Q}/package.json`))}catch{return}}function CQ(Q,$,J,q){let Z=l(FQ(),Q);if(VQ(l(Z,q)))return Z;let K=JJ($),H=K?l(K,J):void 0;return H&&VQ(l(H,q))?H:void 0}function dQ(){return CQ("pdfjs/wasm","pdfjs-dist","wasm","jbig2.wasm")}function iQ(){return CQ("pdfjs/cmaps","pdfjs-dist","cmaps","UniJIS-UCS2-H.bcmap")}function nQ(){let Q=l(FQ(),"tesseract","worker.cjs");return VQ(Q)?Q:void 0}function sQ(){return CQ("tessdata","@tesseract.js-data/eng","4.0.0_best_int","eng.traineddata.gz")}var ZQ;function rQ(){return ZQ??=(async()=>{ZJ();let Q=globalThis;if(!Q.pdfjsWorker)Q.pdfjsWorker=await import("pdfjs-dist/legacy/build/pdf.worker.mjs");return await qJ(()=>import("pdfjs-dist/legacy/build/pdf.mjs"))})(),ZQ.catch(()=>{ZQ=void 0}),ZQ}async function qJ(Q){let $=console.warn;console.warn=(...J)=>{let q=String(J[0]??"");if(/^Warning: Cannot (load "@napi-rs\/canvas"|polyfill `(Path2D|DOMMatrix|ImageData)`)/.test(q))return;$(...J)};try{return await Q()}finally{console.warn=$}}function ZJ(){let Q=globalThis;if(Q.DOMMatrix)return;class ${a=1;b=0;c=0;d=1;e=0;f=0;constructor(J){if(J&&J.length>=6)[this.a,this.b,this.c,this.d,this.e,this.f]=Array.from(J).slice(0,6)}set(J){return[this.a,this.b,this.c,this.d,this.e,this.f]=J,this}product(J,q){return[J.a*q.a+J.c*q.b,J.b*q.a+J.d*q.b,J.a*q.c+J.c*q.d,J.b*q.c+J.d*q.d,J.a*q.e+J.c*q.f+J.e,J.b*q.e+J.d*q.f+J.f]}multiplySelf(J=new $){let q=J instanceof $?J:new $(J);return this.set(this.product(this,q))}preMultiplySelf(J=new $){let q=J instanceof $?J:new $(J);return this.set(this.product(q,this))}multiply(J){return new $(this.toArray()).multiplySelf(J)}translateSelf(J=0,q=0){return this.multiplySelf([1,0,0,1,J,q])}translate(J=0,q=0){return new $(this.toArray()).translateSelf(J,q)}scaleSelf(J=1,q=J){return this.multiplySelf([J,0,0,q,0,0])}scale(J=1,q=J){return new $(this.toArray()).scaleSelf(J,q)}invertSelf(){let J=this.a*this.d-this.b*this.c;if(!J)return this.set([Number.NaN,Number.NaN,Number.NaN,Number.NaN,Number.NaN,Number.NaN]);return this.set([this.d/J,-this.b/J,-this.c/J,this.a/J,(this.c*this.f-this.d*this.e)/J,(this.b*this.e-this.a*this.f)/J])}inverse(){return new $(this.toArray()).invertSelf()}toArray(){return[this.a,this.b,this.c,this.d,this.e,this.f]}}Q.DOMMatrix=$}function oQ(Q){return Q?`${Q.replace(/[\\/]+$/,"")}/`:void 0}function aQ(){let Q=oQ(dQ()),$=oQ(iQ());return{disableFontFace:!0,useSystemFonts:!1,isEvalSupported:!1,verbosity:0,...Q?{wasmUrl:Q}:{},...$?{cMapUrl:$,cMapPacked:!0}:{}}}var KJ=100,HJ=0.5,YJ=200,tQ=4,XJ=0.1,zJ=1,BJ=2,WJ=3;function GJ(Q,$){let[J=1,q=0,Z=0,K=1,H=0,Y=0]=$;return[Q[0]*J+Q[2]*q,Q[1]*J+Q[3]*q,Q[0]*Z+Q[2]*K,Q[1]*Z+Q[3]*K,Q[0]*H+Q[2]*Y+Q[4],Q[1]*H+Q[3]*Y+Q[5]]}async function UJ(Q,$){let[J,q,Z,K]=Q.view,H=Math.abs((Z-J)*(K-q))||1,Y=await Q.getOperatorList(),X=[1,0,0,1,0,0],B=[],F=0,U=!1,V=0,N=[];for(let G=0;G<Y.fnArray.length;G++){let z=Y.fnArray[G],C=Y.argsArray[G],I=()=>Math.abs(X[0]*X[3]-X[1]*X[2]);if(z===$.save)B.push(X);else if(z===$.restore)X=B.pop()??X;else if(z===$.transform)X=GJ(X,C);else if(z===$.setTextRenderingMode){if(C[0]===3)U=!0}else if(z===$.paintImageXObject||z===$.paintImageXObjectRepeat){if(F+=I(),typeof C[0]==="string")N.push({key:C[0],area:I()/H})}else if(z===$.paintInlineImageXObject)F+=I(),N.push({image:C[0],mask:!1,area:I()/H});else if(z===$.paintImageMaskXObject)F+=I(),N.push({image:C[0],mask:!0,area:I()/H});else if(z===$.constructPath)V++}return{coverage:Math.min(1,F/H),invisibleText:U,pathOps:V,pageArea:H,draws:N}}function eQ(Q){let $=Q.replace(/\s/g,"");if($.length<20)return!1;return($.match(/[-�\u0000-\u0008]/g)?.length??0)/$.length>0.3}var Q$=20000,$$=60000,KQ=new Set,e;function VJ(Q){if(KQ.add(Q),!e){let $=console.log;e=$,console.log=(...J)=>{let q=typeof J[0]==="string"?J[0]:"";if(q.startsWith("Warning: ")){for(let Z of KQ)Z(q.slice(9));return}$(...J)}}return()=>{if(KQ.delete(Q),KQ.size===0&&e)console.log=e,e=void 0}}function J$(Q,$,J){let q=$.startsWith("g_")?Q.commonObjs:Q.objs;return new Promise((Z)=>{let K=setTimeout(()=>Z("no answer"),J),H=(Y)=>{clearTimeout(K),Z(Y)};try{q.get($,(Y)=>H(Y??null))}catch{H(null)}})}function FJ(Q,$,J){let{width:q,height:Z,data:K}=$;if(!K||!q||!Z)return;if(J||$.kind===zJ){let X=q+7>>3;if(K.length<X*Z)return;let B=new Uint8Array(q*Z);for(let F=0;F<Z;F++){let U=F*X;for(let V=0;V<q;V++)B[F*q+V]=(K[U+(V>>3)]??0)>>7-(V&7)&1?255:0}return Q({width:q,height:Z,data:B,channels:1,depth:8})}let Y=$.kind===BJ?3:$.kind===WJ?4:K.length/(q*Z);if(Y!==1&&Y!==3&&Y!==4)return;return Q({width:q,height:Z,data:new Uint8Array(K.buffer,K.byteOffset,q*Z*Y),channels:Y,depth:8})}function CJ(Q,$){let J=Q?.name,q=Q?.message??"";if(J!=="PasswordException"&&!/password/i.test(q))return;return Error($?"The PDF's password is not the one given in `password`.":"The PDF is password-protected. Ask the user for the password and call again with `password`.")}async function q$(Q,$){let J=await rQ(),{encode:q}=await import("fast-png"),Z=new Set,K=$.onNote?VJ((X)=>{if(Z.size>=60||Z.has(X))return;Z.add(X),$.onNote?.(`pdf.js: ${X}`)}):void 0,H=J.getDocument({...aQ(),...$.onNote?{verbosity:1}:{},data:Q.slice(),...$.password?{password:$.password}:{}}),Y;try{Y=await H.promise}catch(X){throw await H.destroy().catch(()=>{}),K?.(),CJ(X,$.password)??X}try{return await RJ(Y,J.OPS,q,$)}finally{await H.destroy().catch(()=>{}),K?.()}}async function RJ(Q,$,J,q){let K=(await Q.getMetadata().catch(()=>{return}))?.info??{},H=Q.numPages,Y=[],X=[],B=[],F=[],U=[],V=[],N=0,G=(z,C)=>q.onProgress?.({unit:"page",at:z,total:H,pictures:N,...C?{activity:C}:{}});for(let z=1;z<=H;z++){if(q.selects&&!q.selects(z))continue;q.signal?.throwIfAborted(),G(z),Y.push(z),G(z,"opening the page");let C=await Q.getPage(z);G(z,"reading its text");let I=await C.getTextContent(),P="";for(let j of I.items){if(typeof j.str!=="string")continue;if(P+=j.str,j.hasEOL)P+=`
|
|
12
|
+
`}P=P.replace(/[ \t]+\n/g,`
|
|
13
|
+
`).replace(/\n{3,}/g,`
|
|
14
|
+
|
|
15
|
+
`).trim(),G(z,"reading its layout");let v=await UJ(C,$);G(z);let b=P.replace(/\s/g,"").length,d=v.coverage>=HJ,L=!1;if(d&&v.invisibleText&&b>0)F.push(z);else if(d&&(b<KJ||eQ(P)))L=!0;else if(b===0&&v.coverage===0&&v.pathOps>=YJ)U.push(z);else if(eQ(P))L=!0;if(L)X.push(z);let T=q.wantImages||L&&!!q.recognize,S=[];if(T){let j=0,O=0;for(let k of v.draws){if(O++,"key"in k)G(z,`decoding picture ${O} of ${v.draws.length}`);let A="key"in k?await J$(C,k.key,Q$):k.image;if(A==="no answer"&&"key"in k){let{key:f}=k;q.onNote?.(`page ${z}: picture ${O} of ${v.draws.length} (${f}) did not arrive in ${Q$/1000}s; asking for the page's pictures again`),G(z,`decoding picture ${O} of ${v.draws.length} again`),C.cleanup();let vQ=await Promise.race([C.getOperatorList().then(()=>!0),new Promise((zQ)=>setTimeout(()=>zQ(!1),$$))]).catch(()=>!1);if(A=vQ?await J$(C,f,$$):"no answer",A==="no answer"){let zQ=f.startsWith("g_")?C.commonObjs:C.objs,SQ="unknown";try{SQ=zQ.has(f)?"delivered late":"never delivered"}catch{}q.problems?.push(`page ${z}: picture ${O} of ${v.draws.length} (${f}) was left out, the PDF decoder gave no answer for it when asked twice (${vQ?SQ:"the page's drawing did not come back either"})`),q.onNote?.(`page ${z}: picture ${O} (${f}) left out after the second request`);continue}q.onNote?.(`page ${z}: picture ${O} (${f}) arrived on the second request`)}if(A==="no answer")continue;if(!A){q.problems?.push(`page ${z}: a picture was left out, the PDF decoder could not decode it`);continue}if(A.width<tQ||A.height<tQ)continue;let OQ=FJ(J,A,"mask"in k&&k.mask);if(!OQ){q.problems?.push(`page ${z}: a ${A.width}x${A.height} picture was left out, its pixel layout is one this cannot write`);continue}j++,N++,S.push({png:OQ,width:A.width,height:A.height,coverage:k.area,stem:`p${z}-${j}`})}}let w;if(L&&q.recognize){let j=S.filter((k)=>k.coverage>=XJ);if(j.length>0)G(z,"recognizing text");let O=j.length>0?await q.recognize(z,j):void 0;if(O?.text.trim())B.push(z),w=`[Text recognized from the page image by ${O.by}]
|
|
16
|
+
|
|
17
|
+
${O.text.trim()}`}let i=[];if(q.wantImages)for(let j of S){let O=q.images.add({data:j.png,stem:j.stem,mediaType:"image/png",width:j.width,height:j.height,source:`page ${z}`});if(O)i.push(x(O))}G(z),V.push([`## Page ${z}`,P,w??"",...i].filter((j)=>j.length>0).join(`
|
|
18
|
+
|
|
19
|
+
`)),C.cleanup()}return{markdown:V.join(`
|
|
20
|
+
|
|
21
|
+
`),reader:"pdf.js",...typeof K.Title==="string"&&K.Title.trim()?{title:K.Title.trim()}:{},...typeof K.Author==="string"&&K.Author.trim()?{author:K.Author.trim()}:{},units:{name:"page",total:H,read:Y},...X.length?{scannedPages:X}:{},...B.length?{recognizedPages:B}:{},...F.length?{ocrLayerPages:F}:{},...U.length?{vectorPages:U}:{}}}function Z$(Q){let $=Q?.trim();if(!$)return;let J=[];for(let q of $.split(",")){let Z=q.trim();if(!Z)continue;let K=/^(\d+)\s*(?:-\s*(\d*))?$/.exec(Z);if(!K)throw Error(`range "${Q}" is not understood: use one-based numbers, spans and an open end, like "1-5,9,12-".`);let H=Number(K[1]),Y=K[2]===void 0?H:K[2]===""?Number.POSITIVE_INFINITY:Number(K[2]);if(H<1||Y<H)throw Error(`range "${Z}" is empty: numbers start at 1 and a span runs low to high.`);J.push([H,Y])}if(J.length===0)return;return{selects:(q)=>J.some(([Z,K])=>q>=Z&&q<=K),spec:$.replace(/\s+/g,"")}}function m(Q){let $=[...new Set(Q)].sort((q,Z)=>q-Z),J=[];for(let q=0;q<$.length;){let Z=q;while(Z+1<$.length&&$[Z+1]===$[Z]+1)Z++;J.push(q===Z?`${$[q]}`:`${$[q]}-${$[Z]}`),q=Z+1}return J.join(", ")}import{existsSync as K$}from"node:fs";import{copyFile as NJ,mkdir as LJ,readdir as T0,rename as O0,rm as v0,writeFile as S0}from"node:fs/promises";import{join as HQ}from"node:path";import{resolveClineDataDir as jJ}from"@cerebriline/shared/storage";var QQ="eng",RQ=".traineddata.gz";function LQ(){return HQ(jJ(),"tessdata")}function H$(Q){let J=(typeof Q==="string"?Q.split(/[+,\s]+/):Q??[]).map((q)=>q.trim().toLowerCase()).filter(Boolean);return[...new Set(J)]}async function TJ(Q,$){let J=sQ();if(J&&Q.every((K)=>K===QQ))return J;let q=Q.filter((K)=>!K$(HQ($,`${K}${RQ}`))&&!(K===QQ&&J));if(q.length>0)throw new YQ(q);let Z=HQ($,`${QQ}${RQ}`);if(J&&Q.includes(QQ)&&!K$(Z))await LJ($,{recursive:!0}),await NJ(HQ(J,`${QQ}${RQ}`),Z);return $}class YQ extends Error{languages;constructor(Q){super(`OCR language${Q.length===1?"":"s"} ${Q.join(", ")} ${Q.length===1?"is":"are"} not installed.`);this.languages=Q}}var OJ=180000,vJ=120000,SJ=1e4;function NQ(Q,$,J){let q;return Promise.race([Q,new Promise((Z,K)=>{q=setTimeout(()=>K(Error(`${J} gave no answer in ${$/1000}s`)),$)})]).finally(()=>clearTimeout(q))}class XQ{worker;languages;failure;dead;constructor(Q,$,J){this.worker=Q;this.languages=$;this.failure=J}static async open(Q,$=LQ()){let J=await TJ(Q,$),q=await import("tesseract.js"),Z=q.default??q,K=nQ(),H={},Y=await NQ(Z.createWorker(Q.join("+"),Z.OEM.LSTM_ONLY,{langPath:J,gzip:!0,cacheMethod:"none",...K?{workerPath:K}:{},errorHandler:(X)=>{let B=X instanceof Error?X:Error(`the OCR worker failed: ${String(X)}`);H.error=B,H.raise?.(B)}}),vJ,"Starting the OCR worker");return new XQ(Y,Q,H)}async recognize(Q){if(this.dead)throw this.dead;if(this.failure.error)throw this.dead=this.failure.error,this.dead;try{let{data:$}=await NQ(Promise.race([this.worker.recognize(Buffer.from(Q)),new Promise((J,q)=>{this.failure.raise=q})]),OJ,"The OCR worker");return{text:$.text??"",confidence:Math.round($.confidence??0)}}catch($){if(this.failure.error||$ instanceof Error&&/gave no answer/.test($.message))this.dead=$ instanceof Error?$:Error(String($));throw $}finally{this.failure.raise=void 0}}async close(){await NQ(this.worker.terminate(),SJ,"Stopping the OCR worker").catch(()=>{})}}var PJ=40,AJ=12,IJ=4;var kJ="This is a scanned page from a document. Transcribe all of its text exactly as written, in reading order, keeping paragraphs, headings and lists, and table rows as Markdown tables. Do not describe the page, summarize or add anything. Reply with the text only, or with nothing if the page has no text.";var Y$="The user can change this under Settings > Features > Document Reader.";function DJ(Q){let $=Q.settings.ocr??"tesseract";if(Q.request==="none")return{kind:"none",reason:'Text recognition was skipped (ocr: "none").'};if($==="off")return{kind:"none",reason:`Text recognition (OCR) is turned off. ${Y$}`};let J=!Q.request||Q.request==="auto"?$:Q.request,q=H$(Q.languages??Q.settings.ocrLanguages??["eng"]);if(J==="tesseract")return{kind:"tesseract",languages:q.length?q:["eng"]};if(Q.describeImages)return{kind:"vision"};if(Q.modelSupportsImages)return{kind:"self",why:"no vision model is configured"};return{kind:"tesseract",languages:q.length?q:["eng"],fallback:"No vision model is configured and this model does not take images, so tesseract read the pages instead."}}function X$(Q){let $=DJ(Q),J=[],q=[],Z=[],K,H=0,Y=Q.pageLimit!==void 0?Q.pageLimit:$.kind==="tesseract"?PJ:$.kind==="vision"?AJ:IJ;return{recognize:$.kind==="none"?void 0:async(B,F)=>{if(H>=Y){q.push(B);return}H++;let U=[...F].sort((z,C)=>C.coverage-z.coverage);if($.kind==="self"){let z=U[0];if(z)J.push({page:B,png:z.png});return}if($.kind==="vision")return EJ(Q.describeImages,B,U,Z);K??=XQ.open($.languages,Q.settings.ocrDataDir??LQ());let V;try{V=await K}catch(z){if(!Z.length)Z.push(MJ(z));return}let N=[],G=0;for(let z of U)try{let C=await V.recognize(z.png);if(C.text.trim())N.push(C.text.trim()),G=Math.max(G,C.confidence)}catch(C){Z.push(`page ${B}: ${C instanceof Error?C.message:String(C)}`)}if(!N.length)return;return{text:N.join(`
|
|
22
|
+
|
|
23
|
+
`),by:`tesseract (${$.languages.join("+")}, ${G}% confidence)`}},attachments:J,notes(B,F){if(!B.length)return[];let U=[],V=B.filter((G)=>!F.includes(G));if($.kind==="none")return U.push(`Scanned pages ${m(B)}: an image of text with no text layer, so their words are not in this text. ${$.reason}`),U;if(F.length){let G=$.kind==="vision"?"the vision model":`tesseract (${$.kind==="tesseract"?$.languages.join("+"):"eng"})`;U.push(`Scanned pages ${m(F)}: their text was recognized from the page image by ${G}, and may contain recognition errors.`)}if($.kind==="tesseract"&&$.fallback)U.push($.fallback);if($.kind==="self"&&J.length)U.push(`Scanned pages ${m(J.map((G)=>G.page))} are attached below as images (${$.why}): read their text from them.`);if(q.length)U.push(`Scanned pages ${m(q)} were not read: one call reads at most ${Y} scanned pages. Call again with range: "${q[0]}-" for the rest.`);let N=V.filter((G)=>!q.includes(G)&&!($.kind==="self"&&J.some((z)=>z.page===G)));if(N.length)U.push(`Scanned pages ${m(N)}: no text could be recognized${Z.length?` (${Z.slice(0,3).join("; ")})`:""}.`);return U},problems(B,F){let U=[],V=new Map;for(let G of Z){let z=/^page (\d+): ([\s\S]*)$/.exec(G);if(z)V.set(Number(z[1]),z[2]??"")}let N=Z.filter((G)=>!/^page \d+: /.test(G));for(let G of B){if(F.includes(G))continue;let z=q.includes(G)?`past the ${Y} pages recognized in one call`:V.get(G)??N[0]??($.kind==="none"?$.reason:"nothing readable was found on it");U.push(`page ${G}: a scan with no recognized text, ${z}`)}return U},async close(){if(K)await(await K.catch(()=>{return}))?.close()}}}function MJ(Q){if(Q instanceof YQ)return`${Q.message} ${Y$} In the CLI, --ocr-languages installs them`;return`tesseract did not start: ${Q instanceof Error?Q.message:String(Q)}`}async function EJ(Q,$,J,q){if(!Q)return;let Z=J[0];if(!Z)return;try{let[K]=await Q([{image:Buffer.from(Z.png).toString("base64"),mediaType:"image/png",instruction:kJ}]);return K?.trim()?{text:K.trim(),by:"the vision model"}:void 0}catch(K){q.push(`page ${$}: ${K instanceof Error?K.message:String(K)}`);return}}function _J(Q,$,J,q){switch(J){case"pdf":return q$($,q);case"doc":case"xls":case"ppt":return lQ($,J,q);case"epub":case"mobi":case"azw3":case"fb2":return DQ(Q,$,J,q);default:return mQ($,J,q)}}async function z$(Q,$={}){let J=new Uint8Array(await xJ.readFile(Q.filePath)),q=EQ(Q.namedAs??Q.filePath,J.subarray(0,512));if("unsupported"in q)throw Error(q.unsupported);let{format:Z}=q,K=Z$(Q.range),H=Z==="pdf"?X$({request:Q.recognition.request,languages:Q.recognition.languages,settings:Q.recognition.settings,describeImages:$.describeImages,modelSupportsImages:Q.recognition.modelSupportsImages,...Q.recognition.everyPage?{pageLimit:Number.POSITIVE_INFINITY}:{}}):void 0,Y=[],X=new BQ("images"),B;try{B=await _J(Q.filePath,J,Z,{images:X,wantImages:Q.wantImages,scratchDir:Q.scratchDir,problems:Y,...Q.password?{password:Q.password}:{},...K?{selects:K.selects}:{},...$.signal?{signal:$.signal}:{},...$.onProgress?{onProgress:$.onProgress}:{},...$.onNote?{onNote:$.onNote}:{},...H?.recognize?{recognize:H.recognize}:{}})}finally{await H?.close()}let F=B.scannedPages??[],U=B.recognizedPages??[];return{format:Z,result:B,images:[...X.entries()],recognitionNotes:H?.notes(F,U)??[],recognitionProblems:H?.problems(F,U)??[],attachments:H?.attachments??[],problems:Y}}var B$=".out";var G$=process;function p(Q){return new Promise(($)=>{if(!process.connected||!G$.send){$();return}G$.send(Q,()=>$())})}var jQ=new AbortController,TQ=new Map,hJ=0;function bJ(Q){let $=hJ++;return new Promise((J,q)=>{TQ.set($,{resolve:J,reject:q}),p({type:"describe",id:$,images:[...Q]})})}async function fJ(Q,$){let J=Date.now();try{let q=await z$(Q,{signal:jQ.signal,onProgress:(H)=>void p({type:"progress",progress:H}),onNote:(H)=>void p({type:"note",line:H}),...$?{describeImages:bJ}:{}}),Z=W$(Q.scratchDir,B$);await wJ(Z,{recursive:!0});let K=[];for(let[H,{image:Y,data:X}]of q.images.entries()){let B=W$(Z,String(H));await yJ(B,X),K.push({image:Y,file:B})}await p({type:"done",format:q.format,result:q.result,images:K,recognitionNotes:q.recognitionNotes,recognitionProblems:q.recognitionProblems,attachments:q.attachments,problems:q.problems,usage:{ms:Date.now()-J,peakRssMb:Math.round(process.resourceUsage().maxRSS/1024)}})}catch(q){await p({type:"failed",message:q instanceof Error?q.message:String(q),aborted:jQ.signal.aborted})}await Promise.race([cJ,new Promise((q)=>setTimeout(q,uJ).unref())]),process.exit(0)}var uJ=60000,V$=()=>{},cJ=new Promise((Q)=>{V$=Q}),U$=!1;process.on("message",(Q)=>{if(Q.type==="start"&&!U$)U$=!0,fJ(Q.job,Q.hasVision);else if(Q.type==="received")V$();else if(Q.type==="abort")jQ.abort();else if(Q.type==="described"){let $=TQ.get(Q.id);if(TQ.delete(Q.id),!$)return;if(Q.error!==void 0)$.reject(Error(Q.error));else $.resolve(Q.descriptions??[])}});process.on("disconnect",()=>process.exit(0));p({type:"ready"});
|
|
@@ -19,6 +19,11 @@ export interface DocumentReaderSettings {
|
|
|
19
19
|
ocrDataDir?: string;
|
|
20
20
|
/** Describe extracted pictures with the vision model. @default false */
|
|
21
21
|
describePictures?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* The largest file read, in MB; a larger one is refused by name.
|
|
24
|
+
* @default 1024
|
|
25
|
+
*/
|
|
26
|
+
maxFileMb?: number;
|
|
22
27
|
}
|
|
23
28
|
export declare const BUNDLED_OCR_LANGUAGE = "eng";
|
|
24
29
|
export declare function resolveOcrDataDir(): string;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One document read, as a request that can be handed to another process.
|
|
3
|
+
*
|
|
4
|
+
* Everything a read needs is in `ReadJob` as plain data, and everything it
|
|
5
|
+
* needs from the session while it runs (the vision model, progress, a stop)
|
|
6
|
+
* is in `ReadJobHooks`. `runReadJob` is the work itself: the reader process
|
|
7
|
+
* runs it (`read-child.ts`), and so does this process where no reader process
|
|
8
|
+
* can be started.
|
|
9
|
+
*/
|
|
10
|
+
import { type DocumentFormat, type DocumentReadResult, type ReadProgress } from "./formats";
|
|
11
|
+
import { type ExtractedImage } from "./images";
|
|
12
|
+
import type { DocumentReaderSettings } from "./ocr";
|
|
13
|
+
import { type DescribeImages, type OcrRequest } from "./recognition";
|
|
14
|
+
export interface ReadJob {
|
|
15
|
+
/** The file to read. */
|
|
16
|
+
filePath: string;
|
|
17
|
+
/**
|
|
18
|
+
* The path whose name says what the file is, when that is not `filePath`:
|
|
19
|
+
* a delegated agent's overlay keeps its copy under another name.
|
|
20
|
+
*/
|
|
21
|
+
namedAs?: string;
|
|
22
|
+
/** Whether pictures are taken out as well. */
|
|
23
|
+
wantImages: boolean;
|
|
24
|
+
password?: string;
|
|
25
|
+
/** Which pages, slides, sheets or chapters: `"1-5,9,12-"`. */
|
|
26
|
+
range?: string;
|
|
27
|
+
/** An existing directory the read may write in; the caller removes it. */
|
|
28
|
+
scratchDir: string;
|
|
29
|
+
/** How scanned pages are read. Only a PDF has any. */
|
|
30
|
+
recognition: {
|
|
31
|
+
request?: OcrRequest;
|
|
32
|
+
languages?: string;
|
|
33
|
+
settings: DocumentReaderSettings;
|
|
34
|
+
modelSupportsImages: boolean;
|
|
35
|
+
/** A book kept in the Library is read whole, however many scanned pages. */
|
|
36
|
+
everyPage?: boolean;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface ReadJobHooks {
|
|
40
|
+
/** The session's vision model, when there is one. */
|
|
41
|
+
describeImages?: DescribeImages;
|
|
42
|
+
/** Stops the read at the next page or chapter; the read throws. */
|
|
43
|
+
signal?: AbortSignal;
|
|
44
|
+
onProgress?: (progress: ReadProgress) => void;
|
|
45
|
+
/** Lines for the log, not for the reader of the document. */
|
|
46
|
+
onNote?: (line: string) => void;
|
|
47
|
+
}
|
|
48
|
+
export interface ReadJobResult {
|
|
49
|
+
format: DocumentFormat;
|
|
50
|
+
result: DocumentReadResult;
|
|
51
|
+
/** Every picture with its bytes, in the order they were found. */
|
|
52
|
+
images: {
|
|
53
|
+
image: ExtractedImage;
|
|
54
|
+
data: Uint8Array;
|
|
55
|
+
}[];
|
|
56
|
+
/** What recognition has to say, in sentences, for the result's header. */
|
|
57
|
+
recognitionNotes: string[];
|
|
58
|
+
/** Every scanned page left without text, a line each. */
|
|
59
|
+
recognitionProblems: string[];
|
|
60
|
+
/** Page images for the session's own model to read. */
|
|
61
|
+
attachments: {
|
|
62
|
+
page: number;
|
|
63
|
+
png: Uint8Array;
|
|
64
|
+
}[];
|
|
65
|
+
/** Everything else the read left out, a line each. */
|
|
66
|
+
problems: string[];
|
|
67
|
+
}
|
|
68
|
+
export declare function runReadJob(job: ReadJob, hooks?: ReadJobHooks): Promise<ReadJobResult>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a document in a process of its own.
|
|
3
|
+
*
|
|
4
|
+
* A PDF is decoded page by page into pictures, and a scanned one is then read
|
|
5
|
+
* by an OCR engine: hundreds of megabytes of work in whatever process does
|
|
6
|
+
* it. In a VS Code window that process is the extension host, which every
|
|
7
|
+
* extension shares and which has one fixed heap; measured on a 769-page
|
|
8
|
+
* scanned book, the host ran out of memory and took the session, and every
|
|
9
|
+
* other extension's state, with it.
|
|
10
|
+
*
|
|
11
|
+
* So each read gets a process, started for it and gone when it answers. What
|
|
12
|
+
* the session keeps is the result. A reader that runs out of memory or stops
|
|
13
|
+
* is one file that could not be read, said so with the page it stopped on.
|
|
14
|
+
*
|
|
15
|
+
* Where no reader process can be started (the file that runs in it was not
|
|
16
|
+
* shipped beside this bundle, or no JavaScript runtime is found) the read
|
|
17
|
+
* happens here, as it did before, and a note says so.
|
|
18
|
+
*/
|
|
19
|
+
import type { ReadProgress } from "./formats";
|
|
20
|
+
import type { ExtractedImage } from "./images";
|
|
21
|
+
import { type ReadJob, type ReadJobHooks, type ReadJobResult } from "./read-job";
|
|
22
|
+
/**
|
|
23
|
+
* A read whose pictures are files, not bytes: a scanned book is a picture a
|
|
24
|
+
* page, hundreds of megabytes that the session has no reason to hold. They
|
|
25
|
+
* stay in the job's scratch directory until `release`, which the caller
|
|
26
|
+
* calls once it has done with them, on every path.
|
|
27
|
+
*/
|
|
28
|
+
export interface HeldRead extends Omit<ReadJobResult, "images"> {
|
|
29
|
+
images: {
|
|
30
|
+
image: ExtractedImage;
|
|
31
|
+
file: string;
|
|
32
|
+
}[];
|
|
33
|
+
release(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/** Names the file that runs in the reader process, for a host that keeps it elsewhere. */
|
|
36
|
+
export declare const DOCUMENT_READER_CHILD_ENV = "CLINE_DOCUMENT_READER_CHILD";
|
|
37
|
+
/** `1` reads in this process, whatever is shipped. */
|
|
38
|
+
export declare const DOCUMENT_READER_IN_PROCESS_ENV = "CLINE_DOCUMENT_READER_IN_PROCESS";
|
|
39
|
+
/** How many reader processes run at once. */
|
|
40
|
+
export declare const DOCUMENT_READER_PROCESSES_ENV = "CLINE_DOCUMENT_READER_PROCESSES";
|
|
41
|
+
/** The file the reader process runs, or undefined where none was shipped. */
|
|
42
|
+
export declare function resolveReaderChild(env?: NodeJS.ProcessEnv): string | undefined;
|
|
43
|
+
/** Why a reader process ended without an answer, in a sentence. */
|
|
44
|
+
export declare function describeReaderExit(code: number | null, signal: NodeJS.Signals | null, stderr: string, progress: ReadProgress | undefined): string;
|
|
45
|
+
/** Test seam. */
|
|
46
|
+
export declare function resetReaderProcessState(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Read one document. `job.scratchDir` is created here; it holds the
|
|
49
|
+
* pictures until the result's `release`, and is removed here when the read
|
|
50
|
+
* fails.
|
|
51
|
+
*/
|
|
52
|
+
export declare function readDocumentJob(job: ReadJob, hooks?: ReadJobHooks): Promise<HeldRead>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the session and its reader process say to each other.
|
|
3
|
+
*
|
|
4
|
+
* Sent over Node's IPC channel with structured-clone serialization, so byte
|
|
5
|
+
* arrays arrive as byte arrays.
|
|
6
|
+
*/
|
|
7
|
+
import type { AgentImageToDescribe } from "@cerebriline/shared";
|
|
8
|
+
import type { DocumentFormat, DocumentReadResult, ReadProgress } from "./formats";
|
|
9
|
+
import type { ExtractedImage } from "./images";
|
|
10
|
+
import type { ReadJob } from "./read-job";
|
|
11
|
+
/** Where, inside the job's scratch directory, the pictures are handed back. */
|
|
12
|
+
export declare const READ_OUTPUT_DIRECTORY = ".out";
|
|
13
|
+
export type ParentMessage = {
|
|
14
|
+
type: "start";
|
|
15
|
+
job: ReadJob;
|
|
16
|
+
hasVision: boolean;
|
|
17
|
+
} | {
|
|
18
|
+
type: "abort";
|
|
19
|
+
}
|
|
20
|
+
/** The answer arrived whole: the reader may go. */
|
|
21
|
+
| {
|
|
22
|
+
type: "received";
|
|
23
|
+
} | {
|
|
24
|
+
type: "described";
|
|
25
|
+
id: number;
|
|
26
|
+
descriptions?: (string | undefined)[];
|
|
27
|
+
error?: string;
|
|
28
|
+
};
|
|
29
|
+
export type ChildMessage = {
|
|
30
|
+
type: "ready";
|
|
31
|
+
} | {
|
|
32
|
+
type: "progress";
|
|
33
|
+
progress: ReadProgress;
|
|
34
|
+
} | {
|
|
35
|
+
type: "note";
|
|
36
|
+
line: string;
|
|
37
|
+
} | {
|
|
38
|
+
type: "describe";
|
|
39
|
+
id: number;
|
|
40
|
+
images: AgentImageToDescribe[];
|
|
41
|
+
} | {
|
|
42
|
+
type: "done";
|
|
43
|
+
format: DocumentFormat;
|
|
44
|
+
result: DocumentReadResult;
|
|
45
|
+
/** Each picture's bytes are in `file`. */
|
|
46
|
+
images: {
|
|
47
|
+
image: ExtractedImage;
|
|
48
|
+
file: string;
|
|
49
|
+
}[];
|
|
50
|
+
recognitionNotes: string[];
|
|
51
|
+
recognitionProblems: string[];
|
|
52
|
+
attachments: {
|
|
53
|
+
page: number;
|
|
54
|
+
png: Uint8Array;
|
|
55
|
+
}[];
|
|
56
|
+
problems: string[];
|
|
57
|
+
usage: {
|
|
58
|
+
ms: number;
|
|
59
|
+
peakRssMb: number;
|
|
60
|
+
};
|
|
61
|
+
} | {
|
|
62
|
+
type: "failed";
|
|
63
|
+
message: string;
|
|
64
|
+
aborted: boolean;
|
|
65
|
+
};
|
|
@@ -65,17 +65,10 @@ export declare function planRecognition(input: PlanInput): RecognitionPlan;
|
|
|
65
65
|
export interface PictureToDescribe {
|
|
66
66
|
link: string;
|
|
67
67
|
mediaType: string;
|
|
68
|
-
|
|
68
|
+
/** The bytes, or where to read them when they are asked for: one picture in memory at a time. */
|
|
69
|
+
data: Uint8Array | (() => Promise<Uint8Array>);
|
|
69
70
|
source?: string;
|
|
70
71
|
}
|
|
71
|
-
/**
|
|
72
|
-
* Descriptions of a document's pictures, one request each, in order.
|
|
73
|
-
* `undefined` for any the vision model could not describe.
|
|
74
|
-
*/
|
|
75
|
-
/**
|
|
76
|
-
* One picture described, or the reason it was not. For a caller that has to
|
|
77
|
-
* say why: `describePictures` keeps the answers and drops the reasons.
|
|
78
|
-
*/
|
|
79
72
|
export declare function describePicture(describeImages: DescribeImages, picture: PictureToDescribe, documentName: string): Promise<string | undefined>;
|
|
80
73
|
export declare function describePictures(describeImages: DescribeImages, pictures: readonly PictureToDescribe[], documentName: string): Promise<(string | undefined)[]>;
|
|
81
74
|
/** A description short enough for alt text: its first sentences, up to 300 characters. */
|
|
@@ -18,7 +18,7 @@ export interface DocumentExtractExecutorOptions {
|
|
|
18
18
|
cwd?: string;
|
|
19
19
|
/** A delegated agent's overlay: reads fall through, writes stay private. */
|
|
20
20
|
overlay?: AgentOverlay;
|
|
21
|
-
/** @default
|
|
21
|
+
/** Over the reader's `maxFileMb` setting. @default 1 GB */
|
|
22
22
|
maxFileSizeBytes?: number;
|
|
23
23
|
/** The user's Document Reader settings: how scanned pages are read, and descriptions. */
|
|
24
24
|
reader?: DocumentReaderSettings;
|
|
@@ -29,6 +29,18 @@ export interface DocumentExtractExecutorOptions {
|
|
|
29
29
|
*/
|
|
30
30
|
describeImages?: DescribeImages;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* The largest file read unless the settings say otherwise.
|
|
34
|
+
*
|
|
35
|
+
* 200 MB once, when a book was read inside the session's own process and one
|
|
36
|
+
* large enough could take it down. Each is read in a process of its own now,
|
|
37
|
+
* and out of memory there is one file's error. Measured with that reader on
|
|
38
|
+
* the largest books of a real shelf: a 228 MB EPUB, 812 MB at its peak in 3 s;
|
|
39
|
+
* a 411 MB PDF, 2.6 GB in 80 s.
|
|
40
|
+
*/
|
|
41
|
+
export declare const DEFAULT_MAX_FILE_MB = 1024;
|
|
42
|
+
/** The limit in bytes: an explicit one, else the setting, else the default. */
|
|
43
|
+
export declare function documentReaderLimitBytes(maxFileSizeBytes: number | undefined, reader: DocumentReaderSettings | undefined): number;
|
|
32
44
|
/**
|
|
33
45
|
* The executor options a session's configuration gives the tool: the user's
|
|
34
46
|
* settings and the session's vision model. The same for the lead and every
|
|
@@ -78,10 +90,14 @@ export declare function readDocumentText(filePath: string, options: {
|
|
|
78
90
|
describeImages?: DescribeImages;
|
|
79
91
|
}): Promise<DocumentText>;
|
|
80
92
|
export interface BookDocument extends DocumentText {
|
|
81
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* The pictures inside it; the markdown links them as `images/<file>`.
|
|
95
|
+
* Each one's bytes are in the file at `path`, not in memory: a scanned
|
|
96
|
+
* book is a picture a page. They are there until `release`.
|
|
97
|
+
*/
|
|
82
98
|
images: {
|
|
83
99
|
file: string;
|
|
84
|
-
|
|
100
|
+
path: string;
|
|
85
101
|
mediaType: string;
|
|
86
102
|
width?: number;
|
|
87
103
|
height?: number;
|
|
@@ -107,11 +123,23 @@ export interface BookDocument extends DocumentText {
|
|
|
107
123
|
* whole document was read.
|
|
108
124
|
*/
|
|
109
125
|
problems: string[];
|
|
126
|
+
/**
|
|
127
|
+
* Removes the pictures' files. Called once the book is filed or given
|
|
128
|
+
* up, on every path; a session that dies first leaves them for
|
|
129
|
+
* `sweepAbandonedReads`.
|
|
130
|
+
*/
|
|
131
|
+
release(): Promise<void>;
|
|
110
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Remove scratch directories that reads left behind: a session that ended
|
|
135
|
+
* between reading a book and filing it never released its pictures.
|
|
136
|
+
*/
|
|
137
|
+
export declare function sweepAbandonedReads(scratchDir: string, olderThanMs?: number): Promise<void>;
|
|
111
138
|
/**
|
|
112
139
|
* A document as the Library keeps a book: its text and its pictures.
|
|
113
|
-
* Nothing is written anywhere
|
|
114
|
-
* is kept,
|
|
140
|
+
* Nothing is written anywhere the caller sees; the caller puts the pictures
|
|
141
|
+
* where the book is kept, `describeBookPictures` has a vision model look at
|
|
142
|
+
* them, and `release` removes them.
|
|
115
143
|
*/
|
|
116
144
|
export declare function readDocumentForBook(filePath: string, options: {
|
|
117
145
|
scratchDir: string;
|
|
@@ -19,14 +19,11 @@ export interface ReadSource {
|
|
|
19
19
|
document: BookDocument;
|
|
20
20
|
isbn?: string;
|
|
21
21
|
fingerprint: number[];
|
|
22
|
+
/** The lines on most of its pages: which document it is, see running-heads.ts. */
|
|
23
|
+
runningHeads: string[];
|
|
22
24
|
}
|
|
23
25
|
/** An ISBN printed in the first pages, when there is one. */
|
|
24
26
|
export declare function findIsbn(markdown: string): string | undefined;
|
|
25
|
-
/**
|
|
26
|
-
* What the files of one batch have to do with each other: a folder of ebooks
|
|
27
|
-
* often holds the same book twice, and the Library cannot say so about files
|
|
28
|
-
* it does not hold yet.
|
|
29
|
-
*/
|
|
30
27
|
export declare function compareBatch(sources: readonly ReadSource[]): Map<string, string[]>;
|
|
31
28
|
/**
|
|
32
29
|
* The librarian's tools. The two web tools are there only when a scraping
|