Skip to content

Commit a676bc7

Browse files
committed
✨ add support for fr id card v1
1 parent 9b5d3dc commit a676bc7

File tree

9 files changed

+254
-8
lines changed

9 files changed

+254
-8
lines changed

docs/code_samples/fr/id_card_v1.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from mindee import Client, documents
2+
3+
# Init a new client
4+
mindee_client = Client(api_key="my-api-key")
5+
6+
# Load a file from disk
7+
input_doc = mindee_client.doc_from_path("/path/to/the/file.ext")
8+
9+
# Parse the Carte Nationale d'Identité by passing the appropriate type
10+
result = input_doc.parse(documents.fr.TypeIdCardV1)
11+
12+
# Print a brief summary of the parsed data
13+
print(result.document)

mindee/cli.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ class CommandConfig(Generic[TypeDoc]):
5050
help="French Carte Grise",
5151
doc_class=documents.fr.TypeCarteGriseV1,
5252
),
53+
"fr-carte-vitale": CommandConfig(
54+
help="French Carte Vitale",
55+
doc_class=documents.fr.TypeCarteVitaleV1,
56+
),
57+
"fr-id-card": CommandConfig(
58+
help="French ID Card",
59+
doc_class=documents.fr.TypeIdCardV1,
60+
),
5361
}
5462

5563

mindee/documents/fr/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
from .carte_grise.carte_grise_v1 import CarteGriseV1, TypeCarteGriseV1
2+
from .carte_vitale.carte_vitale_v1 import CarteVitaleV1, TypeCarteVitaleV1
3+
from .id_card.id_card_v1 import IdCardV1, TypeIdCardV1

mindee/documents/fr/carte_vitale/carte_vitale_v1.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
class CarteVitaleV1(Document):
9-
"""A Carte Vitale prediction."""
9+
"""Carte Vitale v1 prediction results."""
1010

