120 lines
3.8 KiB
Python
120 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
from .idfc import IDFCFirstParser
|
|
from .axis import AxisParser
|
|
from .hdfc import HDFCParser
|
|
from .icici import ICICIParser
|
|
from .hsbc import HSBCParser
|
|
from .indian_bank import IndianBankModernParser, IndianBankLegacyParser
|
|
from .indusind import IndusIndParser
|
|
from .kotak import KotakParser
|
|
from .sbi import SBIModernParser, SBIOtherParser
|
|
from .central_bank_of_india import CentralBankOfIndiaParser
|
|
from .yes_bank import YesBankParser
|
|
from .city_union_bank import CityUnionBankParser
|
|
from .bank_of_baroda import BankOfBarodaParser
|
|
from .rbl_bank import RBLBankParser
|
|
from .base import extract_text
|
|
|
|
PARSERS = [
|
|
IDFCFirstParser,
|
|
AxisParser,
|
|
CentralBankOfIndiaParser,
|
|
YesBankParser,
|
|
CityUnionBankParser,
|
|
BankOfBarodaParser,
|
|
RBLBankParser,
|
|
HDFCParser,
|
|
ICICIParser,
|
|
HSBCParser,
|
|
IndianBankModernParser,
|
|
IndianBankLegacyParser,
|
|
IndusIndParser,
|
|
KotakParser,
|
|
SBIOtherParser,
|
|
SBIModernParser,
|
|
]
|
|
|
|
BANK_OPTIONS = [
|
|
("auto", "Auto Detect"),
|
|
("axis", "Axis Bank"),
|
|
("central_bank_of_india", "Central Bank of India"),
|
|
("yes_bank", "YES Bank"),
|
|
("city_union_bank", "City Union Bank"),
|
|
("bank_of_baroda", "Bank of Baroda"),
|
|
("rbl_bank", "RBL Bank"),
|
|
("hdfc", "HDFC Bank"),
|
|
("icici", "ICICI Bank"),
|
|
("hsbc", "HSBC Bank"),
|
|
("idfc", "IDFC FIRST Bank"),
|
|
("indian_bank", "Indian Bank"),
|
|
("indusind", "IndusInd Bank"),
|
|
("kotak", "Kotak Mahindra Bank"),
|
|
("sbi", "State Bank of India"),
|
|
]
|
|
|
|
BANK_PARSERS = {
|
|
"axis": [AxisParser],
|
|
"central_bank_of_india": [CentralBankOfIndiaParser],
|
|
"yes_bank": [YesBankParser],
|
|
"city_union_bank": [CityUnionBankParser],
|
|
"bank_of_baroda": [BankOfBarodaParser],
|
|
"rbl_bank": [RBLBankParser],
|
|
"hdfc": [HDFCParser],
|
|
"icici": [ICICIParser],
|
|
"hsbc": [HSBCParser],
|
|
"idfc": [IDFCFirstParser],
|
|
"indian_bank": [IndianBankModernParser, IndianBankLegacyParser],
|
|
"indusind": [IndusIndParser],
|
|
"kotak": [KotakParser],
|
|
"sbi": [SBIOtherParser, SBIModernParser],
|
|
}
|
|
|
|
|
|
def detect_parser(text):
|
|
scored = sorted(((parser.detect(text), parser) for parser in PARSERS), key=lambda item: item[0], reverse=True)
|
|
if not scored or scored[0][0] <= 0:
|
|
return None, 0
|
|
return scored[0][1](), scored[0][0]
|
|
|
|
|
|
def _selected_parser(bank_key: str, text: str):
|
|
candidates = BANK_PARSERS.get(bank_key, [])
|
|
if not candidates:
|
|
return None, 0
|
|
scored = sorted(((parser.detect(text), parser) for parser in candidates), key=lambda item: item[0], reverse=True)
|
|
if scored and scored[0][0] > 0:
|
|
return scored[0][1](), scored[0][0]
|
|
return None, 0
|
|
|
|
|
|
def parse_pdf(path, bank_hint: str | None = None):
|
|
hint = (bank_hint or "auto").strip().lower()
|
|
if hint == "hsbc":
|
|
return HSBCParser().parse(path, "")
|
|
text = extract_text(path)
|
|
if hint and hint != "auto":
|
|
parser, score = _selected_parser(hint, text)
|
|
if parser is None:
|
|
label = dict(BANK_OPTIONS).get(hint, "the selected bank")
|
|
raise ValueError(
|
|
f"The uploaded statement does not match the selected {label} format. "
|
|
"Please verify the selected bank or choose Auto Detect."
|
|
)
|
|
return parser.parse(path, text)
|
|
parser, score = detect_parser(text)
|
|
if parser is None and not (text or "").strip():
|
|
# Image-only statements cannot be identified by pdftotext. HSBCParser
|
|
# performs its own OCR identification and raises a precise mismatch error.
|
|
try:
|
|
return HSBCParser().parse(path, text)
|
|
except ValueError:
|
|
pass
|
|
if parser is None:
|
|
raise ValueError(
|
|
"Unsupported statement format. Select the bank manually or add a bank-specific parser for this statement layout."
|
|
)
|
|
return parser.parse(path, text)
|
|
|
|
|