HowdenParser 1.0.0__tar.gz → 1.0.1__tar.gz

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.
@@ -3,6 +3,6 @@ from typing import Literal
3
3
  from pydantic import BaseModel
4
4
 
5
5
  class Parameter(BaseModel):
6
- model: str = "llamaparser:"
6
+ provider_and_model: str = "llamaparser:"
7
7
  result_type: Literal["md"] = "md"
8
8
  mode: bool = False
@@ -4,8 +4,10 @@ import logging
4
4
  from pathlib import Path
5
5
  from PyPDF2 import PdfReader
6
6
  import dotenv
7
+ import logging
7
8
 
8
9
  dotenv.load_dotenv()
10
+ logger = logging.getLogger(__name__)
9
11
 
10
12
 
11
13
  class BaseParser(ABC):
@@ -27,7 +29,7 @@ class Parser(BaseParser):
27
29
  """Factory + registry interface for all parsers."""
28
30
 
29
31
  @classmethod
30
- def available_parsers(cls) -> dict[str, list[str]]:
32
+ def available_parsers(cls) -> None:
31
33
  """Return registered parsers and their init arguments."""
32
34
  import inspect
33
35
  result = {}
@@ -35,7 +37,8 @@ class Parser(BaseParser):
35
37
  sig = inspect.signature(parser_cls.__init__)
36
38
  result[name] = [p for p in sig.parameters if p != "self"]
37
39
  result.pop('', None)
38
- return result
40
+ for key, values in result.items():
41
+ print(f"{key} with parameters: {values}")
39
42
 
40
43
  @classmethod
41
44
  def create(cls, config: dict | None = None, **kwargs) -> BaseParser:
@@ -57,9 +60,6 @@ class Parser(BaseParser):
57
60
 
58
61
  return parser_cls(**valid_args)
59
62
 
60
-
61
-
62
-
63
63
  @abstractmethod
64
64
  def parse(self, text: str):
65
65
  pass
@@ -107,10 +107,10 @@ class MistralOCRParser(BaseParser, name="mistralocr"):
107
107
 
108
108
 
109
109
  class LangChainParser(BaseParser, name="langchain"):
110
- def __init__(self, model: str):
110
+ def __init__(self, provider_and_model: str):
111
111
  from langchain.llms import OpenAI
112
- self.model_name = model
113
- self.model = OpenAI(model_name=model)
112
+ self.model = provider_and_model.split(":")[1]
113
+ self.model = OpenAI(model_name=self.model)
114
114
 
115
115
  def parse(self, text: str) -> dict:
116
116
  response = self.model(text)
@@ -138,36 +138,37 @@ class LlamaParser(BaseParser, name="llamaparser"):
138
138
 
139
139
 
140
140
  class HuggingFaceParser(BaseParser, name="huggingface"):
141
- def __init__(self, model: str, result_type: str) -> None:
142
- from transformers import pipeline
143
-
144
- if result_type.lower() in ("md", "markdown"):
145
- self.result_type = "markdown"
146
- else:
147
- self.result_type = "text"
141
+ def __init__(self, provider_and_model: str) -> None:
142
+ from transformers import TrOCRProcessor, VisionEncoderDecoderModel
148
143
 
149
144
  api_key = os.getenv("HF-API-TOKEN")
150
145
  if not api_key:
151
146
  raise EnvironmentError("Missing HF-API-TOKEN in .env file.")
152
147
 
153
- self.parser = pipeline(
154
- task="document-question-answering",
155
- model=model,
156
- use_auth_token=api_key
157
- )
148
+ model_name = provider_and_model.split(":")[1]
149
+ logger.info(f"Loading Hugging Face OCR model: {model_name}")
150
+
151
+ self.processor = TrOCRProcessor.from_pretrained(model_name, token=api_key)
152
+ self.model = VisionEncoderDecoderModel.from_pretrained(model_name, token=api_key)
153
+
154
+ logger.info("Model and processor loaded successfully.")
158
155
 
159
156
  def parse(self, file_path: Path) -> str:
160
- import fitz
161
- pdf_doc = fitz.open(file_path)
162
- output_parts = []
163
-
164
- for page in pdf_doc:
165
- pix = page.get_pixmap(dpi=200)
166
- img_bytes = pix.tobytes("png")
167
- response = self.parser(img_bytes, question="Extract all text")
168
- if response and "answer" in response[0]:
169
- output_parts.append(response[0]["answer"])
170
-
171
- return "\n\n".join(output_parts) if self.result_type == "markdown" else " ".join(output_parts)
157
+ from pdf2image import convert_from_path
158
+ logger.info(f"Converting PDF to images: {file_path}")
159
+ pages = convert_from_path(file_path, dpi=300)
160
+ logger.info(f"PDF conversion complete. Total pages: {len(pages)}")
161
+
162
+ all_text = ""
163
+ for i, page in enumerate(pages, start=1):
164
+ logger.info(f"Running OCR on page {i}/{len(pages)}")
165
+ pixel_values = self.processor(page, return_tensors="pt").pixel_values
166
+ generated_ids = self.model.generate(pixel_values)
167
+ text = self.processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
168
+ all_text += text + "\n"
169
+ logger.debug(f"OCR text (page {i}): {text[:100]}...") # preview first 100 chars
170
+
171
+ logger.info("OCR completed for all pages.")
172
+ return all_text
172
173
 
