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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/extras/code_samples/idcard_fr_v2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from mindee import Client, documents

# Init a new client
mindee_client = Client(api_key="my-api-key")

# Load a file from disk
input_doc = mindee_client.doc_from_path("/path/to/the/file.ext")

# Parse the Carte Nationale d'Identité by passing the appropriate type
result = input_doc.parse(documents.fr.TypeIdCardV2)

# Print a brief summary of the parsed data
print(result.document)
10 changes: 10 additions & 0 deletions docs/predictions/standard/documents/fr/id_card_v2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Carte Nationale d'Identité V2
-----------------------------

**Sample Code:**

.. literalinclude:: /extras/code_samples/idcard_fr_v2.txt
:language: Python

.. autoclass:: mindee.documents.fr.IdCardV2
:members:
1 change: 1 addition & 0 deletions docs/predictions/standard/fr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ France
======

.. include:: ./documents/fr/id_card_v1.rst
.. include:: ./documents/fr/id_card_v2.rst
.. include:: ./documents/fr/carte_vitale_v1.rst
.. include:: ./documents/fr/carte_grise_v1.rst
.. include:: ./documents/fr/bank_account_details_v1.rst
Expand Down
5 changes: 5 additions & 0 deletions mindee/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,11 @@ def _init_default_endpoints(self) -> None:
url_name="idcard_fr",
version="1",
),
ConfigSpec(
doc_class=documents.fr.IdCardV2,
url_name="idcard_fr",
version="2",
),
ConfigSpec(
doc_class=documents.fr.CarteVitaleV1,
url_name="carte_vitale",
Expand Down
1 change: 1 addition & 0 deletions mindee/documents/fr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
from .carte_grise.carte_grise_v1 import CarteGriseV1, TypeCarteGriseV1
from .carte_vitale.carte_vitale_v1 import CarteVitaleV1, TypeCarteVitaleV1
from .id_card.id_card_v1 import IdCardV1, TypeIdCardV1
from .id_card.id_card_v2 import IdCardV2, TypeIdCardV2
177 changes: 177 additions & 0 deletions mindee/documents/fr/id_card/id_card_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
from typing import List, Optional, TypeVar

from mindee.documents.base import Document, TypeApiPrediction, clean_out_string
from mindee.fields.classification import ClassificationField
from mindee.fields.date import DateField
from mindee.fields.text import TextField


class IdCardV2(Document):
"""Carte Nationale d'Identité v2 prediction results."""

alternate_name: TextField
"""The alternate name of the card holder."""
authority: TextField
"""The name of the issuing authority."""
birth_date: DateField
"""The date of birth of the card holder."""
birth_place: TextField
"""The place of birth of the card holder."""
card_access_number: TextField
"""The card access number (CAN)."""
document_number: TextField
"""The document number."""
document_side: ClassificationField
"""The sides of the document which are visible."""
document_type: ClassificationField
"""The document type or format."""
expiry_date: DateField
"""The expiry date of the identification card."""
gender: TextField
"""The gender of the card holder."""
given_names: List[TextField]
"""The given name(s) of the card holder."""
issue_date: DateField
"""The date of issue of the identification card."""
mrz1: TextField
"""The Machine Readable Zone, first line."""
mrz2: TextField
"""The Machine Readable Zone, second line."""
mrz3: TextField
"""The Machine Readable Zone, third line."""
nationality: TextField
"""The nationality of the card holder."""
surname: TextField
"""The surname of the card holder."""

def __init__(
self,
api_prediction=None,
input_source=None,
page_n: Optional[int] = None,
):
"""
Carte Nationale d'Identité v2 prediction results.

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

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

:param api_prediction: Raw prediction from HTTP response
:param page_n: Page number
"""
self.alternate_name = TextField(
api_prediction["alternate_name"],
page_id=page_n,
)
self.authority = TextField(
api_prediction["authority"],
page_id=page_n,
)
self.birth_date = DateField(
api_prediction["birth_date"],
page_id=page_n,
)
self.birth_place = TextField(
api_prediction["birth_place"],
page_id=page_n,
)
self.card_access_number = TextField(
api_prediction["card_access_number"],
page_id=page_n,
)
self.document_number = TextField(
api_prediction["document_number"],
page_id=page_n,
)
self.document_side = ClassificationField(
api_prediction.get("document_side", {}),
page_id=page_n,
)
self.document_type = ClassificationField(
api_prediction.get("document_type", {}),
page_id=page_n,
)
self.expiry_date = DateField(
api_prediction["expiry_date"],
page_id=page_n,
)
self.gender = TextField(
api_prediction["gender"],
page_id=page_n,
)
self.given_names = [
TextField(prediction, page_id=page_n)
for prediction in api_prediction["given_names"]
]
self.issue_date = DateField(
api_prediction["issue_date"],
page_id=page_n,
)
self.mrz1 = TextField(
api_prediction["mrz1"],
page_id=page_n,
)
self.mrz2 = TextField(
api_prediction["mrz2"],
page_id=page_n,
)
self.mrz3 = TextField(
api_prediction["mrz3"],
page_id=page_n,
)
self.nationality = TextField(
api_prediction["nationality"],
page_id=page_n,
)
self.surname = TextField(
api_prediction["surname"],
page_id=page_n,
)

def __str__(self) -> str:
given_names = f"\n { ' ' * 15 }".join(
[str(item) for item in self.given_names],
)
return clean_out_string(
"FR Carte Nationale d'Identité V2 Prediction\n"
"===========================================\n"
f":Filename: {self.filename or ''}\n"
f":Document Type: {self.document_type}\n"
f":Document Sides: {self.document_side}\n"
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"
)


TypeIdCardV2 = TypeVar(
"TypeIdCardV2",
bound=IdCardV2,
)
57 changes: 57 additions & 0 deletions tests/documents/fr/test_id_card_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import json

import pytest

from mindee.documents.fr import IdCardV2

FR_ID_CARD_DATA_DIR = "./tests/data/products/idcard_fr"
FILE_PATH_FR_ID_CARD_V2_COMPLETE = f"{ FR_ID_CARD_DATA_DIR }/response_v2/complete.json"
FILE_PATH_FR_ID_CARD_V2_EMPTY = f"{ FR_ID_CARD_DATA_DIR }/response_v2/empty.json"


@pytest.fixture
def id_card_v2_doc() -> IdCardV2:
json_data = json.load(open(FILE_PATH_FR_ID_CARD_V2_COMPLETE, encoding="utf-8"))
return IdCardV2(json_data["document"]["inference"], page_n=None)


@pytest.fixture
def id_card_v2_doc_empty() -> IdCardV2:
json_data = json.load(open(FILE_PATH_FR_ID_CARD_V2_EMPTY, encoding="utf-8"))
return IdCardV2(json_data["document"]["inference"], page_n=None)


@pytest.fixture
def id_card_v2_page0():
json_data = json.load(open(FILE_PATH_FR_ID_CARD_V2_COMPLETE, encoding="utf-8"))
return IdCardV2(json_data["document"]["inference"]["pages"][0], page_n=0)


def test_empty_doc_constructor(id_card_v2_doc_empty):
assert id_card_v2_doc_empty.nationality.value is None
assert id_card_v2_doc_empty.card_access_number.value is None
assert id_card_v2_doc_empty.document_number.value is None
assert len(id_card_v2_doc_empty.given_names) == 0
assert id_card_v2_doc_empty.surname.value is None
assert id_card_v2_doc_empty.alternate_name.value is None
assert id_card_v2_doc_empty.birth_date.value is None
assert id_card_v2_doc_empty.birth_place.value is None
assert id_card_v2_doc_empty.gender.value is None
assert id_card_v2_doc_empty.expiry_date.value is None
assert id_card_v2_doc_empty.mrz1.value is None
assert id_card_v2_doc_empty.mrz2.value is None
assert id_card_v2_doc_empty.mrz3.value is None
assert id_card_v2_doc_empty.issue_date.value is None
assert id_card_v2_doc_empty.authority.value is None


def test_doc_constructor(id_card_v2_doc):
file_path = f"{ FR_ID_CARD_DATA_DIR }/response_v2/doc_to_string.rst"
reference_str = open(file_path, "r", encoding="utf-8").read()
assert str(id_card_v2_doc) == reference_str


def test_page0_constructor(id_card_v2_page0):
file_path = f"{ FR_ID_CARD_DATA_DIR }/response_v2/page0_to_string.rst"
reference_str = open(file_path, "r", encoding="utf-8").read()
assert str(id_card_v2_page0) == reference_str