Skip to content

Commit 9b731ac

Browse files
authored
✨ add support for FR petrol receipts (#166)
1 parent 1664554 commit 9b731ac

File tree

12 files changed

+265
-2
lines changed

12 files changed

+265
-2
lines changed

.github/workflows/test-code-samples.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ on:
1010

1111
jobs:
1212
test:
13-
name: Run Tests
13+
name: Run Code Samples
1414
timeout-minutes: 30
1515
strategy:
16+
max-parallel: 2
1617
matrix:
1718
python-version:
1819
- "3.7"

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ jobs:
1111
name: Run Tests
1212
timeout-minutes: 30
1313
strategy:
14+
max-parallel: 4
1415
matrix:
1516
os:
1617
- "ubuntu-latest"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from mindee import Client
2+
from mindee.documents.fr import TypePetrolReceiptV1
3+
4+
# Init a new client
5+
mindee_client = Client(api_key="my-api-key")
6+
7+
# Load a file from disk
8+
input_doc = mindee_client.doc_from_path("/path/to/the/file.ext")
9+
10+
# Parse the Petrol Receipt by passing the appropriate type
11+
result = input_doc.parse(TypePetrolReceiptV1)
12+
13+
# Print a brief summary of the parsed data
14+
print(result.document)

mindee/cli.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ class CommandConfig(Generic[TypeDoc]):
7979
help="FR Bank Account Details",
8080
doc_class=documents.fr.TypeBankAccountDetailsV1,
8181
),
82+
"fr-petrol-receipt": CommandConfig(
83+
help="FR Petrol Receipt",
84+
doc_class=documents.fr.TypePetrolReceiptV1,
85+
),
8286
"multi-receipts-detector": CommandConfig(
8387
help="Multi Receipts Detector",
8488
doc_class=documents.TypeMultiReceiptsDetectorV1,

mindee/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,11 @@ def _init_default_endpoints(self) -> None:
459459
url_name="bank_account_details",
460460
version="2",
461461
),
462+
ConfigSpec(
463+
doc_class=documents.fr.PetrolReceiptV1,
464+
url_name="petrol_receipts",
465+
version="1",
466+
),
462467
ConfigSpec(
463468
doc_class=documents.eu.LicensePlateV1,
464469
url_name="license_plates",

mindee/documents/fr/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
from .carte_vitale.carte_vitale_v1 import CarteVitaleV1, TypeCarteVitaleV1
1111
from .id_card.id_card_v1 import IdCardV1, TypeIdCardV1
1212
from .id_card.id_card_v2 import IdCardV2, TypeIdCardV2
13+
from .petrol_receipt.petrol_receipt_v1 import PetrolReceiptV1, TypePetrolReceiptV1

mindee/documents/fr/petrol_receipt/__init__.py

Whitespace-only changes.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from typing import Optional, TypeVar
2+
3+
from mindee.documents.base import Document, TypeApiPrediction, clean_out_string
4+
from mindee.fields.amount import AmountField
5+
6+
from .petrol_receipt_v1_fuel import PetrolReceiptV1Fuel
7+
from .petrol_receipt_v1_total import PetrolReceiptV1Total
8+
9+
10+
class PetrolReceiptV1(Document):
11+
"""Petrol Receipt v1 prediction results."""
12+
13+
fuel: PetrolReceiptV1Fuel
14+
"""The fuel type."""
15+
price: AmountField
16+
"""The price per unit of fuel."""
17+
total: PetrolReceiptV1Total
18+
"""The total amount paid."""
19+
volume: AmountField
20+
"""The volume of fuel purchased."""
21+
22+
def __init__(
23+
self,
24+
api_prediction=None,
25+
input_source=None,
26+
page_n: Optional[int] = None,
27+
):
28+
"""
29+
Petrol Receipt v1 prediction results.
30+
31+
:param api_prediction: Raw prediction from HTTP response
32+
:param input_source: Input object
33+
:param page_n: Page number for multi pages pdf input
34+
"""
35+
super().__init__(
36+
input_source=input_source,
37+
document_type="petrol_receipt",
38+
api_prediction=api_prediction,
39+
page_n=page_n,
40+
)
41+
self._build_from_api_prediction(api_prediction["prediction"], page_n=page_n)
42+
43+
def _build_from_api_prediction(
44+
self, api_prediction: TypeApiPrediction, page_n: Optional[int] = None
45+
) -> None:
46+
"""
47+
Build the object from the prediction API JSON.
48+
49+
:param api_prediction: Raw prediction from HTTP response
50+
:param page_n: Page number
51+
"""
52+
self.fuel = PetrolReceiptV1Fuel(
53+
api_prediction["fuel"],
54+
page_id=page_n,
55+
)
56+
self.price = AmountField(
57+
api_prediction["price"],
58+
page_id=page_n,
59+
)
60+
self.total = PetrolReceiptV1Total(
61+
api_prediction["total"],
62+
page_id=page_n,
63+
)
64+
self.volume = AmountField(
65+
api_prediction["volume"],
66+
page_id=page_n,
67+
)
68+
69+
def __str__(self) -> str:
70+
return clean_out_string(
71+
"FR Petrol Receipt V1 Prediction\n"
72+
"===============================\n"
73+
f":Filename: {self.filename or ''}\n"
74+
f":Fuel Type:\n{self.fuel.to_field_list()}\n"
75+
f":Price per Unit: {self.price}\n"
76+
f":Volume: {self.volume}\n"
77+
f":Total Amount:\n{self.total.to_field_list()}\n"
78+
)
79+
80+
81+
TypePetrolReceiptV1 = TypeVar(
82+
"TypePetrolReceiptV1",
83+
bound=PetrolReceiptV1,
84+
)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from typing import Dict, Optional
2+
3+
from mindee.fields.base import FieldConfidenceMixin, FieldPositionMixin, TypePrediction
4+
5+
6+
class PetrolReceiptV1Fuel(FieldPositionMixin, FieldConfidenceMixin):
7+
"""The fuel type."""
8+
9+
category: Optional[str]
10+
"""The fuel category among a list of 4 possible choices."""
11+
raw_text: Optional[str]
12+
"""As seen on the receipt."""
13+
page_n: int
14+
"""The document page on which the information was found."""
15+
16+
def __init__(
17+
self,
18+
prediction: TypePrediction,
19+
page_id: Optional[int] = None,
20+
):
21+
self._set_confidence(prediction)
22+
self._set_position(prediction)
23+
24+
if page_id is None:
25+
try:
26+
self.page_n = prediction["page_id"]
27+
except KeyError:
28+
pass
29+
else:
30+
self.page_n = page_id
31+
32+
self.category = prediction["category"]
33+
self.raw_text = prediction["raw_text"]
34+
35+
def _printable_values(self) -> Dict[str, str]:
36+
"""Return values for printing."""
37+
return {
38+
"category": self.category if self.category is not None else "",
39+
"raw_text": self.raw_text if self.raw_text is not None else "",
40+
}
41+
42+
def to_field_list(self) -> str:
43+
"""Output the object in a format suitable for inclusion in an rST field list."""
44+
printable = self._printable_values()
45+
return (
46+
f" :Category: {printable['category']}\n"
47+
f" :Raw Name: {printable['raw_text']}"
48+
)
49+
50+
def __str__(self) -> str:
51+
"""Default string representation."""
52+
printable = self._printable_values()
53+
return (
54+
f"Category: {printable['category']}, "
55+
f"Raw Name: {printable['raw_text']}, "
56+
).strip()
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from typing import Dict, Optional
2+
3+
from mindee.fields.base import (
4+
FieldConfidenceMixin,
5+
FieldPositionMixin,
6+
TypePrediction,
7+
float_to_string,
8+
to_opt_float,
9+
)
10+
11+
12+
class PetrolReceiptV1Total(FieldPositionMixin, FieldConfidenceMixin):
13+
"""The total amount paid."""
14+
15+
amount: Optional[float]
16+
"""The amount."""
17+
page_n: int
18+
"""The document page on which the information was found."""
19+
20+
def __init__(
21+
self,
22+
prediction: TypePrediction,
23+
page_id: Optional[int] = None,
24+
):
25+
self._set_confidence(prediction)
26+
self._set_position(prediction)
27+
28+
if page_id is None:
29+
try:
30+
self.page_n = prediction["page_id"]
31+
except KeyError:
32+
pass
33+
else:
34+
self.page_n = page_id
35+
36+
self.amount = to_opt_float(prediction, "amount")
37+
38+
def _printable_values(self) -> Dict[str, str]:
39+
"""Return values for printing."""
40+
return {
41+
"amount": float_to_string(self.amount),
42+
}
43+
44+
def to_field_list(self) -> str:
45+
"""Output the object in a format suitable for inclusion in an rST field list."""
46+
printable = self._printable_values()
47+
return f" :Amount Paid: {printable['amount']}"
48+
49+
def __str__(self) -> str:
50+
"""Default string representation."""
51+
printable = self._printable_values()
52+
return (f"Amount Paid: {printable['amount']}, ").strip()

0 commit comments

Comments
 (0)