@juspay/neurolink 9.88.4 → 9.88.5
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/CHANGELOG.md +6 -0
- package/dist/browser/neurolink.min.js +311 -311
- package/dist/lib/processors/document/PptxProcessor.d.ts +14 -0
- package/dist/lib/processors/document/PptxProcessor.js +60 -2
- package/dist/processors/document/PptxProcessor.d.ts +14 -0
- package/dist/processors/document/PptxProcessor.js +60 -2
- package/package.json +1 -1
|
@@ -42,6 +42,20 @@ export declare class PptxProcessor {
|
|
|
42
42
|
* @throws Error if the buffer is not a valid ZIP/PPTX file
|
|
43
43
|
*/
|
|
44
44
|
static extractText(content: Buffer): Promise<string | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Extract the speaker notes for one slide.
|
|
47
|
+
*
|
|
48
|
+
* Speaker notes live in a separate `ppt/notesSlides/notesSlideN.xml` part
|
|
49
|
+
* whose number is NOT tied to the slide number — the link is declared in the
|
|
50
|
+
* slide's own relationships file (`ppt/slides/_rels/slideN.xml.rels`) via a
|
|
51
|
+
* relationship of type `.../notesSlide`. We resolve that target, then pull the
|
|
52
|
+
* `<a:t>` runs from the notes part. Returns null when the slide has no notes.
|
|
53
|
+
*
|
|
54
|
+
* @param zip - The opened PPTX archive
|
|
55
|
+
* @param slideNumber - 1-indexed slide number
|
|
56
|
+
* @returns The notes text (runs joined by a space), or null when absent
|
|
57
|
+
*/
|
|
58
|
+
private static extractNotesForSlide;
|
|
45
59
|
/**
|
|
46
60
|
* Extract text strings from a slide XML document.
|
|
47
61
|
* Finds all `<a:t>` elements and returns their text content.
|
|
@@ -37,6 +37,14 @@ const TEXT_ELEMENT_REGEX = /<a:t[^>]*>([\s\S]*?)<\/a:t>/g;
|
|
|
37
37
|
* Matches entries like "ppt/slides/slide1.xml", "ppt/slides/slide12.xml".
|
|
38
38
|
*/
|
|
39
39
|
const SLIDE_ENTRY_REGEX = /^ppt\/slides\/slide(\d+)\.xml$/;
|
|
40
|
+
/**
|
|
41
|
+
* A slide's per-slide relationships file, e.g.
|
|
42
|
+
* "ppt/slides/_rels/slide1.xml.rels", which links the slide to its speaker
|
|
43
|
+
* notes part (among other relationships).
|
|
44
|
+
*/
|
|
45
|
+
const SLIDE_RELS_NAME = (n) => `ppt/slides/_rels/slide${n}.xml.rels`;
|
|
46
|
+
/** Matches a single `<Relationship .../>` tag inside a .rels document. */
|
|
47
|
+
const RELATIONSHIP_TAG_REGEX = /<Relationship\b[^>]*\/?>/g;
|
|
40
48
|
/**
|
|
41
49
|
* Static utility class for extracting text from PPTX files.
|
|
42
50
|
*
|
|
@@ -74,15 +82,65 @@ export class PptxProcessor {
|
|
|
74
82
|
parts.push(`Presentation: ${slides.length} slide(s)\n`);
|
|
75
83
|
for (const slide of slides) {
|
|
76
84
|
const texts = PptxProcessor.extractTextFromXml(slide.xml);
|
|
77
|
-
|
|
85
|
+
const notes = PptxProcessor.extractNotesForSlide(zip, slide.slideNumber);
|
|
86
|
+
// Emit a slide section when it has either body text or speaker notes.
|
|
87
|
+
if (texts.length > 0 || notes) {
|
|
78
88
|
parts.push(`### Slide ${slide.slideNumber}`);
|
|
79
|
-
|
|
89
|
+
if (texts.length > 0) {
|
|
90
|
+
parts.push(texts.join("\n"));
|
|
91
|
+
}
|
|
92
|
+
if (notes) {
|
|
93
|
+
parts.push(`**Speaker notes:** ${notes}`);
|
|
94
|
+
}
|
|
80
95
|
parts.push(""); // blank line between slides
|
|
81
96
|
}
|
|
82
97
|
}
|
|
83
98
|
const result = parts.join("\n").trim();
|
|
84
99
|
return result || null;
|
|
85
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Extract the speaker notes for one slide.
|
|
103
|
+
*
|
|
104
|
+
* Speaker notes live in a separate `ppt/notesSlides/notesSlideN.xml` part
|
|
105
|
+
* whose number is NOT tied to the slide number — the link is declared in the
|
|
106
|
+
* slide's own relationships file (`ppt/slides/_rels/slideN.xml.rels`) via a
|
|
107
|
+
* relationship of type `.../notesSlide`. We resolve that target, then pull the
|
|
108
|
+
* `<a:t>` runs from the notes part. Returns null when the slide has no notes.
|
|
109
|
+
*
|
|
110
|
+
* @param zip - The opened PPTX archive
|
|
111
|
+
* @param slideNumber - 1-indexed slide number
|
|
112
|
+
* @returns The notes text (runs joined by a space), or null when absent
|
|
113
|
+
*/
|
|
114
|
+
static extractNotesForSlide(zip, slideNumber) {
|
|
115
|
+
const relsEntry = zip.getEntry(SLIDE_RELS_NAME(slideNumber));
|
|
116
|
+
if (!relsEntry) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
const relsXml = relsEntry.getData().toString("utf-8");
|
|
120
|
+
let notesTarget = null;
|
|
121
|
+
RELATIONSHIP_TAG_REGEX.lastIndex = 0;
|
|
122
|
+
for (let match = RELATIONSHIP_TAG_REGEX.exec(relsXml); match !== null; match = RELATIONSHIP_TAG_REGEX.exec(relsXml)) {
|
|
123
|
+
const tag = match[0];
|
|
124
|
+
if (/Type="[^"]*\/notesSlide"/.test(tag)) {
|
|
125
|
+
notesTarget = tag.match(/Target="([^"]+)"/)?.[1] ?? null;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (!notesTarget) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
// Targets are relative to the slide's folder (ppt/slides/), e.g.
|
|
133
|
+
// "../notesSlides/notesSlide1.xml" → "ppt/notesSlides/notesSlide1.xml".
|
|
134
|
+
const normalized = notesTarget
|
|
135
|
+
.replace(/^\.\.\//, "ppt/")
|
|
136
|
+
.replace(/^\/+/, "");
|
|
137
|
+
const notesEntry = zip.getEntry(normalized);
|
|
138
|
+
if (!notesEntry) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const notes = PptxProcessor.extractTextFromXml(notesEntry.getData().toString("utf-8")).join(" ");
|
|
142
|
+
return notes.trim() || null;
|
|
143
|
+
}
|
|
86
144
|
/**
|
|
87
145
|
* Extract text strings from a slide XML document.
|
|
88
146
|
* Finds all `<a:t>` elements and returns their text content.
|
|
@@ -42,6 +42,20 @@ export declare class PptxProcessor {
|
|
|
42
42
|
* @throws Error if the buffer is not a valid ZIP/PPTX file
|
|
43
43
|
*/
|
|
44
44
|
static extractText(content: Buffer): Promise<string | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Extract the speaker notes for one slide.
|
|
47
|
+
*
|
|
48
|
+
* Speaker notes live in a separate `ppt/notesSlides/notesSlideN.xml` part
|
|
49
|
+
* whose number is NOT tied to the slide number — the link is declared in the
|
|
50
|
+
* slide's own relationships file (`ppt/slides/_rels/slideN.xml.rels`) via a
|
|
51
|
+
* relationship of type `.../notesSlide`. We resolve that target, then pull the
|
|
52
|
+
* `<a:t>` runs from the notes part. Returns null when the slide has no notes.
|
|
53
|
+
*
|
|
54
|
+
* @param zip - The opened PPTX archive
|
|
55
|
+
* @param slideNumber - 1-indexed slide number
|
|
56
|
+
* @returns The notes text (runs joined by a space), or null when absent
|
|
57
|
+
*/
|
|
58
|
+
private static extractNotesForSlide;
|
|
45
59
|
/**
|
|
46
60
|
* Extract text strings from a slide XML document.
|
|
47
61
|
* Finds all `<a:t>` elements and returns their text content.
|
|
@@ -37,6 +37,14 @@ const TEXT_ELEMENT_REGEX = /<a:t[^>]*>([\s\S]*?)<\/a:t>/g;
|
|
|
37
37
|
* Matches entries like "ppt/slides/slide1.xml", "ppt/slides/slide12.xml".
|
|
38
38
|
*/
|
|
39
39
|
const SLIDE_ENTRY_REGEX = /^ppt\/slides\/slide(\d+)\.xml$/;
|
|
40
|
+
/**
|
|
41
|
+
* A slide's per-slide relationships file, e.g.
|
|
42
|
+
* "ppt/slides/_rels/slide1.xml.rels", which links the slide to its speaker
|
|
43
|
+
* notes part (among other relationships).
|
|
44
|
+
*/
|
|
45
|
+
const SLIDE_RELS_NAME = (n) => `ppt/slides/_rels/slide${n}.xml.rels`;
|
|
46
|
+
/** Matches a single `<Relationship .../>` tag inside a .rels document. */
|
|
47
|
+
const RELATIONSHIP_TAG_REGEX = /<Relationship\b[^>]*\/?>/g;
|
|
40
48
|
/**
|
|
41
49
|
* Static utility class for extracting text from PPTX files.
|
|
42
50
|
*
|
|
@@ -74,15 +82,65 @@ export class PptxProcessor {
|
|
|
74
82
|
parts.push(`Presentation: ${slides.length} slide(s)\n`);
|
|
75
83
|
for (const slide of slides) {
|
|
76
84
|
const texts = PptxProcessor.extractTextFromXml(slide.xml);
|
|
77
|
-
|
|
85
|
+
const notes = PptxProcessor.extractNotesForSlide(zip, slide.slideNumber);
|
|
86
|
+
// Emit a slide section when it has either body text or speaker notes.
|
|
87
|
+
if (texts.length > 0 || notes) {
|
|
78
88
|
parts.push(`### Slide ${slide.slideNumber}`);
|
|
79
|
-
|
|
89
|
+
if (texts.length > 0) {
|
|
90
|
+
parts.push(texts.join("\n"));
|
|
91
|
+
}
|
|
92
|
+
if (notes) {
|
|
93
|
+
parts.push(`**Speaker notes:** ${notes}`);
|
|
94
|
+
}
|
|
80
95
|
parts.push(""); // blank line between slides
|
|
81
96
|
}
|
|
82
97
|
}
|
|
83
98
|
const result = parts.join("\n").trim();
|
|
84
99
|
return result || null;
|
|
85
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Extract the speaker notes for one slide.
|
|
103
|
+
*
|
|
104
|
+
* Speaker notes live in a separate `ppt/notesSlides/notesSlideN.xml` part
|
|
105
|
+
* whose number is NOT tied to the slide number — the link is declared in the
|
|
106
|
+
* slide's own relationships file (`ppt/slides/_rels/slideN.xml.rels`) via a
|
|
107
|
+
* relationship of type `.../notesSlide`. We resolve that target, then pull the
|
|
108
|
+
* `<a:t>` runs from the notes part. Returns null when the slide has no notes.
|
|
109
|
+
*
|
|
110
|
+
* @param zip - The opened PPTX archive
|
|
111
|
+
* @param slideNumber - 1-indexed slide number
|
|
112
|
+
* @returns The notes text (runs joined by a space), or null when absent
|
|
113
|
+
*/
|
|
114
|
+
static extractNotesForSlide(zip, slideNumber) {
|
|
115
|
+
const relsEntry = zip.getEntry(SLIDE_RELS_NAME(slideNumber));
|
|
116
|
+
if (!relsEntry) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
const relsXml = relsEntry.getData().toString("utf-8");
|
|
120
|
+
let notesTarget = null;
|
|
121
|
+
RELATIONSHIP_TAG_REGEX.lastIndex = 0;
|
|
122
|
+
for (let match = RELATIONSHIP_TAG_REGEX.exec(relsXml); match !== null; match = RELATIONSHIP_TAG_REGEX.exec(relsXml)) {
|
|
123
|
+
const tag = match[0];
|
|
124
|
+
if (/Type="[^"]*\/notesSlide"/.test(tag)) {
|
|
125
|
+
notesTarget = tag.match(/Target="([^"]+)"/)?.[1] ?? null;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (!notesTarget) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
// Targets are relative to the slide's folder (ppt/slides/), e.g.
|
|
133
|
+
// "../notesSlides/notesSlide1.xml" → "ppt/notesSlides/notesSlide1.xml".
|
|
134
|
+
const normalized = notesTarget
|
|
135
|
+
.replace(/^\.\.\//, "ppt/")
|
|
136
|
+
.replace(/^\/+/, "");
|
|
137
|
+
const notesEntry = zip.getEntry(normalized);
|
|
138
|
+
if (!notesEntry) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const notes = PptxProcessor.extractTextFromXml(notesEntry.getData().toString("utf-8")).join(" ");
|
|
142
|
+
return notes.trim() || null;
|
|
143
|
+
}
|
|
86
144
|
/**
|
|
87
145
|
* Extract text strings from a slide XML document.
|
|
88
146
|
* Finds all `<a:t>` elements and returns their text content.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "9.88.
|
|
3
|
+
"version": "9.88.5",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (58+ servers), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
|
|
6
6
|
"author": {
|