HowdenParser 0.1.12__tar.gz → 0.1.13__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.
- howdenparser-0.1.13/HowdenParser/parameter/mistralocr.py +5 -0
- {howdenparser-0.1.12 → howdenparser-0.1.13}/HowdenParser/parser.py +29 -18
- {howdenparser-0.1.12 → howdenparser-0.1.13}/PKG-INFO +2 -1
- {howdenparser-0.1.12 → howdenparser-0.1.13}/pyproject.toml +2 -2
- howdenparser-0.1.12/HowdenParser/parameter/mistralocr.py +0 -7
- {howdenparser-0.1.12 → howdenparser-0.1.13}/HowdenParser/__init__.py +0 -0
- {howdenparser-0.1.12 → howdenparser-0.1.13}/HowdenParser/parameter/__init__.py +0 -0
- {howdenparser-0.1.12 → howdenparser-0.1.13}/HowdenParser/parameter/huggingface.py +0 -0
- {howdenparser-0.1.12 → howdenparser-0.1.13}/HowdenParser/parameter/llamaparser.py +0 -0
- {howdenparser-0.1.12 → howdenparser-0.1.13}/README.md +0 -0
|
@@ -3,6 +3,7 @@ from dotenv import load_dotenv
|
|
|
3
3
|
import os
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
import logging
|
|
6
|
+
from PyPDF2 import PdfReader
|
|
6
7
|
|
|
7
8
|
load_dotenv()
|
|
8
9
|
|
|
@@ -13,14 +14,17 @@ class BaseParser(ABC):
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class MistralOCRParser(BaseParser):
|
|
16
|
-
def __init__(self,
|
|
17
|
+
def __init__(self, model: str) -> None:
|
|
17
18
|
from mistralai import Mistral
|
|
19
|
+
self.model = model
|
|
20
|
+
self.current_cost: float = 0.0
|
|
21
|
+
self.total_cost_euro: float = 0.0
|
|
22
|
+
|
|
18
23
|
name = "MISTRAL-OCR-API-TOKEN"
|
|
19
24
|
api_key = os.getenv(name)
|
|
20
25
|
if not api_key:
|
|
21
26
|
raise EnvironmentError(f"Missing {name} in .env file.")
|
|
22
27
|
|
|
23
|
-
self.result_type = "md" if result_type.lower() in ("md", "markdown") else "text"
|
|
24
28
|
self.client = Mistral(api_key=api_key)
|
|
25
29
|
|
|
26
30
|
def parse(self, file_path: Path) -> str:
|
|
@@ -36,7 +40,7 @@ class MistralOCRParser(BaseParser):
|
|
|
36
40
|
return signed_url.url
|
|
37
41
|
|
|
38
42
|
ocr_response = self.client.ocr.process(
|
|
39
|
-
model=
|
|
43
|
+
model=self.model,
|
|
40
44
|
document={
|
|
41
45
|
"type": "document_url",
|
|
42
46
|
"document_url": upload_pdf(file_path),
|
|
@@ -44,14 +48,23 @@ class MistralOCRParser(BaseParser):
|
|
|
44
48
|
include_image_base64=True,
|
|
45
49
|
)
|
|
46
50
|
|
|
51
|
+
self.current_cost = 1/1000 * self._count_pages(file_path)
|
|
52
|
+
self.total_cost_euro += self.current_cost
|
|
53
|
+
|
|
47
54
|
return "\n".join(doc.markdown for doc in ocr_response.pages)
|
|
48
55
|
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _count_pages(file_path: Path) -> int:
|
|
58
|
+
reader = PdfReader(str(file_path))
|
|
59
|
+
return len(reader.pages)
|
|
60
|
+
|
|
61
|
+
|
|
49
62
|
|
|
50
63
|
class LangChainParser(BaseParser):
|
|
51
|
-
def __init__(self,
|
|
64
|
+
def __init__(self, model: str):
|
|
52
65
|
from langchain.llms import OpenAI
|
|
53
|
-
self.model_name =
|
|
54
|
-
self.model = OpenAI(model_name=
|
|
66
|
+
self.model_name = model
|
|
67
|
+
self.model = OpenAI(model_name=model)
|
|
55
68
|
|
|
56
69
|
def parse(self, text: str) -> dict:
|
|
57
70
|
response = self.model(text)
|
|
@@ -89,7 +102,7 @@ class LlamaParser(BaseParser):
|
|
|
89
102
|
return text
|
|
90
103
|
|
|
91
104
|
class HuggingFaceParser(BaseParser):
|
|
92
|
-
def __init__(self,
|
|
105
|
+
def __init__(self, model: str, result_type: str) -> None:
|
|
93
106
|
from transformers import pipeline
|
|
94
107
|
|
|
95
108
|
if result_type.lower() in ("md", "markdown"):
|
|
@@ -102,16 +115,15 @@ class HuggingFaceParser(BaseParser):
|
|
|
102
115
|
if not self.api_key:
|
|
103
116
|
raise EnvironmentError(f"Missing {name} in .env file.")
|
|
104
117
|
|
|
105
|
-
# OCR + text extraction pipeline
|
|
106
118
|
# Example model: microsoft/layoutlmv3-base-finetuned-docvqa
|
|
107
119
|
self.parser = pipeline(
|
|
108
120
|
task="document-question-answering",
|
|
109
|
-
model=
|
|
121
|
+
model=model,
|
|
110
122
|
use_auth_token=self.api_key
|
|
111
123
|
)
|
|
112
124
|
|
|
113
125
|
def parse(self, file_path: Path) -> str:
|
|
114
|
-
import fitz
|
|
126
|
+
import fitz
|
|
115
127
|
|
|
116
128
|
pdf_doc = fitz.open(file_path)
|
|
117
129
|
output_parts = []
|
|
@@ -124,7 +136,6 @@ class HuggingFaceParser(BaseParser):
|
|
|
124
136
|
output_parts.append(response[0]["answer"])
|
|
125
137
|
|
|
126
138
|
if self.result_type == "markdown":
|
|
127
|
-
# Here you could add rules to format into markdown
|
|
128
139
|
return "\n\n".join(output_parts)
|
|
129
140
|
else:
|
|
130
141
|
return " ".join(output_parts)
|
|
@@ -132,17 +143,17 @@ class HuggingFaceParser(BaseParser):
|
|
|
132
143
|
# === Step 3: Dynamic factory using string input ===
|
|
133
144
|
class ParserFactory:
|
|
134
145
|
@staticmethod
|
|
135
|
-
def get_parser(
|
|
136
|
-
provider =
|
|
137
|
-
model =
|
|
146
|
+
def get_parser(provider_model: str, **kwargs) -> BaseParser:
|
|
147
|
+
provider = provider_model.partition(":")[0].lower()
|
|
148
|
+
model = provider_model.partition(":")[2]
|
|
138
149
|
if provider == "langchain":
|
|
139
|
-
return LangChainParser(
|
|
150
|
+
return LangChainParser(model=model)
|
|
140
151
|
elif provider == "llamaparser":
|
|
141
152
|
return LlamaParser(kwargs["result_type"], kwargs["mode"])
|
|
142
153
|
elif provider == "huggingface":
|
|
143
|
-
return HuggingFaceParser(
|
|
154
|
+
return HuggingFaceParser(model=model, **kwargs)
|
|
144
155
|
elif provider == "mistralocr":
|
|
145
|
-
return MistralOCRParser(
|
|
156
|
+
return MistralOCRParser(model)
|
|
146
157
|
else:
|
|
147
|
-
raise ValueError(f"Unknown parser type: {
|
|
158
|
+
raise ValueError(f"Unknown parser type: {provider_model}")
|
|
148
159
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: HowdenParser
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.13
|
|
4
4
|
Summary: A simple configuration manager with Pydantic and JSON export.
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: config,configuration,pydantic,json
|
|
@@ -16,6 +16,7 @@ Requires-Dist: howdenconfig (>=0.1.13,<0.2.0)
|
|
|
16
16
|
Requires-Dist: langchain (>=0.3.27,<0.4.0)
|
|
17
17
|
Requires-Dist: llama-parse (>=0.6.58,<0.7.0)
|
|
18
18
|
Requires-Dist: mistralai (>=1.9.3,<2.0.0)
|
|
19
|
+
Requires-Dist: pypdf2 (>=3.0.1,<4.0.0)
|
|
19
20
|
Requires-Dist: transformers (>=4.55.2,<5.0.0)
|
|
20
21
|
Project-URL: Documentation, https://github.com/yourusername/config
|
|
21
22
|
Project-URL: Homepage, https://github.com/yourusername/config
|
|
@@ -3,7 +3,7 @@ name = "HowdenParser"
|
|
|
3
3
|
description = ""
|
|
4
4
|
readme = "README.md"
|
|
5
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)",]
|
|
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)",]
|
|
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 = "0.1.
|
|
17
|
+
version = "0.1.13"
|
|
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"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|