@veryfront/ext-document-kreuzberg 0.1.988 → 0.1.990
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/esm/extensions/ext-document-kreuzberg/src/index.d.ts +8 -3
- package/esm/extensions/ext-document-kreuzberg/src/index.d.ts.map +1 -1
- package/esm/extensions/ext-document-kreuzberg/src/index.js +108 -2
- package/esm/extensions/ext-document-kreuzberg/src/native-progress-extraction-worker.js +161 -0
- package/package.json +5 -3
|
@@ -7,21 +7,26 @@
|
|
|
7
7
|
* @module extensions/ext-document-kreuzberg
|
|
8
8
|
*/
|
|
9
9
|
import "../../../_dnt.polyfills.js";
|
|
10
|
-
import type { ExtensionFactory } from "veryfront/extensions";
|
|
11
|
-
import type { DocumentExtractor, KreuzbergExtractor } from "veryfront/extensions/compat";
|
|
10
|
+
import type { ExtensionFactory, ExtensionLogger } from "veryfront/extensions";
|
|
11
|
+
import type { DocumentExtractionOptions, DocumentExtractor, KreuzbergExtractor } from "veryfront/extensions/compat";
|
|
12
12
|
/** Maximum time to wait for fallback worker extraction before aborting. */
|
|
13
13
|
export declare const EXTRACTION_TIMEOUT_MS = 120000;
|
|
14
|
+
export declare const NATIVE_PROGRESS_IDLE_TIMEOUT_MS = 120000;
|
|
15
|
+
export declare const NATIVE_PROGRESS_HARD_TIMEOUT_MS: number;
|
|
14
16
|
declare function extractInWorkerDeno(buffer: ArrayBuffer, mimeType: string): Promise<string>;
|
|
15
17
|
export interface KreuzbergDocumentExtractorDeps {
|
|
16
18
|
isDenoRuntime?: boolean;
|
|
17
19
|
loadNativeKreuzberg?: () => Promise<KreuzbergExtractor>;
|
|
18
20
|
extractInWorkerDeno?: typeof extractInWorkerDeno;
|
|
21
|
+
extractWithNativeProgressDeno?: typeof extractWithNativeProgressDeno;
|
|
22
|
+
logger?: Pick<ExtensionLogger, "warn">;
|
|
19
23
|
}
|
|
24
|
+
declare function extractWithNativeProgressDeno(buffer: ArrayBuffer, mimeType: string, options: DocumentExtractionOptions): Promise<string>;
|
|
20
25
|
export declare class KreuzbergDocumentExtractor implements DocumentExtractor {
|
|
21
26
|
private readonly deps;
|
|
22
27
|
constructor(deps?: KreuzbergDocumentExtractorDeps);
|
|
23
28
|
importKreuzberg(): Promise<KreuzbergExtractor>;
|
|
24
|
-
extractInWorker(buffer: ArrayBuffer, mimeType: string): Promise<string>;
|
|
29
|
+
extractInWorker(buffer: ArrayBuffer, mimeType: string, options?: DocumentExtractionOptions): Promise<string>;
|
|
25
30
|
}
|
|
26
31
|
declare const extDocumentKreuzberg: ExtensionFactory;
|
|
27
32
|
export default extDocumentKreuzberg;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-document-kreuzberg/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,4BAA4B,CAAC;AAKpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-document-kreuzberg/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,4BAA4B,CAAC;AAKpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAC1F,OAAO,KAAK,EACV,yBAAyB,EAEzB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,yCAAyC,CAAC;AAIjD,2EAA2E;AAC3E,eAAO,MAAM,qBAAqB,SAAU,CAAC;AAC7C,eAAO,MAAM,+BAA+B,SAAU,CAAC;AACvD,eAAO,MAAM,+BAA+B,QAAc,CAAC;AAE3D,iBAAS,mBAAmB,CAC1B,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CA0CjB;AAED,MAAM,WAAW,8BAA8B;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACxD,mBAAmB,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACjD,6BAA6B,CAAC,EAAE,OAAO,6BAA6B,CAAC;IACrE,MAAM,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;CACxC;AAuCD,iBAAS,6BAA6B,CACpC,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,CAgFjB;AAED,qBAAa,0BAA2B,YAAW,iBAAiB;IACtD,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,GAAE,8BAAmC;IAEtE,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAIxC,eAAe,CACnB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,MAAM,CAAC;CAgDnB;AAED,QAAA,MAAM,oBAAoB,EAAE,gBAiB3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -12,6 +12,8 @@ import { isMissingPackageError, loadKreuzberg, loadKreuzbergNative } from "./kre
|
|
|
12
12
|
import { isDeno } from "./runtime.js";
|
|
13
13
|
/** Maximum time to wait for fallback worker extraction before aborting. */
|
|
14
14
|
export const EXTRACTION_TIMEOUT_MS = 120_000;
|
|
15
|
+
export const NATIVE_PROGRESS_IDLE_TIMEOUT_MS = 120_000;
|
|
16
|
+
export const NATIVE_PROGRESS_HARD_TIMEOUT_MS = 10 * 60_000;
|
|
15
17
|
function extractInWorkerDeno(buffer, mimeType) {
|
|
16
18
|
return new Promise((resolve, reject) => {
|
|
17
19
|
// The worker ships as raw TypeScript in the compiled binary and from source
|
|
@@ -49,11 +51,98 @@ function extractInWorkerDeno(buffer, mimeType) {
|
|
|
49
51
|
function isPdfMimeType(mimeType) {
|
|
50
52
|
return mimeType.toLowerCase().split(";")[0]?.trim() === "application/pdf";
|
|
51
53
|
}
|
|
54
|
+
function normalizeMimeType(mimeType) {
|
|
55
|
+
return mimeType.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
56
|
+
}
|
|
57
|
+
function isNativeProgressMimeType(mimeType) {
|
|
58
|
+
const normalized = normalizeMimeType(mimeType);
|
|
59
|
+
return normalized === "application/pdf" ||
|
|
60
|
+
normalized === "application/vnd.ms-powerpoint" ||
|
|
61
|
+
normalized === "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
62
|
+
}
|
|
52
63
|
async function extractWithNativeKreuzberg(buffer, mimeType, loadNative) {
|
|
53
64
|
const { extractBytes } = await loadNative();
|
|
54
65
|
const result = await extractBytes(new Uint8Array(buffer), mimeType);
|
|
55
66
|
return result.content;
|
|
56
67
|
}
|
|
68
|
+
function warningDetails(mimeType, error) {
|
|
69
|
+
return {
|
|
70
|
+
mimeType,
|
|
71
|
+
error: error instanceof Error ? error.message : String(error),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function extractWithNativeProgressDeno(buffer, mimeType, options) {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
const workerFile = globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).url.endsWith(".ts")
|
|
77
|
+
? "./native-progress-extraction-worker.ts"
|
|
78
|
+
: "./native-progress-extraction-worker.js";
|
|
79
|
+
const workerUrl = new URL(workerFile, globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).url);
|
|
80
|
+
const worker = new Worker(workerUrl, { type: "module" });
|
|
81
|
+
const idleTimeoutMs = options.idleTimeoutMs ?? NATIVE_PROGRESS_IDLE_TIMEOUT_MS;
|
|
82
|
+
const hardTimeoutMs = options.hardTimeoutMs ?? NATIVE_PROGRESS_HARD_TIMEOUT_MS;
|
|
83
|
+
let settled = false;
|
|
84
|
+
let idleTimer;
|
|
85
|
+
const clearIdleTimer = () => {
|
|
86
|
+
if (!idleTimer)
|
|
87
|
+
return;
|
|
88
|
+
clearTimeout(idleTimer);
|
|
89
|
+
idleTimer = undefined;
|
|
90
|
+
};
|
|
91
|
+
const cleanup = () => {
|
|
92
|
+
settled = true;
|
|
93
|
+
clearIdleTimer();
|
|
94
|
+
clearTimeout(hardTimer);
|
|
95
|
+
worker.terminate();
|
|
96
|
+
};
|
|
97
|
+
const fail = (error) => {
|
|
98
|
+
if (settled)
|
|
99
|
+
return;
|
|
100
|
+
cleanup();
|
|
101
|
+
reject(error);
|
|
102
|
+
};
|
|
103
|
+
const resetIdleTimer = () => {
|
|
104
|
+
clearIdleTimer();
|
|
105
|
+
idleTimer = dntShim.setTimeout(() => {
|
|
106
|
+
fail(new Error(`Text extraction made no progress for ${idleTimeoutMs / 1000}s. ` +
|
|
107
|
+
"The file may be corrupted or unsupported"));
|
|
108
|
+
}, idleTimeoutMs);
|
|
109
|
+
};
|
|
110
|
+
const hardTimer = dntShim.setTimeout(() => {
|
|
111
|
+
fail(new Error(`Text extraction exceeded the hard timeout after ${hardTimeoutMs / 1000}s. ` +
|
|
112
|
+
"The file may be corrupted or unsupported"));
|
|
113
|
+
}, hardTimeoutMs);
|
|
114
|
+
resetIdleTimer();
|
|
115
|
+
worker.onmessage = async (event) => {
|
|
116
|
+
if (settled)
|
|
117
|
+
return;
|
|
118
|
+
const message = event.data;
|
|
119
|
+
if (message.type === "progress") {
|
|
120
|
+
clearIdleTimer();
|
|
121
|
+
try {
|
|
122
|
+
await options.onProgress?.(message.event);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
fail(error instanceof Error ? error : new Error(String(error)));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (!settled)
|
|
129
|
+
resetIdleTimer();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (message.type === "error") {
|
|
133
|
+
fail(new Error(message.error));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
cleanup();
|
|
137
|
+
resolve(message.content);
|
|
138
|
+
};
|
|
139
|
+
worker.onerror = (event) => {
|
|
140
|
+
fail(new Error(`Text extraction worker failed: ${event.message ?? "unknown"}`));
|
|
141
|
+
};
|
|
142
|
+
const requestBuffer = buffer.slice(0);
|
|
143
|
+
worker.postMessage({ buffer: requestBuffer, mimeType }, [requestBuffer]);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
57
146
|
export class KreuzbergDocumentExtractor {
|
|
58
147
|
deps;
|
|
59
148
|
constructor(deps = {}) {
|
|
@@ -62,7 +151,7 @@ export class KreuzbergDocumentExtractor {
|
|
|
62
151
|
importKreuzberg() {
|
|
63
152
|
return loadKreuzberg();
|
|
64
153
|
}
|
|
65
|
-
async extractInWorker(buffer, mimeType) {
|
|
154
|
+
async extractInWorker(buffer, mimeType, options = {}) {
|
|
66
155
|
const isDenoRuntime = this.deps.isDenoRuntime ?? isDeno;
|
|
67
156
|
const extractWithWorker = this.deps.extractInWorkerDeno ?? extractInWorkerDeno;
|
|
68
157
|
// Node/Bun extract in-process via @kreuzberg/node. Deno keeps the isolated
|
|
@@ -73,6 +162,23 @@ export class KreuzbergDocumentExtractor {
|
|
|
73
162
|
const result = await extractBytes(new Uint8Array(buffer), mimeType);
|
|
74
163
|
return result.content;
|
|
75
164
|
}
|
|
165
|
+
if (options.onProgress && isNativeProgressMimeType(mimeType)) {
|
|
166
|
+
try {
|
|
167
|
+
return await (this.deps.extractWithNativeProgressDeno ?? extractWithNativeProgressDeno)(buffer, mimeType, options);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
// Keep progress opportunistic: if page/slide extraction cannot handle a
|
|
171
|
+
// document, fall back to the previous opaque extraction path.
|
|
172
|
+
const message = "[ext-document-kreuzberg] native progress extraction failed; falling back to opaque extraction";
|
|
173
|
+
const details = warningDetails(mimeType, error);
|
|
174
|
+
if (this.deps.logger) {
|
|
175
|
+
this.deps.logger.warn(message, details);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
console.warn(message, details);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
76
182
|
if (isPdfMimeType(mimeType)) {
|
|
77
183
|
try {
|
|
78
184
|
return await extractWithNativeKreuzberg(buffer, mimeType, this.deps.loadNativeKreuzberg ?? loadKreuzbergNative);
|
|
@@ -86,7 +192,6 @@ export class KreuzbergDocumentExtractor {
|
|
|
86
192
|
}
|
|
87
193
|
}
|
|
88
194
|
const extDocumentKreuzberg = () => {
|
|
89
|
-
const extractor = new KreuzbergDocumentExtractor();
|
|
90
195
|
return {
|
|
91
196
|
name: "ext-document-kreuzberg",
|
|
92
197
|
version: "0.1.0",
|
|
@@ -97,6 +202,7 @@ const extDocumentKreuzberg = () => {
|
|
|
97
202
|
{ type: "fs:read" },
|
|
98
203
|
],
|
|
99
204
|
setup(ctx) {
|
|
205
|
+
const extractor = new KreuzbergDocumentExtractor({ logger: ctx.logger });
|
|
100
206
|
ctx.provide("DocumentExtractor", extractor);
|
|
101
207
|
ctx.logger.info("[ext-document-kreuzberg] document extraction registered");
|
|
102
208
|
},
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { PDFDocument } from "pdf-lib";
|
|
2
|
+
import JSZip from "jszip";
|
|
3
|
+
import { loadKreuzbergNative } from "./kreuzberg.js";
|
|
4
|
+
function postProgress(event) {
|
|
5
|
+
self.postMessage({ type: "progress", event });
|
|
6
|
+
}
|
|
7
|
+
function normalizeMimeType(mimeType) {
|
|
8
|
+
return mimeType.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
9
|
+
}
|
|
10
|
+
function isPdfMimeType(mimeType) {
|
|
11
|
+
return normalizeMimeType(mimeType) === "application/pdf";
|
|
12
|
+
}
|
|
13
|
+
function isPptxMimeType(mimeType) {
|
|
14
|
+
return normalizeMimeType(mimeType) === "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
15
|
+
}
|
|
16
|
+
function decodeXmlText(value) {
|
|
17
|
+
return value.replace(
|
|
18
|
+
/&#x([0-9a-f]+);/gi,
|
|
19
|
+
(_, hex) => String.fromCodePoint(Number.parseInt(hex, 16))
|
|
20
|
+
).replace(/&#(\d+);/g, (_, decimal) => String.fromCodePoint(Number.parseInt(decimal, 10))).replace(/"/g, '"').replace(/'/g, "'").replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
|
|
21
|
+
}
|
|
22
|
+
function extractPptxSlideText(xml) {
|
|
23
|
+
return Array.from(xml.matchAll(/<a:t(?:\s[^>]*)?>([\s\S]*?)<\/a:t>/g)).map((match) => decodeXmlText(match[1] ?? "").trim()).filter(Boolean).join(" ").trim();
|
|
24
|
+
}
|
|
25
|
+
function slideNumber(path) {
|
|
26
|
+
return Number(path.match(/\/slide(\d+)\.xml$/)?.[1] ?? 0);
|
|
27
|
+
}
|
|
28
|
+
function getXmlAttribute(tag, name) {
|
|
29
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
30
|
+
return tag.match(new RegExp(`\\s${escapedName}=(["'])(.*?)\\1`))?.[2];
|
|
31
|
+
}
|
|
32
|
+
function normalizeZipPath(path) {
|
|
33
|
+
const parts = [];
|
|
34
|
+
for (const part of path.split("/")) {
|
|
35
|
+
if (!part || part === ".") continue;
|
|
36
|
+
if (part === "..") {
|
|
37
|
+
parts.pop();
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
parts.push(part);
|
|
41
|
+
}
|
|
42
|
+
return parts.join("/");
|
|
43
|
+
}
|
|
44
|
+
function normalizePresentationTarget(target) {
|
|
45
|
+
const path = target.split(/[?#]/)[0] ?? target;
|
|
46
|
+
if (path.startsWith("/")) return normalizeZipPath(path.slice(1));
|
|
47
|
+
if (path.startsWith("ppt/")) return normalizeZipPath(path);
|
|
48
|
+
return normalizeZipPath(`ppt/${path}`);
|
|
49
|
+
}
|
|
50
|
+
function presentationSlideRelationshipIds(xml) {
|
|
51
|
+
return Array.from(xml.matchAll(/<(?:\w+:)?sldId\b[^>]*>/g)).map((match) => getXmlAttribute(match[0], "r:id")).filter((id) => typeof id === "string" && id.length > 0);
|
|
52
|
+
}
|
|
53
|
+
function presentationRelationships(xml) {
|
|
54
|
+
const relationships = /* @__PURE__ */ new Map();
|
|
55
|
+
for (const match of xml.matchAll(/<Relationship\b[^>]*>/g)) {
|
|
56
|
+
const tag = match[0];
|
|
57
|
+
const id = getXmlAttribute(tag, "Id");
|
|
58
|
+
const target = getXmlAttribute(tag, "Target");
|
|
59
|
+
if (!id || !target) continue;
|
|
60
|
+
const path = normalizePresentationTarget(target);
|
|
61
|
+
if (/^ppt\/slides\/slide\d+\.xml$/.test(path)) {
|
|
62
|
+
relationships.set(id, path);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return relationships;
|
|
66
|
+
}
|
|
67
|
+
async function pptxSlidePaths(zip) {
|
|
68
|
+
const fallback = Object.keys(zip.files).filter((path) => /^ppt\/slides\/slide\d+\.xml$/.test(path)).sort((left, right) => slideNumber(left) - slideNumber(right));
|
|
69
|
+
const presentation = zip.file("ppt/presentation.xml");
|
|
70
|
+
const rels = zip.file("ppt/_rels/presentation.xml.rels");
|
|
71
|
+
if (!presentation || !rels) return fallback;
|
|
72
|
+
const [presentationXml, relsXml] = await Promise.all([
|
|
73
|
+
presentation.async("text"),
|
|
74
|
+
rels.async("text")
|
|
75
|
+
]);
|
|
76
|
+
const relationships = presentationRelationships(relsXml);
|
|
77
|
+
const fallbackSet = new Set(fallback);
|
|
78
|
+
const ordered = [];
|
|
79
|
+
for (const id of presentationSlideRelationshipIds(presentationXml)) {
|
|
80
|
+
const path = relationships.get(id);
|
|
81
|
+
if (path && fallbackSet.has(path) && !ordered.includes(path)) {
|
|
82
|
+
ordered.push(path);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (!ordered.length) return fallback;
|
|
86
|
+
return [
|
|
87
|
+
...ordered,
|
|
88
|
+
...fallback.filter((path) => !ordered.includes(path))
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
async function extractPdfByPage(buffer) {
|
|
92
|
+
const { extractBytes } = await loadKreuzbergNative();
|
|
93
|
+
const source = await PDFDocument.load(buffer, { ignoreEncryption: true });
|
|
94
|
+
const total = source.getPageCount();
|
|
95
|
+
const pages = [];
|
|
96
|
+
for (let index = 0; index < total; index += 1) {
|
|
97
|
+
const singlePage = await PDFDocument.create();
|
|
98
|
+
const [page] = await singlePage.copyPages(source, [index]);
|
|
99
|
+
singlePage.addPage(page);
|
|
100
|
+
const bytes = await singlePage.save({ useObjectStreams: false });
|
|
101
|
+
const result = await extractBytes(new Uint8Array(bytes), "application/pdf");
|
|
102
|
+
const content = result.content.trim();
|
|
103
|
+
pages.push(content);
|
|
104
|
+
postProgress({
|
|
105
|
+
unit: "page",
|
|
106
|
+
current: index + 1,
|
|
107
|
+
total,
|
|
108
|
+
characters: content.length
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return pages.filter(Boolean).join("\n\n");
|
|
112
|
+
}
|
|
113
|
+
async function extractPptxBySlide(buffer, mimeType) {
|
|
114
|
+
const zip = await JSZip.loadAsync(buffer);
|
|
115
|
+
const slidePaths = await pptxSlidePaths(zip);
|
|
116
|
+
if (!slidePaths.length) {
|
|
117
|
+
const { extractBytes } = await loadKreuzbergNative();
|
|
118
|
+
const result = await extractBytes(new Uint8Array(buffer), mimeType);
|
|
119
|
+
postProgress({ unit: "file", current: 1, total: 1, characters: result.content.length });
|
|
120
|
+
return result.content;
|
|
121
|
+
}
|
|
122
|
+
const slides = [];
|
|
123
|
+
for (const [index, path] of slidePaths.entries()) {
|
|
124
|
+
const file = zip.file(path);
|
|
125
|
+
const xml = file ? await file.async("text") : "";
|
|
126
|
+
const content = extractPptxSlideText(xml);
|
|
127
|
+
slides.push(content);
|
|
128
|
+
postProgress({
|
|
129
|
+
unit: "slide",
|
|
130
|
+
current: index + 1,
|
|
131
|
+
total: slidePaths.length,
|
|
132
|
+
characters: content.length
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return slides.filter(Boolean).join("\n\n");
|
|
136
|
+
}
|
|
137
|
+
async function extractWholeFile(buffer, mimeType) {
|
|
138
|
+
const { extractBytes } = await loadKreuzbergNative();
|
|
139
|
+
const result = await extractBytes(new Uint8Array(buffer), mimeType);
|
|
140
|
+
postProgress({ unit: "file", current: 1, total: 1, characters: result.content.length });
|
|
141
|
+
return result.content;
|
|
142
|
+
}
|
|
143
|
+
self.onmessage = async (event) => {
|
|
144
|
+
if (event.origin && event.origin !== self.location.origin) {
|
|
145
|
+
self.postMessage(
|
|
146
|
+
{
|
|
147
|
+
type: "error",
|
|
148
|
+
error: "Rejected document extraction request from invalid origin"
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
const { buffer, mimeType } = event.data;
|
|
155
|
+
const content = isPdfMimeType(mimeType) ? await extractPdfByPage(buffer) : isPptxMimeType(mimeType) ? await extractPptxBySlide(buffer, mimeType) : await extractWholeFile(buffer, mimeType);
|
|
156
|
+
self.postMessage({ type: "done", content });
|
|
157
|
+
} catch (error) {
|
|
158
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
159
|
+
self.postMessage({ type: "error", error: message });
|
|
160
|
+
}
|
|
161
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veryfront/ext-document-kreuzberg",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.990",
|
|
4
4
|
"description": "Veryfront first-party extension package for ext-document-kreuzberg",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"veryfront",
|
|
@@ -50,10 +50,12 @@
|
|
|
50
50
|
"@deno/shim-crypto": "~0.3.1",
|
|
51
51
|
"@deno/shim-timers": "~0.1.0",
|
|
52
52
|
"@kreuzberg/node": "4.4.2",
|
|
53
|
-
"@kreuzberg/wasm": "4.5.2"
|
|
53
|
+
"@kreuzberg/wasm": "4.5.2",
|
|
54
|
+
"jszip": "3.10.1",
|
|
55
|
+
"pdf-lib": "1.17.1"
|
|
54
56
|
},
|
|
55
57
|
"peerDependencies": {
|
|
56
|
-
"veryfront": "^0.1.
|
|
58
|
+
"veryfront": "^0.1.990"
|
|
57
59
|
},
|
|
58
60
|
"type": "module",
|
|
59
61
|
"types": "./esm/extensions/ext-document-kreuzberg/src/index.d.ts",
|