173
174
 
@@ -1,22 +1,27 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: HowdenParser
3
- Version: 1.0.0
3
+ Version: 1.0.1
4
4
  Summary: A simple configuration manager with Pydantic and JSON export.
5
5
  License: MIT
6
6
  Keywords: config,configuration,pydantic,json
7
7
  Author: JesperThoftIllemannJ
8
8
  Author-email: jesper.jaeger@howdendanmark.dk
9
- Requires-Python: >=3.12,<4.0
9
+ Requires-Python: >=3.12,<3.14
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Dist: fitz (>=0.0.1.dev2,<0.0.2)
15
+ Requires-Dist: hf-xet (>=1.1.7,<2.0.0)
15
16
  Requires-Dist: howdenconfig (>=0.1.13,<0.2.0)
16
17
  Requires-Dist: langchain (>=0.3.27,<0.4.0)
17
18
  Requires-Dist: llama-parse (>=0.6.58,<0.7.0)
18
19
  Requires-Dist: mistralai (>=1.9.3,<2.0.0)
20
+ Requires-Dist: pdf2image (>=1.17.0,<2.0.0)
19
21
  Requires-Dist: pypdf2 (>=3.0.1,<4.0.0)
22
+ Requires-Dist: torch (>=2.8.0,<3.0.0)
23
+ Requires-Dist: torchaudio (>=2.8.0,<3.0.0)
24
+ Requires-Dist: torchvision (>=0.23.0,<0.24.0)
20
25
  Requires-Dist: transformers (>=4.55.2,<5.0.0)
21
26
  Project-URL: Documentation, https://github.com/yourusername/config
22
27
  Project-URL: Homepage, https://github.com/yourusername/config
@@ -2,8 +2,8 @@
2
2
  name = "HowdenParser"
3
3
  description = ""
4
4
  readme = "README.md"
5
- requires-python = ">=3.12,<4.0"
6
- dependencies = [ "mistralai (>=1.9.3,<2.0.0)", "llama-parse (>=0.6.58,<0.7.0)", "langchain (>=0.3.27,<0.4.0)", "transformers (>=4.55.2,<5.0.0)", "fitz (>=0.0.1.dev2,<0.0.2)", "howdenconfig (>=0.1.13,<0.2.0)", "pypdf2 (>=3.0.1,<4.0.0)",]
5
+ requires-python = ">=3.12,<3.14"
6
+ dependencies = [ "mistralai (>=1.9.3,<2.0.0)", "llama-parse (>=0.6.58,<0.7.0)", "langchain (>=0.3.27,<0.4.0)", "transformers (>=4.55.2,<5.0.0)", "fitz (>=0.0.1.dev2,<0.0.2)", "howdenconfig (>=0.1.13,<0.2.0)", "pypdf2 (>=3.0.1,<4.0.0)", "pdf2image (>=1.17.0,<2.0.0)", "torch (>=2.8.0,<3.0.0)", "torchvision (>=0.23.0,<0.24.0)", "torchaudio (>=2.8.0,<3.0.0)", "hf-xet (>=1.1.7,<2.0.0)",]
7
7
  [[project.authors]]
8
8
  name = "JesperThoftIllemannJ"
9
9
  email = "jesper.jaeger@howdendanmark.dk"
@@ -14,7 +14,7 @@ build-backend = "poetry.core.masonry.api"
14
14
 
15
15
  [tool.poetry]
16
16
  name = "HowdenParser"
17
- version = "1.0.0"
17
+ version = "1.0.1"
18
18
  description = "A simple configuration manager with Pydantic and JSON export."
19
19
  authors = [ "JesperThoftIllemannJ <jesper.jaeger@howdendanmark.dk>",]
20
20
  readme = "README.md"
@@ -26,5 +26,14 @@ documentation = "https://github.com/yourusername/config"
26
26
  [[tool.poetry.packages]]
27
27
  include = "HowdenParser"
28
28
 
29
+ [tool.poetry.dependencies.torch]
30
+ source = "pypi"
31
+
32
+ [tool.poetry.dependencies.torchvision]
33
+ source = "pypi"
34
+
35
+ [tool.poetry.dependencies.torchaudio]
36
+ source = "pypi"
37
+
29
38
  [tool.poetry.group.dev.dependencies]
30
39
  toml = "^0.10.2"
File without changes