@veryfront/ext-document-kreuzberg 0.1.993 → 0.1.995
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/extraction-config.d.ts +1 -1
- package/esm/extensions/ext-document-kreuzberg/src/extraction-config.d.ts.map +1 -1
- package/esm/extensions/ext-document-kreuzberg/src/extraction-config.js +7 -3
- package/esm/extensions/ext-document-kreuzberg/src/native-progress-extraction-worker.js +138 -6
- package/package.json +2 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function extractionConfigForMimeType(mimeType: string): Record<string, unknown
|
|
1
|
+
export declare function extractionConfigForMimeType(mimeType: string): Record<string, unknown>;
|
|
2
2
|
//# sourceMappingURL=extraction-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extraction-config.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-document-kreuzberg/src/extraction-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"extraction-config.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-document-kreuzberg/src/extraction-config.ts"],"names":[],"mappings":"AAmBA,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIrF"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
const
|
|
1
|
+
const MARKDOWN_EXTRACTION_CONFIG = {
|
|
2
|
+
outputFormat: "markdown",
|
|
3
|
+
};
|
|
4
|
+
const PDF_MARKDOWN_EXTRACTION_CONFIG = {
|
|
5
|
+
...MARKDOWN_EXTRACTION_CONFIG,
|
|
2
6
|
images: { extractImages: false },
|
|
3
7
|
pdfOptions: {
|
|
4
8
|
extractImages: false,
|
|
@@ -12,6 +16,6 @@ function normalizeMimeType(mimeType) {
|
|
|
12
16
|
}
|
|
13
17
|
export function extractionConfigForMimeType(mimeType) {
|
|
14
18
|
return normalizeMimeType(mimeType) === "application/pdf"
|
|
15
|
-
?
|
|
16
|
-
:
|
|
19
|
+
? PDF_MARKDOWN_EXTRACTION_CONFIG
|
|
20
|
+
: MARKDOWN_EXTRACTION_CONFIG;
|
|
17
21
|
}
|
|
@@ -23,6 +23,12 @@ function decodeXmlText(value) {
|
|
|
23
23
|
function extractPptxSlideText(xml) {
|
|
24
24
|
return Array.from(xml.matchAll(/<a:t(?:\s[^>]*)?>([\s\S]*?)<\/a:t>/g)).map((match) => decodeXmlText(match[1] ?? "").trim()).filter(Boolean).join(" ").trim();
|
|
25
25
|
}
|
|
26
|
+
function normalizePptxText(value) {
|
|
27
|
+
return value.replace(/\s+/g, " ").trim();
|
|
28
|
+
}
|
|
29
|
+
function cleanExtractedMarkdown(value) {
|
|
30
|
+
return value.replace(/!\[[^\]\n]*\]\(\s*\)/g, "").replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
31
|
+
}
|
|
26
32
|
function slideNumber(path) {
|
|
27
33
|
return Number(path.match(/\/slide(\d+)\.xml$/)?.[1] ?? 0);
|
|
28
34
|
}
|
|
@@ -30,6 +36,72 @@ function getXmlAttribute(tag, name) {
|
|
|
30
36
|
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31
37
|
return tag.match(new RegExp(`\\s${escapedName}=(["'])(.*?)\\1`))?.[2];
|
|
32
38
|
}
|
|
39
|
+
function pptxShapeRole(shapeXml) {
|
|
40
|
+
const placeholderTag = shapeXml.match(/<(?:\w+:)?ph\b[^>]*>/)?.[0] ?? "";
|
|
41
|
+
const placeholderType = getXmlAttribute(placeholderTag, "type");
|
|
42
|
+
if (placeholderType === "title" || placeholderType === "ctrTitle") return "title";
|
|
43
|
+
if (placeholderType === "subTitle") return "subtitle";
|
|
44
|
+
const propertyTag = shapeXml.match(/<(?:\w+:)?cNvPr\b[^>]*>/)?.[0] ?? "";
|
|
45
|
+
const name = getXmlAttribute(propertyTag, "name")?.toLowerCase() ?? "";
|
|
46
|
+
if (name.includes("subtitle")) return "subtitle";
|
|
47
|
+
if (name.includes("title")) return "title";
|
|
48
|
+
return "body";
|
|
49
|
+
}
|
|
50
|
+
function pptxTextShapes(xml) {
|
|
51
|
+
const shapes = Array.from(xml.matchAll(/<p:sp\b[\s\S]*?<\/p:sp>/g)).map((match) => {
|
|
52
|
+
const shapeXml = match[0];
|
|
53
|
+
return {
|
|
54
|
+
role: pptxShapeRole(shapeXml),
|
|
55
|
+
text: extractPptxSlideText(shapeXml)
|
|
56
|
+
};
|
|
57
|
+
}).filter((shape) => shape.text.length > 0);
|
|
58
|
+
const hasExplicitHeading = shapes.some(
|
|
59
|
+
(shape) => shape.role === "title" || shape.role === "subtitle"
|
|
60
|
+
);
|
|
61
|
+
if (!hasExplicitHeading && shapes.length === 1) {
|
|
62
|
+
return [{ ...shapes[0], role: "title" }];
|
|
63
|
+
}
|
|
64
|
+
return shapes;
|
|
65
|
+
}
|
|
66
|
+
function pptxShapeRoleQueues(xml) {
|
|
67
|
+
const roles = /* @__PURE__ */ new Map();
|
|
68
|
+
for (const shape of pptxTextShapes(xml)) {
|
|
69
|
+
const key = normalizePptxText(shape.text);
|
|
70
|
+
if (!key) continue;
|
|
71
|
+
const queue = roles.get(key) ?? [];
|
|
72
|
+
queue.push(shape.role);
|
|
73
|
+
roles.set(key, queue);
|
|
74
|
+
}
|
|
75
|
+
return roles;
|
|
76
|
+
}
|
|
77
|
+
function normalizePptxMarkdownHeadings(markdown, xml) {
|
|
78
|
+
const roles = pptxShapeRoleQueues(xml);
|
|
79
|
+
if (roles.size === 0) return markdown;
|
|
80
|
+
return cleanExtractedMarkdown(
|
|
81
|
+
markdown.split("\n").map((line) => {
|
|
82
|
+
const heading = line.match(/^#{1,6}\s+(.+?)\s*$/);
|
|
83
|
+
if (!heading) return line;
|
|
84
|
+
const text = heading[1] ?? "";
|
|
85
|
+
const queue = roles.get(normalizePptxText(text));
|
|
86
|
+
const role = queue?.shift();
|
|
87
|
+
if (!role) return line;
|
|
88
|
+
if (role === "title") return `# ${text}`;
|
|
89
|
+
if (role === "subtitle") return `## ${text}`;
|
|
90
|
+
return text;
|
|
91
|
+
}).join("\n")
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
function formatPptxShapeText(shape) {
|
|
95
|
+
if (shape.role === "title") return `# ${shape.text}`;
|
|
96
|
+
if (shape.role === "subtitle") return `## ${shape.text}`;
|
|
97
|
+
return shape.text;
|
|
98
|
+
}
|
|
99
|
+
function formatPptxSlideText(xml) {
|
|
100
|
+
const shapes = pptxTextShapes(xml);
|
|
101
|
+
const nonShapeText = extractPptxSlideText(xml.replace(/<p:sp\b[\s\S]*?<\/p:sp>/g, ""));
|
|
102
|
+
if (shapes.length === 0) return nonShapeText || extractPptxSlideText(xml);
|
|
103
|
+
return [...shapes.map(formatPptxShapeText), nonShapeText].filter(Boolean).join("\n\n").trim();
|
|
104
|
+
}
|
|
33
105
|
function normalizeZipPath(path) {
|
|
34
106
|
const parts = [];
|
|
35
107
|
for (const part of path.split("/")) {
|
|
@@ -89,6 +161,42 @@ async function pptxSlidePaths(zip) {
|
|
|
89
161
|
...fallback.filter((path) => !ordered.includes(path))
|
|
90
162
|
];
|
|
91
163
|
}
|
|
164
|
+
async function buildSingleSlidePptx(slideXml) {
|
|
165
|
+
const zip = new JSZip();
|
|
166
|
+
zip.file(
|
|
167
|
+
"[Content_Types].xml",
|
|
168
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
169
|
+
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
170
|
+
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
171
|
+
<Default Extension="xml" ContentType="application/xml"/>
|
|
172
|
+
<Override PartName="/ppt/presentation.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"/>
|
|
173
|
+
<Override PartName="/ppt/slides/slide1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>
|
|
174
|
+
</Types>`
|
|
175
|
+
);
|
|
176
|
+
zip.file(
|
|
177
|
+
"_rels/.rels",
|
|
178
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
179
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
180
|
+
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="ppt/presentation.xml"/>
|
|
181
|
+
</Relationships>`
|
|
182
|
+
);
|
|
183
|
+
zip.file(
|
|
184
|
+
"ppt/presentation.xml",
|
|
185
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
186
|
+
<p:presentation xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
187
|
+
<p:sldIdLst><p:sldId id="256" r:id="rId1"/></p:sldIdLst>
|
|
188
|
+
</p:presentation>`
|
|
189
|
+
);
|
|
190
|
+
zip.file(
|
|
191
|
+
"ppt/_rels/presentation.xml.rels",
|
|
192
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
193
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
194
|
+
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide1.xml"/>
|
|
195
|
+
</Relationships>`
|
|
196
|
+
);
|
|
197
|
+
zip.file("ppt/slides/slide1.xml", slideXml);
|
|
198
|
+
return await zip.generateAsync({ type: "uint8array" });
|
|
199
|
+
}
|
|
92
200
|
async function extractPdfByPage(buffer) {
|
|
93
201
|
const { extractBytes } = await loadKreuzbergNative();
|
|
94
202
|
const source = await PDFDocument.load(buffer, { ignoreEncryption: true });
|
|
@@ -119,17 +227,37 @@ async function extractPdfByPage(buffer) {
|
|
|
119
227
|
async function extractPptxBySlide(buffer, mimeType) {
|
|
120
228
|
const zip = await JSZip.loadAsync(buffer);
|
|
121
229
|
const slidePaths = await pptxSlidePaths(zip);
|
|
230
|
+
const config = extractionConfigForMimeType(mimeType);
|
|
231
|
+
let nativeExtractor;
|
|
232
|
+
try {
|
|
233
|
+
nativeExtractor = await loadKreuzbergNative();
|
|
234
|
+
} catch (error) {
|
|
235
|
+
if (!slidePaths.length) throw error;
|
|
236
|
+
}
|
|
122
237
|
if (!slidePaths.length) {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
238
|
+
const result = await nativeExtractor.extractBytes(
|
|
239
|
+
new Uint8Array(buffer),
|
|
240
|
+
mimeType,
|
|
241
|
+
config
|
|
242
|
+
);
|
|
243
|
+
const content = cleanExtractedMarkdown(result.content);
|
|
244
|
+
postProgress({ unit: "file", current: 1, total: 1, characters: content.length });
|
|
245
|
+
return content;
|
|
127
246
|
}
|
|
128
247
|
const slides = [];
|
|
129
248
|
for (const [index, path] of slidePaths.entries()) {
|
|
130
249
|
const file = zip.file(path);
|
|
131
250
|
const xml = file ? await file.async("text") : "";
|
|
132
|
-
|
|
251
|
+
let content;
|
|
252
|
+
if (nativeExtractor) {
|
|
253
|
+
try {
|
|
254
|
+
const slideBytes = await buildSingleSlidePptx(xml);
|
|
255
|
+
const result = await nativeExtractor.extractBytes(slideBytes, mimeType, config);
|
|
256
|
+
content = normalizePptxMarkdownHeadings(cleanExtractedMarkdown(result.content), xml);
|
|
257
|
+
} catch {
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
content ||= formatPptxSlideText(xml);
|
|
133
261
|
slides.push(content);
|
|
134
262
|
postProgress({
|
|
135
263
|
unit: "slide",
|
|
@@ -142,7 +270,11 @@ async function extractPptxBySlide(buffer, mimeType) {
|
|
|
142
270
|
}
|
|
143
271
|
async function extractWholeFile(buffer, mimeType) {
|
|
144
272
|
const { extractBytes } = await loadKreuzbergNative();
|
|
145
|
-
const result = await extractBytes(
|
|
273
|
+
const result = await extractBytes(
|
|
274
|
+
new Uint8Array(buffer),
|
|
275
|
+
mimeType,
|
|
276
|
+
extractionConfigForMimeType(mimeType)
|
|
277
|
+
);
|
|
146
278
|
postProgress({ unit: "file", current: 1, total: 1, characters: result.content.length });
|
|
147
279
|
return result.content;
|
|
148
280
|
}
|
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.995",
|
|
4
4
|
"description": "Veryfront first-party extension package for ext-document-kreuzberg",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"veryfront",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"pdf-lib": "1.17.1"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"veryfront": "^0.1.
|
|
58
|
+
"veryfront": "^0.1.995"
|
|
59
59
|
},
|
|
60
60
|
"type": "module",
|
|
61
61
|
"types": "./esm/extensions/ext-document-kreuzberg/src/index.d.ts",
|