langchain-fastocr 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,6 @@
1
+ """LangChain document loader for the FastOCR Document OCR API."""
2
+
3
+ from ._version import __version__
4
+ from .loader import FastOCRLoader
5
+
6
+ __all__ = ["__version__", "FastOCRLoader"]
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,90 @@
1
+ """Document loader that reads scanned PDFs and images with FastOCR."""
2
+ import logging
3
+ from pathlib import Path
4
+ from typing import Any, Dict, Iterator, Literal, Optional, Sequence, Union
5
+
6
+ from fastocr_sdk import FastOCR
7
+ from langchain_core.document_loaders import BaseLoader
8
+ from langchain_core.documents import Document
9
+
10
+ from ._version import __version__
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ USER_AGENT = f"langchain-fastocr/{__version__}"
15
+ SUPPORTED_SUFFIXES = (".pdf", ".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp")
16
+
17
+ PathLike = Union[str, Path]
18
+
19
+
20
+ class FastOCRLoader(BaseLoader):
21
+ """Load scanned PDFs and images as LangChain documents, one document per file.
22
+
23
+ Args:
24
+ file_path: One path or a list of paths (PDF, PNG, JPG, JPEG, GIF, WebP or BMP).
25
+ api_key: A FastOCR API key. Defaults to the FASTOCR_API_KEY environment variable.
26
+ output: "text" returns the text. "pdf" also saves a searchable PDF beside each
27
+ input file as <name>.searchable.pdf and records its path in the metadata.
28
+ base_url: Overrides the API address. Defaults to FASTOCR_BASE_URL, then https://api.fastocr.org.
29
+ timeout: Seconds to wait for each document to finish.
30
+
31
+ Each document's metadata has source, file_name, fastocr_document_id, pages_billed and
32
+ status. A "partial" status means the account ran out of API pages partway: the text
33
+ covers only the processed pages and a warning is logged. A failed document raises the
34
+ SDK's DocumentFailedError.
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ file_path: Union[PathLike, Sequence[PathLike]],
40
+ *,
41
+ api_key: Optional[str] = None,
42
+ output: Literal["text", "pdf"] = "text",
43
+ base_url: Optional[str] = None,
44
+ timeout: float = 300.0,
45
+ ) -> None:
46
+ if output not in ("text", "pdf"):
47
+ raise ValueError("output must be 'text' or 'pdf'")
48
+ paths = [file_path] if isinstance(file_path, (str, Path)) else list(file_path)
49
+ self.paths = [Path(path).expanduser() for path in paths]
50
+ for path in self.paths:
51
+ if path.suffix.lower() not in SUPPORTED_SUFFIXES:
52
+ raise ValueError(f"{path.name}: FastOCR accepts PDF, PNG, JPG, JPEG, GIF, WebP and BMP files")
53
+ self.api_key = api_key
54
+ self.output = output
55
+ self.base_url = base_url
56
+ self.timeout = timeout
57
+
58
+ def lazy_load(self) -> Iterator[Document]:
59
+ with self._client() as client:
60
+ for path in self.paths:
61
+ yield self._load_one(client, path)
62
+
63
+ def _client(self) -> FastOCR:
64
+ client = FastOCR(api_key=self.api_key, base_url=self.base_url)
65
+ sdk_agent = client._http.headers.get("User-Agent", "")
66
+ client._http.headers["User-Agent"] = f"{USER_AGENT} {sdk_agent}".strip()
67
+ return client
68
+
69
+ def _load_one(self, client: FastOCR, path: Path) -> Document:
70
+ job = client.documents.process(path, timeout=self.timeout)
71
+ if job.is_partial:
72
+ logger.warning(
73
+ "%s: only %s of %s pages were processed because the account ran out of API pages",
74
+ path.name,
75
+ job.pages_billed,
76
+ job.pages_total,
77
+ )
78
+ metadata: Dict[str, Any] = {
79
+ "source": str(path),
80
+ "file_name": path.name,
81
+ "fastocr_document_id": job.id,
82
+ "pages_billed": job.pages_billed,
83
+ "status": job.status,
84
+ }
85
+ text = client.documents.get_text(job.id)
86
+ if self.output == "pdf":
87
+ destination = path.with_name(f"{path.stem}.searchable.pdf")
88
+ client.documents.download_searchable_pdf(job.id, destination)
89
+ metadata["searchable_pdf_path"] = str(destination)
90
+ return Document(page_content=text, metadata=metadata)
File without changes
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.5
2
+ Name: langchain-fastocr
3
+ Version: 0.1.0
4
+ Summary: LangChain document loader for the FastOCR Document OCR API: load scanned PDFs and images as text, in 100+ languages.
5
+ Project-URL: Homepage, https://fastocr.org
6
+ Project-URL: Documentation, https://fastocr.org/docs
7
+ Project-URL: Repository, https://github.com/fastocr-org/langchain-fastocr
8
+ Project-URL: Changelog, https://github.com/fastocr-org/langchain-fastocr/blob/main/CHANGELOG.md
9
+ Project-URL: Issues, https://github.com/fastocr-org/langchain-fastocr/issues
10
+ Author-email: FastOCR <support@fastocr.org>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: document-loader,fastocr,langchain,ocr,pdf,rag,scanned-pdf
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: fastocr-sdk<0.3,>=0.2.0
28
+ Requires-Dist: langchain-core>=0.3.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: mypy>=1.10; extra == 'dev'
31
+ Requires-Dist: pytest>=7.4.0; extra == 'dev'
32
+ Requires-Dist: respx>=0.21.0; extra == 'dev'
33
+ Requires-Dist: ruff>=0.6; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ <div align="center">
37
+
38
+ <a href="https://fastocr.org">
39
+ <picture>
40
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/fastocr-org/langchain-fastocr/main/docs/images/logo-dark.png">
41
+ <img src="https://raw.githubusercontent.com/fastocr-org/langchain-fastocr/main/docs/images/logo-light.png" alt="FastOCR" width="200">
42
+ </picture>
43
+ </a>
44
+
45
+ <h3>A LangChain document loader that reads scanned PDFs and images with FastOCR.</h3>
46
+
47
+ <p>
48
+ <a href="https://github.com/fastocr-org/langchain-fastocr/actions/workflows/ci.yml"><img src="https://github.com/fastocr-org/langchain-fastocr/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
49
+ <a href="https://pypi.org/project/langchain-fastocr/"><img src="https://img.shields.io/pypi/v/langchain-fastocr.svg?label=pypi" alt="PyPI"></a>
50
+ <a href="https://pypi.org/project/langchain-fastocr/"><img src="https://img.shields.io/pypi/pyversions/langchain-fastocr.svg" alt="Python"></a>
51
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
52
+ </p>
53
+
54
+ <p>
55
+ <a href="https://fastocr.org">Website</a> ·
56
+ <a href="https://fastocr.org/docs">Docs</a> ·
57
+ <a href="https://fastocr.org/developers/keys">Get an API key</a>
58
+ </p>
59
+
60
+ <img src="https://raw.githubusercontent.com/fastocr-org/langchain-fastocr/main/docs/images/readme-hero.gif" alt="FastOCR reads a scanned page in English, Arabic and Hindi and returns its text" width="800">
61
+
62
+ </div>
63
+
64
+ ## Quickstart
65
+
66
+ ```bash
67
+ pip install langchain-fastocr
68
+ export FASTOCR_API_KEY="your_api_key"
69
+ ```
70
+
71
+ ```python
72
+ from langchain_fastocr import FastOCRLoader
73
+
74
+ documents = FastOCRLoader("scanned_contract.pdf").load()
75
+ print(documents[0].page_content)
76
+ ```
77
+
78
+ Python 3.10 or newer. The distribution is `langchain-fastocr` and the import is `langchain_fastocr`.
79
+
80
+ ## What you get back
81
+
82
+ `FastOCRLoader` returns one `Document` per file.
83
+
84
+ | You get | Where |
85
+ |---|---|
86
+ | The text of the whole file | `page_content` |
87
+ | The file's path and name | `metadata["source"]`, `metadata["file_name"]` |
88
+ | The FastOCR document id | `metadata["fastocr_document_id"]` |
89
+ | Pages billed | `metadata["pages_billed"]` |
90
+ | `completed` or `partial` | `metadata["status"]` |
91
+ | A searchable PDF, with `output="pdf"` | saved as `<name>.searchable.pdf` beside the input; its path is in `metadata["searchable_pdf_path"]` |
92
+
93
+ If the account runs out of API pages partway through a file, you still get the text of the pages that were processed, with `status` set to `partial` and a warning in the log. A document that fails raises the error from [`fastocr-sdk`](https://pypi.org/project/fastocr-sdk/) with its message and code.
94
+
95
+ ## Languages and files
96
+
97
+ - 100+ languages, detected automatically. No language setting is needed.
98
+ - PDF files up to 1 GiB, and PNG, JPG, JPEG, GIF, WebP and BMP images up to 20 MiB. An image counts as one page.
99
+
100
+ ## Get an API key and pages
101
+
102
+ Any signed-in FastOCR account can create an API key and start right away.
103
+
104
+ 1. Sign in and create an API key in the [developer console](https://fastocr.org/developers/keys). You accept the [API terms](https://fastocr.org/api-terms) with your first key.
105
+ 2. Set the key as `FASTOCR_API_KEY`, or pass `api_key=` to the loader.
106
+ 3. When you need more than the free pages, buy a prepaid API page pack by card in the [developer console](https://fastocr.org/developers/keys#buy-api-pages).
107
+
108
+ Each account gets 50 free document pages per month.
109
+
110
+ ## Examples
111
+
112
+ ### RAG over scanned PDFs
113
+
114
+ ```python
115
+ from langchain_core.vectorstores import InMemoryVectorStore
116
+ from langchain_fastocr import FastOCRLoader
117
+ from langchain_openai import OpenAIEmbeddings
118
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
119
+
120
+ documents = FastOCRLoader("scanned_contract.pdf").load()
121
+ chunks = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=150).split_documents(documents)
122
+
123
+ store = InMemoryVectorStore.from_documents(chunks, OpenAIEmbeddings())
124
+ for hit in store.as_retriever(search_kwargs={"k": 3}).invoke("When can the contract be terminated?"):
125
+ print(hit.metadata["file_name"], hit.page_content[:200])
126
+ ```
127
+
128
+ Each chunk keeps its file's metadata, so answers can cite the source file. This example also needs `pip install langchain-openai langchain-text-splitters numpy` and an OpenAI key; any other embeddings class works the same way.
129
+
130
+ ### A folder of scans
131
+
132
+ ```python
133
+ from pathlib import Path
134
+
135
+ from langchain_fastocr import FastOCRLoader
136
+
137
+ scans = sorted(p for p in Path("scans").iterdir() if p.suffix.lower() in {".pdf", ".png", ".jpg", ".jpeg"})
138
+ for document in FastOCRLoader(scans).lazy_load():
139
+ print(document.metadata["file_name"], document.metadata["pages_billed"])
140
+ ```
141
+
142
+ `lazy_load()` yields each document as soon as its file is finished. The loader runs one file at a time.
143
+
144
+ ### Searchable PDFs for an archive
145
+
146
+ ```python
147
+ from langchain_fastocr import FastOCRLoader
148
+
149
+ documents = FastOCRLoader(["invoice-001.pdf", "invoice-002.pdf"], output="pdf").load()
150
+ for document in documents:
151
+ print(document.metadata["searchable_pdf_path"])
152
+ ```
153
+
154
+ Each searchable PDF is saved beside its input, as `invoice-001.searchable.pdf`. An existing file with that name is replaced. Index the text and keep the PDF.
155
+
156
+ ## Options
157
+
158
+ | Argument | Default | Meaning |
159
+ |---|---|---|
160
+ | `file_path` | required | One path or a list of paths |
161
+ | `api_key` | `FASTOCR_API_KEY` | Your FastOCR API key |
162
+ | `output` | `"text"` | `"pdf"` also saves a searchable PDF beside each input |
163
+ | `base_url` | `FASTOCR_BASE_URL`, then `https://api.fastocr.org` | API address |
164
+ | `timeout` | `300.0` | Seconds to wait for each document |
165
+
166
+ ## Support and license
167
+
168
+ Questions: support@fastocr.org. Bugs and requests: [GitHub issues](https://github.com/fastocr-org/langchain-fastocr/issues). MIT license; see [LICENSE](LICENSE).
@@ -0,0 +1,8 @@
1
+ langchain_fastocr/__init__.py,sha256=T2EE59oU-yfxXBxxanzHrfN2MnDum88kkIu2fEkN4tA,179
2
+ langchain_fastocr/_version.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
3
+ langchain_fastocr/loader.py,sha256=_iUMkk-CQUmjvLi0jR30fHnNoSLOZCr5_sUVX_QObs0,3801
4
+ langchain_fastocr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ langchain_fastocr-0.1.0.dist-info/METADATA,sha256=lH_f3FkbKUgT2St0eusvK6BiAisBtd2fePihm4d6W0w,7355
6
+ langchain_fastocr-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
7
+ langchain_fastocr-0.1.0.dist-info/licenses/LICENSE,sha256=iAEJvhOAbbRmyZP6iiDxfCJrifPj_5COWm4eVHmbOQ8,1064
8
+ langchain_fastocr-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FastOCR
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.