HowdenParser 0.1.2__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.
@@ -0,0 +1,3 @@
1
+ from .parser import ParserFactory
2
+
3
+ __all__ = ["ParserFactory"]
@@ -0,0 +1,137 @@
1
+ from abc import ABC, abstractmethod
2
+ from dotenv import load_dotenv
3
+ import os
4
+ from pathlib import Path
5
+
6
+ load_dotenv()
7
+
8
+ class BaseParser(ABC):
9
+ @abstractmethod
10
+ def parse(self, text: str) -> dict:
11
+ pass
12
+
13
+
14
+ class MistralOCRParser(BaseParser):
15
+ def __init__(self, result_type: str, **kwargs) -> None:
16
+ from mistralai import Mistral
17
+ name = "MISTRAL-OCR-API-TOKEN"
18
+ api_key = os.getenv(name)
19
+ if not api_key:
20
+ raise EnvironmentError(f"Missing {name} in .env file.")
21
+
22
+ self.result_type = "md" if result_type.lower() in ("md", "markdown") else "text"
23
+ self.client = Mistral(api_key=api_key)
24
+
25
+ def parse(self, file_path: Path) -> str:
26
+ def upload_pdf(filename):
27
+ uploaded_pdf = self.client.files.upload(
28
+ file={
29
+ "file_name": filename,
30
+ "content": open(filename, "rb"),
31
+ },
32
+ purpose="ocr"
33
+ )
34
+ signed_url = self.client.files.get_signed_url(file_id=uploaded_pdf.id)
35
+ return signed_url.url
36
+
37
+ ocr_response = self.client.ocr.process(
38
+ model="mistral-ocr-latest",
39
+ document={
40
+ "type": "document_url",
41
+ "document_url": upload_pdf(file_path),
42
+ },
43
+ include_image_base64=True,
44
+ )
45
+
46
+ return "\n".join(doc.markdown for doc in ocr_response.pages)
47
+
48
+
49
+ class LangChainParser(BaseParser):
50
+ def __init__(self, model_name: str):
51
+ from langchain.llms import OpenAI
52
+ self.model_name = model_name
53
+ self.model = OpenAI(model_name=model_name)
54
+
55
+ def parse(self, text: str) -> dict:
56
+ response = self.model(text)
57
+ return {"source": "LangChain", "output": response}
58
+
59
+
60
+ class LlamaParser(BaseParser):
61
+ def __init__(self, result_type: str, mode: bool, **kwargs) -> None:
62
+ from llama_parse import LlamaParse, ResultType
63
+ if result_type.lower() == "md" or result_type.lower() == "markdown":
64
+ self.result_type = ResultType.MD
65
+ name = "LLAMA-PARSER-API-TOKEN"
66
+ self.api_key = os.getenv(name)
67
+ if not self.api_key:
68
+ raise EnvironmentError(f"Missing {name} in .env file.")
69
+
70
+ self.parser = LlamaParse(
71
+ api_key=self.api_key,
72
+ result_type=self.result_type,
73
+ premium_mode=mode
74
+ )
75
+
76
+ def parse(self, file_path: Path) -> str:
77
+ documents = self.parser.load_data(str(file_path))
78
+ return "\n".join(doc.text for doc in documents)
79
+
80
+ class HuggingFaceParser(BaseParser):
81
+ def __init__(self, result_type: str, mode: bool, **kwargs) -> None:
82
+ from transformers import pipeline
83
+
84
+ if result_type.lower() in ("md", "markdown"):
85
+ self.result_type = "markdown"
86
+ else:
87
+ self.result_type = "text"
88
+
89
+ name = "HF-API-TOKEN"
90
+ self.api_key = os.getenv(name)
91
+ if not self.api_key:
92
+ raise EnvironmentError(f"Missing {name} in .env file.")
93
+
94
+ # OCR + text extraction pipeline
95
+ # Example model: microsoft/layoutlmv3-base-finetuned-docvqa
96
+ self.parser = pipeline(
97
+ task="document-question-answering",
98
+ model="impira/layoutlm-document-qa",
99
+ use_auth_token=self.api_key
100
+ )
101
+
102
+ def parse(self, file_path: Path) -> str:
103
+ import fitz # PyMuPDF for PDF → images
104
+
105
+ pdf_doc = fitz.open(file_path)
106
+ output_parts = []
107
+
108
+ for page in pdf_doc:
109
+ pix = page.get_pixmap(dpi=200)
110
+ img_bytes = pix.tobytes("png")
111
+ response = self.parser(img_bytes, question="Extract all text")
112
+ if response and "answer" in response[0]:
113
+ output_parts.append(response[0]["answer"])
114
+
115
+ if self.result_type == "markdown":
116
+ # Here you could add rules to format into markdown
117
+ return "\n\n".join(output_parts)
118
+ else:
119
+ return " ".join(output_parts)
120
+
121
+ # === Step 3: Dynamic factory using string input ===
122
+ class ParserFactory:
123
+ @staticmethod
124
+ def get_parser(parser_type: str, **kwargs) -> BaseParser:
125
+ provider = parser_type.partition(":")[0].lower()
126
+ model = parser_type.partition(":")[2]
127
+ if provider == "langchain":
128
+ return LangChainParser(model_name=model)
129
+ elif provider == "llamaparser":
130
+ return LlamaParser(**kwargs)
131
+ elif provider == "huggingface":
132
+ return HuggingFaceParser(model_name=model, **kwargs)
133
+ elif provider == "mistralocr":
134
+ return MistralOCRParser(**kwargs)
135
+ else:
136
+ raise ValueError(f"Unknown parser type: {parser_type}")
137
+
@@ -0,0 +1,28 @@
1
+ Metadata-Version: 2.3
2
+ Name: HowdenParser
3
+ Version: 0.1.2
4
+ Summary: A simple configuration manager with Pydantic and JSON export.
5
+ License: MIT
6
+ Keywords: config,configuration,pydantic,json
7
+ Author: JesperThoftIllemannJ
8
+ Author-email: jesper.jaeger@howdendanmark.dk
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 2
11
+ Classifier: Programming Language :: Python :: 2.7
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.4
14
+ Classifier: Programming Language :: Python :: 3.5
15
+ Classifier: Programming Language :: Python :: 3.6
16
+ Classifier: Programming Language :: Python :: 3.7
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
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
+ Project-URL: Documentation, https://github.com/yourusername/config
24
+ Project-URL: Homepage, https://github.com/yourusername/config
25
+ Project-URL: Repository, https://github.com/yourusername/config
26
+ Description-Content-Type: text/markdown
27
+
28
+ .\build.ps1
@@ -0,0 +1 @@
1
+ .\build.ps1
@@ -0,0 +1,3 @@
1
+ from .huggingface import Parameter as Huggingface
2
+ from .llamaparser import Parameter as Llamaparser
3
+ from .mistralocr import Parameter as Mistralocr
@@ -0,0 +1,6 @@
1
+ from typing import Literal
2
+ from pydantic import BaseModel
3
+
4
+ class Parameter(BaseModel):
5
+ model: str = "huggingface:HURIDOCS/pdf-segmentation"
6
+
@@ -0,0 +1,8 @@
1
+
2
+ from typing import Literal
3
+ from pydantic import BaseModel
4
+
5
+ class Parameter(BaseModel):
6
+ model: str = "llamaparser:"
7
+ result_type: Literal["md"] = "md"
8
+ mode: bool = False
@@ -0,0 +1,7 @@
1
+ from typing import Literal
2
+ from pydantic import BaseModel
3
+
4
+ class Parameter(BaseModel):
5
+ model: str = "mistralocr:"
6
+ result_type: Literal["md"] = "md"
7
+ mode: bool = False
@@ -0,0 +1,21 @@
1
+ [build-system]
2
+ requires = [ "poetry-core>=2.0.0,<3.0.0",]
3
+ build-backend = "poetry.core.masonry.api"
4
+
5
+ [tool.poetry]
6
+ name = "HowdenParser"
7
+ version = "0.1.2"
8
+ description = "A simple configuration manager with Pydantic and JSON export."
9
+ authors = [ "JesperThoftIllemannJ <jesper.jaeger@howdendanmark.dk>",]
10
+ readme = "README.md"
11
+ license = "MIT"
12
+ keywords = [ "config", "configuration", "pydantic", "json",]
13
+ homepage = "https://github.com/yourusername/config"
14
+ repository = "https://github.com/yourusername/config"
15
+ documentation = "https://github.com/yourusername/config"
16
+ [[tool.poetry.packages]]
17
+ include = "HowdenParser"
18
+
19
+ [[tool.poetry.packages]]
20
+ include = "parameter"
21
+