1111
given_names: List[TextField]
1212
"""The given name(s) of the card holder."""
@@ -24,7 +24,7 @@ def __init__(
2424
page_n: Optional[int] = None,
2525
):
2626
"""
27-
document.
27+
Carte Vitale v1 prediction results.
2828
2929
:param api_prediction: Raw prediction from HTTP response
3030
:param input_source: Input object
@@ -65,12 +65,14 @@ def _build_from_api_prediction(
6565
)
6666

6767
def __str__(self) -> str:
68+
given_names = "\n".join([str(item) for item in self.given_names])
6869
return clean_out_string(
69-
"----- Carte Vitale V1 -----\n"
70-
f"Given Name(s): {self.given_names}"
71-
f"Surname: {self.surname}"
72-
f"Social Security Number: {self.social_security}"
73-
f"Issuance Date: {self.issuance_date}"
70+
"----- FR Carte Vitale V1 -----\n"
71+
f"Filename: {self.filename or ''}\n"
72+
f"Given Name(s): { given_names }\n"
73+
f"Surname: { self.surname }\n"
74+
f"Social Security Number: { self.social_security }\n"
75+
f"Issuance Date: { self.issuance_date }\n"
7476
"----------------------"
7577
)
7678

mindee/documents/fr/id_card/__init__.py

Whitespace-only changes.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
from typing import List, Optional, TypeVar
2+
3+
from mindee.documents.base import Document, TypeApiPrediction, clean_out_string
4+
from mindee.fields.date import DateField
5+
from mindee.fields.text import TextField
6+
7+
8+
class IdCardV1(Document):
9+
"""Carte Nationale d'Identité v1 prediction results."""
10+
11+
document_side: TextField
12+
"""The side of the document which is visible."""
13+
id_number: TextField
14+
"""The identification card number."""
15+
given_names: List[TextField]
16+
"""The given name(s) of the card holder."""
17+
surname: TextField
18+
"""The surname of the card holder."""
19+
birth_date: DateField
20+
"""The date of birth of the card holder."""
21+
birth_place: TextField
22+
"""The place of birth of the card holder."""
23+
expiry_date: DateField
24+
"""The expiry date of the identification card."""
25+
authority: TextField
26+
"""The name of the issuing authority."""
27+
gender: TextField
28+
"""The gender of the card holder."""
29+
mrz1: TextField
30+
"""Machine Readable Zone, first line"""
31+
mrz2: TextField
32+
"""Machine Readable Zone, second line"""
33+
34+
def __init__(
35+
self,
36+
api_prediction=None,
37+
input_source=None,
38+
page_n: Optional[int] = None,
39+
):
40+
"""
41+
Carte Nationale d'Identité v1 prediction results.
42+
43+
:param api_prediction: Raw prediction from HTTP response
44+
:param input_source: Input object
45+
:param page_n: Page number for multi pages pdf input
46+
"""
47+
super().__init__(
48+
input_source=input_source,
49+
document_type="id_card",
50+
api_prediction=api_prediction,
51+
page_n=page_n,
52+
)
53+
self._build_from_api_prediction(api_prediction["prediction"], page_n=page_n)
54+
55+
def _build_from_api_prediction(
56+
self, api_prediction: TypeApiPrediction, page_n: Optional[int] = None
57+
) -> None:
58+
"""
59+
Build the object from the prediction API JSON.
60+
61+
:param api_prediction: Raw prediction from HTTP response
62+
:param page_n: Page number
63+
"""
64+
self.document_side = TextField(
65+
api_prediction.get("document_side", {}),
66+
page_n=page_n,
67+
)
68+
self.id_number = TextField(
69+
api_prediction["id_number"],
70+
page_n=page_n,
71+
)
72+
self.given_names = [
73+
TextField(prediction, page_n=page_n)
74+
for prediction in api_prediction["given_names"]
75+
]
76+
self.surname = TextField(
77+
api_prediction["surname"],
78+
page_n=page_n,
79+
)
80+
self.birth_date = DateField(
81+
api_prediction["birth_date"],
82+
page_n=page_n,
83+
)
84+
self.birth_place = TextField(
85+
api_prediction["birth_place"],
86+
page_n=page_n,
87+
)
88+
self.expiry_date = DateField(
89+
api_prediction["expiry_date"],
90+
page_n=page_n,
91+
)
92+
self.authority = TextField(
93+
api_prediction["authority"],
94+
page_n=page_n,
95+
)
96+
self.gender = TextField(
97+
api_prediction["gender"],
98+
page_n=page_n,
99+
)
100+
self.mrz1 = TextField(
101+
api_prediction["mrz1"],
102+
page_n=page_n,
103+
)
104+
self.mrz2 = TextField(
105+
api_prediction["mrz2"],
106+
page_n=page_n,
107+
)
108+
109+
def __str__(self) -> str:
110+
given_names = "\n".join([str(item) for item in self.given_names])
111+
return clean_out_string(
112+
"----- FR Carte Nationale d'Identité V1 -----\n"
113+
f"Filename: {self.filename or ''}\n"
114+
f"Document Side: { self.document_side }\n"
115+
f"Identity Number: { self.id_number }\n"
116+
f"Given Name(s): { given_names }\n"
117+
f"Surname: { self.surname }\n"
118+
f"Date of Birth: { self.birth_date }\n"
119+
f"Place of Birth: { self.birth_place }\n"
120+
f"Expiry Date: { self.expiry_date }\n"
121+
f"Issuing Authority: { self.authority }\n"
122+
f"Gender: { self.gender }\n"
123+
f"MRZ Line 1: { self.mrz1 }\n"
124+
f"MRZ Line 2: { self.mrz2 }\n"
125+
"----------------------"
126+
)
127+
128+
129+
TypeIdCardV1 = TypeVar("TypeIdCardV1", bound=IdCardV1)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import json
2+
3+
import pytest
4+
5+
from mindee.documents.fr.carte_vitale.carte_vitale_v1 import CarteVitaleV1
6+
7+
FR_CARTE_VITALE_DATA_DIR = "./tests/data/fr/carte_vitale"
8+
9+
FILE_PATH_FR_CARTE_VITALE_V1_COMPLETE = (
10+
f"{ FR_CARTE_VITALE_DATA_DIR }/response_v1/complete.json"
11+
)
12+
FILE_PATH_FR_CARTE_VITALE_V1_EMPTY = (
13+
f"{ FR_CARTE_VITALE_DATA_DIR }/response_v1/empty.json"
14+
)
15+
16+
17+
@pytest.fixture
18+
def carte_vitale_v1_doc() -> CarteVitaleV1:
19+
json_data = json.load(open(FILE_PATH_FR_CARTE_VITALE_V1_COMPLETE))
20+
return CarteVitaleV1(json_data["document"]["inference"], page_n=None)
21+
22+
23+
@pytest.fixture
24+
def carte_vitale_v1_doc_empty() -> CarteVitaleV1:
25+
json_data = json.load(open(FILE_PATH_FR_CARTE_VITALE_V1_EMPTY))
26+
return CarteVitaleV1(json_data["document"]["inference"], page_n=None)
27+
28+
29+
@pytest.fixture
30+
def carte_vitale_v1_page0():
31+
json_data = json.load(open(FILE_PATH_FR_CARTE_VITALE_V1_COMPLETE))
32+
return CarteVitaleV1(json_data["document"]["inference"]["pages"][0], page_n=0)
33+
34+
35+
def test_doc_constructor(carte_vitale_v1_doc):
36+
reference_str = (
37+
open(f"{ FR_CARTE_VITALE_DATA_DIR }/response_v1/doc_to_string.txt")
38+
.read()
39+
.strip()
40+
)
41+
assert str(carte_vitale_v1_doc) == reference_str
42+
43+
44+
def test_page0_constructor(carte_vitale_v1_page0):
45+
reference_str = (
46+
open(f"{ FR_CARTE_VITALE_DATA_DIR }/response_v1/page0_to_string.txt")
47+
.read()
48+
.strip()
49+
)
50+
assert str(carte_vitale_v1_page0) == reference_str
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import json
2+
3+
import pytest
4+
5+
from mindee.documents.fr.id_card.id_card_v1 import IdCardV1
6+
7+
FR_ID_CARD_DATA_DIR = "./tests/data/fr/id_card"
8+
9+
FILE_PATH_FR_ID_CARD_V1_COMPLETE = f"{ FR_ID_CARD_DATA_DIR }/response_v1/complete.json"
10+
FILE_PATH_FR_ID_CARD_V1_EMPTY = f"{ FR_ID_CARD_DATA_DIR }/response_v1/empty.json"
11+
12+
13+
@pytest.fixture
14+
def id_card_v1_doc() -> IdCardV1:
15+
json_data = json.load(open(FILE_PATH_FR_ID_CARD_V1_COMPLETE))
16+
return IdCardV1(json_data["document"]["inference"], page_n=None)
17+
18+
19+
@pytest.fixture
20+
def id_card_v1_doc_empty() -> IdCardV1:
21+
json_data = json.load(open(FILE_PATH_FR_ID_CARD_V1_EMPTY))
22+
return IdCardV1(json_data["document"]["inference"], page_n=None)
23+
24+
25+
@pytest.fixture
26+
def id_card_v1_page0():
27+
json_data = json.load(open(FILE_PATH_FR_ID_CARD_V1_COMPLETE))
28+
return IdCardV1(json_data["document"]["inference"]["pages"][0], page_n=0)
29+
30+
31+
def test_doc_constructor(id_card_v1_doc):
32+
reference_str = (
33+
open(f"{ FR_ID_CARD_DATA_DIR }/response_v1/doc_to_string.txt").read().strip()
34+
)
35+
assert str(id_card_v1_doc) == reference_str
36+
37+
38+
def test_page0_constructor(id_card_v1_page0):
39+
reference_str = (
40+
open(f"{ FR_ID_CARD_DATA_DIR }/response_v1/page0_to_string.txt").read().strip()
41+
)
42+
assert str(id_card_v1_page0) == reference_str

0 commit comments

Comments
 (0)