Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions mindee/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class CommandConfig(Generic[TypeDoc]):
help="Financial Document (receipt or invoice)",
doc_class=documents.TypeFinancialV1,
),
"proof-of-address": CommandConfig(
help="Proof of Address",
doc_class=documents.TypeProofOfAddressV1,
),
"us-check": CommandConfig(
help="US Bank Check",
doc_class=documents.us.TypeBankCheckV1,
Expand Down
22 changes: 16 additions & 6 deletions mindee/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
InvoiceV3,
InvoiceV4,
PassportV1,
ProofOfAddressV1,
ReceiptV3,
ReceiptV4,
fr,
us,
)
from mindee.documents.base import Document, TypeDocument
from mindee.documents.config import DocumentConfig, DocumentConfigDict
from mindee.documents.fr import CarteGriseV1
from mindee.documents.us import BankCheckV1
from mindee.endpoints import OTS_OWNER, CustomEndpoint, HTTPException, StandardEndpoint
from mindee.input.page_options import PageOptions
from mindee.input.sources import (
Expand Down Expand Up @@ -249,24 +250,33 @@ def _init_default_endpoints(self) -> None:
)
],
),
(OTS_OWNER, BankCheckV1.__name__): DocumentConfig(
(OTS_OWNER, us.BankCheckV1.__name__): DocumentConfig(
document_type="bank_check_v1",
document_class=BankCheckV1,
document_class=us.BankCheckV1,
endpoints=[
StandardEndpoint(
url_name="bank_check", version="1", api_key=self.api_key
)
],
),
(OTS_OWNER, CarteGriseV1.__name__): DocumentConfig(
(OTS_OWNER, fr.CarteGriseV1.__name__): DocumentConfig(
document_type="carte_grise_v1",
document_class=CarteGriseV1,
document_class=fr.CarteGriseV1,
endpoints=[
StandardEndpoint(
url_name="carte_grise", version="1", api_key=self.api_key
)
],
),
(OTS_OWNER, ProofOfAddressV1.__name__): DocumentConfig(
document_type="proof_of_address_v1",
document_class=ProofOfAddressV1,
endpoints=[
StandardEndpoint(
url_name="proof_of_address", version="1", api_key=self.api_key
)
],
),
(OTS_OWNER, CropperV1.__name__): DocumentConfig(
document_type="cropper_v1",
document_class=CropperV1,
Expand Down
1 change: 1 addition & 0 deletions mindee/documents/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
from mindee.documents.financial import FinancialV1, TypeFinancialV1
from mindee.documents.invoice import InvoiceV3, InvoiceV4, TypeInvoiceV3, TypeInvoiceV4
from mindee.documents.passport import PassportV1, TypePassportV1
from mindee.documents.proof_of_address import ProofOfAddressV1, TypeProofOfAddressV1
from mindee.documents.receipt import ReceiptV3, ReceiptV4, TypeReceiptV3, TypeReceiptV4
1 change: 1 addition & 0 deletions mindee/documents/proof_of_address/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .proof_of_address_v1 import ProofOfAddressV1, TypeProofOfAddressV1
111 changes: 111 additions & 0 deletions mindee/documents/proof_of_address/proof_of_address_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
from typing import List, Optional, TypeVar

from mindee.documents.base import Document, TypeApiPrediction, clean_out_string
from mindee.fields.company_registration import CompanyRegistrationField
from mindee.fields.date import DateField
from mindee.fields.locale import LocaleField
from mindee.fields.text import TextField


class ProofOfAddressV1(Document):
locale: LocaleField
"""locale information"""
date: DateField
"""ISO date yyyy-mm-dd. Works both for European and US dates."""
dates: List[DateField] = []
"""All extracted ISO date yyyy-mm-dd"""
issuer_address: TextField
"""Address of the document's issuer."""
issuer_company_registration: List[CompanyRegistrationField] = []
"""Generic: VAT NUMBER, TAX ID, COMPANY REGISTRATION NUMBER or country specific."""
issuer_name: TextField
"""Name of the person or company issuing the document."""
recipient_address: TextField
"""Address of the recipient."""
recipient_company_registration: List[CompanyRegistrationField] = []
"""Generic: VAT NUMBER, TAX ID, COMPANY REGISTRATION NUMBER or country specific."""
recipient_name: TextField
"""Name of the document's recipient."""

def __init__(
self,
api_prediction=None,
input_source=None,
page_n: Optional[int] = None,
document_type="proof_of_address",
):
"""
Proof of Address document.

:param api_prediction: Raw prediction from HTTP response
:param input_source: Input object
:param page_n: Page number for multi pages pdf input
"""
super().__init__(
input_source=input_source,
document_type=document_type,
api_prediction=api_prediction,
page_n=page_n,
)
self._build_from_api_prediction(api_prediction["prediction"], page_n=page_n)

def _build_from_api_prediction(
self, api_prediction: TypeApiPrediction, page_n: Optional[int] = None
) -> None:
"""
Build the object from the prediction API JSON.

:param api_prediction: Raw prediction from HTTP response
:param page_n: Page number for multi pages pdf input
"""
self.locale = LocaleField(
api_prediction["locale"], value_key="language", page_n=page_n
)
self.date = DateField(api_prediction["date"], page_n=page_n)
self.dates = [
DateField(tax_prediction, page_n=page_n)
for tax_prediction in api_prediction["dates"]
]
self.issuer_name = TextField(api_prediction["issuer_name"], page_n=page_n)
self.issuer_address = TextField(api_prediction["issuer_address"], page_n=page_n)
self.issuer_company_registration = [
CompanyRegistrationField(tax_prediction, page_n=page_n)
for tax_prediction in api_prediction["issuer_company_registration"]
]
self.recipient_name = TextField(api_prediction["recipient_name"], page_n=page_n)
self.recipient_address = TextField(
api_prediction["recipient_address"], page_n=page_n
)
self.recipient_company_registration = [
CompanyRegistrationField(tax_prediction, page_n=page_n)
for tax_prediction in api_prediction["recipient_company_registration"]
]

def __str__(self) -> str:
issuer_company_registrations = "; ".join(
[str(n.value) for n in self.issuer_company_registration]
)
recipient_company_registrations = "; ".join(
[str(n.value) for n in self.recipient_company_registration]
)
dates = "\n ".join([str(n.value) for n in self.dates])
return clean_out_string(
"----- Proof of Address V1 -----\n"
f"Filename: {self.filename or ''}\n"
f"Locale: {self.locale}\n"
f"Issuer name: {self.issuer_name}\n"
f"Issuer Address: {self.issuer_address}\n"
f"Issuer Company Registrations: {issuer_company_registrations}\n"
f"Recipient name: {self.recipient_name}\n"
f"Recipient Address: {self.recipient_address}\n"
f"Recipient Company Registrations: {recipient_company_registrations}\n"
f"Issuance Date: {self.date}\n"
f"Dates: {dates}\n"
"----------------------"
)

def _checklist(self) -> None:
pass


TypeProofOfAddressV1 = TypeVar("TypeProofOfAddressV1", bound=ProofOfAddressV1)
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
RECEIPT_DATA_DIR = "./tests/data/receipt"
INVOICE_DATA_DIR = "./tests/data/invoice"
PASSPORT_DATA_DIR = "./tests/data/passport"
PROOF_OF_ADDRESS_DATA_DIR = "./tests/data/proof_of_address"
US_BANK_CHECK_DATA_DIR = "./tests/data/us/bank_check"
FR_CARTE_GRISE_DATA_DIR = "./tests/data/fr/carte_grise"
CUSTOM_DATA_DIR = "./tests/data/custom"
Expand Down
68 changes: 68 additions & 0 deletions tests/documents/test_proof_of_address_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import json

import pytest

from mindee.documents.proof_of_address.proof_of_address_v1 import ProofOfAddressV1
from tests import PROOF_OF_ADDRESS_DATA_DIR

FILE_PATH_PROOF_OF_ADDRESS_V1_COMPLETE = (
f"{PROOF_OF_ADDRESS_DATA_DIR}/response_v1/complete.json"
)


@pytest.fixture
def proof_of_address_v1_doc_object() -> ProofOfAddressV1:
json_data = json.load(open(FILE_PATH_PROOF_OF_ADDRESS_V1_COMPLETE))
return ProofOfAddressV1(
api_prediction=json_data["document"]["inference"], page_n=None
)


@pytest.fixture
def proof_of_address_v1_doc_object_empty() -> ProofOfAddressV1:
json_data = json.load(open(f"{PROOF_OF_ADDRESS_DATA_DIR}/response_v1/empty.json"))
return ProofOfAddressV1(
api_prediction=json_data["document"]["inference"], page_n=None
)


@pytest.fixture
def proof_of_address_v1_page_object() -> ProofOfAddressV1:
json_data = json.load(open(FILE_PATH_PROOF_OF_ADDRESS_V1_COMPLETE))
return ProofOfAddressV1(
api_prediction=json_data["document"]["inference"]["pages"][0], page_n=0
)


def test_doc_constructor(proof_of_address_v1_doc_object):
doc_str = (
open(f"{PROOF_OF_ADDRESS_DATA_DIR}/response_v1/doc_to_string.txt")
.read()
.strip()
)
assert proof_of_address_v1_doc_object.issuer_name.page_n == 0
assert str(proof_of_address_v1_doc_object) == doc_str


def test_page_constructor(proof_of_address_v1_page_object):
doc_str = (
open(f"{PROOF_OF_ADDRESS_DATA_DIR}/response_v1/page0_to_string.txt")
.read()
.strip()
)
assert proof_of_address_v1_page_object.orientation.value == 0
assert proof_of_address_v1_page_object.issuer_name.page_n == 0
assert str(proof_of_address_v1_page_object) == doc_str
assert len(proof_of_address_v1_page_object.cropper) == 0


def test_all_na(proof_of_address_v1_doc_object_empty):
assert proof_of_address_v1_doc_object_empty.locale.value is None
assert proof_of_address_v1_doc_object_empty.date.value is None
assert len(proof_of_address_v1_doc_object_empty.dates) == 0
assert proof_of_address_v1_doc_object_empty.issuer_address.value is None
assert len(proof_of_address_v1_doc_object_empty.issuer_company_registration) == 0
assert proof_of_address_v1_doc_object_empty.issuer_name.value is None
assert proof_of_address_v1_doc_object_empty.recipient_address.value is None
assert len(proof_of_address_v1_doc_object_empty.recipient_company_registration) == 0
assert proof_of_address_v1_doc_object_empty.recipient_name.value is None