From 992f2eee88c352b3183a51f7ea637159d4200c62 Mon Sep 17 00:00:00 2001 From: Fibi Date: Mon, 23 Dec 2024 03:38:15 +0100 Subject: [PATCH 1/5] add word-extractor package --- libs/langchain-community/package.json | 6 +++++ yarn.lock | 33 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/libs/langchain-community/package.json b/libs/langchain-community/package.json index b759b36153af..d2312880528f 100644 --- a/libs/langchain-community/package.json +++ b/libs/langchain-community/package.json @@ -124,6 +124,7 @@ "@types/pg": "^8.11.0", "@types/pg-copy-streams": "^1.2.2", "@types/uuid": "^9", + "@types/word-extractor": "^1", "@types/ws": "^8", "@typescript-eslint/eslint-plugin": "^5.58.0", "@typescript-eslint/parser": "^5.58.0", @@ -216,6 +217,7 @@ "voy-search": "0.6.2", "weaviate-ts-client": "^1.4.0", "web-auth-library": "^1.0.3", + "word-extractor": "^1.0.4", "youtube-transcript": "^1.0.6", "youtubei.js": "^9.1.0" }, @@ -342,6 +344,7 @@ "voy-search": "0.6.2", "weaviate-ts-client": "*", "web-auth-library": "^1.0.3", + "word-extractor": "*", "ws": "^8.14.2", "youtube-transcript": "^1.0.6", "youtubei.js": "^9.1.0" @@ -698,6 +701,9 @@ "web-auth-library": { "optional": true }, + "word-extractor": { + "optional": true + }, "ws": { "optional": true }, diff --git a/yarn.lock b/yarn.lock index 9e5a48455320..3338c85515e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11864,6 +11864,7 @@ __metadata: "@types/pg": ^8.11.0 "@types/pg-copy-streams": ^1.2.2 "@types/uuid": ^9 + "@types/word-extractor": ^1 "@types/ws": ^8 "@typescript-eslint/eslint-plugin": ^5.58.0 "@typescript-eslint/parser": ^5.58.0 @@ -11963,6 +11964,7 @@ __metadata: voy-search: 0.6.2 weaviate-ts-client: ^1.4.0 web-auth-library: ^1.0.3 + word-extractor: ^1.0.4 youtube-transcript: ^1.0.6 youtubei.js: ^9.1.0 zod: ^3.22.3 @@ -12090,6 +12092,7 @@ __metadata: voy-search: 0.6.2 weaviate-ts-client: "*" web-auth-library: ^1.0.3 + word-extractor: "*" ws: ^8.14.2 youtube-transcript: ^1.0.6 youtubei.js: ^9.1.0 @@ -12328,6 +12331,8 @@ __metadata: optional: true web-auth-library: optional: true + word-extractor: + optional: true ws: optional: true youtube-transcript: @@ -20143,6 +20148,15 @@ __metadata: languageName: node linkType: hard +"@types/word-extractor@npm:^1": + version: 1.0.6 + resolution: "@types/word-extractor@npm:1.0.6" + dependencies: + "@types/node": "*" + checksum: 3619602252493e1ad2671af6ce73a342cdc8452d5a3473123474ab6f3f5deb466b9c4cfdcbac75eacb430f545ae5708e3165b01e03b42053ca9fa87d2920fe3d + languageName: node + linkType: hard + "@types/ws@npm:8.5.9": version: 8.5.9 resolution: "@types/ws@npm:8.5.9" @@ -39872,6 +39886,15 @@ __metadata: languageName: node linkType: hard +"saxes@npm:^5.0.1": + version: 5.0.1 + resolution: "saxes@npm:5.0.1" + dependencies: + xmlchars: ^2.2.0 + checksum: 5636b55cf15f7cf0baa73f2797bf992bdcf75d1b39d82c0aa4608555c774368f6ac321cb641fd5f3d3ceb87805122cd47540da6a7b5960fe0dbdb8f8c263f000 + languageName: node + linkType: hard + "saxes@npm:^6.0.0": version: 6.0.0 resolution: "saxes@npm:6.0.0" @@ -44266,6 +44289,16 @@ __metadata: languageName: node linkType: hard +"word-extractor@npm:^1.0.4": + version: 1.0.4 + resolution: "word-extractor@npm:1.0.4" + dependencies: + saxes: ^5.0.1 + yauzl: ^2.10.0 + checksum: 04ed0ef1dfd6b26ab2094671e72f16e5a948f9978da3fd6b9d01ff475ecd048199f529d989f1d0dfe3da684a1aa8bb86e4388edabd706fd74a0be4eb030183cd + languageName: node + linkType: hard + "word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": version: 1.2.3 resolution: "word-wrap@npm:1.2.3" From 6e2e59dafa8863251ae208c5a079d80cc5b5614e Mon Sep 17 00:00:00 2001 From: Fibi Date: Mon, 23 Dec 2024 03:38:47 +0100 Subject: [PATCH 2/5] add .doc loader --- .../src/document_loaders/fs/docx.ts | 82 ++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/libs/langchain-community/src/document_loaders/fs/docx.ts b/libs/langchain-community/src/document_loaders/fs/docx.ts index 72518aec3b2e..e1edef2fc8e7 100644 --- a/libs/langchain-community/src/document_loaders/fs/docx.ts +++ b/libs/langchain-community/src/document_loaders/fs/docx.ts @@ -1,19 +1,33 @@ import { Document } from "@langchain/core/documents"; import { BufferLoader } from "langchain/document_loaders/fs/buffer"; +type DocxLoaderOptions = { + type: "docx" | "doc"; +}; /** * A class that extends the `BufferLoader` class. It represents a document * loader that loads documents from DOCX files. + * It has a constructor that takes a `filePathOrBlob` parameter representing the path to the word + * file or a Blob object, and an optional `options` parameter of type + * `DocxLoaderOptions` */ export class DocxLoader extends BufferLoader { - constructor(filePathOrBlob: string | Blob) { + protected options: DocxLoaderOptions = { type: "docx" }; + + constructor(filePathOrBlob: string | Blob, options?: DocxLoaderOptions) { super(filePathOrBlob); + if (options) { + this.options = { + ...options, + }; + } } /** * A method that takes a `raw` buffer and `metadata` as parameters and * returns a promise that resolves to an array of `Document` instances. It - * uses the `extractRawText` function from the `mammoth` module to extract + * uses the `extractRawText` function from the `mammoth` module or + * `extract` method from the `word-extractor` module to extract * the raw text content from the buffer. If the extracted text content is * empty, it returns an empty array. Otherwise, it creates a new * `Document` instance with the extracted text content and the provided @@ -26,6 +40,31 @@ export class DocxLoader extends BufferLoader { raw: Buffer, metadata: Document["metadata"] ): Promise { + if (this.options.type === "doc") { + return this.parseDoc(raw, metadata); + } + return this.parseDocx(raw, metadata); + } + + /** + * A private method that takes a `raw` buffer and `metadata` as parameters and + * returns a promise that resolves to an array of `Document` instances. It + * uses the `extractRawText` function from the `mammoth` module to extract + * the raw text content from the buffer. If the extracted text content is + * empty, it returns an empty array. Otherwise, it creates a new + * `Document` instance with the extracted text content and the provided + * metadata, and returns it as an array. + * @param raw The raw buffer from which to extract text content. + * @param metadata The metadata to be associated with the created `Document` instance. + * @returns A promise that resolves to an array of `Document` instances. + */ + private async parseDocx( + raw: Buffer, + metadata: Document["metadata"] + ): Promise { + if (this.options.type === "doc") { + return this.parseDoc(raw, metadata); + } const { extractRawText } = await DocxLoaderImports(); const docx = await extractRawText({ buffer: raw, @@ -40,6 +79,33 @@ export class DocxLoader extends BufferLoader { }), ]; } + + /** + * A private method that takes a `raw` buffer and `metadata` as parameters and + * returns a promise that resolves to an array of `Document` instances. It + * uses the `extract` method from the `word-extractor` module to extract + * the raw text content from the buffer. If the extracted text content is + * empty, it returns an empty array. Otherwise, it creates a new + * `Document` instance with the extracted text content and the provided + * metadata, and returns it as an array. + * @param raw The raw buffer from which to extract text content. + * @param metadata The metadata to be associated with the created `Document` instance. + * @returns A promise that resolves to an array of `Document` instances. + */ + private async parseDoc( + raw: Buffer, + metadata: Document["metadata"] + ): Promise { + const WordExtractor = await DocLoaderImports(); + const extractor = new WordExtractor(); + const doc = await extractor.extract(raw); + return [ + new Document({ + pageContent: doc.getBody(), + metadata, + }), + ]; + } } async function DocxLoaderImports() { @@ -53,3 +119,15 @@ async function DocxLoaderImports() { ); } } + +async function DocLoaderImports() { + try { + const WordExtractor = await import("word-extractor"); + return WordExtractor.default; + } catch (e) { + console.error(e); + throw new Error( + "Failed to load word-extractor. Please install it with eg. `npm install word-extractor`." + ); + } +} From 25f64eeb42c44dc1047532d109d14db2538c52b5 Mon Sep 17 00:00:00 2001 From: Fibi Date: Mon, 23 Dec 2024 03:38:55 +0100 Subject: [PATCH 3/5] add .doc loader test --- .../src/document_loaders/tests/docx.test.ts | 16 +++++++++++++++- .../tests/example_data/attention.doc | Bin 0 -> 56832 bytes 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 libs/langchain-community/src/document_loaders/tests/example_data/attention.doc diff --git a/libs/langchain-community/src/document_loaders/tests/docx.test.ts b/libs/langchain-community/src/document_loaders/tests/docx.test.ts index 63395bb51bc0..82e66aa91907 100644 --- a/libs/langchain-community/src/document_loaders/tests/docx.test.ts +++ b/libs/langchain-community/src/document_loaders/tests/docx.test.ts @@ -3,7 +3,7 @@ import * as url from "node:url"; import * as path from "node:path"; import { DocxLoader } from "../fs/docx.js"; -test("Test Word doc loader from file", async () => { +test("Test Word doc loader from .docx file", async () => { const filePath = path.resolve( path.dirname(url.fileURLToPath(import.meta.url)), "./example_data/attention.docx" @@ -14,3 +14,17 @@ test("Test Word doc loader from file", async () => { expect(docs.length).toBe(1); // not much text in the example expect(docs[0].pageContent).toContain("an interesting activity"); }); + +test("Test Word doc loader from .doc file", async () => { + const filePath = path.resolve( + path.dirname(url.fileURLToPath(import.meta.url)), + "./example_data/attention.doc" + ); + const loader = new DocxLoader(filePath, { + type: "doc", + }); + const docs = await loader.load(); + + expect(docs.length).toBe(1); // not much text in the example + expect(docs[0].pageContent).toContain("an interesting activity"); +}); diff --git a/libs/langchain-community/src/document_loaders/tests/example_data/attention.doc b/libs/langchain-community/src/document_loaders/tests/example_data/attention.doc new file mode 100644 index 0000000000000000000000000000000000000000..e68399c5a7c86d6c165d989fc7e02566984b2920 GIT binary patch literal 56832 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 SAHF{hEuwrJ`N@rH`~L- Date: Mon, 23 Dec 2024 03:39:34 +0100 Subject: [PATCH 4/5] update docx docs --- .../document_loaders/file_loaders/docx.mdx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/core_docs/docs/integrations/document_loaders/file_loaders/docx.mdx b/docs/core_docs/docs/integrations/document_loaders/file_loaders/docx.mdx index baaf464a5e5b..86675b3da726 100644 --- a/docs/core_docs/docs/integrations/document_loaders/file_loaders/docx.mdx +++ b/docs/core_docs/docs/integrations/document_loaders/file_loaders/docx.mdx @@ -23,3 +23,28 @@ const loader = new DocxLoader( const docs = await loader.load(); ``` + + +# Doc files + +This example goes over how to load data from doc files. + +# Setup + +```bash npm2yarn +npm install @langchain/community @langchain/core word-extractor +``` + +# Usage + +```typescript +import { DocxLoader } from "@langchain/community/document_loaders/fs/docx"; + +const loader = new DocxLoader( + "src/document_loaders/tests/example_data/attentio.docx", + { + type: "doc", + } +); + +const docs = await loader.load(); From bb1b49929b6f2f477df5b2b8b472620160036825 Mon Sep 17 00:00:00 2001 From: Fibi Date: Thu, 26 Dec 2024 04:11:58 +0100 Subject: [PATCH 5/5] better documentation --- .../document_loaders/file_loaders/docx.mdx | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/docs/core_docs/docs/integrations/document_loaders/file_loaders/docx.mdx b/docs/core_docs/docs/integrations/document_loaders/file_loaders/docx.mdx index 86675b3da726..8e46cde7a1b8 100644 --- a/docs/core_docs/docs/integrations/document_loaders/file_loaders/docx.mdx +++ b/docs/core_docs/docs/integrations/document_loaders/file_loaders/docx.mdx @@ -4,17 +4,38 @@ hide_table_of_contents: true # Docx files -This example goes over how to load data from docx files. +The `DocxLoader` allows you to extract text data from Microsoft Word documents. It supports both the modern `.docx` format and the legacy `.doc` format. Depending on the file type, additional dependencies are required. -# Setup +--- + +## Setup + +To use `DocxLoader`, you'll need the `@langchain/community` integration along with either `mammoth` or `word-extractor` package: + +- **`mammoth`**: For processing `.docx` files. +- **`word-extractor`**: For handling `.doc` files. + +### Installation + +#### For `.docx` Files ```bash npm2yarn npm install @langchain/community @langchain/core mammoth ``` -# Usage +#### For `.doc` Files + +```bash npm2yarn +npm install @langchain/community @langchain/core word-extractor +``` + +## Usage -```typescript +### Loading `.docx` Files + +For `.docx` files, there is no need to explicitly specify any parameters when initializing the loader: + +```javascript import { DocxLoader } from "@langchain/community/document_loaders/fs/docx"; const loader = new DocxLoader( @@ -24,27 +45,19 @@ const loader = new DocxLoader( const docs = await loader.load(); ``` +### Loading `.doc` Files -# Doc files - -This example goes over how to load data from doc files. - -# Setup - -```bash npm2yarn -npm install @langchain/community @langchain/core word-extractor -``` +For `.doc` files, you must explicitly specify the `type` as `doc` when initializing the loader: -# Usage - -```typescript +```javascript import { DocxLoader } from "@langchain/community/document_loaders/fs/docx"; const loader = new DocxLoader( - "src/document_loaders/tests/example_data/attentio.docx", + "src/document_loaders/tests/example_data/attention.doc", { type: "doc", } ); const docs = await loader.load(); +```