@xberg-io/langchain-xberg 1.0.3 → 1.0.8
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/README.md +3 -3
- package/dist/index.cjs +6 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
A [LangChain.js](https://js.langchain.com) document loader for [Xberg](https://github.com/xberg-io/xberg).
|
|
13
13
|
Point it at a file, a directory, or raw bytes and it returns LangChain `Document`s with the extracted
|
|
14
|
-
text, tables, and rich metadata from
|
|
14
|
+
text, tables, and rich metadata from 101 document formats — with optional OCR for scans and images.
|
|
15
15
|
|
|
16
16
|
Extraction runs locally in-process through the `@xberg-io/xberg` native binding. No API key, no cloud
|
|
17
17
|
call, no data leaves your machine.
|
|
@@ -69,13 +69,13 @@ const pages = await loader.load(); // metadata.page is 0-indexed
|
|
|
69
69
|
|
|
70
70
|
## Supported formats
|
|
71
71
|
|
|
72
|
-
Xberg extracts from
|
|
72
|
+
Xberg extracts from 101 formats including PDF, DOCX, PPTX, XLSX, HTML, EPUB, images, and more. See the
|
|
73
73
|
[Xberg documentation](https://docs.xberg.io) for the full list and the extraction configuration
|
|
74
74
|
reference.
|
|
75
75
|
|
|
76
76
|
## Part of Xberg.io
|
|
77
77
|
|
|
78
|
-
- [Xberg](https://github.com/xberg-io/xberg) — document intelligence: text, tables, metadata from
|
|
78
|
+
- [Xberg](https://github.com/xberg-io/xberg) — document intelligence: text, tables, metadata from 101 formats with optional OCR.
|
|
79
79
|
- [Xberg Enterprise](https://github.com/xberg-io/xberg-enterprise) — managed extraction API with SDKs, dashboards, and observability.
|
|
80
80
|
|
|
81
81
|
## License
|
package/dist/index.cjs
CHANGED
|
@@ -243,11 +243,15 @@ var XbergLoader = class extends import_base.BaseDocumentLoader {
|
|
|
243
243
|
async buildInputs() {
|
|
244
244
|
if (this.data !== void 0) {
|
|
245
245
|
const source = `bytes://${this.mimeType}`;
|
|
246
|
-
const input = { kind:
|
|
246
|
+
const input = { kind: import_xberg.ExtractInputKind.Bytes, bytes: this.data, mimeType: this.mimeType };
|
|
247
247
|
return { inputs: [input], sources: [source], batch: false };
|
|
248
248
|
}
|
|
249
249
|
const { paths, batch } = await this.resolvePaths();
|
|
250
|
-
const inputs = paths.map((path) => ({
|
|
250
|
+
const inputs = paths.map((path) => ({
|
|
251
|
+
kind: import_xberg.ExtractInputKind.Uri,
|
|
252
|
+
uri: path,
|
|
253
|
+
mimeType: this.mimeType
|
|
254
|
+
}));
|
|
251
255
|
return { inputs, sources: paths, batch };
|
|
252
256
|
}
|
|
253
257
|
async resolvePaths() {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/loader.ts","../src/mapping.ts"],"sourcesContent":["export { XbergLoader, type XbergLoaderOptions } from \"./loader\";\n","import { stat } from \"node:fs/promises\";\nimport { BaseDocumentLoader } from \"@langchain/core/document_loaders/base\";\nimport type { Document } from \"@langchain/core/documents\";\nimport { extract, extractBatch } from \"@xberg-io/xberg\";\nimport type { ExtractInput, ExtractionConfig } from \"@xberg-io/xberg\";\nimport fastGlob from \"fast-glob\";\nimport { isChunkingEnabled, isPerPageEnabled, resultToDocuments, type ResultEnvelope } from \"./mapping\";\n\nconst DEFAULT_GLOB = \"**/*\";\n\nexport interface XbergLoaderOptions {\n /** File path, list of file paths, or directory path to load. */\n filePath?: string | string[];\n /** Raw bytes to extract from. Mutually exclusive with `filePath`. */\n data?: Uint8Array;\n /** MIME type hint. Required when using `data`, optional for `filePath`. */\n mimeType?: string;\n /** Glob pattern for directory mode. Defaults to matching all files. */\n glob?: string;\n /** Xberg extraction configuration controlling output format, OCR, pages, chunking, etc. */\n config?: ExtractionConfig;\n}\n\n/**\n * Load documents using Xberg, supporting 90+ file formats with true async extraction.\n *\n * By default each source becomes one Document. Enable `chunking` on the\n * `ExtractionConfig` to emit one Document per chunk, or `pages` for one Document\n * per page. Multiple paths (a list or a directory glob) are extracted with a single\n * `extractBatch` call so concurrency happens Rust-side.\n */\nexport class XbergLoader extends BaseDocumentLoader {\n private readonly filePath?: string | string[];\n private readonly data?: Uint8Array;\n private readonly mimeType?: string;\n private readonly glob?: string;\n private readonly config?: ExtractionConfig;\n\n constructor(options: XbergLoaderOptions) {\n super();\n const { filePath, data, mimeType, glob, config } = options;\n if (filePath === undefined && data === undefined) {\n throw new Error(\"Either 'filePath' or 'data' must be provided.\");\n }\n if (filePath !== undefined && data !== undefined) {\n throw new Error(\"Cannot specify both 'filePath' and 'data'. Use one or the other.\");\n }\n if (data !== undefined && mimeType === undefined) {\n throw new Error(\"'mimeType' is required when using 'data'.\");\n }\n\n this.filePath = filePath;\n this.data = data;\n this.mimeType = mimeType;\n this.glob = glob;\n this.config = config;\n }\n\n async load(): Promise<Document[]> {\n const { inputs, sources, batch } = await this.buildInputs();\n if (inputs.length === 0) {\n return [];\n }\n\n let result;\n try {\n result = batch ? await extractBatch(inputs, this.config ?? null) : await extract(inputs[0], this.config ?? null);\n } catch (error) {\n const source = sources[0] ?? \"input\";\n throw new Error(`Failed to extract '${source}': ${errorMessage(error)}`);\n }\n\n return resultToDocuments(result as unknown as ResultEnvelope, sources, {\n chunking: isChunkingEnabled(this.config),\n perPage: isPerPageEnabled(this.config),\n });\n }\n\n private async buildInputs(): Promise<{ inputs: ExtractInput[]; sources: string[]; batch: boolean }> {\n if (this.data !== undefined) {\n const source = `bytes://${this.mimeType}`;\n const input: ExtractInput = { kind: \"bytes\", bytes: this.data, mimeType: this.mimeType };\n return { inputs: [input], sources: [source], batch: false };\n }\n\n const { paths, batch } = await this.resolvePaths();\n const inputs: ExtractInput[] = paths.map((path) => ({ kind: \"uri\", uri: path, mimeType: this.mimeType }));\n return { inputs, sources: paths, batch };\n }\n\n private async resolvePaths(): Promise<{ paths: string[]; batch: boolean }> {\n const filePath = this.filePath;\n if (Array.isArray(filePath)) {\n return { paths: filePath, batch: true };\n }\n if (typeof filePath === \"string\") {\n if (await isDirectory(filePath)) {\n const pattern = this.glob ?? DEFAULT_GLOB;\n const matches = await fastGlob(pattern, { cwd: filePath, onlyFiles: true, absolute: true });\n return { paths: matches.sort(), batch: true };\n }\n return { paths: [filePath], batch: false };\n }\n return { paths: [], batch: false };\n }\n}\n\nasync function isDirectory(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import { Document } from \"@langchain/core/documents\";\nimport type { DocumentCounts, ExtractionConfig, Keyword, Metadata, ProcessingWarning, Table } from \"@xberg-io/xberg\";\n\n// Metadata fields (from Xberg Metadata) that carry JSON-friendly scalar/list values,\n// mapped from the binding's camelCase keys to the snake_case output keys used by the\n// Python adapter. Opaque nested fields (pages, format, imagePreprocessing, jsonSchema,\n// error) are skipped because they are native objects, not plain data. ~keep\nconst METADATA_FIELDS: ReadonlyArray<readonly [string, keyof Metadata]> = [\n [\"title\", \"title\"],\n [\"subject\", \"subject\"],\n [\"authors\", \"authors\"],\n [\"keywords\", \"keywords\"],\n [\"language\", \"language\"],\n [\"created_at\", \"createdAt\"],\n [\"modified_at\", \"modifiedAt\"],\n [\"created_by\", \"createdBy\"],\n [\"modified_by\", \"modifiedBy\"],\n [\"category\", \"category\"],\n [\"tags\", \"tags\"],\n [\"document_version\", \"documentVersion\"],\n [\"abstract_text\", \"abstractText\"],\n [\"output_format\", \"outputFormat\"],\n [\"ocr_used\", \"ocrUsed\"],\n [\"extraction_duration_ms\", \"extractionDurationMs\"],\n];\n\nconst CONTENT_SEPARATOR = \"\\n\\n\";\n\nexport interface ChunkMetadataShape {\n chunkIndex: number;\n totalChunks: number;\n headingPath?: string[];\n tokenCount?: number;\n firstPage?: number;\n lastPage?: number;\n}\n\nexport interface ChunkShape {\n content: string;\n chunkType: unknown;\n metadata: ChunkMetadataShape;\n}\n\nexport interface PageShape {\n pageNumber: number;\n content: string;\n tables?: Table[];\n isBlank?: boolean;\n}\n\n// Structural view of a binding ExtractedDocument. The binding types its own fields\n// through unexported `Js*` aliases; this interface uses the clean exported types plus\n// local chunk/page shapes so the mapper is fully typed and testable without the addon. ~keep\nexport interface ExtractedDoc {\n content?: string;\n mimeType?: string;\n metadata?: Metadata;\n tables?: Table[];\n counts?: DocumentCounts;\n detectedLanguages?: string[];\n chunks?: ChunkShape[];\n pages?: PageShape[];\n extractedKeywords?: Keyword[];\n qualityScore?: number;\n processingWarnings?: ProcessingWarning[];\n}\n\nexport interface ResultEnvelope {\n errors?: Array<{ source: string; message: string }>;\n results?: ExtractedDoc[];\n}\n\nexport interface SplitOptions {\n chunking: boolean;\n perPage: boolean;\n}\n\nexport function isChunkingEnabled(config?: ExtractionConfig | null): boolean {\n return config?.chunking != null;\n}\n\nexport function isPerPageEnabled(config?: ExtractionConfig | null): boolean {\n return Boolean(config?.pages?.extractPages);\n}\n\nexport function flattenMetadata(metadata?: Metadata): Record<string, unknown> {\n const flat: Record<string, unknown> = {};\n if (!metadata) {\n return flat;\n }\n\n for (const [snakeKey, camelKey] of METADATA_FIELDS) {\n const value = metadata[camelKey];\n if (value != null) {\n flat[snakeKey] = value;\n }\n }\n\n const additional = metadata.additional;\n if (additional && Object.keys(additional).length > 0) {\n flat.additional = { ...additional };\n }\n\n return flat;\n}\n\nexport function assembleContent(content: string | undefined, tables: Table[] | undefined): string {\n const text = content ?? \"\";\n if (!tables || tables.length === 0) {\n return text;\n }\n const parts = tables.map((table) => table.markdown ?? \"\").filter((markdown) => markdown.length > 0);\n if (parts.length === 0) {\n return text;\n }\n return [text, ...parts].join(CONTENT_SEPARATOR);\n}\n\nexport function buildMetadata(document: ExtractedDoc, source: string): Record<string, unknown> {\n const metadata = flattenMetadata(document.metadata);\n\n metadata.mime_type = document.mimeType;\n if (document.qualityScore != null) {\n metadata.quality_score = document.qualityScore;\n }\n if (document.detectedLanguages && document.detectedLanguages.length > 0) {\n metadata.detected_languages = document.detectedLanguages;\n }\n if (document.counts != null) {\n metadata.page_count = document.counts.pages;\n }\n\n if (document.extractedKeywords && document.extractedKeywords.length > 0) {\n metadata.extracted_keywords = document.extractedKeywords.map((keyword) => ({\n text: keyword.text,\n score: keyword.score,\n algorithm: String(keyword.algorithm),\n }));\n }\n\n const tables = document.tables ?? [];\n metadata.table_count = tables.length;\n if (tables.length > 0) {\n metadata.tables = tables.map((table) => ({\n cells: table.cells,\n markdown: table.markdown,\n page_number: table.pageNumber,\n }));\n }\n\n if (document.processingWarnings && document.processingWarnings.length > 0) {\n metadata.processing_warnings = document.processingWarnings.map((warning) => ({\n source: warning.source,\n message: warning.message,\n }));\n }\n\n metadata.source = source;\n return metadata;\n}\n\nfunction chunksToDocuments(document: ExtractedDoc, source: string): Document[] {\n const baseMetadata = buildMetadata(document, source);\n const documents: Document[] = [];\n\n for (const chunk of document.chunks ?? []) {\n const metadata: Record<string, unknown> = { ...baseMetadata };\n const chunkMetadata = chunk.metadata;\n metadata.chunk_index = chunkMetadata.chunkIndex;\n metadata.total_chunks = chunkMetadata.totalChunks;\n metadata.chunk_type = String(chunk.chunkType);\n if (chunkMetadata.headingPath && chunkMetadata.headingPath.length > 0) {\n metadata.heading_path = [...chunkMetadata.headingPath];\n }\n if (chunkMetadata.tokenCount != null) {\n metadata.token_count = chunkMetadata.tokenCount;\n }\n if (chunkMetadata.firstPage != null) {\n // Xberg uses 1-indexed pages; LangChain convention is 0-indexed. ~keep\n metadata.page = chunkMetadata.firstPage - 1;\n metadata.first_page = chunkMetadata.firstPage;\n }\n if (chunkMetadata.lastPage != null) {\n metadata.last_page = chunkMetadata.lastPage;\n }\n documents.push(new Document({ pageContent: chunk.content, metadata }));\n }\n\n return documents;\n}\n\nfunction pagesToDocuments(document: ExtractedDoc, source: string): Document[] {\n const baseMetadata = buildMetadata(document, source);\n const documents: Document[] = [];\n\n for (const page of document.pages ?? []) {\n const metadata: Record<string, unknown> = { ...baseMetadata };\n // Xberg uses 1-indexed pages; LangChain convention is 0-indexed. ~keep\n metadata.page = page.pageNumber - 1;\n if (page.isBlank != null) {\n metadata.is_blank = page.isBlank;\n }\n const pageContent = assembleContent(page.content, page.tables);\n documents.push(new Document({ pageContent, metadata }));\n }\n\n return documents;\n}\n\nexport function documentToDocuments(document: ExtractedDoc, source: string, options: SplitOptions): Document[] {\n if (options.chunking && document.chunks && document.chunks.length > 0) {\n return chunksToDocuments(document, source);\n }\n if (options.perPage && document.pages && document.pages.length > 0) {\n return pagesToDocuments(document, source);\n }\n const metadata = buildMetadata(document, source);\n const pageContent = assembleContent(document.content, document.tables);\n return [new Document({ pageContent, metadata })];\n}\n\nexport function resultToDocuments(result: ResultEnvelope, sources: string[], options: SplitOptions): Document[] {\n if (result.errors && result.errors.length > 0) {\n const error = result.errors[0];\n throw new Error(`Failed to extract '${error.source}': ${error.message}`);\n }\n\n const documents: Document[] = [];\n const results = result.results ?? [];\n results.forEach((document, index) => {\n const source = sources[index] ?? (sources.length > 0 ? sources[sources.length - 1] : \"\");\n documents.push(...documentToDocuments(document, source, options));\n });\n return documents;\n}\n"],"mappings":"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","names":["fastGlob"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/loader.ts","../src/mapping.ts"],"sourcesContent":["export { XbergLoader, type XbergLoaderOptions } from \"./loader\";\n","import { stat } from \"node:fs/promises\";\nimport { BaseDocumentLoader } from \"@langchain/core/document_loaders/base\";\nimport type { Document } from \"@langchain/core/documents\";\nimport { extract, extractBatch, ExtractInputKind } from \"@xberg-io/xberg\";\nimport type { ExtractInput, ExtractionConfig } from \"@xberg-io/xberg\";\nimport fastGlob from \"fast-glob\";\nimport { isChunkingEnabled, isPerPageEnabled, resultToDocuments, type ResultEnvelope } from \"./mapping\";\n\nconst DEFAULT_GLOB = \"**/*\";\n\nexport interface XbergLoaderOptions {\n /** File path, list of file paths, or directory path to load. */\n filePath?: string | string[];\n /** Raw bytes to extract from. Mutually exclusive with `filePath`. */\n data?: Uint8Array;\n /** MIME type hint. Required when using `data`, optional for `filePath`. */\n mimeType?: string;\n /** Glob pattern for directory mode. Defaults to matching all files. */\n glob?: string;\n /** Xberg extraction configuration controlling output format, OCR, pages, chunking, etc. */\n config?: ExtractionConfig;\n}\n\n/**\n * Load documents using Xberg, supporting 101 file formats with true async extraction.\n *\n * By default each source becomes one Document. Enable `chunking` on the\n * `ExtractionConfig` to emit one Document per chunk, or `pages` for one Document\n * per page. Multiple paths (a list or a directory glob) are extracted with a single\n * `extractBatch` call so concurrency happens Rust-side.\n */\nexport class XbergLoader extends BaseDocumentLoader {\n private readonly filePath?: string | string[];\n private readonly data?: Uint8Array;\n private readonly mimeType?: string;\n private readonly glob?: string;\n private readonly config?: ExtractionConfig;\n\n constructor(options: XbergLoaderOptions) {\n super();\n const { filePath, data, mimeType, glob, config } = options;\n if (filePath === undefined && data === undefined) {\n throw new Error(\"Either 'filePath' or 'data' must be provided.\");\n }\n if (filePath !== undefined && data !== undefined) {\n throw new Error(\"Cannot specify both 'filePath' and 'data'. Use one or the other.\");\n }\n if (data !== undefined && mimeType === undefined) {\n throw new Error(\"'mimeType' is required when using 'data'.\");\n }\n\n this.filePath = filePath;\n this.data = data;\n this.mimeType = mimeType;\n this.glob = glob;\n this.config = config;\n }\n\n async load(): Promise<Document[]> {\n const { inputs, sources, batch } = await this.buildInputs();\n if (inputs.length === 0) {\n return [];\n }\n\n let result;\n try {\n result = batch ? await extractBatch(inputs, this.config ?? null) : await extract(inputs[0], this.config ?? null);\n } catch (error) {\n const source = sources[0] ?? \"input\";\n throw new Error(`Failed to extract '${source}': ${errorMessage(error)}`);\n }\n\n return resultToDocuments(result as unknown as ResultEnvelope, sources, {\n chunking: isChunkingEnabled(this.config),\n perPage: isPerPageEnabled(this.config),\n });\n }\n\n private async buildInputs(): Promise<{ inputs: ExtractInput[]; sources: string[]; batch: boolean }> {\n if (this.data !== undefined) {\n const source = `bytes://${this.mimeType}`;\n const input: ExtractInput = { kind: ExtractInputKind.Bytes, bytes: this.data, mimeType: this.mimeType };\n return { inputs: [input], sources: [source], batch: false };\n }\n\n const { paths, batch } = await this.resolvePaths();\n const inputs: ExtractInput[] = paths.map((path) => ({\n kind: ExtractInputKind.Uri,\n uri: path,\n mimeType: this.mimeType,\n }));\n return { inputs, sources: paths, batch };\n }\n\n private async resolvePaths(): Promise<{ paths: string[]; batch: boolean }> {\n const filePath = this.filePath;\n if (Array.isArray(filePath)) {\n return { paths: filePath, batch: true };\n }\n if (typeof filePath === \"string\") {\n if (await isDirectory(filePath)) {\n const pattern = this.glob ?? DEFAULT_GLOB;\n const matches = await fastGlob(pattern, { cwd: filePath, onlyFiles: true, absolute: true });\n return { paths: matches.sort(), batch: true };\n }\n return { paths: [filePath], batch: false };\n }\n return { paths: [], batch: false };\n }\n}\n\nasync function isDirectory(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import { Document } from \"@langchain/core/documents\";\nimport type { DocumentCounts, ExtractionConfig, Keyword, Metadata, ProcessingWarning, Table } from \"@xberg-io/xberg\";\n\n// Metadata fields (from Xberg Metadata) that carry JSON-friendly scalar/list values,\n// mapped from the binding's camelCase keys to the snake_case output keys used by the\n// Python adapter. Opaque nested fields (pages, format, imagePreprocessing, jsonSchema,\n// error) are skipped because they are native objects, not plain data. ~keep\nconst METADATA_FIELDS: ReadonlyArray<readonly [string, keyof Metadata]> = [\n [\"title\", \"title\"],\n [\"subject\", \"subject\"],\n [\"authors\", \"authors\"],\n [\"keywords\", \"keywords\"],\n [\"language\", \"language\"],\n [\"created_at\", \"createdAt\"],\n [\"modified_at\", \"modifiedAt\"],\n [\"created_by\", \"createdBy\"],\n [\"modified_by\", \"modifiedBy\"],\n [\"category\", \"category\"],\n [\"tags\", \"tags\"],\n [\"document_version\", \"documentVersion\"],\n [\"abstract_text\", \"abstractText\"],\n [\"output_format\", \"outputFormat\"],\n [\"ocr_used\", \"ocrUsed\"],\n [\"extraction_duration_ms\", \"extractionDurationMs\"],\n];\n\nconst CONTENT_SEPARATOR = \"\\n\\n\";\n\nexport interface ChunkMetadataShape {\n chunkIndex: number;\n totalChunks: number;\n headingPath?: string[];\n tokenCount?: number;\n firstPage?: number;\n lastPage?: number;\n}\n\nexport interface ChunkShape {\n content: string;\n chunkType: unknown;\n metadata: ChunkMetadataShape;\n}\n\nexport interface PageShape {\n pageNumber: number;\n content: string;\n tables?: Table[];\n isBlank?: boolean;\n}\n\n// Structural view of a binding ExtractedDocument. The binding types its own fields\n// through unexported `Js*` aliases; this interface uses the clean exported types plus\n// local chunk/page shapes so the mapper is fully typed and testable without the addon. ~keep\nexport interface ExtractedDoc {\n content?: string;\n mimeType?: string;\n metadata?: Metadata;\n tables?: Table[];\n counts?: DocumentCounts;\n detectedLanguages?: string[];\n chunks?: ChunkShape[];\n pages?: PageShape[];\n extractedKeywords?: Keyword[];\n qualityScore?: number;\n processingWarnings?: ProcessingWarning[];\n}\n\nexport interface ResultEnvelope {\n errors?: Array<{ source: string; message: string }>;\n results?: ExtractedDoc[];\n}\n\nexport interface SplitOptions {\n chunking: boolean;\n perPage: boolean;\n}\n\nexport function isChunkingEnabled(config?: ExtractionConfig | null): boolean {\n return config?.chunking != null;\n}\n\nexport function isPerPageEnabled(config?: ExtractionConfig | null): boolean {\n return Boolean(config?.pages?.extractPages);\n}\n\nexport function flattenMetadata(metadata?: Metadata): Record<string, unknown> {\n const flat: Record<string, unknown> = {};\n if (!metadata) {\n return flat;\n }\n\n for (const [snakeKey, camelKey] of METADATA_FIELDS) {\n const value = metadata[camelKey];\n if (value != null) {\n flat[snakeKey] = value;\n }\n }\n\n const additional = metadata.additional;\n if (additional && Object.keys(additional).length > 0) {\n flat.additional = { ...additional };\n }\n\n return flat;\n}\n\nexport function assembleContent(content: string | undefined, tables: Table[] | undefined): string {\n const text = content ?? \"\";\n if (!tables || tables.length === 0) {\n return text;\n }\n const parts = tables.map((table) => table.markdown ?? \"\").filter((markdown) => markdown.length > 0);\n if (parts.length === 0) {\n return text;\n }\n return [text, ...parts].join(CONTENT_SEPARATOR);\n}\n\nexport function buildMetadata(document: ExtractedDoc, source: string): Record<string, unknown> {\n const metadata = flattenMetadata(document.metadata);\n\n metadata.mime_type = document.mimeType;\n if (document.qualityScore != null) {\n metadata.quality_score = document.qualityScore;\n }\n if (document.detectedLanguages && document.detectedLanguages.length > 0) {\n metadata.detected_languages = document.detectedLanguages;\n }\n if (document.counts != null) {\n metadata.page_count = document.counts.pages;\n }\n\n if (document.extractedKeywords && document.extractedKeywords.length > 0) {\n metadata.extracted_keywords = document.extractedKeywords.map((keyword) => ({\n text: keyword.text,\n score: keyword.score,\n algorithm: String(keyword.algorithm),\n }));\n }\n\n const tables = document.tables ?? [];\n metadata.table_count = tables.length;\n if (tables.length > 0) {\n metadata.tables = tables.map((table) => ({\n cells: table.cells,\n markdown: table.markdown,\n page_number: table.pageNumber,\n }));\n }\n\n if (document.processingWarnings && document.processingWarnings.length > 0) {\n metadata.processing_warnings = document.processingWarnings.map((warning) => ({\n source: warning.source,\n message: warning.message,\n }));\n }\n\n metadata.source = source;\n return metadata;\n}\n\nfunction chunksToDocuments(document: ExtractedDoc, source: string): Document[] {\n const baseMetadata = buildMetadata(document, source);\n const documents: Document[] = [];\n\n for (const chunk of document.chunks ?? []) {\n const metadata: Record<string, unknown> = { ...baseMetadata };\n const chunkMetadata = chunk.metadata;\n metadata.chunk_index = chunkMetadata.chunkIndex;\n metadata.total_chunks = chunkMetadata.totalChunks;\n metadata.chunk_type = String(chunk.chunkType);\n if (chunkMetadata.headingPath && chunkMetadata.headingPath.length > 0) {\n metadata.heading_path = [...chunkMetadata.headingPath];\n }\n if (chunkMetadata.tokenCount != null) {\n metadata.token_count = chunkMetadata.tokenCount;\n }\n if (chunkMetadata.firstPage != null) {\n // Xberg uses 1-indexed pages; LangChain convention is 0-indexed. ~keep\n metadata.page = chunkMetadata.firstPage - 1;\n metadata.first_page = chunkMetadata.firstPage;\n }\n if (chunkMetadata.lastPage != null) {\n metadata.last_page = chunkMetadata.lastPage;\n }\n documents.push(new Document({ pageContent: chunk.content, metadata }));\n }\n\n return documents;\n}\n\nfunction pagesToDocuments(document: ExtractedDoc, source: string): Document[] {\n const baseMetadata = buildMetadata(document, source);\n const documents: Document[] = [];\n\n for (const page of document.pages ?? []) {\n const metadata: Record<string, unknown> = { ...baseMetadata };\n // Xberg uses 1-indexed pages; LangChain convention is 0-indexed. ~keep\n metadata.page = page.pageNumber - 1;\n if (page.isBlank != null) {\n metadata.is_blank = page.isBlank;\n }\n const pageContent = assembleContent(page.content, page.tables);\n documents.push(new Document({ pageContent, metadata }));\n }\n\n return documents;\n}\n\nexport function documentToDocuments(document: ExtractedDoc, source: string, options: SplitOptions): Document[] {\n if (options.chunking && document.chunks && document.chunks.length > 0) {\n return chunksToDocuments(document, source);\n }\n if (options.perPage && document.pages && document.pages.length > 0) {\n return pagesToDocuments(document, source);\n }\n const metadata = buildMetadata(document, source);\n const pageContent = assembleContent(document.content, document.tables);\n return [new Document({ pageContent, metadata })];\n}\n\nexport function resultToDocuments(result: ResultEnvelope, sources: string[], options: SplitOptions): Document[] {\n if (result.errors && result.errors.length > 0) {\n const error = result.errors[0];\n throw new Error(`Failed to extract '${error.source}': ${error.message}`);\n }\n\n const documents: Document[] = [];\n const results = result.results ?? [];\n results.forEach((document, index) => {\n const source = sources[index] ?? (sources.length > 0 ? sources[sources.length - 1] : \"\");\n documents.push(...documentToDocuments(document, source, options));\n });\n return documents;\n}\n"],"mappings":"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","names":["fastGlob"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -15,7 +15,7 @@ interface XbergLoaderOptions {
|
|
|
15
15
|
config?: ExtractionConfig;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* Load documents using Xberg, supporting
|
|
18
|
+
* Load documents using Xberg, supporting 101 file formats with true async extraction.
|
|
19
19
|
*
|
|
20
20
|
* By default each source becomes one Document. Enable `chunking` on the
|
|
21
21
|
* `ExtractionConfig` to emit one Document per chunk, or `pages` for one Document
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ interface XbergLoaderOptions {
|
|
|
15
15
|
config?: ExtractionConfig;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* Load documents using Xberg, supporting
|
|
18
|
+
* Load documents using Xberg, supporting 101 file formats with true async extraction.
|
|
19
19
|
*
|
|
20
20
|
* By default each source becomes one Document. Enable `chunking` on the
|
|
21
21
|
* `ExtractionConfig` to emit one Document per chunk, or `pages` for one Document
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/loader.ts
|
|
2
2
|
import { stat } from "fs/promises";
|
|
3
3
|
import { BaseDocumentLoader } from "@langchain/core/document_loaders/base";
|
|
4
|
-
import { extract, extractBatch } from "@xberg-io/xberg";
|
|
4
|
+
import { extract, extractBatch, ExtractInputKind } from "@xberg-io/xberg";
|
|
5
5
|
import fastGlob from "fast-glob";
|
|
6
6
|
|
|
7
7
|
// src/mapping.ts
|
|
@@ -207,11 +207,15 @@ var XbergLoader = class extends BaseDocumentLoader {
|
|
|
207
207
|
async buildInputs() {
|
|
208
208
|
if (this.data !== void 0) {
|
|
209
209
|
const source = `bytes://${this.mimeType}`;
|
|
210
|
-
const input = { kind:
|
|
210
|
+
const input = { kind: ExtractInputKind.Bytes, bytes: this.data, mimeType: this.mimeType };
|
|
211
211
|
return { inputs: [input], sources: [source], batch: false };
|
|
212
212
|
}
|
|
213
213
|
const { paths, batch } = await this.resolvePaths();
|
|
214
|
-
const inputs = paths.map((path) => ({
|
|
214
|
+
const inputs = paths.map((path) => ({
|
|
215
|
+
kind: ExtractInputKind.Uri,
|
|
216
|
+
uri: path,
|
|
217
|
+
mimeType: this.mimeType
|
|
218
|
+
}));
|
|
215
219
|
return { inputs, sources: paths, batch };
|
|
216
220
|
}
|
|
217
221
|
async resolvePaths() {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/loader.ts","../src/mapping.ts"],"sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { BaseDocumentLoader } from \"@langchain/core/document_loaders/base\";\nimport type { Document } from \"@langchain/core/documents\";\nimport { extract, extractBatch } from \"@xberg-io/xberg\";\nimport type { ExtractInput, ExtractionConfig } from \"@xberg-io/xberg\";\nimport fastGlob from \"fast-glob\";\nimport { isChunkingEnabled, isPerPageEnabled, resultToDocuments, type ResultEnvelope } from \"./mapping\";\n\nconst DEFAULT_GLOB = \"**/*\";\n\nexport interface XbergLoaderOptions {\n /** File path, list of file paths, or directory path to load. */\n filePath?: string | string[];\n /** Raw bytes to extract from. Mutually exclusive with `filePath`. */\n data?: Uint8Array;\n /** MIME type hint. Required when using `data`, optional for `filePath`. */\n mimeType?: string;\n /** Glob pattern for directory mode. Defaults to matching all files. */\n glob?: string;\n /** Xberg extraction configuration controlling output format, OCR, pages, chunking, etc. */\n config?: ExtractionConfig;\n}\n\n/**\n * Load documents using Xberg, supporting 90+ file formats with true async extraction.\n *\n * By default each source becomes one Document. Enable `chunking` on the\n * `ExtractionConfig` to emit one Document per chunk, or `pages` for one Document\n * per page. Multiple paths (a list or a directory glob) are extracted with a single\n * `extractBatch` call so concurrency happens Rust-side.\n */\nexport class XbergLoader extends BaseDocumentLoader {\n private readonly filePath?: string | string[];\n private readonly data?: Uint8Array;\n private readonly mimeType?: string;\n private readonly glob?: string;\n private readonly config?: ExtractionConfig;\n\n constructor(options: XbergLoaderOptions) {\n super();\n const { filePath, data, mimeType, glob, config } = options;\n if (filePath === undefined && data === undefined) {\n throw new Error(\"Either 'filePath' or 'data' must be provided.\");\n }\n if (filePath !== undefined && data !== undefined) {\n throw new Error(\"Cannot specify both 'filePath' and 'data'. Use one or the other.\");\n }\n if (data !== undefined && mimeType === undefined) {\n throw new Error(\"'mimeType' is required when using 'data'.\");\n }\n\n this.filePath = filePath;\n this.data = data;\n this.mimeType = mimeType;\n this.glob = glob;\n this.config = config;\n }\n\n async load(): Promise<Document[]> {\n const { inputs, sources, batch } = await this.buildInputs();\n if (inputs.length === 0) {\n return [];\n }\n\n let result;\n try {\n result = batch ? await extractBatch(inputs, this.config ?? null) : await extract(inputs[0], this.config ?? null);\n } catch (error) {\n const source = sources[0] ?? \"input\";\n throw new Error(`Failed to extract '${source}': ${errorMessage(error)}`);\n }\n\n return resultToDocuments(result as unknown as ResultEnvelope, sources, {\n chunking: isChunkingEnabled(this.config),\n perPage: isPerPageEnabled(this.config),\n });\n }\n\n private async buildInputs(): Promise<{ inputs: ExtractInput[]; sources: string[]; batch: boolean }> {\n if (this.data !== undefined) {\n const source = `bytes://${this.mimeType}`;\n const input: ExtractInput = { kind: \"bytes\", bytes: this.data, mimeType: this.mimeType };\n return { inputs: [input], sources: [source], batch: false };\n }\n\n const { paths, batch } = await this.resolvePaths();\n const inputs: ExtractInput[] = paths.map((path) => ({ kind: \"uri\", uri: path, mimeType: this.mimeType }));\n return { inputs, sources: paths, batch };\n }\n\n private async resolvePaths(): Promise<{ paths: string[]; batch: boolean }> {\n const filePath = this.filePath;\n if (Array.isArray(filePath)) {\n return { paths: filePath, batch: true };\n }\n if (typeof filePath === \"string\") {\n if (await isDirectory(filePath)) {\n const pattern = this.glob ?? DEFAULT_GLOB;\n const matches = await fastGlob(pattern, { cwd: filePath, onlyFiles: true, absolute: true });\n return { paths: matches.sort(), batch: true };\n }\n return { paths: [filePath], batch: false };\n }\n return { paths: [], batch: false };\n }\n}\n\nasync function isDirectory(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import { Document } from \"@langchain/core/documents\";\nimport type { DocumentCounts, ExtractionConfig, Keyword, Metadata, ProcessingWarning, Table } from \"@xberg-io/xberg\";\n\n// Metadata fields (from Xberg Metadata) that carry JSON-friendly scalar/list values,\n// mapped from the binding's camelCase keys to the snake_case output keys used by the\n// Python adapter. Opaque nested fields (pages, format, imagePreprocessing, jsonSchema,\n// error) are skipped because they are native objects, not plain data. ~keep\nconst METADATA_FIELDS: ReadonlyArray<readonly [string, keyof Metadata]> = [\n [\"title\", \"title\"],\n [\"subject\", \"subject\"],\n [\"authors\", \"authors\"],\n [\"keywords\", \"keywords\"],\n [\"language\", \"language\"],\n [\"created_at\", \"createdAt\"],\n [\"modified_at\", \"modifiedAt\"],\n [\"created_by\", \"createdBy\"],\n [\"modified_by\", \"modifiedBy\"],\n [\"category\", \"category\"],\n [\"tags\", \"tags\"],\n [\"document_version\", \"documentVersion\"],\n [\"abstract_text\", \"abstractText\"],\n [\"output_format\", \"outputFormat\"],\n [\"ocr_used\", \"ocrUsed\"],\n [\"extraction_duration_ms\", \"extractionDurationMs\"],\n];\n\nconst CONTENT_SEPARATOR = \"\\n\\n\";\n\nexport interface ChunkMetadataShape {\n chunkIndex: number;\n totalChunks: number;\n headingPath?: string[];\n tokenCount?: number;\n firstPage?: number;\n lastPage?: number;\n}\n\nexport interface ChunkShape {\n content: string;\n chunkType: unknown;\n metadata: ChunkMetadataShape;\n}\n\nexport interface PageShape {\n pageNumber: number;\n content: string;\n tables?: Table[];\n isBlank?: boolean;\n}\n\n// Structural view of a binding ExtractedDocument. The binding types its own fields\n// through unexported `Js*` aliases; this interface uses the clean exported types plus\n// local chunk/page shapes so the mapper is fully typed and testable without the addon. ~keep\nexport interface ExtractedDoc {\n content?: string;\n mimeType?: string;\n metadata?: Metadata;\n tables?: Table[];\n counts?: DocumentCounts;\n detectedLanguages?: string[];\n chunks?: ChunkShape[];\n pages?: PageShape[];\n extractedKeywords?: Keyword[];\n qualityScore?: number;\n processingWarnings?: ProcessingWarning[];\n}\n\nexport interface ResultEnvelope {\n errors?: Array<{ source: string; message: string }>;\n results?: ExtractedDoc[];\n}\n\nexport interface SplitOptions {\n chunking: boolean;\n perPage: boolean;\n}\n\nexport function isChunkingEnabled(config?: ExtractionConfig | null): boolean {\n return config?.chunking != null;\n}\n\nexport function isPerPageEnabled(config?: ExtractionConfig | null): boolean {\n return Boolean(config?.pages?.extractPages);\n}\n\nexport function flattenMetadata(metadata?: Metadata): Record<string, unknown> {\n const flat: Record<string, unknown> = {};\n if (!metadata) {\n return flat;\n }\n\n for (const [snakeKey, camelKey] of METADATA_FIELDS) {\n const value = metadata[camelKey];\n if (value != null) {\n flat[snakeKey] = value;\n }\n }\n\n const additional = metadata.additional;\n if (additional && Object.keys(additional).length > 0) {\n flat.additional = { ...additional };\n }\n\n return flat;\n}\n\nexport function assembleContent(content: string | undefined, tables: Table[] | undefined): string {\n const text = content ?? \"\";\n if (!tables || tables.length === 0) {\n return text;\n }\n const parts = tables.map((table) => table.markdown ?? \"\").filter((markdown) => markdown.length > 0);\n if (parts.length === 0) {\n return text;\n }\n return [text, ...parts].join(CONTENT_SEPARATOR);\n}\n\nexport function buildMetadata(document: ExtractedDoc, source: string): Record<string, unknown> {\n const metadata = flattenMetadata(document.metadata);\n\n metadata.mime_type = document.mimeType;\n if (document.qualityScore != null) {\n metadata.quality_score = document.qualityScore;\n }\n if (document.detectedLanguages && document.detectedLanguages.length > 0) {\n metadata.detected_languages = document.detectedLanguages;\n }\n if (document.counts != null) {\n metadata.page_count = document.counts.pages;\n }\n\n if (document.extractedKeywords && document.extractedKeywords.length > 0) {\n metadata.extracted_keywords = document.extractedKeywords.map((keyword) => ({\n text: keyword.text,\n score: keyword.score,\n algorithm: String(keyword.algorithm),\n }));\n }\n\n const tables = document.tables ?? [];\n metadata.table_count = tables.length;\n if (tables.length > 0) {\n metadata.tables = tables.map((table) => ({\n cells: table.cells,\n markdown: table.markdown,\n page_number: table.pageNumber,\n }));\n }\n\n if (document.processingWarnings && document.processingWarnings.length > 0) {\n metadata.processing_warnings = document.processingWarnings.map((warning) => ({\n source: warning.source,\n message: warning.message,\n }));\n }\n\n metadata.source = source;\n return metadata;\n}\n\nfunction chunksToDocuments(document: ExtractedDoc, source: string): Document[] {\n const baseMetadata = buildMetadata(document, source);\n const documents: Document[] = [];\n\n for (const chunk of document.chunks ?? []) {\n const metadata: Record<string, unknown> = { ...baseMetadata };\n const chunkMetadata = chunk.metadata;\n metadata.chunk_index = chunkMetadata.chunkIndex;\n metadata.total_chunks = chunkMetadata.totalChunks;\n metadata.chunk_type = String(chunk.chunkType);\n if (chunkMetadata.headingPath && chunkMetadata.headingPath.length > 0) {\n metadata.heading_path = [...chunkMetadata.headingPath];\n }\n if (chunkMetadata.tokenCount != null) {\n metadata.token_count = chunkMetadata.tokenCount;\n }\n if (chunkMetadata.firstPage != null) {\n // Xberg uses 1-indexed pages; LangChain convention is 0-indexed. ~keep\n metadata.page = chunkMetadata.firstPage - 1;\n metadata.first_page = chunkMetadata.firstPage;\n }\n if (chunkMetadata.lastPage != null) {\n metadata.last_page = chunkMetadata.lastPage;\n }\n documents.push(new Document({ pageContent: chunk.content, metadata }));\n }\n\n return documents;\n}\n\nfunction pagesToDocuments(document: ExtractedDoc, source: string): Document[] {\n const baseMetadata = buildMetadata(document, source);\n const documents: Document[] = [];\n\n for (const page of document.pages ?? []) {\n const metadata: Record<string, unknown> = { ...baseMetadata };\n // Xberg uses 1-indexed pages; LangChain convention is 0-indexed. ~keep\n metadata.page = page.pageNumber - 1;\n if (page.isBlank != null) {\n metadata.is_blank = page.isBlank;\n }\n const pageContent = assembleContent(page.content, page.tables);\n documents.push(new Document({ pageContent, metadata }));\n }\n\n return documents;\n}\n\nexport function documentToDocuments(document: ExtractedDoc, source: string, options: SplitOptions): Document[] {\n if (options.chunking && document.chunks && document.chunks.length > 0) {\n return chunksToDocuments(document, source);\n }\n if (options.perPage && document.pages && document.pages.length > 0) {\n return pagesToDocuments(document, source);\n }\n const metadata = buildMetadata(document, source);\n const pageContent = assembleContent(document.content, document.tables);\n return [new Document({ pageContent, metadata })];\n}\n\nexport function resultToDocuments(result: ResultEnvelope, sources: string[], options: SplitOptions): Document[] {\n if (result.errors && result.errors.length > 0) {\n const error = result.errors[0];\n throw new Error(`Failed to extract '${error.source}': ${error.message}`);\n }\n\n const documents: Document[] = [];\n const results = result.results ?? [];\n results.forEach((document, index) => {\n const source = sources[index] ?? (sources.length > 0 ? sources[sources.length - 1] : \"\");\n documents.push(...documentToDocuments(document, source, options));\n });\n return documents;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/loader.ts","../src/mapping.ts"],"sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { BaseDocumentLoader } from \"@langchain/core/document_loaders/base\";\nimport type { Document } from \"@langchain/core/documents\";\nimport { extract, extractBatch, ExtractInputKind } from \"@xberg-io/xberg\";\nimport type { ExtractInput, ExtractionConfig } from \"@xberg-io/xberg\";\nimport fastGlob from \"fast-glob\";\nimport { isChunkingEnabled, isPerPageEnabled, resultToDocuments, type ResultEnvelope } from \"./mapping\";\n\nconst DEFAULT_GLOB = \"**/*\";\n\nexport interface XbergLoaderOptions {\n /** File path, list of file paths, or directory path to load. */\n filePath?: string | string[];\n /** Raw bytes to extract from. Mutually exclusive with `filePath`. */\n data?: Uint8Array;\n /** MIME type hint. Required when using `data`, optional for `filePath`. */\n mimeType?: string;\n /** Glob pattern for directory mode. Defaults to matching all files. */\n glob?: string;\n /** Xberg extraction configuration controlling output format, OCR, pages, chunking, etc. */\n config?: ExtractionConfig;\n}\n\n/**\n * Load documents using Xberg, supporting 101 file formats with true async extraction.\n *\n * By default each source becomes one Document. Enable `chunking` on the\n * `ExtractionConfig` to emit one Document per chunk, or `pages` for one Document\n * per page. Multiple paths (a list or a directory glob) are extracted with a single\n * `extractBatch` call so concurrency happens Rust-side.\n */\nexport class XbergLoader extends BaseDocumentLoader {\n private readonly filePath?: string | string[];\n private readonly data?: Uint8Array;\n private readonly mimeType?: string;\n private readonly glob?: string;\n private readonly config?: ExtractionConfig;\n\n constructor(options: XbergLoaderOptions) {\n super();\n const { filePath, data, mimeType, glob, config } = options;\n if (filePath === undefined && data === undefined) {\n throw new Error(\"Either 'filePath' or 'data' must be provided.\");\n }\n if (filePath !== undefined && data !== undefined) {\n throw new Error(\"Cannot specify both 'filePath' and 'data'. Use one or the other.\");\n }\n if (data !== undefined && mimeType === undefined) {\n throw new Error(\"'mimeType' is required when using 'data'.\");\n }\n\n this.filePath = filePath;\n this.data = data;\n this.mimeType = mimeType;\n this.glob = glob;\n this.config = config;\n }\n\n async load(): Promise<Document[]> {\n const { inputs, sources, batch } = await this.buildInputs();\n if (inputs.length === 0) {\n return [];\n }\n\n let result;\n try {\n result = batch ? await extractBatch(inputs, this.config ?? null) : await extract(inputs[0], this.config ?? null);\n } catch (error) {\n const source = sources[0] ?? \"input\";\n throw new Error(`Failed to extract '${source}': ${errorMessage(error)}`);\n }\n\n return resultToDocuments(result as unknown as ResultEnvelope, sources, {\n chunking: isChunkingEnabled(this.config),\n perPage: isPerPageEnabled(this.config),\n });\n }\n\n private async buildInputs(): Promise<{ inputs: ExtractInput[]; sources: string[]; batch: boolean }> {\n if (this.data !== undefined) {\n const source = `bytes://${this.mimeType}`;\n const input: ExtractInput = { kind: ExtractInputKind.Bytes, bytes: this.data, mimeType: this.mimeType };\n return { inputs: [input], sources: [source], batch: false };\n }\n\n const { paths, batch } = await this.resolvePaths();\n const inputs: ExtractInput[] = paths.map((path) => ({\n kind: ExtractInputKind.Uri,\n uri: path,\n mimeType: this.mimeType,\n }));\n return { inputs, sources: paths, batch };\n }\n\n private async resolvePaths(): Promise<{ paths: string[]; batch: boolean }> {\n const filePath = this.filePath;\n if (Array.isArray(filePath)) {\n return { paths: filePath, batch: true };\n }\n if (typeof filePath === \"string\") {\n if (await isDirectory(filePath)) {\n const pattern = this.glob ?? DEFAULT_GLOB;\n const matches = await fastGlob(pattern, { cwd: filePath, onlyFiles: true, absolute: true });\n return { paths: matches.sort(), batch: true };\n }\n return { paths: [filePath], batch: false };\n }\n return { paths: [], batch: false };\n }\n}\n\nasync function isDirectory(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import { Document } from \"@langchain/core/documents\";\nimport type { DocumentCounts, ExtractionConfig, Keyword, Metadata, ProcessingWarning, Table } from \"@xberg-io/xberg\";\n\n// Metadata fields (from Xberg Metadata) that carry JSON-friendly scalar/list values,\n// mapped from the binding's camelCase keys to the snake_case output keys used by the\n// Python adapter. Opaque nested fields (pages, format, imagePreprocessing, jsonSchema,\n// error) are skipped because they are native objects, not plain data. ~keep\nconst METADATA_FIELDS: ReadonlyArray<readonly [string, keyof Metadata]> = [\n [\"title\", \"title\"],\n [\"subject\", \"subject\"],\n [\"authors\", \"authors\"],\n [\"keywords\", \"keywords\"],\n [\"language\", \"language\"],\n [\"created_at\", \"createdAt\"],\n [\"modified_at\", \"modifiedAt\"],\n [\"created_by\", \"createdBy\"],\n [\"modified_by\", \"modifiedBy\"],\n [\"category\", \"category\"],\n [\"tags\", \"tags\"],\n [\"document_version\", \"documentVersion\"],\n [\"abstract_text\", \"abstractText\"],\n [\"output_format\", \"outputFormat\"],\n [\"ocr_used\", \"ocrUsed\"],\n [\"extraction_duration_ms\", \"extractionDurationMs\"],\n];\n\nconst CONTENT_SEPARATOR = \"\\n\\n\";\n\nexport interface ChunkMetadataShape {\n chunkIndex: number;\n totalChunks: number;\n headingPath?: string[];\n tokenCount?: number;\n firstPage?: number;\n lastPage?: number;\n}\n\nexport interface ChunkShape {\n content: string;\n chunkType: unknown;\n metadata: ChunkMetadataShape;\n}\n\nexport interface PageShape {\n pageNumber: number;\n content: string;\n tables?: Table[];\n isBlank?: boolean;\n}\n\n// Structural view of a binding ExtractedDocument. The binding types its own fields\n// through unexported `Js*` aliases; this interface uses the clean exported types plus\n// local chunk/page shapes so the mapper is fully typed and testable without the addon. ~keep\nexport interface ExtractedDoc {\n content?: string;\n mimeType?: string;\n metadata?: Metadata;\n tables?: Table[];\n counts?: DocumentCounts;\n detectedLanguages?: string[];\n chunks?: ChunkShape[];\n pages?: PageShape[];\n extractedKeywords?: Keyword[];\n qualityScore?: number;\n processingWarnings?: ProcessingWarning[];\n}\n\nexport interface ResultEnvelope {\n errors?: Array<{ source: string; message: string }>;\n results?: ExtractedDoc[];\n}\n\nexport interface SplitOptions {\n chunking: boolean;\n perPage: boolean;\n}\n\nexport function isChunkingEnabled(config?: ExtractionConfig | null): boolean {\n return config?.chunking != null;\n}\n\nexport function isPerPageEnabled(config?: ExtractionConfig | null): boolean {\n return Boolean(config?.pages?.extractPages);\n}\n\nexport function flattenMetadata(metadata?: Metadata): Record<string, unknown> {\n const flat: Record<string, unknown> = {};\n if (!metadata) {\n return flat;\n }\n\n for (const [snakeKey, camelKey] of METADATA_FIELDS) {\n const value = metadata[camelKey];\n if (value != null) {\n flat[snakeKey] = value;\n }\n }\n\n const additional = metadata.additional;\n if (additional && Object.keys(additional).length > 0) {\n flat.additional = { ...additional };\n }\n\n return flat;\n}\n\nexport function assembleContent(content: string | undefined, tables: Table[] | undefined): string {\n const text = content ?? \"\";\n if (!tables || tables.length === 0) {\n return text;\n }\n const parts = tables.map((table) => table.markdown ?? \"\").filter((markdown) => markdown.length > 0);\n if (parts.length === 0) {\n return text;\n }\n return [text, ...parts].join(CONTENT_SEPARATOR);\n}\n\nexport function buildMetadata(document: ExtractedDoc, source: string): Record<string, unknown> {\n const metadata = flattenMetadata(document.metadata);\n\n metadata.mime_type = document.mimeType;\n if (document.qualityScore != null) {\n metadata.quality_score = document.qualityScore;\n }\n if (document.detectedLanguages && document.detectedLanguages.length > 0) {\n metadata.detected_languages = document.detectedLanguages;\n }\n if (document.counts != null) {\n metadata.page_count = document.counts.pages;\n }\n\n if (document.extractedKeywords && document.extractedKeywords.length > 0) {\n metadata.extracted_keywords = document.extractedKeywords.map((keyword) => ({\n text: keyword.text,\n score: keyword.score,\n algorithm: String(keyword.algorithm),\n }));\n }\n\n const tables = document.tables ?? [];\n metadata.table_count = tables.length;\n if (tables.length > 0) {\n metadata.tables = tables.map((table) => ({\n cells: table.cells,\n markdown: table.markdown,\n page_number: table.pageNumber,\n }));\n }\n\n if (document.processingWarnings && document.processingWarnings.length > 0) {\n metadata.processing_warnings = document.processingWarnings.map((warning) => ({\n source: warning.source,\n message: warning.message,\n }));\n }\n\n metadata.source = source;\n return metadata;\n}\n\nfunction chunksToDocuments(document: ExtractedDoc, source: string): Document[] {\n const baseMetadata = buildMetadata(document, source);\n const documents: Document[] = [];\n\n for (const chunk of document.chunks ?? []) {\n const metadata: Record<string, unknown> = { ...baseMetadata };\n const chunkMetadata = chunk.metadata;\n metadata.chunk_index = chunkMetadata.chunkIndex;\n metadata.total_chunks = chunkMetadata.totalChunks;\n metadata.chunk_type = String(chunk.chunkType);\n if (chunkMetadata.headingPath && chunkMetadata.headingPath.length > 0) {\n metadata.heading_path = [...chunkMetadata.headingPath];\n }\n if (chunkMetadata.tokenCount != null) {\n metadata.token_count = chunkMetadata.tokenCount;\n }\n if (chunkMetadata.firstPage != null) {\n // Xberg uses 1-indexed pages; LangChain convention is 0-indexed. ~keep\n metadata.page = chunkMetadata.firstPage - 1;\n metadata.first_page = chunkMetadata.firstPage;\n }\n if (chunkMetadata.lastPage != null) {\n metadata.last_page = chunkMetadata.lastPage;\n }\n documents.push(new Document({ pageContent: chunk.content, metadata }));\n }\n\n return documents;\n}\n\nfunction pagesToDocuments(document: ExtractedDoc, source: string): Document[] {\n const baseMetadata = buildMetadata(document, source);\n const documents: Document[] = [];\n\n for (const page of document.pages ?? []) {\n const metadata: Record<string, unknown> = { ...baseMetadata };\n // Xberg uses 1-indexed pages; LangChain convention is 0-indexed. ~keep\n metadata.page = page.pageNumber - 1;\n if (page.isBlank != null) {\n metadata.is_blank = page.isBlank;\n }\n const pageContent = assembleContent(page.content, page.tables);\n documents.push(new Document({ pageContent, metadata }));\n }\n\n return documents;\n}\n\nexport function documentToDocuments(document: ExtractedDoc, source: string, options: SplitOptions): Document[] {\n if (options.chunking && document.chunks && document.chunks.length > 0) {\n return chunksToDocuments(document, source);\n }\n if (options.perPage && document.pages && document.pages.length > 0) {\n return pagesToDocuments(document, source);\n }\n const metadata = buildMetadata(document, source);\n const pageContent = assembleContent(document.content, document.tables);\n return [new Document({ pageContent, metadata })];\n}\n\nexport function resultToDocuments(result: ResultEnvelope, sources: string[], options: SplitOptions): Document[] {\n if (result.errors && result.errors.length > 0) {\n const error = result.errors[0];\n throw new Error(`Failed to extract '${error.source}': ${error.message}`);\n }\n\n const documents: Document[] = [];\n const results = result.results ?? [];\n results.forEach((document, index) => {\n const source = sources[index] ?? (sources.length > 0 ? sources[sources.length - 1] : \"\");\n documents.push(...documentToDocuments(document, source, options));\n });\n return documents;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xberg-io/langchain-xberg",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "LangChain.js document loader for Xberg — extract text, tables, and metadata from
|
|
3
|
+
"version": "1.0.8",
|
|
4
|
+
"description": "LangChain.js document loader for Xberg — extract text, tables, and metadata from 101 document formats with optional OCR.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"langchain",
|
|
7
7
|
"langchainjs",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"test": "vitest run"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@xberg-io/xberg": "1.0.
|
|
50
|
+
"@xberg-io/xberg": "1.0.8",
|
|
51
51
|
"fast-glob": "^3.3.2"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|