diff --git a/docs/extras/code_samples/bank_account_details_v1.txt b/docs/extras/code_samples/bank_account_details_v1.txt new file mode 100644 index 00000000..36354173 --- /dev/null +++ b/docs/extras/code_samples/bank_account_details_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.fr.BankAccountDetailsV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/bank_account_details_v2.txt b/docs/extras/code_samples/bank_account_details_v2.txt new file mode 100644 index 00000000..79d1cdec --- /dev/null +++ b/docs/extras/code_samples/bank_account_details_v2.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.fr.BankAccountDetailsV2, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/bank_check_v1.txt b/docs/extras/code_samples/bank_check_v1.txt new file mode 100644 index 00000000..77785368 --- /dev/null +++ b/docs/extras/code_samples/bank_check_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.us.BankCheckV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/barcode_reader_v1.txt b/docs/extras/code_samples/barcode_reader_v1.txt new file mode 100644 index 00000000..d46dbc71 --- /dev/null +++ b/docs/extras/code_samples/barcode_reader_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.BarcodeReaderV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/expense_receipts_v5.txt b/docs/extras/code_samples/expense_receipts_v5.txt new file mode 100644 index 00000000..cb512f26 --- /dev/null +++ b/docs/extras/code_samples/expense_receipts_v5.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.ReceiptV5, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/financial_document_v1.txt b/docs/extras/code_samples/financial_document_v1.txt new file mode 100644 index 00000000..09316d4d --- /dev/null +++ b/docs/extras/code_samples/financial_document_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.FinancialDocumentV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/idcard_fr_v1.txt b/docs/extras/code_samples/idcard_fr_v1.txt new file mode 100644 index 00000000..783918f9 --- /dev/null +++ b/docs/extras/code_samples/idcard_fr_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.fr.IdCardV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/idcard_fr_v2.txt b/docs/extras/code_samples/idcard_fr_v2.txt new file mode 100644 index 00000000..5811aac8 --- /dev/null +++ b/docs/extras/code_samples/idcard_fr_v2.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.fr.IdCardV2, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/invoices_v4.txt b/docs/extras/code_samples/invoices_v4.txt new file mode 100644 index 00000000..04eb3145 --- /dev/null +++ b/docs/extras/code_samples/invoices_v4.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.InvoiceV4, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/license_plates_v1.txt b/docs/extras/code_samples/license_plates_v1.txt new file mode 100644 index 00000000..14af92f1 --- /dev/null +++ b/docs/extras/code_samples/license_plates_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.eu.LicensePlateV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/multi_receipts_detector_v1.txt b/docs/extras/code_samples/multi_receipts_detector_v1.txt new file mode 100644 index 00000000..6a16410a --- /dev/null +++ b/docs/extras/code_samples/multi_receipts_detector_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.MultiReceiptsDetectorV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/passport_v1.txt b/docs/extras/code_samples/passport_v1.txt new file mode 100644 index 00000000..4b094740 --- /dev/null +++ b/docs/extras/code_samples/passport_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.PassportV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/proof_of_address_v1.txt b/docs/extras/code_samples/proof_of_address_v1.txt new file mode 100644 index 00000000..d6049ea1 --- /dev/null +++ b/docs/extras/code_samples/proof_of_address_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.ProofOfAddressV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/us_driver_license_v1.txt b/docs/extras/code_samples/us_driver_license_v1.txt new file mode 100644 index 00000000..2e9a3718 --- /dev/null +++ b/docs/extras/code_samples/us_driver_license_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.us.DriverLicenseV1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/extras/code_samples/us_w9_v1.txt b/docs/extras/code_samples/us_w9_v1.txt new file mode 100644 index 00000000..733c5000 --- /dev/null +++ b/docs/extras/code_samples/us_w9_v1.txt @@ -0,0 +1,18 @@ +from mindee import Client, PredictResponse, product + +# Init a new client +mindee_client = Client(api_key="my-api-key") + +# Load a file from disk +input_doc = mindee_client.source_from_path("/path/to/the/file.ext") + +# Load a file from disk and parse it. +# The endpoint name must be specified since it cannot be determined from the class. +result: PredictResponse = mindee_client.parse(product.us.W9V1, input_doc) + +# Print a brief summary of the parsed data +print(result.document) + +# # Iterate over all the fields in the document +# for field_name, field_values in result.document.inference.prediction.fields.items(): +# print(field_name, "=", field_values) diff --git a/docs/predictions/standard/product/barcode_reader_v1.rst b/docs/predictions/standard/product/barcode_reader_v1.rst new file mode 100644 index 00000000..238ede03 --- /dev/null +++ b/docs/predictions/standard/product/barcode_reader_v1.rst @@ -0,0 +1,10 @@ +Barcode Reader V1 +----------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/barcode_reader_v1.txt + :language: Python + +.. autoclass:: mindee.product.BarcodeReaderV1 + :members: diff --git a/docs/predictions/standard/product/eu/license_plate_v1.rst b/docs/predictions/standard/product/eu/license_plate_v1.rst new file mode 100644 index 00000000..38fa25f6 --- /dev/null +++ b/docs/predictions/standard/product/eu/license_plate_v1.rst @@ -0,0 +1,10 @@ +License Plate V1 +---------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/license_plates_v1.txt + :language: Python + +.. autoclass:: mindee.product.eu.LicensePlateV1 + :members: diff --git a/docs/predictions/standard/product/financial_document_v1.rst b/docs/predictions/standard/product/financial_document_v1.rst new file mode 100644 index 00000000..ee237f3b --- /dev/null +++ b/docs/predictions/standard/product/financial_document_v1.rst @@ -0,0 +1,13 @@ +Financial Document V1 +--------------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/financial_document_v1.txt + :language: Python + +.. autoclass:: mindee.product.FinancialDocumentV1 + :members: + +.. autoclass:: mindee.product.FinancialDocumentV1LineItem + :members: diff --git a/docs/predictions/standard/product/fr/bank_account_details_v1.rst b/docs/predictions/standard/product/fr/bank_account_details_v1.rst new file mode 100644 index 00000000..c10820b2 --- /dev/null +++ b/docs/predictions/standard/product/fr/bank_account_details_v1.rst @@ -0,0 +1,10 @@ +Bank Account Details V1 +----------------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/bank_account_details_v1.txt + :language: Python + +.. autoclass:: mindee.product.fr.BankAccountDetailsV1 + :members: diff --git a/docs/predictions/standard/product/fr/bank_account_details_v2.rst b/docs/predictions/standard/product/fr/bank_account_details_v2.rst new file mode 100644 index 00000000..0daed880 --- /dev/null +++ b/docs/predictions/standard/product/fr/bank_account_details_v2.rst @@ -0,0 +1,13 @@ +Bank Account Details V2 +----------------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/bank_account_details_v2.txt + :language: Python + +.. autoclass:: mindee.product.fr.BankAccountDetailsV2 + :members: + +.. autoclass:: mindee.product.fr.BankAccountDetailsV2Bban + :members: diff --git a/docs/predictions/standard/product/fr/carte_vitale_v1.rst b/docs/predictions/standard/product/fr/carte_vitale_v1.rst new file mode 100644 index 00000000..446aa6db --- /dev/null +++ b/docs/predictions/standard/product/fr/carte_vitale_v1.rst @@ -0,0 +1,10 @@ +Carte Vitale V1 +--------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/carte_vitale_v1.txt + :language: Python + +.. autoclass:: mindee.product.fr.CarteVitaleV1 + :members: diff --git a/docs/predictions/standard/product/fr/id_card_v1.rst b/docs/predictions/standard/product/fr/id_card_v1.rst new file mode 100644 index 00000000..1702261a --- /dev/null +++ b/docs/predictions/standard/product/fr/id_card_v1.rst @@ -0,0 +1,10 @@ +Carte Nationale d'Identité V1 +----------------------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/idcard_fr_v1.txt + :language: Python + +.. autoclass:: mindee.product.fr.IdCardV1 + :members: diff --git a/docs/predictions/standard/product/fr/id_card_v2.rst b/docs/predictions/standard/product/fr/id_card_v2.rst new file mode 100644 index 00000000..f15954eb --- /dev/null +++ b/docs/predictions/standard/product/fr/id_card_v2.rst @@ -0,0 +1,10 @@ +Carte Nationale d'Identité V2 +----------------------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/idcard_fr_v2.txt + :language: Python + +.. autoclass:: mindee.product.fr.IdCardV2 + :members: diff --git a/docs/predictions/standard/product/invoice_v4.rst b/docs/predictions/standard/product/invoice_v4.rst new file mode 100644 index 00000000..86c3d9af --- /dev/null +++ b/docs/predictions/standard/product/invoice_v4.rst @@ -0,0 +1,13 @@ +Invoice V4 +---------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/invoices_v4.txt + :language: Python + +.. autoclass:: mindee.product.InvoiceV4 + :members: + +.. autoclass:: mindee.product.InvoiceV4LineItem + :members: diff --git a/docs/predictions/standard/product/multi_receipts_detector_v1.rst b/docs/predictions/standard/product/multi_receipts_detector_v1.rst new file mode 100644 index 00000000..a778ff6f --- /dev/null +++ b/docs/predictions/standard/product/multi_receipts_detector_v1.rst @@ -0,0 +1,10 @@ +Multi Receipts Detector V1 +-------------------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/multi_receipts_detector_v1.txt + :language: Python + +.. autoclass:: mindee.product.MultiReceiptsDetectorV1 + :members: diff --git a/docs/predictions/standard/product/passport_v1.rst b/docs/predictions/standard/product/passport_v1.rst new file mode 100644 index 00000000..14be4bd2 --- /dev/null +++ b/docs/predictions/standard/product/passport_v1.rst @@ -0,0 +1,10 @@ +Passport V1 +----------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/passport_v1.txt + :language: Python + +.. autoclass:: mindee.product.PassportV1 + :members: diff --git a/docs/predictions/standard/product/proof_of_address_v1.rst b/docs/predictions/standard/product/proof_of_address_v1.rst new file mode 100644 index 00000000..74a3ce8b --- /dev/null +++ b/docs/predictions/standard/product/proof_of_address_v1.rst @@ -0,0 +1,10 @@ +Proof of Address V1 +------------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/proof_of_address_v1.txt + :language: Python + +.. autoclass:: mindee.product.ProofOfAddressV1 + :members: diff --git a/docs/predictions/standard/product/receipt_v5.rst b/docs/predictions/standard/product/receipt_v5.rst new file mode 100644 index 00000000..94a09095 --- /dev/null +++ b/docs/predictions/standard/product/receipt_v5.rst @@ -0,0 +1,13 @@ +Receipt V5 +---------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/expense_receipts_v5.txt + :language: Python + +.. autoclass:: mindee.product.ReceiptV5 + :members: + +.. autoclass:: mindee.product.ReceiptV5LineItem + :members: diff --git a/docs/predictions/standard/product/us/bank_check_v1.rst b/docs/predictions/standard/product/us/bank_check_v1.rst new file mode 100644 index 00000000..28bff4d5 --- /dev/null +++ b/docs/predictions/standard/product/us/bank_check_v1.rst @@ -0,0 +1,10 @@ +Bank Check V1 +------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/bank_check_v1.txt + :language: Python + +.. autoclass:: mindee.product.us.BankCheckV1 + :members: diff --git a/docs/predictions/standard/product/us/driver_license_v1.rst b/docs/predictions/standard/product/us/driver_license_v1.rst new file mode 100644 index 00000000..819ed681 --- /dev/null +++ b/docs/predictions/standard/product/us/driver_license_v1.rst @@ -0,0 +1,10 @@ +Driver License V1 +----------------- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/us_driver_license_v1.txt + :language: Python + +.. autoclass:: mindee.product.us.DriverLicenseV1 + :members: diff --git a/docs/predictions/standard/product/us/w9_v1.rst b/docs/predictions/standard/product/us/w9_v1.rst new file mode 100644 index 00000000..834a27ac --- /dev/null +++ b/docs/predictions/standard/product/us/w9_v1.rst @@ -0,0 +1,10 @@ +W9 V1 +----- + +**Sample Code:** + +.. literalinclude:: /extras/code_samples/us_w9_v1.txt + :language: Python + +.. autoclass:: mindee.product.us.W9V1 + :members: diff --git a/mindee/parsing/common/__init__.py b/mindee/parsing/common/__init__.py index 7c72e132..7dc4b1e9 100644 --- a/mindee/parsing/common/__init__.py +++ b/mindee/parsing/common/__init__.py @@ -12,4 +12,4 @@ from mindee.parsing.common.predict_response import PredictResponse from mindee.parsing.common.prediction import Prediction from mindee.parsing.common.string_dict import StringDict -from mindee.parsing.common.summary_helper import clean_out_string, line_separator +from mindee.parsing.common.summary_helper import clean_out_string, format_for_display, line_separator diff --git a/mindee/parsing/common/summary_helper.py b/mindee/parsing/common/summary_helper.py index 4906347b..d7f31799 100644 --- a/mindee/parsing/common/summary_helper.py +++ b/mindee/parsing/common/summary_helper.py @@ -1,5 +1,5 @@ import re -from typing import List +from typing import List, Optional def line_separator(column_sizes: List[int], separator: str) -> str: @@ -14,3 +14,13 @@ def clean_out_string(out_string: str) -> str: """Clean up the string representation.""" regexp = re.compile(r" \n") return regexp.sub("\n", out_string).strip() + + +def format_for_display( + out_string: Optional[str] = None, max_col_size: Optional[int] = None +) -> str: + if not out_string or len(out_string) == 0: + return "" + if max_col_size is None: + return out_string + return out_string if len(out_string) < max_col_size else f"{out_string[:max_col_size-3]}..." diff --git a/mindee/parsing/standard/__init__.py b/mindee/parsing/standard/__init__.py index 7cd6e6ae..96e937e7 100644 --- a/mindee/parsing/standard/__init__.py +++ b/mindee/parsing/standard/__init__.py @@ -1,10 +1,16 @@ from mindee.parsing.standard.amount import AmountField -from mindee.parsing.standard.base import BaseField +from mindee.parsing.standard.base import ( + BaseField, + FieldConfidenceMixin, + FieldPositionMixin, + to_opt_float, + float_to_string, +) from mindee.parsing.standard.classification import ClassificationField from mindee.parsing.standard.company_registration import CompanyRegistrationField from mindee.parsing.standard.date import DateField from mindee.parsing.standard.locale import LocaleField -from mindee.parsing.standard.payment_details import PaymentDetails +from mindee.parsing.standard.payment_details import PaymentDetailsField from mindee.parsing.standard.position import PositionField from mindee.parsing.standard.tax import Taxes, TaxField from mindee.parsing.standard.text import StringField diff --git a/mindee/parsing/standard/company_registration.py b/mindee/parsing/standard/company_registration.py index 2783ea2f..be8ec5bd 100644 --- a/mindee/parsing/standard/company_registration.py +++ b/mindee/parsing/standard/company_registration.py @@ -21,7 +21,7 @@ def __init__( self.type = raw_prediction["type"] self._set_position(raw_prediction) - def __str__(self) -> str: + def display(self) -> str: if self.value: return f"{self.type}: {self.value}" return "" diff --git a/mindee/parsing/standard/payment_details.py b/mindee/parsing/standard/payment_details.py index a78a8fbe..29849466 100644 --- a/mindee/parsing/standard/payment_details.py +++ b/mindee/parsing/standard/payment_details.py @@ -4,7 +4,7 @@ from mindee.parsing.standard.base import BaseField, FieldPositionMixin -class PaymentDetails(FieldPositionMixin, BaseField): +class PaymentDetailsField(FieldPositionMixin, BaseField): """Information on a single payment.""" account_number: Optional[str] = None diff --git a/mindee/product/__init__.py b/mindee/product/__init__.py index abf08d1f..9e69bd70 100644 --- a/mindee/product/__init__.py +++ b/mindee/product/__init__.py @@ -1,19 +1,19 @@ from mindee.product import eu, fr, us -from mindee.product.cropper import CropperV1 -from mindee.product.custom import CustomV1 - -# from mindee.product.financial_document import ( -# FinancialDocumentV1, -# FinancialDocumentV1LineItem, -# ) -# from mindee.product.invoice import InvoiceV4 -from mindee.product.invoice_splitter import InvoiceSplitterV1 +from mindee.product.barcode_reader.barcode_reader_v1 import BarcodeReaderV1 +from mindee.product.cropper.cropper_v1 import CropperV1 +from mindee.product.custom.custom_v1 import CustomV1 +from mindee.product.financial_document.financial_document_v1 import FinancialDocumentV1 +from mindee.product.invoice.invoice_v4 import InvoiceV4 +from mindee.product.invoice_splitter.invoice_splitter_v1 import InvoiceSplitterV1 # from mindee.product.material_certificate import ( # MaterialCertificateV1, # ) -from mindee.product.receipt import ( # ReceiptV5,; ReceiptV5LineItem, - ReceiptV4, - ReceiptV4Document, +from mindee.product.multi_receipts_detector.multi_receipts_detector_v1 import ( + MultiReceiptsDetectorV1, ) +from mindee.product.passport.passport_v1 import PassportV1 +from mindee.product.proof_of_address.proof_of_address_v1 import ProofOfAddressV1 +from mindee.product.receipt.receipt_v4 import ReceiptV4 +from mindee.product.receipt.receipt_v5 import ReceiptV5 diff --git a/mindee/product/barcode_reader/__init__.py b/mindee/product/barcode_reader/__init__.py new file mode 100644 index 00000000..4c9af958 --- /dev/null +++ b/mindee/product/barcode_reader/__init__.py @@ -0,0 +1,2 @@ +from mindee.product.barcode_reader.barcode_reader_v1 import BarcodeReaderV1 +from mindee.product.barcode_reader.barcode_reader_v1_document import BarcodeReaderV1Document diff --git a/mindee/product/barcode_reader/barcode_reader_v1.py b/mindee/product/barcode_reader/barcode_reader_v1.py new file mode 100644 index 00000000..20e63d17 --- /dev/null +++ b/mindee/product/barcode_reader/barcode_reader_v1.py @@ -0,0 +1,32 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.barcode_reader.barcode_reader_v1_document import ( + BarcodeReaderV1Document, +) + + +class BarcodeReaderV1(Inference): + """Inference prediction for Barcode Reader, API version 1.""" + + prediction: BarcodeReaderV1Document + """Document-level prediction.""" + pages: List[Page[BarcodeReaderV1Document]] + """Page-level prediction(s).""" + endpoint_name = "barcode_reader" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Barcode Reader v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = BarcodeReaderV1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(BarcodeReaderV1Document, page)) diff --git a/mindee/product/barcode_reader/barcode_reader_v1_document.py b/mindee/product/barcode_reader/barcode_reader_v1_document.py new file mode 100644 index 00000000..b5e7e777 --- /dev/null +++ b/mindee/product/barcode_reader/barcode_reader_v1_document.py @@ -0,0 +1,43 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import StringField + + +class BarcodeReaderV1Document(Prediction): + """Document data for Barcode Reader, API version 1.""" + + codes_1d: List[StringField] + """List of decoded 1D barcodes.""" + codes_2d: List[StringField] + """List of decoded 2D barcodes.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Barcode Reader document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.codes_1d = [ + StringField(prediction, page_id=page_id) + for prediction in raw_prediction["codes_1d"] + ] + self.codes_2d = [ + StringField(prediction, page_id=page_id) + for prediction in raw_prediction["codes_2d"] + ] + + def __str__(self) -> str: + codes_1d = f"\n { ' ' * 13 }".join( + [str(item) for item in self.codes_1d], + ) + codes_2d = f"\n { ' ' * 13 }".join( + [str(item) for item in self.codes_2d], + ) + + return clean_out_string(f":Barcodes 1D: {codes_1d}\n" f":Barcodes 2D: {codes_2d}\n") diff --git a/mindee/product/eu/__init__.py b/mindee/product/eu/__init__.py index e69de29b..fe1f733a 100644 --- a/mindee/product/eu/__init__.py +++ b/mindee/product/eu/__init__.py @@ -0,0 +1,2 @@ +from mindee.product.eu.license_plate.license_plate_v1 import LicensePlateV1 +from mindee.product.eu.license_plate.license_plate_v1_document import LicensePlateV1Document diff --git a/mindee/product/eu/license_plate/__init__.py b/mindee/product/eu/license_plate/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mindee/product/eu/license_plate/license_plate_v1.py b/mindee/product/eu/license_plate/license_plate_v1.py new file mode 100644 index 00000000..350d7801 --- /dev/null +++ b/mindee/product/eu/license_plate/license_plate_v1.py @@ -0,0 +1,32 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.eu.license_plate.license_plate_v1_document import ( + LicensePlateV1Document, +) + + +class LicensePlateV1(Inference): + """Inference prediction for License Plate, API version 1.""" + + prediction: LicensePlateV1Document + """Document-level prediction.""" + pages: List[Page[LicensePlateV1Document]] + """Page-level prediction(s).""" + endpoint_name = "license_plates" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + License Plate v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = LicensePlateV1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(LicensePlateV1Document, page)) diff --git a/mindee/product/eu/license_plate/license_plate_v1_document.py b/mindee/product/eu/license_plate/license_plate_v1_document.py new file mode 100644 index 00000000..07e3c9d2 --- /dev/null +++ b/mindee/product/eu/license_plate/license_plate_v1_document.py @@ -0,0 +1,34 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import StringField + + +class LicensePlateV1Document(Prediction): + """Document data for License Plate, API version 1.""" + + license_plates: List[StringField] + """List of all license plates found in the image.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + License Plate document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.license_plates = [ + StringField(prediction, page_id=page_id) + for prediction in raw_prediction["license_plates"] + ] + + def __str__(self) -> str: + license_plates = f"\n { ' ' * 16 }".join( + [str(item) for item in self.license_plates], + ) + + return clean_out_string(f":License Plates: {license_plates}\n") diff --git a/mindee/product/financial_document/__init__.py b/mindee/product/financial_document/__init__.py new file mode 100644 index 00000000..42ae24bd --- /dev/null +++ b/mindee/product/financial_document/__init__.py @@ -0,0 +1,3 @@ +from mindee.product.financial_document.financial_document_v1 import FinancialDocumentV1 +from mindee.product.financial_document.financial_document_v1_document import FinancialDocumentV1Document +from mindee.product.financial_document.financial_document_v1_line_item import FinancialDocumentV1LineItem diff --git a/mindee/product/financial_document/financial_document_v1.py b/mindee/product/financial_document/financial_document_v1.py new file mode 100644 index 00000000..11d7026c --- /dev/null +++ b/mindee/product/financial_document/financial_document_v1.py @@ -0,0 +1,32 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.financial_document.financial_document_v1_document import ( + FinancialDocumentV1Document, +) + + +class FinancialDocumentV1(Inference): + """Inference prediction for Financial Document, API version 1.""" + + prediction: FinancialDocumentV1Document + """Document-level prediction.""" + pages: List[Page[FinancialDocumentV1Document]] + """Page-level prediction(s).""" + endpoint_name = "financial_document" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Financial Document v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = FinancialDocumentV1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(FinancialDocumentV1Document, page)) diff --git a/mindee/product/financial_document/financial_document_v1_document.py b/mindee/product/financial_document/financial_document_v1_document.py new file mode 100644 index 00000000..f30109e1 --- /dev/null +++ b/mindee/product/financial_document/financial_document_v1_document.py @@ -0,0 +1,242 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import ( + AmountField, + ClassificationField, + CompanyRegistrationField, + DateField, + LocaleField, + PaymentDetailsField, + StringField, + Taxes, +) + +from mindee.product.financial_document.financial_document_v1_line_item import ( + FinancialDocumentV1LineItem, +) + + +class FinancialDocumentV1Document(Prediction): + """Document data for Financial Document, API version 1.""" + + category: ClassificationField + """The purchase category among predefined classes.""" + customer_address: StringField + """The address of the customer.""" + customer_company_registrations: List[CompanyRegistrationField] + """List of company registrations associated to the customer.""" + customer_name: StringField + """The name of the customer.""" + date: DateField + """The date the purchase was made.""" + document_type: ClassificationField + """One of: 'INVOICE', 'CREDIT NOTE', 'CREDIT CARD RECEIPT', 'EXPENSE RECEIPT'.""" + due_date: DateField + """The date on which the payment is due.""" + invoice_number: StringField + """The invoice number or identifier.""" + line_items: List[FinancialDocumentV1LineItem] + """List of line item details.""" + locale: LocaleField + """The locale detected on the document.""" + reference_numbers: List[StringField] + """List of Reference numbers, including PO number.""" + subcategory: ClassificationField + """The purchase subcategory among predefined classes for transport and food.""" + supplier_address: StringField + """The address of the supplier or merchant.""" + supplier_company_registrations: List[CompanyRegistrationField] + """List of company registrations associated to the supplier.""" + supplier_name: StringField + """The name of the supplier or merchant.""" + supplier_payment_details: List[PaymentDetailsField] + """List of payment details associated to the supplier.""" + supplier_phone_number: StringField + """The phone number of the supplier or merchant.""" + taxes: Taxes + """List of tax lines information.""" + time: StringField + """The time the purchase was made.""" + tip: AmountField + """The total amount of tip and gratuity""" + total_amount: AmountField + """The total amount paid: includes taxes, tips, fees, and other charges.""" + total_net: AmountField + """The net amount paid: does not include taxes, fees, and discounts.""" + total_tax: AmountField + """The total amount of taxes.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Financial Document document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.category = ClassificationField( + raw_prediction["category"], + page_id=page_id, + ) + self.customer_address = StringField( + raw_prediction["customer_address"], + page_id=page_id, + ) + self.customer_company_registrations = [ + CompanyRegistrationField(prediction, page_id=page_id) + for prediction in raw_prediction["customer_company_registrations"] + ] + self.customer_name = StringField( + raw_prediction["customer_name"], + page_id=page_id, + ) + self.date = DateField( + raw_prediction["date"], + page_id=page_id, + ) + self.document_type = ClassificationField( + raw_prediction["document_type"], + page_id=page_id, + ) + self.due_date = DateField( + raw_prediction["due_date"], + page_id=page_id, + ) + self.invoice_number = StringField( + raw_prediction["invoice_number"], + page_id=page_id, + ) + self.line_items = [ + FinancialDocumentV1LineItem(prediction, page_id=page_id) + for prediction in raw_prediction["line_items"] + ] + self.locale = LocaleField( + raw_prediction["locale"], + page_id=page_id, + ) + self.reference_numbers = [ + StringField(prediction, page_id=page_id) + for prediction in raw_prediction["reference_numbers"] + ] + self.subcategory = ClassificationField( + raw_prediction["subcategory"], + page_id=page_id, + ) + self.supplier_address = StringField( + raw_prediction["supplier_address"], + page_id=page_id, + ) + self.supplier_company_registrations = [ + CompanyRegistrationField(prediction, page_id=page_id) + for prediction in raw_prediction["supplier_company_registrations"] + ] + self.supplier_name = StringField( + raw_prediction["supplier_name"], + page_id=page_id, + ) + self.supplier_payment_details = [ + PaymentDetailsField(prediction, page_id=page_id) + for prediction in raw_prediction["supplier_payment_details"] + ] + self.supplier_phone_number = StringField( + raw_prediction["supplier_phone_number"], + page_id=page_id, + ) + self.taxes = Taxes(raw_prediction["taxes"], page_id=page_id) + self.time = StringField( + raw_prediction["time"], + page_id=page_id, + ) + self.tip = AmountField( + raw_prediction["tip"], + page_id=page_id, + ) + self.total_amount = AmountField( + raw_prediction["total_amount"], + page_id=page_id, + ) + self.total_net = AmountField( + raw_prediction["total_net"], + page_id=page_id, + ) + self.total_tax = AmountField( + raw_prediction["total_tax"], + page_id=page_id, + ) + + @staticmethod + def _line_items_separator(char: str) -> str: + out_str = " " + out_str += f"+{char * 38}" + out_str += f"+{char * 14}" + out_str += f"+{char * 10}" + out_str += f"+{char * 12}" + out_str += f"+{char * 14}" + out_str += f"+{char * 14}" + out_str += f"+{char * 12}" + return out_str + "+" + + def _line_items_to_str(self) -> str: + if not self.line_items: + return "" + + lines = f"\n{self._line_items_separator('-')}\n ".join( + [item.to_table_line() for item in self.line_items] + ) + out_str = "" + out_str += f"\n{self._line_items_separator('-')}\n " + out_str += " | Description " + out_str += " | Product code" + out_str += " | Quantity" + out_str += " | Tax Amount" + out_str += " | Tax Rate (%)" + out_str += " | Total Amount" + out_str += " | Unit Price" + out_str += f" |\n{self._line_items_separator('=')}" + out_str += f"\n {lines}" + out_str += f"\n{self._line_items_separator('-')}" + return out_str + + def __str__(self) -> str: + customer_company_registrations = f"\n { ' ' * 32 }".join( + [str(item) for item in self.customer_company_registrations], + ) + reference_numbers = f"\n { ' ' * 19 }".join( + [str(item) for item in self.reference_numbers], + ) + supplier_company_registrations = f"\n { ' ' * 32 }".join( + [str(item) for item in self.supplier_company_registrations], + ) + supplier_payment_details = f"\n { ' ' * 26 }".join( + [str(item) for item in self.supplier_payment_details], + ) + + return clean_out_string( + f":Locale: {self.locale}\n" + f":Invoice Number: {self.invoice_number}\n" + f":Reference Numbers: {reference_numbers}\n" + f":Purchase Date: {self.date}\n" + f":Due Date: {self.due_date}\n" + f":Total Net: {self.total_net}\n" + f":Total Amount: {self.total_amount}\n" + f":Taxes: {self.taxes}\n" + f":Supplier Payment Details: {supplier_payment_details}\n" + f":Supplier name: {self.supplier_name}\n" + f":Customer Name: {self.customer_name}\n" + f":Supplier Company Registrations: {supplier_company_registrations}\n" + f":Supplier Address: {self.supplier_address}\n" + f":Supplier Phone Number: {self.supplier_phone_number}\n" + f":Customer Company Registrations: {customer_company_registrations}\n" + f":Customer Address: {self.customer_address}\n" + f":Document Type: {self.document_type}\n" + f":Purchase Subcategory: {self.subcategory}\n" + f":Purchase Category: {self.category}\n" + f":Total Tax: {self.total_tax}\n" + f":Tip and Gratuity: {self.tip}\n" + f":Purchase Time: {self.time}\n" + f":Line Items: {self._line_items_to_str()}\n" + ) diff --git a/mindee/product/financial_document/financial_document_v1_line_item.py b/mindee/product/financial_document/financial_document_v1_line_item.py new file mode 100644 index 00000000..2b235172 --- /dev/null +++ b/mindee/product/financial_document/financial_document_v1_line_item.py @@ -0,0 +1,93 @@ +from typing import Dict, Optional + +from mindee.parsing.common import format_for_display, StringDict +from mindee.parsing.standard import ( + FieldConfidenceMixin, + FieldPositionMixin, + float_to_string, + to_opt_float, +) + + +class FinancialDocumentV1LineItem(FieldPositionMixin, FieldConfidenceMixin): + """List of line item details.""" + + description: Optional[str] + """The item description.""" + product_code: Optional[str] + """The product code referring to the item.""" + quantity: Optional[float] + """The item quantity""" + tax_amount: Optional[float] + """The item tax amount.""" + tax_rate: Optional[float] + """The item tax rate in percentage.""" + total_amount: Optional[float] + """The item total amount.""" + unit_price: Optional[float] + """The item unit price.""" + page_n: int + """The document page on which the information was found.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + self._set_confidence(raw_prediction) + self._set_position(raw_prediction) + + if page_id is None: + try: + self.page_n = raw_prediction["page_id"] + except KeyError: + pass + else: + self.page_n = page_id + + self.description = raw_prediction["description"] + self.product_code = raw_prediction["product_code"] + self.quantity = to_opt_float(raw_prediction, "quantity") + self.tax_amount = to_opt_float(raw_prediction, "tax_amount") + self.tax_rate = to_opt_float(raw_prediction, "tax_rate") + self.total_amount = to_opt_float(raw_prediction, "total_amount") + self.unit_price = to_opt_float(raw_prediction, "unit_price") + + def _printable_values(self) -> Dict[str, str]: + """Return values for printing.""" + return { + "description": format_for_display(self.description, 36), + "product_code": format_for_display(self.product_code, None), + "quantity": float_to_string(self.quantity), + "tax_amount": float_to_string(self.tax_amount), + "tax_rate": float_to_string(self.tax_rate), + "total_amount": float_to_string(self.total_amount), + "unit_price": float_to_string(self.unit_price), + } + + def to_table_line(self) -> str: + """Output in a format suitable for inclusion in an rST table.""" + printable = self._printable_values() + return ( + "|" + f" {printable['description']:<36} |" + f" {printable['product_code']:<12} |" + f" {printable['quantity']:<8} |" + f" {printable['tax_amount']:<10} |" + f" {printable['tax_rate']:<12} |" + f" {printable['total_amount']:<12} |" + f" {printable['unit_price']:<10} |" + ) + + def __str__(self) -> str: + """Default string representation.""" + printable = self._printable_values() + return ( + f"Description: {printable['description']}, " + f"Product code: {printable['product_code']}, " + f"Quantity: {printable['quantity']}, " + f"Tax Amount: {printable['tax_amount']}, " + f"Tax Rate (%): {printable['tax_rate']}, " + f"Total Amount: {printable['total_amount']}, " + f"Unit Price: {printable['unit_price']}, " + ).strip() diff --git a/mindee/product/fr/__init__.py b/mindee/product/fr/__init__.py index bcbba07a..b5b3523c 100644 --- a/mindee/product/fr/__init__.py +++ b/mindee/product/fr/__init__.py @@ -1,2 +1,13 @@ from mindee.product.fr.carte_vitale.carte_vitale_v1 import CarteVitaleV1 +from mindee.product.fr.carte_vitale.carte_vitale_v1_document import CarteVitaleV1Document from mindee.product.fr.id_card.id_card_v1 import IdCardV1 +from mindee.product.fr.id_card.id_card_v1_document import IdCardV1Document +from mindee.product.fr.id_card.id_card_v1_page import IdCardV1Page +from mindee.product.fr.id_card.id_card_v2 import IdCardV2 +from mindee.product.fr.id_card.id_card_v2_document import IdCardV2Document +from mindee.product.fr.id_card.id_card_v2_page import IdCardV2Page +from mindee.product.fr.bank_account_details.bank_account_details_v1 import BankAccountDetailsV1 +from mindee.product.fr.bank_account_details.bank_account_details_v1_document import BankAccountDetailsV1Document +from mindee.product.fr.bank_account_details.bank_account_details_v2 import BankAccountDetailsV2 +from mindee.product.fr.bank_account_details.bank_account_details_v2_document import BankAccountDetailsV2Document +from mindee.product.fr.bank_account_details.bank_account_details_v2_bban import BankAccountDetailsV2Bban diff --git a/mindee/product/fr/bank_account_details/__init__.py b/mindee/product/fr/bank_account_details/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mindee/product/fr/bank_account_details/bank_account_details_v1.py b/mindee/product/fr/bank_account_details/bank_account_details_v1.py new file mode 100644 index 00000000..bb900336 --- /dev/null +++ b/mindee/product/fr/bank_account_details/bank_account_details_v1.py @@ -0,0 +1,32 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.fr.bank_account_details.bank_account_details_v1_document import ( + BankAccountDetailsV1Document, +) + + +class BankAccountDetailsV1(Inference): + """Inference prediction for Bank Account Details, API version 1.""" + + prediction: BankAccountDetailsV1Document + """Document-level prediction.""" + pages: List[Page[BankAccountDetailsV1Document]] + """Page-level prediction(s).""" + endpoint_name = "bank_account_details" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Bank Account Details v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = BankAccountDetailsV1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(BankAccountDetailsV1Document, page)) diff --git a/mindee/product/fr/bank_account_details/bank_account_details_v1_document.py b/mindee/product/fr/bank_account_details/bank_account_details_v1_document.py new file mode 100644 index 00000000..8a0ecf58 --- /dev/null +++ b/mindee/product/fr/bank_account_details/bank_account_details_v1_document.py @@ -0,0 +1,47 @@ +from typing import Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import StringField + + +class BankAccountDetailsV1Document(Prediction): + """Document data for Bank Account Details, API version 1.""" + + account_holder_name: StringField + """The name of the account holder as seen on the document.""" + iban: StringField + """The International Bank Account Number (IBAN).""" + swift: StringField + """The bank's SWIFT Business Identifier Code (BIC).""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Bank Account Details document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.account_holder_name = StringField( + raw_prediction["account_holder_name"], + page_id=page_id, + ) + self.iban = StringField( + raw_prediction["iban"], + page_id=page_id, + ) + self.swift = StringField( + raw_prediction["swift"], + page_id=page_id, + ) + + def __str__(self) -> str: + + return clean_out_string( + f":IBAN: {self.iban}\n" + f":Account Holder's Name: {self.account_holder_name}\n" + f":SWIFT Code: {self.swift}\n" + ) diff --git a/mindee/product/fr/bank_account_details/bank_account_details_v2.py b/mindee/product/fr/bank_account_details/bank_account_details_v2.py new file mode 100644 index 00000000..d0f617d4 --- /dev/null +++ b/mindee/product/fr/bank_account_details/bank_account_details_v2.py @@ -0,0 +1,32 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.fr.bank_account_details.bank_account_details_v2_document import ( + BankAccountDetailsV2Document, +) + + +class BankAccountDetailsV2(Inference): + """Inference prediction for Bank Account Details, API version 2.""" + + prediction: BankAccountDetailsV2Document + """Document-level prediction.""" + pages: List[Page[BankAccountDetailsV2Document]] + """Page-level prediction(s).""" + endpoint_name = "bank_account_details" + """Name of the endpoint.""" + endpoint_version = "2" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Bank Account Details v2 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = BankAccountDetailsV2Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(BankAccountDetailsV2Document, page)) diff --git a/mindee/product/fr/bank_account_details/bank_account_details_v2_bban.py b/mindee/product/fr/bank_account_details/bank_account_details_v2_bban.py new file mode 100644 index 00000000..3154d03d --- /dev/null +++ b/mindee/product/fr/bank_account_details/bank_account_details_v2_bban.py @@ -0,0 +1,72 @@ +from typing import Dict, Optional + +from mindee.parsing.common import format_for_display, StringDict +from mindee.parsing.standard import ( + FieldConfidenceMixin, + FieldPositionMixin, +) + + +class BankAccountDetailsV2Bban(FieldPositionMixin, FieldConfidenceMixin): + """Full extraction of BBAN, including: branch code, bank code, account and key.""" + + bban_bank_code: Optional[str] + """The BBAN bank code outputted as a string.""" + bban_branch_code: Optional[str] + """The BBAN branch code outputted as a string.""" + bban_key: Optional[str] + """The BBAN key outputted as a string.""" + bban_number: Optional[str] + """The BBAN Account number outputted as a string.""" + page_n: int + """The document page on which the information was found.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + self._set_confidence(raw_prediction) + self._set_position(raw_prediction) + + if page_id is None: + try: + self.page_n = raw_prediction["page_id"] + except KeyError: + pass + else: + self.page_n = page_id + + self.bban_bank_code = raw_prediction["bban_bank_code"] + self.bban_branch_code = raw_prediction["bban_branch_code"] + self.bban_key = raw_prediction["bban_key"] + self.bban_number = raw_prediction["bban_number"] + + def _printable_values(self) -> Dict[str, str]: + """Return values for printing.""" + return { + "bban_bank_code": format_for_display(self.bban_bank_code, None), + "bban_branch_code": format_for_display(self.bban_branch_code, None), + "bban_key": format_for_display(self.bban_key, None), + "bban_number": format_for_display(self.bban_number, None), + } + + def to_field_list(self) -> str: + """Output the object in a format suitable for inclusion in an rST field list.""" + printable = self._printable_values() + return ( + f" :Bank Code: {printable['bban_bank_code']}\n" + f" :Branch Code: {printable['bban_branch_code']}\n" + f" :Key: {printable['bban_key']}\n" + f" :Account Number: {printable['bban_number']}" + ) + + def __str__(self) -> str: + """Default string representation.""" + printable = self._printable_values() + return ( + f"Bank Code: {printable['bban_bank_code']}, " + f"Branch Code: {printable['bban_branch_code']}, " + f"Key: {printable['bban_key']}, " + f"Account Number: {printable['bban_number']}, " + ).strip() diff --git a/mindee/product/fr/bank_account_details/bank_account_details_v2_document.py b/mindee/product/fr/bank_account_details/bank_account_details_v2_document.py new file mode 100644 index 00000000..9779b46e --- /dev/null +++ b/mindee/product/fr/bank_account_details/bank_account_details_v2_document.py @@ -0,0 +1,58 @@ +from typing import Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import StringField + +from mindee.product.fr.bank_account_details.bank_account_details_v2_bban import ( + BankAccountDetailsV2Bban, +) + + +class BankAccountDetailsV2Document(Prediction): + """Document data for Bank Account Details, API version 2.""" + + account_holders_names: StringField + """Full extraction of the account holders names.""" + bban: BankAccountDetailsV2Bban + """Full extraction of BBAN, including: branch code, bank code, account and key.""" + iban: StringField + """Full extraction of the IBAN number.""" + swift_code: StringField + """Full extraction of the SWIFT code.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Bank Account Details document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.account_holders_names = StringField( + raw_prediction["account_holders_names"], + page_id=page_id, + ) + self.bban = BankAccountDetailsV2Bban( + raw_prediction["bban"], + page_id=page_id, + ) + self.iban = StringField( + raw_prediction["iban"], + page_id=page_id, + ) + self.swift_code = StringField( + raw_prediction["swift_code"], + page_id=page_id, + ) + + def __str__(self) -> str: + + return clean_out_string( + f":Account Holder's Names: {self.account_holders_names}\n" + f":Basic Bank Account Number:\n{self.bban.to_field_list()}\n" + f":IBAN: {self.iban}\n" + f":SWIFT Code: {self.swift_code}\n" + ) diff --git a/mindee/product/fr/id_card/id_card_v1_page.py b/mindee/product/fr/id_card/id_card_v1_page.py index 9322815a..3c0003a6 100644 --- a/mindee/product/fr/id_card/id_card_v1_page.py +++ b/mindee/product/fr/id_card/id_card_v1_page.py @@ -1,9 +1,10 @@ from typing import Optional from mindee.parsing.common import StringDict, clean_out_string -from mindee.parsing.standard import ClassificationField from mindee.product.fr.id_card.id_card_v1_document import IdCardV1Document +from mindee.parsing.standard import ClassificationField + class IdCardV1Page(IdCardV1Document): """Page data for Carte Nationale d'Identité, API version 1.""" diff --git a/mindee/product/fr/id_card/id_card_v2.py b/mindee/product/fr/id_card/id_card_v2.py new file mode 100644 index 00000000..5501b114 --- /dev/null +++ b/mindee/product/fr/id_card/id_card_v2.py @@ -0,0 +1,31 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.fr.id_card.id_card_v2_document import IdCardV2Document +from mindee.product.fr.id_card.id_card_v2_page import IdCardV2Page + + +class IdCardV2(Inference): + """Inference prediction for Carte Nationale d'Identité, API version 2.""" + + prediction: IdCardV2Document + """Document-level prediction.""" + pages: List[Page[IdCardV2Page]] + """Page-level prediction(s).""" + endpoint_name = "idcard_fr" + """Name of the endpoint.""" + endpoint_version = "2" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Carte Nationale d'Identité v2 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = IdCardV2Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(IdCardV2Page, page)) diff --git a/mindee/product/fr/id_card/id_card_v2_document.py b/mindee/product/fr/id_card/id_card_v2_document.py new file mode 100644 index 00000000..f1c899b2 --- /dev/null +++ b/mindee/product/fr/id_card/id_card_v2_document.py @@ -0,0 +1,134 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import DateField, StringField + + +class IdCardV2Document(Prediction): + """Document data for Carte Nationale d'Identité, API version 2.""" + + alternate_name: StringField + """The alternate name of the card holder.""" + authority: StringField + """The name of the issuing authority.""" + birth_date: DateField + """The date of birth of the card holder.""" + birth_place: StringField + """The place of birth of the card holder.""" + card_access_number: StringField + """The card access number (CAN).""" + document_number: StringField + """The document number.""" + expiry_date: DateField + """The expiry date of the identification card.""" + gender: StringField + """The gender of the card holder.""" + given_names: List[StringField] + """The given name(s) of the card holder.""" + issue_date: DateField + """The date of issue of the identification card.""" + mrz1: StringField + """The Machine Readable Zone, first line.""" + mrz2: StringField + """The Machine Readable Zone, second line.""" + mrz3: StringField + """The Machine Readable Zone, third line.""" + nationality: StringField + """The nationality of the card holder.""" + surname: StringField + """The surname of the card holder.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Carte Nationale d'Identité document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.alternate_name = StringField( + raw_prediction["alternate_name"], + page_id=page_id, + ) + self.authority = StringField( + raw_prediction["authority"], + page_id=page_id, + ) + self.birth_date = DateField( + raw_prediction["birth_date"], + page_id=page_id, + ) + self.birth_place = StringField( + raw_prediction["birth_place"], + page_id=page_id, + ) + self.card_access_number = StringField( + raw_prediction["card_access_number"], + page_id=page_id, + ) + self.document_number = StringField( + raw_prediction["document_number"], + page_id=page_id, + ) + self.expiry_date = DateField( + raw_prediction["expiry_date"], + page_id=page_id, + ) + self.gender = StringField( + raw_prediction["gender"], + page_id=page_id, + ) + self.given_names = [ + StringField(prediction, page_id=page_id) + for prediction in raw_prediction["given_names"] + ] + self.issue_date = DateField( + raw_prediction["issue_date"], + page_id=page_id, + ) + self.mrz1 = StringField( + raw_prediction["mrz1"], + page_id=page_id, + ) + self.mrz2 = StringField( + raw_prediction["mrz2"], + page_id=page_id, + ) + self.mrz3 = StringField( + raw_prediction["mrz3"], + page_id=page_id, + ) + self.nationality = StringField( + raw_prediction["nationality"], + page_id=page_id, + ) + self.surname = StringField( + raw_prediction["surname"], + page_id=page_id, + ) + + def __str__(self) -> str: + given_names = f"\n { ' ' * 15 }".join( + [str(item) for item in self.given_names], + ) + + return clean_out_string( + f":Nationality: {self.nationality}\n" + f":Card Access Number: {self.card_access_number}\n" + f":Document Number: {self.document_number}\n" + f":Given Name(s): {given_names}\n" + f":Surname: {self.surname}\n" + f":Alternate Name: {self.alternate_name}\n" + f":Date of Birth: {self.birth_date}\n" + f":Place of Birth: {self.birth_place}\n" + f":Gender: {self.gender}\n" + f":Expiry Date: {self.expiry_date}\n" + f":Mrz Line 1: {self.mrz1}\n" + f":Mrz Line 2: {self.mrz2}\n" + f":Mrz Line 3: {self.mrz3}\n" + f":Date of Issue: {self.issue_date}\n" + f":Issuing Authority: {self.authority}\n" + ) diff --git a/mindee/product/fr/id_card/id_card_v2_page.py b/mindee/product/fr/id_card/id_card_v2_page.py new file mode 100644 index 00000000..2926c4fd --- /dev/null +++ b/mindee/product/fr/id_card/id_card_v2_page.py @@ -0,0 +1,41 @@ +from typing import Optional + +from mindee.parsing.common import StringDict, clean_out_string +from mindee.product.fr.id_card.id_card_v2_document import IdCardV2Document + +from mindee.parsing.standard import ClassificationField + + +class IdCardV2Page(IdCardV2Document): + """Page data for Carte Nationale d'Identité, API version 2.""" + + document_side: ClassificationField + """The sides of the document which are visible.""" + document_type: ClassificationField + """The document type or format.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Carte Nationale d'Identité page. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + super().__init__(raw_prediction=raw_prediction, page_id=page_id) + self.document_side = ClassificationField( + raw_prediction["document_side"], + page_id=page_id, + ) + self.document_type = ClassificationField( + raw_prediction["document_type"], + page_id=page_id, + ) + + def __str__(self) -> str: + return clean_out_string( + f":Document Type: {self.document_type}\n" f":Document Sides: {self.document_side}\n" + f"{super().__str__()}" + ) diff --git a/mindee/product/invoice/invoice_v4.py b/mindee/product/invoice/invoice_v4.py new file mode 100644 index 00000000..7fd3b066 --- /dev/null +++ b/mindee/product/invoice/invoice_v4.py @@ -0,0 +1,30 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.invoice.invoice_v4_document import InvoiceV4Document + + +class InvoiceV4(Inference): + """Inference prediction for Invoice, API version 4.""" + + prediction: InvoiceV4Document + """Document-level prediction.""" + pages: List[Page[InvoiceV4Document]] + """Page-level prediction(s).""" + endpoint_name = "invoices" + """Name of the endpoint.""" + endpoint_version = "4" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Invoice v4 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = InvoiceV4Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(InvoiceV4Document, page)) diff --git a/mindee/product/invoice/invoice_v4_document.py b/mindee/product/invoice/invoice_v4_document.py new file mode 100644 index 00000000..f65f0654 --- /dev/null +++ b/mindee/product/invoice/invoice_v4_document.py @@ -0,0 +1,198 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import ( + AmountField, + ClassificationField, + CompanyRegistrationField, + DateField, + LocaleField, + PaymentDetailsField, + StringField, + Taxes, +) + +from mindee.product.invoice.invoice_v4_line_item import InvoiceV4LineItem + + +class InvoiceV4Document(Prediction): + """Document data for Invoice, API version 4.""" + + customer_address: StringField + """The address of the customer.""" + customer_company_registrations: List[CompanyRegistrationField] + """List of company registrations associated to the customer.""" + customer_name: StringField + """The name of the customer or client.""" + date: DateField + """The date the purchase was made.""" + document_type: ClassificationField + """One of: 'INVOICE', 'CREDIT NOTE'.""" + due_date: DateField + """The date on which the payment is due.""" + invoice_number: StringField + """The invoice number or identifier.""" + line_items: List[InvoiceV4LineItem] + """List of line item details.""" + locale: LocaleField + """The locale detected on the document.""" + reference_numbers: List[StringField] + """List of Reference numbers, including PO number.""" + supplier_address: StringField + """The address of the supplier or merchant.""" + supplier_company_registrations: List[CompanyRegistrationField] + """List of company registrations associated to the supplier.""" + supplier_name: StringField + """The name of the supplier or merchant.""" + supplier_payment_details: List[PaymentDetailsField] + """List of payment details associated to the supplier.""" + taxes: Taxes + """List of tax line details.""" + total_amount: AmountField + """The total amount paid: includes taxes, tips, fees, and other charges.""" + total_net: AmountField + """The net amount paid: does not include taxes, fees, and discounts.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Invoice document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.customer_address = StringField( + raw_prediction["customer_address"], + page_id=page_id, + ) + self.customer_company_registrations = [ + CompanyRegistrationField(prediction, page_id=page_id) + for prediction in raw_prediction["customer_company_registrations"] + ] + self.customer_name = StringField( + raw_prediction["customer_name"], + page_id=page_id, + ) + self.date = DateField( + raw_prediction["date"], + page_id=page_id, + ) + self.document_type = ClassificationField( + raw_prediction["document_type"], + page_id=page_id, + ) + self.due_date = DateField( + raw_prediction["due_date"], + page_id=page_id, + ) + self.invoice_number = StringField( + raw_prediction["invoice_number"], + page_id=page_id, + ) + self.line_items = [ + InvoiceV4LineItem(prediction, page_id=page_id) + for prediction in raw_prediction["line_items"] + ] + self.locale = LocaleField( + raw_prediction["locale"], + page_id=page_id, + ) + self.reference_numbers = [ + StringField(prediction, page_id=page_id) + for prediction in raw_prediction["reference_numbers"] + ] + self.supplier_address = StringField( + raw_prediction["supplier_address"], + page_id=page_id, + ) + self.supplier_company_registrations = [ + CompanyRegistrationField(prediction, page_id=page_id) + for prediction in raw_prediction["supplier_company_registrations"] + ] + self.supplier_name = StringField( + raw_prediction["supplier_name"], + page_id=page_id, + ) + self.supplier_payment_details = [ + PaymentDetailsField(prediction, page_id=page_id) + for prediction in raw_prediction["supplier_payment_details"] + ] + self.taxes = Taxes(raw_prediction["taxes"], page_id=page_id) + self.total_amount = AmountField( + raw_prediction["total_amount"], + page_id=page_id, + ) + self.total_net = AmountField( + raw_prediction["total_net"], + page_id=page_id, + ) + + @staticmethod + def _line_items_separator(char: str) -> str: + out_str = " " + out_str += f"+{char * 38}" + out_str += f"+{char * 14}" + out_str += f"+{char * 10}" + out_str += f"+{char * 12}" + out_str += f"+{char * 14}" + out_str += f"+{char * 14}" + out_str += f"+{char * 12}" + return out_str + "+" + + def _line_items_to_str(self) -> str: + if not self.line_items: + return "" + + lines = f"\n{self._line_items_separator('-')}\n ".join( + [item.to_table_line() for item in self.line_items] + ) + out_str = "" + out_str += f"\n{self._line_items_separator('-')}\n " + out_str += " | Description " + out_str += " | Product code" + out_str += " | Quantity" + out_str += " | Tax Amount" + out_str += " | Tax Rate (%)" + out_str += " | Total Amount" + out_str += " | Unit Price" + out_str += f" |\n{self._line_items_separator('=')}" + out_str += f"\n {lines}" + out_str += f"\n{self._line_items_separator('-')}" + return out_str + + def __str__(self) -> str: + customer_company_registrations = f"\n { ' ' * 32 }".join( + [str(item) for item in self.customer_company_registrations], + ) + reference_numbers = f"\n { ' ' * 19 }".join( + [str(item) for item in self.reference_numbers], + ) + supplier_company_registrations = f"\n { ' ' * 32 }".join( + [str(item) for item in self.supplier_company_registrations], + ) + supplier_payment_details = f"\n { ' ' * 26 }".join( + [str(item) for item in self.supplier_payment_details], + ) + + return clean_out_string( + f":Locale: {self.locale}\n" + f":Invoice Number: {self.invoice_number}\n" + f":Reference Numbers: {reference_numbers}\n" + f":Purchase Date: {self.date}\n" + f":Due Date: {self.due_date}\n" + f":Total Net: {self.total_net}\n" + f":Total Amount: {self.total_amount}\n" + f":Taxes: {self.taxes}\n" + f":Supplier Payment Details: {supplier_payment_details}\n" + f":Supplier Name: {self.supplier_name}\n" + f":Supplier Company Registrations: {supplier_company_registrations}\n" + f":Supplier Address: {self.supplier_address}\n" + f":Customer Name: {self.customer_name}\n" + f":Customer Company Registrations: {customer_company_registrations}\n" + f":Customer Address: {self.customer_address}\n" + f":Document Type: {self.document_type}\n" + f":Line Items: {self._line_items_to_str()}\n" + ) diff --git a/mindee/product/invoice/invoice_v4_line_item.py b/mindee/product/invoice/invoice_v4_line_item.py new file mode 100644 index 00000000..77c5a335 --- /dev/null +++ b/mindee/product/invoice/invoice_v4_line_item.py @@ -0,0 +1,93 @@ +from typing import Dict, Optional + +from mindee.parsing.common import format_for_display, StringDict +from mindee.parsing.standard import ( + FieldConfidenceMixin, + FieldPositionMixin, + float_to_string, + to_opt_float, +) + + +class InvoiceV4LineItem(FieldPositionMixin, FieldConfidenceMixin): + """List of line item details.""" + + description: Optional[str] + """The item description.""" + product_code: Optional[str] + """The product code referring to the item.""" + quantity: Optional[float] + """The item quantity""" + tax_amount: Optional[float] + """The item tax amount.""" + tax_rate: Optional[float] + """The item tax rate in percentage.""" + total_amount: Optional[float] + """The item total amount.""" + unit_price: Optional[float] + """The item unit price.""" + page_n: int + """The document page on which the information was found.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + self._set_confidence(raw_prediction) + self._set_position(raw_prediction) + + if page_id is None: + try: + self.page_n = raw_prediction["page_id"] + except KeyError: + pass + else: + self.page_n = page_id + + self.description = raw_prediction["description"] + self.product_code = raw_prediction["product_code"] + self.quantity = to_opt_float(raw_prediction, "quantity") + self.tax_amount = to_opt_float(raw_prediction, "tax_amount") + self.tax_rate = to_opt_float(raw_prediction, "tax_rate") + self.total_amount = to_opt_float(raw_prediction, "total_amount") + self.unit_price = to_opt_float(raw_prediction, "unit_price") + + def _printable_values(self) -> Dict[str, str]: + """Return values for printing.""" + return { + "description": format_for_display(self.description, 36), + "product_code": format_for_display(self.product_code, None), + "quantity": float_to_string(self.quantity), + "tax_amount": float_to_string(self.tax_amount), + "tax_rate": float_to_string(self.tax_rate), + "total_amount": float_to_string(self.total_amount), + "unit_price": float_to_string(self.unit_price), + } + + def to_table_line(self) -> str: + """Output in a format suitable for inclusion in an rST table.""" + printable = self._printable_values() + return ( + "|" + f" {printable['description']:<36} |" + f" {printable['product_code']:<12} |" + f" {printable['quantity']:<8} |" + f" {printable['tax_amount']:<10} |" + f" {printable['tax_rate']:<12} |" + f" {printable['total_amount']:<12} |" + f" {printable['unit_price']:<10} |" + ) + + def __str__(self) -> str: + """Default string representation.""" + printable = self._printable_values() + return ( + f"Description: {printable['description']}, " + f"Product code: {printable['product_code']}, " + f"Quantity: {printable['quantity']}, " + f"Tax Amount: {printable['tax_amount']}, " + f"Tax Rate (%): {printable['tax_rate']}, " + f"Total Amount: {printable['total_amount']}, " + f"Unit Price: {printable['unit_price']}, " + ).strip() diff --git a/mindee/product/multi_receipts_detector/__init__.py b/mindee/product/multi_receipts_detector/__init__.py new file mode 100644 index 00000000..11239e33 --- /dev/null +++ b/mindee/product/multi_receipts_detector/__init__.py @@ -0,0 +1,2 @@ +from mindee.product.multi_receipts_detector.multi_receipts_detector_v1 import MultiReceiptsDetectorV1 +from mindee.product.multi_receipts_detector.multi_receipts_detector_v1_document import MultiReceiptsDetectorV1Document diff --git a/mindee/product/multi_receipts_detector/multi_receipts_detector_v1.py b/mindee/product/multi_receipts_detector/multi_receipts_detector_v1.py new file mode 100644 index 00000000..9238f64d --- /dev/null +++ b/mindee/product/multi_receipts_detector/multi_receipts_detector_v1.py @@ -0,0 +1,32 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.multi_receipts_detector.multi_receipts_detector_v1_document import ( + MultiReceiptsDetectorV1Document, +) + + +class MultiReceiptsDetectorV1(Inference): + """Inference prediction for Multi Receipts Detector, API version 1.""" + + prediction: MultiReceiptsDetectorV1Document + """Document-level prediction.""" + pages: List[Page[MultiReceiptsDetectorV1Document]] + """Page-level prediction(s).""" + endpoint_name = "multi_receipts_detector" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Multi Receipts Detector v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = MultiReceiptsDetectorV1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(MultiReceiptsDetectorV1Document, page)) diff --git a/mindee/product/multi_receipts_detector/multi_receipts_detector_v1_document.py b/mindee/product/multi_receipts_detector/multi_receipts_detector_v1_document.py new file mode 100644 index 00000000..09efa98c --- /dev/null +++ b/mindee/product/multi_receipts_detector/multi_receipts_detector_v1_document.py @@ -0,0 +1,34 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import PositionField + + +class MultiReceiptsDetectorV1Document(Prediction): + """Document data for Multi Receipts Detector, API version 1.""" + + receipts: List[PositionField] + """Positions of the receipts on the document.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Multi Receipts Detector document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.receipts = [ + PositionField(prediction, page_id=page_id) + for prediction in raw_prediction["receipts"] + ] + + def __str__(self) -> str: + receipts = f"\n { ' ' * 18 }".join( + [str(item) for item in self.receipts], + ) + + return clean_out_string(f":List of Receipts: {receipts}\n") diff --git a/mindee/product/passport/__init__.py b/mindee/product/passport/__init__.py new file mode 100644 index 00000000..d0fc9e09 --- /dev/null +++ b/mindee/product/passport/__init__.py @@ -0,0 +1,2 @@ +from mindee.product.passport.passport_v1 import PassportV1 +from mindee.product.passport.passport_v1_document import PassportV1Document diff --git a/mindee/product/passport/passport_v1.py b/mindee/product/passport/passport_v1.py new file mode 100644 index 00000000..118a89e0 --- /dev/null +++ b/mindee/product/passport/passport_v1.py @@ -0,0 +1,30 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.passport.passport_v1_document import PassportV1Document + + +class PassportV1(Inference): + """Inference prediction for Passport, API version 1.""" + + prediction: PassportV1Document + """Document-level prediction.""" + pages: List[Page[PassportV1Document]] + """Page-level prediction(s).""" + endpoint_name = "passport" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Passport v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = PassportV1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(PassportV1Document, page)) diff --git a/mindee/product/passport/passport_v1_document.py b/mindee/product/passport/passport_v1_document.py new file mode 100644 index 00000000..e929b07c --- /dev/null +++ b/mindee/product/passport/passport_v1_document.py @@ -0,0 +1,106 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import DateField, StringField + + +class PassportV1Document(Prediction): + """Document data for Passport, API version 1.""" + + birth_date: DateField + """The date of birth of the passport holder.""" + birth_place: StringField + """The place of birth of the passport holder.""" + country: StringField + """The country's 3 letter code (ISO 3166-1 alpha-3).""" + expiry_date: DateField + """The expiry date of the passport.""" + gender: StringField + """The gender of the passport holder.""" + given_names: List[StringField] + """The given name(s) of the passport holder.""" + id_number: StringField + """The passport's identification number.""" + issuance_date: DateField + """The date the passport was issued.""" + mrz1: StringField + """Machine Readable Zone, first line""" + mrz2: StringField + """Machine Readable Zone, second line""" + surname: StringField + """The surname of the passport holder.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Passport document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.birth_date = DateField( + raw_prediction["birth_date"], + page_id=page_id, + ) + self.birth_place = StringField( + raw_prediction["birth_place"], + page_id=page_id, + ) + self.country = StringField( + raw_prediction["country"], + page_id=page_id, + ) + self.expiry_date = DateField( + raw_prediction["expiry_date"], + page_id=page_id, + ) + self.gender = StringField( + raw_prediction["gender"], + page_id=page_id, + ) + self.given_names = [ + StringField(prediction, page_id=page_id) + for prediction in raw_prediction["given_names"] + ] + self.id_number = StringField( + raw_prediction["id_number"], + page_id=page_id, + ) + self.issuance_date = DateField( + raw_prediction["issuance_date"], + page_id=page_id, + ) + self.mrz1 = StringField( + raw_prediction["mrz1"], + page_id=page_id, + ) + self.mrz2 = StringField( + raw_prediction["mrz2"], + page_id=page_id, + ) + self.surname = StringField( + raw_prediction["surname"], + page_id=page_id, + ) + + def __str__(self) -> str: + given_names = f"\n { ' ' * 15 }".join( + [str(item) for item in self.given_names], + ) + + return clean_out_string( + f":Country Code: {self.country}\n" + f":ID Number: {self.id_number}\n" + f":Given Name(s): {given_names}\n" + f":Surname: {self.surname}\n" + f":Date of Birth: {self.birth_date}\n" + f":Place of Birth: {self.birth_place}\n" + f":Gender: {self.gender}\n" + f":Date of Issue: {self.issuance_date}\n" + f":Expiry Date: {self.expiry_date}\n" + f":MRZ Line 1: {self.mrz1}\n" + f":MRZ Line 2: {self.mrz2}\n" + ) diff --git a/mindee/product/proof_of_address/__init__.py b/mindee/product/proof_of_address/__init__.py new file mode 100644 index 00000000..b71ab66e --- /dev/null +++ b/mindee/product/proof_of_address/__init__.py @@ -0,0 +1,2 @@ +from mindee.product.proof_of_address.proof_of_address_v1 import ProofOfAddressV1 +from mindee.product.proof_of_address.proof_of_address_v1_document import ProofOfAddressV1Document diff --git a/mindee/product/proof_of_address/proof_of_address_v1.py b/mindee/product/proof_of_address/proof_of_address_v1.py new file mode 100644 index 00000000..22142e11 --- /dev/null +++ b/mindee/product/proof_of_address/proof_of_address_v1.py @@ -0,0 +1,32 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.proof_of_address.proof_of_address_v1_document import ( + ProofOfAddressV1Document, +) + + +class ProofOfAddressV1(Inference): + """Inference prediction for Proof of Address, API version 1.""" + + prediction: ProofOfAddressV1Document + """Document-level prediction.""" + pages: List[Page[ProofOfAddressV1Document]] + """Page-level prediction(s).""" + endpoint_name = "proof_of_address" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Proof of Address v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = ProofOfAddressV1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(ProofOfAddressV1Document, page)) diff --git a/mindee/product/proof_of_address/proof_of_address_v1_document.py b/mindee/product/proof_of_address/proof_of_address_v1_document.py new file mode 100644 index 00000000..d1c03a96 --- /dev/null +++ b/mindee/product/proof_of_address/proof_of_address_v1_document.py @@ -0,0 +1,103 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import ( + CompanyRegistrationField, + DateField, + LocaleField, + StringField, +) + + +class ProofOfAddressV1Document(Prediction): + """Document data for Proof of Address, API version 1.""" + + date: DateField + """The date the document was issued.""" + dates: List[DateField] + """List of dates found on the document.""" + issuer_address: StringField + """The address of the document's issuer.""" + issuer_company_registration: List[CompanyRegistrationField] + """List of company registrations found for the issuer.""" + issuer_name: StringField + """The name of the person or company issuing the document.""" + locale: LocaleField + """The locale detected on the document.""" + recipient_address: StringField + """The address of the recipient.""" + recipient_company_registration: List[CompanyRegistrationField] + """List of company registrations found for the recipient.""" + recipient_name: StringField + """The name of the person or company receiving the document.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Proof of Address document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.date = DateField( + raw_prediction["date"], + page_id=page_id, + ) + self.dates = [ + DateField(prediction, page_id=page_id) + for prediction in raw_prediction["dates"] + ] + self.issuer_address = StringField( + raw_prediction["issuer_address"], + page_id=page_id, + ) + self.issuer_company_registration = [ + CompanyRegistrationField(prediction, page_id=page_id) + for prediction in raw_prediction["issuer_company_registration"] + ] + self.issuer_name = StringField( + raw_prediction["issuer_name"], + page_id=page_id, + ) + self.locale = LocaleField( + raw_prediction["locale"], + page_id=page_id, + ) + self.recipient_address = StringField( + raw_prediction["recipient_address"], + page_id=page_id, + ) + self.recipient_company_registration = [ + CompanyRegistrationField(prediction, page_id=page_id) + for prediction in raw_prediction["recipient_company_registration"] + ] + self.recipient_name = StringField( + raw_prediction["recipient_name"], + page_id=page_id, + ) + + def __str__(self) -> str: + dates = f"\n { ' ' * 7 }".join( + [str(item) for item in self.dates], + ) + issuer_company_registration = f"\n { ' ' * 30 }".join( + [str(item) for item in self.issuer_company_registration], + ) + recipient_company_registration = f"\n { ' ' * 33 }".join( + [str(item) for item in self.recipient_company_registration], + ) + + return clean_out_string( + f":Locale: {self.locale}\n" + f":Issuer Name: {self.issuer_name}\n" + f":Issuer Company Registrations: {issuer_company_registration}\n" + f":Issuer Address: {self.issuer_address}\n" + f":Recipient Name: {self.recipient_name}\n" + f":Recipient Company Registrations: {recipient_company_registration}\n" + f":Recipient Address: {self.recipient_address}\n" + f":Dates: {dates}\n" + f":Date of Issue: {self.date}\n" + ) diff --git a/mindee/product/receipt/__init__.py b/mindee/product/receipt/__init__.py index 1d50efd9..ce10926d 100644 --- a/mindee/product/receipt/__init__.py +++ b/mindee/product/receipt/__init__.py @@ -1,5 +1,6 @@ from mindee.product.receipt.receipt_v4 import ReceiptV4 from mindee.product.receipt.receipt_v4_document import ReceiptV4Document -# from mindee.product.receipt.receipt_v5 import ReceiptV5 -# from mindee.product.receipt.receipt_v5_line_item import ReceiptV5LineItem +from mindee.product.receipt.receipt_v5 import ReceiptV5 +from mindee.product.receipt.receipt_v5_document import ReceiptV5Document +from mindee.product.receipt.receipt_v5_line_item import ReceiptV5LineItem diff --git a/mindee/product/receipt/receipt_v5.py b/mindee/product/receipt/receipt_v5.py new file mode 100644 index 00000000..738fb2cd --- /dev/null +++ b/mindee/product/receipt/receipt_v5.py @@ -0,0 +1,30 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.receipt.receipt_v5_document import ReceiptV5Document + + +class ReceiptV5(Inference): + """Inference prediction for Receipt, API version 5.""" + + prediction: ReceiptV5Document + """Document-level prediction.""" + pages: List[Page[ReceiptV5Document]] + """Page-level prediction(s).""" + endpoint_name = "expense_receipts" + """Name of the endpoint.""" + endpoint_version = "5" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Receipt v5 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = ReceiptV5Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(ReceiptV5Document, page)) diff --git a/mindee/product/receipt/receipt_v5_document.py b/mindee/product/receipt/receipt_v5_document.py new file mode 100644 index 00000000..d6e85420 --- /dev/null +++ b/mindee/product/receipt/receipt_v5_document.py @@ -0,0 +1,175 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import ( + AmountField, + ClassificationField, + CompanyRegistrationField, + DateField, + LocaleField, + StringField, + Taxes, +) + +from mindee.product.receipt.receipt_v5_line_item import ReceiptV5LineItem + + +class ReceiptV5Document(Prediction): + """Document data for Receipt, API version 5.""" + + category: ClassificationField + """The purchase category among predefined classes.""" + date: DateField + """The date the purchase was made.""" + document_type: ClassificationField + """One of: 'CREDIT CARD RECEIPT', 'EXPENSE RECEIPT'.""" + line_items: List[ReceiptV5LineItem] + """List of line item details.""" + locale: LocaleField + """The locale detected on the document.""" + subcategory: ClassificationField + """The purchase subcategory among predefined classes for transport and food.""" + supplier_address: StringField + """The address of the supplier or merchant.""" + supplier_company_registrations: List[CompanyRegistrationField] + """List of company registrations associated to the supplier.""" + supplier_name: StringField + """The name of the supplier or merchant.""" + supplier_phone_number: StringField + """The phone number of the supplier or merchant.""" + taxes: Taxes + """List of tax lines information.""" + time: StringField + """The time the purchase was made.""" + tip: AmountField + """The total amount of tip and gratuity.""" + total_amount: AmountField + """The total amount paid: includes taxes, discounts, fees, tips, and gratuity.""" + total_net: AmountField + """The net amount paid: does not include taxes, fees, and discounts.""" + total_tax: AmountField + """The total amount of taxes.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Receipt document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.category = ClassificationField( + raw_prediction["category"], + page_id=page_id, + ) + self.date = DateField( + raw_prediction["date"], + page_id=page_id, + ) + self.document_type = ClassificationField( + raw_prediction["document_type"], + page_id=page_id, + ) + self.line_items = [ + ReceiptV5LineItem(prediction, page_id=page_id) + for prediction in raw_prediction["line_items"] + ] + self.locale = LocaleField( + raw_prediction["locale"], + page_id=page_id, + ) + self.subcategory = ClassificationField( + raw_prediction["subcategory"], + page_id=page_id, + ) + self.supplier_address = StringField( + raw_prediction["supplier_address"], + page_id=page_id, + ) + self.supplier_company_registrations = [ + CompanyRegistrationField(prediction, page_id=page_id) + for prediction in raw_prediction["supplier_company_registrations"] + ] + self.supplier_name = StringField( + raw_prediction["supplier_name"], + page_id=page_id, + ) + self.supplier_phone_number = StringField( + raw_prediction["supplier_phone_number"], + page_id=page_id, + ) + self.taxes = Taxes(raw_prediction["taxes"], page_id=page_id) + self.time = StringField( + raw_prediction["time"], + page_id=page_id, + ) + self.tip = AmountField( + raw_prediction["tip"], + page_id=page_id, + ) + self.total_amount = AmountField( + raw_prediction["total_amount"], + page_id=page_id, + ) + self.total_net = AmountField( + raw_prediction["total_net"], + page_id=page_id, + ) + self.total_tax = AmountField( + raw_prediction["total_tax"], + page_id=page_id, + ) + + @staticmethod + def _line_items_separator(char: str) -> str: + out_str = " " + out_str += f"+{char * 38}" + out_str += f"+{char * 10}" + out_str += f"+{char * 14}" + out_str += f"+{char * 12}" + return out_str + "+" + + def _line_items_to_str(self) -> str: + if not self.line_items: + return "" + + lines = f"\n{self._line_items_separator('-')}\n ".join( + [item.to_table_line() for item in self.line_items] + ) + out_str = "" + out_str += f"\n{self._line_items_separator('-')}\n " + out_str += " | Description " + out_str += " | Quantity" + out_str += " | Total Amount" + out_str += " | Unit Price" + out_str += f" |\n{self._line_items_separator('=')}" + out_str += f"\n {lines}" + out_str += f"\n{self._line_items_separator('-')}" + return out_str + + def __str__(self) -> str: + supplier_company_registrations = f"\n { ' ' * 32 }".join( + [str(item) for item in self.supplier_company_registrations], + ) + + return clean_out_string( + f":Expense Locale: {self.locale}\n" + f":Purchase Category: {self.category}\n" + f":Purchase Subcategory: {self.subcategory}\n" + f":Document Type: {self.document_type}\n" + f":Purchase Date: {self.date}\n" + f":Purchase Time: {self.time}\n" + f":Total Amount: {self.total_amount}\n" + f":Total Net: {self.total_net}\n" + f":Total Tax: {self.total_tax}\n" + f":Tip and Gratuity: {self.tip}\n" + f":Taxes: {self.taxes}\n" + f":Supplier Name: {self.supplier_name}\n" + f":Supplier Company Registrations: {supplier_company_registrations}\n" + f":Supplier Address: {self.supplier_address}\n" + f":Supplier Phone Number: {self.supplier_phone_number}\n" + f":Line Items: {self._line_items_to_str()}\n" + ) diff --git a/mindee/product/receipt/receipt_v5_line_item.py b/mindee/product/receipt/receipt_v5_line_item.py new file mode 100644 index 00000000..66a11e23 --- /dev/null +++ b/mindee/product/receipt/receipt_v5_line_item.py @@ -0,0 +1,75 @@ +from typing import Dict, Optional + +from mindee.parsing.common import format_for_display, StringDict +from mindee.parsing.standard import ( + FieldConfidenceMixin, + FieldPositionMixin, + float_to_string, + to_opt_float, +) + + +class ReceiptV5LineItem(FieldPositionMixin, FieldConfidenceMixin): + """List of line item details.""" + + description: Optional[str] + """The item description.""" + quantity: Optional[float] + """The item quantity.""" + total_amount: Optional[float] + """The item total amount.""" + unit_price: Optional[float] + """The item unit price.""" + page_n: int + """The document page on which the information was found.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + self._set_confidence(raw_prediction) + self._set_position(raw_prediction) + + if page_id is None: + try: + self.page_n = raw_prediction["page_id"] + except KeyError: + pass + else: + self.page_n = page_id + + self.description = raw_prediction["description"] + self.quantity = to_opt_float(raw_prediction, "quantity") + self.total_amount = to_opt_float(raw_prediction, "total_amount") + self.unit_price = to_opt_float(raw_prediction, "unit_price") + + def _printable_values(self) -> Dict[str, str]: + """Return values for printing.""" + return { + "description": format_for_display(self.description, 36), + "quantity": float_to_string(self.quantity), + "total_amount": float_to_string(self.total_amount), + "unit_price": float_to_string(self.unit_price), + } + + def to_table_line(self) -> str: + """Output in a format suitable for inclusion in an rST table.""" + printable = self._printable_values() + return ( + "|" + f" {printable['description']:<36} |" + f" {printable['quantity']:<8} |" + f" {printable['total_amount']:<12} |" + f" {printable['unit_price']:<10} |" + ) + + def __str__(self) -> str: + """Default string representation.""" + printable = self._printable_values() + return ( + f"Description: {printable['description']}, " + f"Quantity: {printable['quantity']}, " + f"Total Amount: {printable['total_amount']}, " + f"Unit Price: {printable['unit_price']}, " + ).strip() diff --git a/mindee/product/us/__init__.py b/mindee/product/us/__init__.py index e69de29b..602c7403 100644 --- a/mindee/product/us/__init__.py +++ b/mindee/product/us/__init__.py @@ -0,0 +1,9 @@ +from mindee.product.us.bank_check.bank_check_v1 import BankCheckV1 +from mindee.product.us.bank_check.bank_check_v1_document import BankCheckV1Document +from mindee.product.us.bank_check.bank_check_v1_page import BankCheckV1Page +from mindee.product.us.driver_license.driver_license_v1 import DriverLicenseV1 +from mindee.product.us.driver_license.driver_license_v1_document import DriverLicenseV1Document +from mindee.product.us.driver_license.driver_license_v1_page import DriverLicenseV1Page +from mindee.product.us.w9.w9_v1 import W9V1 +from mindee.product.us.w9.w9_v1_document import W9V1Document +from mindee.product.us.w9.w9_v1_page import W9V1Page diff --git a/mindee/product/us/bank_check/__init__.py b/mindee/product/us/bank_check/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mindee/product/us/bank_check/bank_check_v1.py b/mindee/product/us/bank_check/bank_check_v1.py new file mode 100644 index 00000000..d56f8e6c --- /dev/null +++ b/mindee/product/us/bank_check/bank_check_v1.py @@ -0,0 +1,31 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.us.bank_check.bank_check_v1_document import BankCheckV1Document +from mindee.product.us.bank_check.bank_check_v1_page import BankCheckV1Page + + +class BankCheckV1(Inference): + """Inference prediction for Bank Check, API version 1.""" + + prediction: BankCheckV1Document + """Document-level prediction.""" + pages: List[Page[BankCheckV1Page]] + """Page-level prediction(s).""" + endpoint_name = "bank_check" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Bank Check v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = BankCheckV1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(BankCheckV1Page, page)) diff --git a/mindee/product/us/bank_check/bank_check_v1_document.py b/mindee/product/us/bank_check/bank_check_v1_document.py new file mode 100644 index 00000000..a1070fb4 --- /dev/null +++ b/mindee/product/us/bank_check/bank_check_v1_document.py @@ -0,0 +1,71 @@ +from typing import List, Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import AmountField, DateField, StringField + + +class BankCheckV1Document(Prediction): + """Document data for Bank Check, API version 1.""" + + account_number: StringField + """The check payer's account number.""" + amount: AmountField + """The amount of the check.""" + check_number: StringField + """The issuer's check number.""" + date: DateField + """The date the check was issued.""" + payees: List[StringField] + """List of the check's payees (recipients).""" + routing_number: StringField + """The check issuer's routing number.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Bank Check document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.account_number = StringField( + raw_prediction["account_number"], + page_id=page_id, + ) + self.amount = AmountField( + raw_prediction["amount"], + page_id=page_id, + ) + self.check_number = StringField( + raw_prediction["check_number"], + page_id=page_id, + ) + self.date = DateField( + raw_prediction["date"], + page_id=page_id, + ) + self.payees = [ + StringField(prediction, page_id=page_id) + for prediction in raw_prediction["payees"] + ] + self.routing_number = StringField( + raw_prediction["routing_number"], + page_id=page_id, + ) + + def __str__(self) -> str: + payees = f"\n { ' ' * 8 }".join( + [str(item) for item in self.payees], + ) + + return clean_out_string( + f":Check Issue Date: {self.date}\n" + f":Amount: {self.amount}\n" + f":Payees: {payees}\n" + f":Routing Number: {self.routing_number}\n" + f":Account Number: {self.account_number}\n" + f":Check Number: {self.check_number}\n" + ) diff --git a/mindee/product/us/bank_check/bank_check_v1_page.py b/mindee/product/us/bank_check/bank_check_v1_page.py new file mode 100644 index 00000000..33f457b0 --- /dev/null +++ b/mindee/product/us/bank_check/bank_check_v1_page.py @@ -0,0 +1,44 @@ +from typing import List, Optional + +from mindee.parsing.common import StringDict, clean_out_string +from mindee.product.us.bank_check.bank_check_v1_document import BankCheckV1Document + +from mindee.parsing.standard import PositionField + + +class BankCheckV1Page(BankCheckV1Document): + """Page data for Bank Check, API version 1.""" + + check_position: PositionField + """The position of the check on the document.""" + signatures_positions: List[PositionField] + """List of signature positions""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Bank Check page. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + super().__init__(raw_prediction=raw_prediction, page_id=page_id) + self.check_position = PositionField( + raw_prediction["check_position"], + page_id=page_id, + ) + self.signatures_positions = [ + PositionField(prediction, page_id=page_id) + for prediction in raw_prediction["signatures_positions"] + ] + + def __str__(self) -> str: + signatures_positions = f"\n { ' ' * 21 }".join( + [str(item) for item in self.signatures_positions], + ) + return clean_out_string( + f":Check Position: {self.check_position}\n" f":Signature Positions: {signatures_positions}\n" + f"{super().__str__()}" + ) diff --git a/mindee/product/us/driver_license/__init__.py b/mindee/product/us/driver_license/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mindee/product/us/driver_license/driver_license_v1.py b/mindee/product/us/driver_license/driver_license_v1.py new file mode 100644 index 00000000..76b5d6f0 --- /dev/null +++ b/mindee/product/us/driver_license/driver_license_v1.py @@ -0,0 +1,33 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.us.driver_license.driver_license_v1_document import ( + DriverLicenseV1Document, +) +from mindee.product.us.driver_license.driver_license_v1_page import DriverLicenseV1Page + + +class DriverLicenseV1(Inference): + """Inference prediction for Driver License, API version 1.""" + + prediction: DriverLicenseV1Document + """Document-level prediction.""" + pages: List[Page[DriverLicenseV1Page]] + """Page-level prediction(s).""" + endpoint_name = "us_driver_license" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + Driver License v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = DriverLicenseV1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(DriverLicenseV1Page, page)) diff --git a/mindee/product/us/driver_license/driver_license_v1_document.py b/mindee/product/us/driver_license/driver_license_v1_document.py new file mode 100644 index 00000000..2e2cb4fc --- /dev/null +++ b/mindee/product/us/driver_license/driver_license_v1_document.py @@ -0,0 +1,145 @@ +from typing import Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string +from mindee.parsing.standard import DateField, StringField + + +class DriverLicenseV1Document(Prediction): + """Document data for Driver License, API version 1.""" + + address: StringField + """US driver license holders address""" + date_of_birth: DateField + """US driver license holders date of birth""" + dd_number: StringField + """Document Discriminator Number of the US Driver License""" + dl_class: StringField + """US driver license holders class""" + driver_license_id: StringField + """ID number of the US Driver License.""" + endorsements: StringField + """US driver license holders endorsements""" + expiry_date: DateField + """Date on which the documents expires.""" + eye_color: StringField + """US driver license holders eye colour""" + first_name: StringField + """US driver license holders first name(s)""" + hair_color: StringField + """US driver license holders hair colour""" + height: StringField + """US driver license holders hight""" + issued_date: DateField + """Date on which the documents was issued.""" + last_name: StringField + """US driver license holders last name""" + restrictions: StringField + """US driver license holders restrictions""" + sex: StringField + """US driver license holders gender""" + state: StringField + """US State""" + weight: StringField + """US driver license holders weight""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Driver License document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + self.address = StringField( + raw_prediction["address"], + page_id=page_id, + ) + self.date_of_birth = DateField( + raw_prediction["date_of_birth"], + page_id=page_id, + ) + self.dd_number = StringField( + raw_prediction["dd_number"], + page_id=page_id, + ) + self.dl_class = StringField( + raw_prediction["dl_class"], + page_id=page_id, + ) + self.driver_license_id = StringField( + raw_prediction["driver_license_id"], + page_id=page_id, + ) + self.endorsements = StringField( + raw_prediction["endorsements"], + page_id=page_id, + ) + self.expiry_date = DateField( + raw_prediction["expiry_date"], + page_id=page_id, + ) + self.eye_color = StringField( + raw_prediction["eye_color"], + page_id=page_id, + ) + self.first_name = StringField( + raw_prediction["first_name"], + page_id=page_id, + ) + self.hair_color = StringField( + raw_prediction["hair_color"], + page_id=page_id, + ) + self.height = StringField( + raw_prediction["height"], + page_id=page_id, + ) + self.issued_date = DateField( + raw_prediction["issued_date"], + page_id=page_id, + ) + self.last_name = StringField( + raw_prediction["last_name"], + page_id=page_id, + ) + self.restrictions = StringField( + raw_prediction["restrictions"], + page_id=page_id, + ) + self.sex = StringField( + raw_prediction["sex"], + page_id=page_id, + ) + self.state = StringField( + raw_prediction["state"], + page_id=page_id, + ) + self.weight = StringField( + raw_prediction["weight"], + page_id=page_id, + ) + + def __str__(self) -> str: + + return clean_out_string( + f":State: {self.state}\n" + f":Driver License ID: {self.driver_license_id}\n" + f":Expiry Date: {self.expiry_date}\n" + f":Date Of Issue: {self.issued_date}\n" + f":Last Name: {self.last_name}\n" + f":First Name: {self.first_name}\n" + f":Address: {self.address}\n" + f":Date Of Birth: {self.date_of_birth}\n" + f":Restrictions: {self.restrictions}\n" + f":Endorsements: {self.endorsements}\n" + f":Driver License Class: {self.dl_class}\n" + f":Sex: {self.sex}\n" + f":Height: {self.height}\n" + f":Weight: {self.weight}\n" + f":Hair Color: {self.hair_color}\n" + f":Eye Color: {self.eye_color}\n" + f":Document Discriminator: {self.dd_number}\n" + ) diff --git a/mindee/product/us/driver_license/driver_license_v1_page.py b/mindee/product/us/driver_license/driver_license_v1_page.py new file mode 100644 index 00000000..e5cefe4f --- /dev/null +++ b/mindee/product/us/driver_license/driver_license_v1_page.py @@ -0,0 +1,43 @@ +from typing import Optional + +from mindee.parsing.common import StringDict, clean_out_string +from mindee.product.us.driver_license.driver_license_v1_document import ( + DriverLicenseV1Document, +) + +from mindee.parsing.standard import PositionField + + +class DriverLicenseV1Page(DriverLicenseV1Document): + """Page data for Driver License, API version 1.""" + + photo: PositionField + """Has a photo of the US driver license holder""" + signature: PositionField + """Has a signature of the US driver license holder""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + Driver License page. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + super().__init__(raw_prediction=raw_prediction, page_id=page_id) + self.photo = PositionField( + raw_prediction["photo"], + page_id=page_id, + ) + self.signature = PositionField( + raw_prediction["signature"], + page_id=page_id, + ) + + def __str__(self) -> str: + return clean_out_string( + f":Photo: {self.photo}\n" f":Signature: {self.signature}\n" + f"{super().__str__()}" + ) diff --git a/mindee/product/us/w9/__init__.py b/mindee/product/us/w9/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mindee/product/us/w9/w9_v1.py b/mindee/product/us/w9/w9_v1.py new file mode 100644 index 00000000..9a872bfc --- /dev/null +++ b/mindee/product/us/w9/w9_v1.py @@ -0,0 +1,31 @@ +from typing import List + +from mindee.parsing.common import Inference, Page, StringDict +from mindee.product.us.w9.w9_v1_document import W9V1Document +from mindee.product.us.w9.w9_v1_page import W9V1Page + + +class W9V1(Inference): + """Inference prediction for W9, API version 1.""" + + prediction: W9V1Document + """Document-level prediction.""" + pages: List[Page[W9V1Page]] + """Page-level prediction(s).""" + endpoint_name = "us_w9" + """Name of the endpoint.""" + endpoint_version = "1" + """Version of the endpoint.""" + + def __init__(self, raw_prediction: StringDict): + """ + W9 v1 inference. + + :param raw_prediction: Raw prediction from the HTTP response. + """ + super().__init__(raw_prediction) + + self.prediction = W9V1Document(raw_prediction["prediction"]) + self.pages = [] + for page in raw_prediction["pages"]: + self.pages.append(Page(W9V1Page, page)) diff --git a/mindee/product/us/w9/w9_v1_document.py b/mindee/product/us/w9/w9_v1_document.py new file mode 100644 index 00000000..bb93d07c --- /dev/null +++ b/mindee/product/us/w9/w9_v1_document.py @@ -0,0 +1,23 @@ +from typing import Optional + +from mindee.parsing.common import Prediction, StringDict, clean_out_string + + +class W9V1Document(Prediction): + """Document data for W9, API version 1.""" + + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + W9 document. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + + def __str__(self) -> str: + return "" diff --git a/mindee/product/us/w9/w9_v1_page.py b/mindee/product/us/w9/w9_v1_page.py new file mode 100644 index 00000000..3e639d7f --- /dev/null +++ b/mindee/product/us/w9/w9_v1_page.py @@ -0,0 +1,113 @@ +from typing import Optional + +from mindee.parsing.common import StringDict, clean_out_string +from mindee.product.us.w9.w9_v1_document import W9V1Document + +from mindee.parsing.standard import PositionField, StringField + + +class W9V1Page(W9V1Document): + """Page data for W9, API version 1.""" + + address: StringField + """The street address (number, street, and apt. or suite no.) of the applicant.""" + business_name: StringField + """The business name or disregarded entity name, if different from Name.""" + city_state_zip: StringField + """The city, state, and ZIP code of the applicant.""" + ein: StringField + """The employer identification number.""" + name: StringField + """Name as shown on the applicant's income tax return.""" + signature_date_position: PositionField + """Position of the signature date on the document.""" + signature_position: PositionField + """Position of the signature on the document.""" + ssn: StringField + """The applicant's social security number.""" + tax_classification: StringField + """The federal tax classification, which can vary depending on the revision date.""" + tax_classification_llc: StringField + """Depending on revision year, among S, C, P or D for Limited Liability Company Classification.""" + tax_classification_other_details: StringField + """Tax Classification Other Details.""" + w9_revision_date: StringField + """The Revision month and year of the W9 form.""" + + def __init__( + self, + raw_prediction: StringDict, + page_id: Optional[int] = None, + ): + """ + W9 page. + + :param raw_prediction: Raw prediction from HTTP response + :param page_id: Page number for multi pages pdf input + """ + super().__init__(raw_prediction=raw_prediction, page_id=page_id) + self.address = StringField( + raw_prediction["address"], + page_id=page_id, + ) + self.business_name = StringField( + raw_prediction["business_name"], + page_id=page_id, + ) + self.city_state_zip = StringField( + raw_prediction["city_state_zip"], + page_id=page_id, + ) + self.ein = StringField( + raw_prediction["ein"], + page_id=page_id, + ) + self.name = StringField( + raw_prediction["name"], + page_id=page_id, + ) + self.signature_date_position = PositionField( + raw_prediction["signature_date_position"], + page_id=page_id, + ) + self.signature_position = PositionField( + raw_prediction["signature_position"], + page_id=page_id, + ) + self.ssn = StringField( + raw_prediction["ssn"], + page_id=page_id, + ) + self.tax_classification = StringField( + raw_prediction["tax_classification"], + page_id=page_id, + ) + self.tax_classification_llc = StringField( + raw_prediction["tax_classification_llc"], + page_id=page_id, + ) + self.tax_classification_other_details = StringField( + raw_prediction["tax_classification_other_details"], + page_id=page_id, + ) + self.w9_revision_date = StringField( + raw_prediction["w9_revision_date"], + page_id=page_id, + ) + + def __str__(self) -> str: + return clean_out_string( + + f":Name: {self.name}\n" + f":SSN: {self.ssn}\n" + f":Address: {self.address}\n" + f":City State Zip: {self.city_state_zip}\n" + f":Business Name: {self.business_name}\n" + f":EIN: {self.ein}\n" + f":Tax Classification: {self.tax_classification}\n" + f":Tax Classification Other Details: {self.tax_classification_other_details}\n" + f":W9 Revision Date: {self.w9_revision_date}\n" + f":Signature Position: {self.signature_position}\n" + f":Signature Date Position: {self.signature_date_position}\n" + f":Tax Classification LLC: {self.tax_classification_llc}\n" + f"{super().__str__()}" + ) diff --git a/tests/fields/test_payment_details.py b/tests/fields/test_payment_details.py index 3ef57859..8bb61ced 100644 --- a/tests/fields/test_payment_details.py +++ b/tests/fields/test_payment_details.py @@ -1,4 +1,4 @@ -from mindee.parsing.standard.payment_details import PaymentDetails +from mindee.parsing.standard.payment_details import PaymentDetailsField def test_constructor(): @@ -17,7 +17,7 @@ def test_constructor(): ] }, } - payment_detail = PaymentDetails(field_dict) + payment_detail = PaymentDetailsField(field_dict) assert payment_detail.account_number == "account_number" assert payment_detail.iban == "iban" assert payment_detail.routing_number == "routing_number" @@ -41,7 +41,7 @@ def test_constructor_all_na(): ] }, } - payment_detail = PaymentDetails(field_dict) + payment_detail = PaymentDetailsField(field_dict) assert payment_detail.account_number is None assert payment_detail.iban is None assert payment_detail.routing_number is None @@ -64,7 +64,7 @@ def test_constructor_all_none(): ] }, } - payment_detail = PaymentDetails(field_dict) + payment_detail = PaymentDetailsField(field_dict) assert payment_detail.account_number is None assert payment_detail.iban is None assert payment_detail.routing_number is None diff --git a/tests/product/barcode_reader/test_barcode_reader_v1.py b/tests/product/barcode_reader/test_barcode_reader_v1.py new file mode 100644 index 00000000..e8dfb61e --- /dev/null +++ b/tests/product/barcode_reader/test_barcode_reader_v1.py @@ -0,0 +1,60 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product import BarcodeReaderV1 +from mindee.product.barcode_reader.barcode_reader_v1_document import ( + BarcodeReaderV1Document, +) +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[BarcodeReaderV1Document, Page[BarcodeReaderV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "barcode_reader" / "response_v1" / "complete.json") + ) + return Document(BarcodeReaderV1, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[BarcodeReaderV1Document, Page[BarcodeReaderV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "barcode_reader" / "response_v1" / "empty.json") + ) + return Document(BarcodeReaderV1, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[BarcodeReaderV1Document]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "barcode_reader" / "response_v1" / "complete.json") + ) + return Page(BarcodeReaderV1Document, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[BarcodeReaderV1Document, Page[BarcodeReaderV1Document]]): + reference_str = open( + PRODUCT_DATA_DIR / "barcode_reader" / "response_v1" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[BarcodeReaderV1Document, Page[BarcodeReaderV1Document]]): + prediction = empty_doc.inference.prediction + assert len(prediction.codes_1d) == 0 + assert len(prediction.codes_2d) == 0 + + +def test_complete_page_0(complete_page_0: Page[BarcodeReaderV1Document]): + reference_str = open( + PRODUCT_DATA_DIR / "barcode_reader" / "response_v1" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/cropper/test_cropper_v1.py b/tests/product/cropper/test_cropper_v1.py index 09849b42..2acb465e 100644 --- a/tests/product/cropper/test_cropper_v1.py +++ b/tests/product/cropper/test_cropper_v1.py @@ -54,7 +54,5 @@ def test_complete_page_0(complete_page_0: Page[CropperV1Page]): "r", encoding="utf-8", ).read() - assert complete_page_0.orientation - assert complete_page_0.orientation.value == 0 assert complete_page_0.id == 0 assert str(complete_page_0) == reference_str diff --git a/tests/product/eu/license_plate/test_license_plate_v1.py b/tests/product/eu/license_plate/test_license_plate_v1.py new file mode 100644 index 00000000..48dccf25 --- /dev/null +++ b/tests/product/eu/license_plate/test_license_plate_v1.py @@ -0,0 +1,59 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product.eu import LicensePlateV1 +from mindee.product.eu.license_plate.license_plate_v1_document import ( + LicensePlateV1Document, +) +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[LicensePlateV1Document, Page[LicensePlateV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "license_plates" / "response_v1" / "complete.json") + ) + return Document(LicensePlateV1, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[LicensePlateV1Document, Page[LicensePlateV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "license_plates" / "response_v1" / "empty.json") + ) + return Document(LicensePlateV1, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[LicensePlateV1Document]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "license_plates" / "response_v1" / "complete.json") + ) + return Page(LicensePlateV1Document, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[LicensePlateV1Document, Page[LicensePlateV1Document]]): + reference_str = open( + PRODUCT_DATA_DIR / "license_plates" / "response_v1" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[LicensePlateV1Document, Page[LicensePlateV1Document]]): + prediction = empty_doc.inference.prediction + assert len(prediction.license_plates) == 0 + + +def test_complete_page_0(complete_page_0: Page[LicensePlateV1Document]): + reference_str = open( + PRODUCT_DATA_DIR / "license_plates" / "response_v1" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/fr/bank_account_details/test_bank_account_details_v1.py b/tests/product/fr/bank_account_details/test_bank_account_details_v1.py new file mode 100644 index 00000000..8d6d53f1 --- /dev/null +++ b/tests/product/fr/bank_account_details/test_bank_account_details_v1.py @@ -0,0 +1,61 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product.fr import BankAccountDetailsV1 +from mindee.product.fr.bank_account_details.bank_account_details_v1_document import ( + BankAccountDetailsV1Document, +) +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[BankAccountDetailsV1Document, Page[BankAccountDetailsV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "bank_account_details" / "response_v1" / "complete.json") + ) + return Document(BankAccountDetailsV1, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[BankAccountDetailsV1Document, Page[BankAccountDetailsV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "bank_account_details" / "response_v1" / "empty.json") + ) + return Document(BankAccountDetailsV1, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[BankAccountDetailsV1Document]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "bank_account_details" / "response_v1" / "complete.json") + ) + return Page(BankAccountDetailsV1Document, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[BankAccountDetailsV1Document, Page[BankAccountDetailsV1Document]]): + reference_str = open( + PRODUCT_DATA_DIR / "bank_account_details" / "response_v1" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[BankAccountDetailsV1Document, Page[BankAccountDetailsV1Document]]): + prediction = empty_doc.inference.prediction + assert prediction.iban.value is None + assert prediction.account_holder_name.value is None + assert prediction.swift.value is None + + +def test_complete_page_0(complete_page_0: Page[BankAccountDetailsV1Document]): + reference_str = open( + PRODUCT_DATA_DIR / "bank_account_details" / "response_v1" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/fr/bank_account_details/test_bank_account_details_v2.py b/tests/product/fr/bank_account_details/test_bank_account_details_v2.py new file mode 100644 index 00000000..a8fa3566 --- /dev/null +++ b/tests/product/fr/bank_account_details/test_bank_account_details_v2.py @@ -0,0 +1,65 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product.fr import BankAccountDetailsV2 +from mindee.product.fr.bank_account_details.bank_account_details_v2_document import ( + BankAccountDetailsV2Document, +) +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[BankAccountDetailsV2Document, Page[BankAccountDetailsV2Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "bank_account_details" / "response_v2" / "complete.json") + ) + return Document(BankAccountDetailsV2, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[BankAccountDetailsV2Document, Page[BankAccountDetailsV2Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "bank_account_details" / "response_v2" / "empty.json") + ) + return Document(BankAccountDetailsV2, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[BankAccountDetailsV2Document]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "bank_account_details" / "response_v2" / "complete.json") + ) + return Page(BankAccountDetailsV2Document, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[BankAccountDetailsV2Document, Page[BankAccountDetailsV2Document]]): + reference_str = open( + PRODUCT_DATA_DIR / "bank_account_details" / "response_v2" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[BankAccountDetailsV2Document, Page[BankAccountDetailsV2Document]]): + prediction = empty_doc.inference.prediction + assert prediction.account_holders_names.value is None + assert prediction.bban.bban_bank_code is None + assert prediction.bban.bban_branch_code is None + assert prediction.bban.bban_key is None + assert prediction.bban.bban_number is None + assert prediction.iban.value is None + assert prediction.swift_code.value is None + + +def test_complete_page_0(complete_page_0: Page[BankAccountDetailsV2Document]): + reference_str = open( + PRODUCT_DATA_DIR / "bank_account_details" / "response_v2" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/fr/carte_vitale/test_carte_vitale_v1.py b/tests/product/fr/carte_vitale/test_carte_vitale_v1.py index ff8a6f51..d99af0e1 100644 --- a/tests/product/fr/carte_vitale/test_carte_vitale_v1.py +++ b/tests/product/fr/carte_vitale/test_carte_vitale_v1.py @@ -35,9 +35,7 @@ def complete_page_0() -> Page[CarteVitaleV1Document]: return Page(CarteVitaleV1Document, json_data["document"]["inference"]["pages"][0]) -def test_complete_doc( - complete_doc: Document[CarteVitaleV1Document, Page[CarteVitaleV1Document]] -): +def test_complete_doc(complete_doc: Document[CarteVitaleV1Document, Page[CarteVitaleV1Document]]): reference_str = open( PRODUCT_DATA_DIR / "carte_vitale" / "response_v1" / "summary_full.rst", "r", @@ -46,9 +44,7 @@ def test_complete_doc( assert str(complete_doc) == reference_str -def test_empty_doc( - empty_doc: Document[CarteVitaleV1Document, Page[CarteVitaleV1Document]] -): +def test_empty_doc(empty_doc: Document[CarteVitaleV1Document, Page[CarteVitaleV1Document]]): prediction = empty_doc.inference.prediction assert len(prediction.given_names) == 0 assert prediction.surname.value is None @@ -62,7 +58,5 @@ def test_complete_page_0(complete_page_0: Page[CarteVitaleV1Document]): "r", encoding="utf-8", ).read() - assert complete_page_0.orientation - assert complete_page_0.orientation.value == 0 assert complete_page_0.id == 0 assert str(complete_page_0) == reference_str diff --git a/tests/product/fr/id_card/test_id_card_v1.py b/tests/product/fr/id_card/test_id_card_v1.py index c5843f2c..8fbba796 100644 --- a/tests/product/fr/id_card/test_id_card_v1.py +++ b/tests/product/fr/id_card/test_id_card_v1.py @@ -63,7 +63,5 @@ def test_complete_page_0(complete_page_0: Page[IdCardV1Page]): "r", encoding="utf-8", ).read() - assert complete_page_0.orientation - assert complete_page_0.orientation.value == 0 assert complete_page_0.id == 0 assert str(complete_page_0) == reference_str diff --git a/tests/product/fr/id_card/test_id_card_v2.py b/tests/product/fr/id_card/test_id_card_v2.py new file mode 100644 index 00000000..f98a0a4e --- /dev/null +++ b/tests/product/fr/id_card/test_id_card_v2.py @@ -0,0 +1,72 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product.fr import IdCardV2 +from mindee.product.fr.id_card.id_card_v2_document import IdCardV2Document +from mindee.product.fr.id_card.id_card_v2_page import IdCardV2Page +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[IdCardV2Document, Page[IdCardV2Page]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "idcard_fr" / "response_v2" / "complete.json") + ) + return Document(IdCardV2, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[IdCardV2Document, Page[IdCardV2Page]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "idcard_fr" / "response_v2" / "empty.json") + ) + return Document(IdCardV2, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[IdCardV2Page]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "idcard_fr" / "response_v2" / "complete.json") + ) + return Page(IdCardV2Page, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[IdCardV2Document, Page[IdCardV2Page]]): + reference_str = open( + PRODUCT_DATA_DIR / "idcard_fr" / "response_v2" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[IdCardV2Document, Page[IdCardV2Page]]): + prediction = empty_doc.inference.prediction + assert prediction.nationality.value is None + assert prediction.card_access_number.value is None + assert prediction.document_number.value is None + assert len(prediction.given_names) == 0 + assert prediction.surname.value is None + assert prediction.alternate_name.value is None + assert prediction.birth_date.value is None + assert prediction.birth_place.value is None + assert prediction.gender.value is None + assert prediction.expiry_date.value is None + assert prediction.mrz1.value is None + assert prediction.mrz2.value is None + assert prediction.mrz3.value is None + assert prediction.issue_date.value is None + assert prediction.authority.value is None + + +def test_complete_page_0(complete_page_0: Page[IdCardV2Page]): + reference_str = open( + PRODUCT_DATA_DIR / "idcard_fr" / "response_v2" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/invoice/test_invoice_v4.py b/tests/product/invoice/test_invoice_v4.py new file mode 100644 index 00000000..72aaa8bd --- /dev/null +++ b/tests/product/invoice/test_invoice_v4.py @@ -0,0 +1,72 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product import InvoiceV4 +from mindee.product.invoice.invoice_v4_document import InvoiceV4Document +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[InvoiceV4Document, Page[InvoiceV4Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "invoices" / "response_v4" / "complete.json") + ) + return Document(InvoiceV4, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[InvoiceV4Document, Page[InvoiceV4Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "invoices" / "response_v4" / "empty.json") + ) + return Document(InvoiceV4, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[InvoiceV4Document]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "invoices" / "response_v4" / "complete.json") + ) + return Page(InvoiceV4Document, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[InvoiceV4Document, Page[InvoiceV4Document]]): + reference_str = open( + PRODUCT_DATA_DIR / "invoices" / "response_v4" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[InvoiceV4Document, Page[InvoiceV4Document]]): + prediction = empty_doc.inference.prediction + assert prediction.locale.value is None + assert prediction.invoice_number.value is None + assert len(prediction.reference_numbers) == 0 + assert prediction.date.value is None + assert prediction.due_date.value is None + assert prediction.total_net.value is None + assert prediction.total_amount.value is None + assert len(prediction.taxes) == 0 + assert len(prediction.supplier_payment_details) == 0 + assert prediction.supplier_name.value is None + assert len(prediction.supplier_company_registrations) == 0 + assert prediction.supplier_address.value is None + assert prediction.customer_name.value is None + assert len(prediction.customer_company_registrations) == 0 + assert prediction.customer_address.value is None + assert len(prediction.line_items) == 0 + + +def test_complete_page_0(complete_page_0: Page[InvoiceV4Document]): + reference_str = open( + PRODUCT_DATA_DIR / "invoices" / "response_v4" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/multi_receipts_detector/test_multi_receipts_detector_v1.py b/tests/product/multi_receipts_detector/test_multi_receipts_detector_v1.py new file mode 100644 index 00000000..980e13bc --- /dev/null +++ b/tests/product/multi_receipts_detector/test_multi_receipts_detector_v1.py @@ -0,0 +1,61 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product import MultiReceiptsDetectorV1 +from mindee.product.multi_receipts_detector.multi_receipts_detector_v1_document import ( + MultiReceiptsDetectorV1Document, +) +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[MultiReceiptsDetectorV1Document, Page[MultiReceiptsDetectorV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "multi_receipts_detector" / "response_v1" / "complete.json") + ) + return Document(MultiReceiptsDetectorV1, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[MultiReceiptsDetectorV1Document, Page[MultiReceiptsDetectorV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "multi_receipts_detector" / "response_v1" / "empty.json") + ) + return Document(MultiReceiptsDetectorV1, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[MultiReceiptsDetectorV1Document]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "multi_receipts_detector" / "response_v1" / "complete.json") + ) + return Page(MultiReceiptsDetectorV1Document, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc( + complete_doc: Document[MultiReceiptsDetectorV1Document, Page[MultiReceiptsDetectorV1Document]]): + reference_str = open( + PRODUCT_DATA_DIR / "multi_receipts_detector" / "response_v1" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc( + empty_doc: Document[MultiReceiptsDetectorV1Document, Page[MultiReceiptsDetectorV1Document]]): + prediction = empty_doc.inference.prediction + assert len(prediction.receipts) == 0 + + +def test_complete_page_0(complete_page_0: Page[MultiReceiptsDetectorV1Document]): + reference_str = open( + PRODUCT_DATA_DIR / "multi_receipts_detector" / "response_v1" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/passport/test_passport_v1.py b/tests/product/passport/test_passport_v1.py new file mode 100644 index 00000000..75c50094 --- /dev/null +++ b/tests/product/passport/test_passport_v1.py @@ -0,0 +1,67 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product import PassportV1 +from mindee.product.passport.passport_v1_document import PassportV1Document +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[PassportV1Document, Page[PassportV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "passport" / "response_v1" / "complete.json") + ) + return Document(PassportV1, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[PassportV1Document, Page[PassportV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "passport" / "response_v1" / "empty.json") + ) + return Document(PassportV1, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[PassportV1Document]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "passport" / "response_v1" / "complete.json") + ) + return Page(PassportV1Document, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[PassportV1Document, Page[PassportV1Document]]): + reference_str = open( + PRODUCT_DATA_DIR / "passport" / "response_v1" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[PassportV1Document, Page[PassportV1Document]]): + prediction = empty_doc.inference.prediction + assert prediction.country.value is None + assert prediction.id_number.value is None + assert len(prediction.given_names) == 0 + assert prediction.surname.value is None + assert prediction.birth_date.value is None + assert prediction.birth_place.value is None + assert prediction.gender.value is None + assert prediction.issuance_date.value is None + assert prediction.expiry_date.value is None + assert prediction.mrz1.value is None + assert prediction.mrz2.value is None + + +def test_complete_page_0(complete_page_0: Page[PassportV1Document]): + reference_str = open( + PRODUCT_DATA_DIR / "passport" / "response_v1" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/proof_of_address/test_proof_of_address_v1.py b/tests/product/proof_of_address/test_proof_of_address_v1.py new file mode 100644 index 00000000..def38f4e --- /dev/null +++ b/tests/product/proof_of_address/test_proof_of_address_v1.py @@ -0,0 +1,67 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product import ProofOfAddressV1 +from mindee.product.proof_of_address.proof_of_address_v1_document import ( + ProofOfAddressV1Document, +) +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[ProofOfAddressV1Document, Page[ProofOfAddressV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "proof_of_address" / "response_v1" / "complete.json") + ) + return Document(ProofOfAddressV1, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[ProofOfAddressV1Document, Page[ProofOfAddressV1Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "proof_of_address" / "response_v1" / "empty.json") + ) + return Document(ProofOfAddressV1, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[ProofOfAddressV1Document]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "proof_of_address" / "response_v1" / "complete.json") + ) + return Page(ProofOfAddressV1Document, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[ProofOfAddressV1Document, Page[ProofOfAddressV1Document]]): + reference_str = open( + PRODUCT_DATA_DIR / "proof_of_address" / "response_v1" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[ProofOfAddressV1Document, Page[ProofOfAddressV1Document]]): + prediction = empty_doc.inference.prediction + assert prediction.locale.value is None + assert prediction.issuer_name.value is None + assert len(prediction.issuer_company_registration) == 0 + assert prediction.issuer_address.value is None + assert prediction.recipient_name.value is None + assert len(prediction.recipient_company_registration) == 0 + assert prediction.recipient_address.value is None + assert len(prediction.dates) == 0 + assert prediction.date.value is None + + +def test_complete_page_0(complete_page_0: Page[ProofOfAddressV1Document]): + reference_str = open( + PRODUCT_DATA_DIR / "proof_of_address" / "response_v1" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/receipt/test_receipt_v5.py b/tests/product/receipt/test_receipt_v5.py new file mode 100644 index 00000000..43a6fc3a --- /dev/null +++ b/tests/product/receipt/test_receipt_v5.py @@ -0,0 +1,69 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product import ReceiptV5 +from mindee.product.receipt.receipt_v5_document import ReceiptV5Document +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[ReceiptV5Document, Page[ReceiptV5Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "expense_receipts" / "response_v5" / "complete.json") + ) + return Document(ReceiptV5, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[ReceiptV5Document, Page[ReceiptV5Document]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "expense_receipts" / "response_v5" / "empty.json") + ) + return Document(ReceiptV5, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[ReceiptV5Document]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "expense_receipts" / "response_v5" / "complete.json") + ) + return Page(ReceiptV5Document, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[ReceiptV5Document, Page[ReceiptV5Document]]): + reference_str = open( + PRODUCT_DATA_DIR / "expense_receipts" / "response_v5" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[ReceiptV5Document, Page[ReceiptV5Document]]): + prediction = empty_doc.inference.prediction + assert prediction.locale.value is None + assert prediction.date.value is None + assert prediction.time.value is None + assert prediction.total_amount.value is None + assert prediction.total_net.value is None + assert prediction.total_tax.value is None + assert prediction.tip.value is None + assert len(prediction.taxes) == 0 + assert prediction.supplier_name.value is None + assert len(prediction.supplier_company_registrations) == 0 + assert prediction.supplier_address.value is None + assert prediction.supplier_phone_number.value is None + assert len(prediction.line_items) == 0 + + +def test_complete_page_0(complete_page_0: Page[ReceiptV5Document]): + reference_str = open( + PRODUCT_DATA_DIR / "expense_receipts" / "response_v5" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/us/bank_check/test_bank_check_v1.py b/tests/product/us/bank_check/test_bank_check_v1.py new file mode 100644 index 00000000..154a755d --- /dev/null +++ b/tests/product/us/bank_check/test_bank_check_v1.py @@ -0,0 +1,63 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product.us import BankCheckV1 +from mindee.product.us.bank_check.bank_check_v1_document import BankCheckV1Document +from mindee.product.us.bank_check.bank_check_v1_page import BankCheckV1Page +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[BankCheckV1Document, Page[BankCheckV1Page]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "bank_check" / "response_v1" / "complete.json") + ) + return Document(BankCheckV1, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[BankCheckV1Document, Page[BankCheckV1Page]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "bank_check" / "response_v1" / "empty.json") + ) + return Document(BankCheckV1, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[BankCheckV1Page]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "bank_check" / "response_v1" / "complete.json") + ) + return Page(BankCheckV1Page, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[BankCheckV1Document, Page[BankCheckV1Page]]): + reference_str = open( + PRODUCT_DATA_DIR / "bank_check" / "response_v1" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[BankCheckV1Document, Page[BankCheckV1Page]]): + prediction = empty_doc.inference.prediction + assert prediction.date.value is None + assert prediction.amount.value is None + assert len(prediction.payees) == 0 + assert prediction.routing_number.value is None + assert prediction.account_number.value is None + assert prediction.check_number.value is None + + +def test_complete_page_0(complete_page_0: Page[BankCheckV1Page]): + reference_str = open( + PRODUCT_DATA_DIR / "bank_check" / "response_v1" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/us/driver_license/test_driver_license_v1.py b/tests/product/us/driver_license/test_driver_license_v1.py new file mode 100644 index 00000000..5af7fbb3 --- /dev/null +++ b/tests/product/us/driver_license/test_driver_license_v1.py @@ -0,0 +1,76 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product.us import DriverLicenseV1 +from mindee.product.us.driver_license.driver_license_v1_document import ( + DriverLicenseV1Document, +) +from mindee.product.us.driver_license.driver_license_v1_page import DriverLicenseV1Page +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[DriverLicenseV1Document, Page[DriverLicenseV1Page]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "us_driver_license" / "response_v1" / "complete.json") + ) + return Document(DriverLicenseV1, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[DriverLicenseV1Document, Page[DriverLicenseV1Page]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "us_driver_license" / "response_v1" / "empty.json") + ) + return Document(DriverLicenseV1, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[DriverLicenseV1Page]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "us_driver_license" / "response_v1" / "complete.json") + ) + return Page(DriverLicenseV1Page, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[DriverLicenseV1Document, Page[DriverLicenseV1Page]]): + reference_str = open( + PRODUCT_DATA_DIR / "us_driver_license" / "response_v1" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[DriverLicenseV1Document, Page[DriverLicenseV1Page]]): + prediction = empty_doc.inference.prediction + assert prediction.state.value is None + assert prediction.driver_license_id.value is None + assert prediction.expiry_date.value is None + assert prediction.issued_date.value is None + assert prediction.last_name.value is None + assert prediction.first_name.value is None + assert prediction.address.value is None + assert prediction.date_of_birth.value is None + assert prediction.restrictions.value is None + assert prediction.endorsements.value is None + assert prediction.dl_class.value is None + assert prediction.sex.value is None + assert prediction.height.value is None + assert prediction.weight.value is None + assert prediction.hair_color.value is None + assert prediction.eye_color.value is None + assert prediction.dd_number.value is None + + +def test_complete_page_0(complete_page_0: Page[DriverLicenseV1Page]): + reference_str = open( + PRODUCT_DATA_DIR / "us_driver_license" / "response_v1" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str diff --git a/tests/product/us/w9/test_w9_v1.py b/tests/product/us/w9/test_w9_v1.py new file mode 100644 index 00000000..57945cbd --- /dev/null +++ b/tests/product/us/w9/test_w9_v1.py @@ -0,0 +1,69 @@ +import json + +import pytest + +from mindee.parsing.common.document import Document +from mindee.parsing.common.page import Page +from mindee.product.us import W9V1 +from mindee.product.us.w9.w9_v1_document import W9V1Document +from mindee.product.us.w9.w9_v1_page import W9V1Page +from tests.product import PRODUCT_DATA_DIR + + +@pytest.fixture +def complete_doc() -> Document[W9V1Document, Page[W9V1Page]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "us_w9" / "response_v1" / "complete.json") + ) + return Document(W9V1, json_data["document"]) + + +@pytest.fixture +def empty_doc() -> Document[W9V1Document, Page[W9V1Page]]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "us_w9" / "response_v1" / "empty.json") + ) + return Document(W9V1, json_data["document"]) + + +@pytest.fixture +def complete_page_0() -> Page[W9V1Page]: + json_data = json.load( + open(PRODUCT_DATA_DIR / "us_w9" / "response_v1" / "complete.json") + ) + return Page(W9V1Page, json_data["document"]["inference"]["pages"][0]) + + +def test_complete_doc(complete_doc: Document[W9V1Document, Page[W9V1Page]]): + reference_str = open( + PRODUCT_DATA_DIR / "us_w9" / "response_v1" / "summary_full.rst", + "r", + encoding="utf-8", + ).read() + assert str(complete_doc) == reference_str + + +def test_empty_doc(empty_doc: Document[W9V1Document, Page[W9V1Page]]): + prediction = empty_doc.inference.pages[0].prediction + assert prediction.name.value is None + assert prediction.ssn.value is None + assert prediction.address.value is None + assert prediction.city_state_zip.value is None + assert prediction.business_name.value is None + assert prediction.ein.value is None + assert prediction.tax_classification.value is None + assert prediction.tax_classification_other_details.value is None + assert prediction.w9_revision_date.value is None + assert not prediction.signature_position.polygon + assert not prediction.signature_date_position.polygon + assert prediction.tax_classification_llc.value is None + + +def test_complete_page_0(complete_page_0: Page[W9V1Page]): + reference_str = open( + PRODUCT_DATA_DIR / "us_w9" / "response_v1" / "summary_page0.rst", + "r", + encoding="utf-8", + ).read() + assert complete_page_0.id == 0 + assert str(complete_page_0) == reference_str