From 52a85da84c2e1ec92e9e6b4a1646ce45039a99ed Mon Sep 17 00:00:00 2001 From: dcleres Date: Wed, 30 Oct 2024 09:56:26 +0100 Subject: [PATCH 01/12] Close #LGVISIUM-89: Clarified the clipping behavior --- example/clipping_test-1.png | Bin 0 -> 98729 bytes example/clipping_test.pdf | Bin 0 -> 38716 bytes src/app/common/schemas.py | 6 +- tests/test_data_extraction_from_bbox.py | 160 ++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 example/clipping_test-1.png create mode 100644 example/clipping_test.pdf diff --git a/example/clipping_test-1.png b/example/clipping_test-1.png new file mode 100644 index 0000000000000000000000000000000000000000..c8bc709c2ce5061cc360bb94f6634f450974ead8 GIT binary patch literal 98729 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%0DwJ*J3u6R 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 D7j9nU literal 0 HcmV?d00001 diff --git a/example/clipping_test.pdf b/example/clipping_test.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2b6a8f212f3890cbd1b4c76fe114031d2bd846d5 GIT binary patch literal 38716 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 literal 0 HcmV?d00001 diff --git a/src/app/common/schemas.py b/src/app/common/schemas.py index 6467882d..2ecbdeeb 100644 --- a/src/app/common/schemas.py +++ b/src/app/common/schemas.py @@ -141,7 +141,11 @@ class ExtractDataRequest(ABC, BaseModel): filename: Path = Field(..., example=Path("document.png")) page_number: int = Field(..., example=1) # 1-based index - bbox: BoundingBox = Field(..., example={"x0": 0.0, "y0": 0.0, "x1": 100.0, "y1": 100.0}) + bbox: BoundingBox = Field( + ..., + description="Bounding box in pixels for the PNG image, not for PDF coordinates.", + example={"x0": 0.0, "y0": 0.0, "x1": 100.0, "y1": 100.0}, + ) format: FormatTypes = Field(..., example=FormatTypes.COORDINATES.value) @field_validator("filename", mode="before") diff --git a/tests/test_data_extraction_from_bbox.py b/tests/test_data_extraction_from_bbox.py index f387552f..1deef7be 100644 --- a/tests/test_data_extraction_from_bbox.py +++ b/tests/test_data_extraction_from_bbox.py @@ -20,11 +20,17 @@ TEST_PDF_PATH = Path(__file__).parent.parent / "example" / "example_borehole_profile.pdf" TEST_PNG_KEY = Path("dataextraction/sample-1.png") TEST_PNG_PATH = Path(__file__).parent.parent / "example" / "sample-1.png" + TEST_ROTATED_PNG_KEY = Path("dataextraction/16132-1.png") TEST_ROTATED_PNG_PATH = Path(__file__).parent.parent / "example" / "16132-1.png" TEST_ROTATED_PDF_KEY = Path("16132.pdf") TEST_ROTATED_PDF_PATH = Path(__file__).parent.parent / "example" / "16132.pdf" # Rotated PDF of 270 degrees +TEST_CLIPPING_BEHAVIOR_PDF_PATH = Path(__file__).parent.parent / "example" / "clipping_test.pdf" +TEST_CLIPPING_BEHAVIOR_PDF_KEY = Path("clipping_test.pdf") +TEST_CLIPPING_BEHAVIOR_PNG_PATH = Path(__file__).parent.parent / "example" / "clipping_test-1.png" +TEST_CLIPPING_BEHAVIOR_PNG_KEY = Path("dataextraction/clipping_test-1.png") + def get_default_small_coordinate_request(): """Return a default ExtractDataRequest for coordinates.""" @@ -63,6 +69,11 @@ def upload_test_pdf(s3_client): s3_client.upload_file( Filename=str(TEST_ROTATED_PDF_PATH), Bucket=config.test_bucket_name, Key=str(TEST_ROTATED_PDF_KEY) ) + s3_client.upload_file( + Filename=str(TEST_CLIPPING_BEHAVIOR_PDF_PATH), + Bucket=config.test_bucket_name, + Key=str(TEST_CLIPPING_BEHAVIOR_PDF_KEY), + ) @pytest.fixture(scope="function") @@ -72,6 +83,11 @@ def upload_test_png(s3_client, upload_test_pdf): s3_client.upload_file( Filename=str(TEST_ROTATED_PNG_PATH), Bucket=config.test_bucket_name, Key=str(TEST_ROTATED_PNG_KEY) ) + s3_client.upload_file( + Filename=str(TEST_CLIPPING_BEHAVIOR_PNG_PATH), + Bucket=config.test_bucket_name, + Key=str(TEST_CLIPPING_BEHAVIOR_PNG_KEY), + ) def test_load_pdf_from_aws(upload_test_pdf): @@ -130,6 +146,111 @@ def test_extract_text_success(test_client: TestClient, upload_test_pdf, upload_t assert json_response["text"] == target_text +def test_clipping_behavior(test_client: TestClient, upload_test_pdf, upload_test_png): + """Test the extract_data endpoint with a valid request.""" + #################################################################################################### + ### Extract Data on Normal PDF with bounding box with all text inside + #################################################################################################### + target_text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut" + + request = ExtractDataRequest( + filename=TEST_CLIPPING_BEHAVIOR_PDF_KEY.name, + page_number=1, + bbox={"x0": 311, "y0": 269, "x1": 821, "y1": 704}, # pixels + format=FormatTypes.TEXT, + ) + response = test_client.post("/api/V1/extract_data", content=request.model_dump_json()) + assert response.status_code == 200 + json_response = response.json() + assert "bbox" in json_response + assert json_response["text"] == target_text + + #################################################################################################### + ### Extract Data on Normal PDF with bounding box with text on the boundary (e.g., the bounding box line is on the + ### text) + #################################################################################################### + target_text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut" + + request = ExtractDataRequest( + filename=TEST_CLIPPING_BEHAVIOR_PDF_KEY.name, + page_number=1, + bbox={"x0": 311, "y0": 299, "x1": 813, "y1": 704}, # pixels + format=FormatTypes.TEXT, + ) + response = test_client.post("/api/V1/extract_data", content=request.model_dump_json()) + assert response.status_code == 200 + json_response = response.json() + assert "bbox" in json_response + assert json_response["text"] == target_text + + #################################################################################################### + ### Extract Data on Normal PDF with bounding box with only a few words selected out of the text. + ### Here the text was done with multiple Text Boxes (e.g., each line is a different Text Box). + #################################################################################################### + target_text = "Lorem ipsum" + + request = ExtractDataRequest( + filename=TEST_CLIPPING_BEHAVIOR_PDF_KEY.name, + page_number=1, + bbox={"x0": 311, "y0": 269, "x1": 611, "y1": 336}, # pixels + format=FormatTypes.TEXT, + ) + response = test_client.post("/api/V1/extract_data", content=request.model_dump_json()) + assert response.status_code == 200 + json_response = response.json() + assert "bbox" in json_response + assert json_response["text"] == target_text + + #################################################################################################### + ### Extract Data on Normal PDF with bounding box with only a few words selected out of the text. + ### Here the text was done with one Text Box. + #################################################################################################### + target_text = "Lorem ipsum" + + request = ExtractDataRequest( + filename=TEST_CLIPPING_BEHAVIOR_PDF_KEY.name, + page_number=1, + bbox={"x0": 1848, "y0": 242, "x1": 2145, "y1": 303}, # pixels + format=FormatTypes.TEXT, + ) + response = test_client.post("/api/V1/extract_data", content=request.model_dump_json()) + assert response.status_code == 200 + json_response = response.json() + assert "bbox" in json_response + assert json_response["text"] == target_text + + #################################################################################################### + ### Extract Data on Normal PDF with bounding box with only one part of one word selected out of the text. + #################################################################################################### + target_text = "Lo" + + request = ExtractDataRequest( + filename=TEST_CLIPPING_BEHAVIOR_PDF_KEY.name, + page_number=1, + bbox={"x0": 315, "y0": 281, "x1": 371, "y1": 330}, # pixels + format=FormatTypes.TEXT, + ) + response = test_client.post("/api/V1/extract_data", content=request.model_dump_json()) + assert response.status_code == 200 + json_response = response.json() + assert "bbox" in json_response + assert json_response["text"] == target_text + + target_text = "Lorem" + + request = ExtractDataRequest( + filename=TEST_CLIPPING_BEHAVIOR_PDF_KEY.name, + page_number=1, + bbox={"x0": 315, "y0": 300, "x1": 465, "y1": 330}, # pixels + format=FormatTypes.TEXT, + ) + response = test_client.post("/api/V1/extract_data", content=request.model_dump_json()) + assert response.status_code == 200 + json_response = response.json() + assert "bbox" in json_response + assert json_response["text"] == target_text + + def test_extract_text_empty(test_client: TestClient, upload_test_pdf, upload_test_png): """Test the extract_data endpoint with a valid request.""" request = ExtractDataRequest( @@ -147,6 +268,9 @@ def test_extract_text_empty(test_client: TestClient, upload_test_pdf, upload_tes def test_extract_coordinate_success(test_client: TestClient, upload_test_pdf, upload_test_png): """Test the extract_data endpoint with a valid request.""" + #################################################################################################### + ### Extract Data on Normal PDF with LV03 coordinates + #################################################################################################### request = get_default_coordinate_request() response = test_client.post("/api/V1/extract_data", content=request.model_dump_json()) assert response.status_code == 200 @@ -157,6 +281,42 @@ def test_extract_coordinate_success(test_client: TestClient, upload_test_pdf, up assert json_response["coordinates"]["north"] == 157500 assert json_response["coordinates"]["projection"] == "LV03" + #################################################################################################### + ### Extract Data on Rotated PDF with LV03 coordinates + #################################################################################################### + request = ExtractDataRequest( + filename=TEST_CLIPPING_BEHAVIOR_PDF_KEY.name, + page_number=1, + bbox={"x0": 1625, "y0": 900, "x1": 2819, "y1": 968}, # pixels + format=FormatTypes.COORDINATES, + ) + response = test_client.post("/api/V1/extract_data", content=request.model_dump_json()) + assert response.status_code == 200 + json_response = response.json() + assert "bbox" in json_response + assert "coordinates" in json_response + assert json_response["coordinates"]["east"] == 684592.0 + assert json_response["coordinates"]["north"] == 252857.0 + assert json_response["coordinates"]["projection"] == "LV03" + + #################################################################################################### + ### Extract Data on Rotated PDF with LV95 coordinates + #################################################################################################### + request = ExtractDataRequest( + filename=TEST_CLIPPING_BEHAVIOR_PDF_KEY.name, + page_number=1, + bbox={"x0": 1625, "y0": 1000, "x1": 2819, "y1": 1068}, # pixels + format=FormatTypes.COORDINATES, + ) + response = test_client.post("/api/V1/extract_data", content=request.model_dump_json()) + assert response.status_code == 200 + json_response = response.json() + assert "bbox" in json_response + assert "coordinates" in json_response + assert json_response["coordinates"]["east"] == 2682834.0 + assert json_response["coordinates"]["north"] == 1253400.0 + assert json_response["coordinates"]["projection"] == "LV95" + def test_incomplete_request(test_client: TestClient, upload_test_pdf, upload_test_png): """Test the extract_data endpoint with an incomplete request.""" From d1e1222dc703f15931fc4e94b18bceb53dd0fe85 Mon Sep 17 00:00:00 2001 From: dcleres Date: Thu, 31 Oct 2024 10:10:00 +0100 Subject: [PATCH 02/12] Clarified the behavior of the different API data classes --- src/app/common/schemas.py | 223 +++++++++++++++++++++++++++++++++----- 1 file changed, 197 insertions(+), 26 deletions(-) diff --git a/src/app/common/schemas.py b/src/app/common/schemas.py index 2ecbdeeb..c747630c 100644 --- a/src/app/common/schemas.py +++ b/src/app/common/schemas.py @@ -31,18 +31,35 @@ class PNGRequest(BaseModel): @field_validator("filename", mode="before") @classmethod def validate_filename(cls, value: str) -> str: + """Ensure the filename is not empty.""" return validate_filename(value) class Config: """Make to allow using non-standard types like Path.""" - arbitrary_types_allowed = True # This allows using non-standard types like Path + arbitrary_types_allowed: bool = True # This allows using non-standard types like Path class PNGResponse(BaseModel): - """Response schema for the create_pngs endpoint.""" + """Response schema for the `create_pngs` endpoint, representing the output of PNG file creation and storage. - keys: list[str] # keys in the S3 bucket + This schema lists the keys (identifiers) of the created PNG files stored in an S3 bucket, + enabling users to retrieve or reference them as needed. + """ + + keys: list[str] = Field( + ..., + description=""" + List of unique identifiers (keys) for the generated PNG files stored in the S3 bucket. Each key allows + access to a specific file within the bucket. + """, + example=[ + "dataextraction/file1-1.png", + "dataextraction/file1-2.png", + "dataextraction/file2-1.png", + "dataextraction/file3-1.png", + ], + ) ######################################################################################################################## @@ -59,12 +76,45 @@ class FormatTypes(str, Enum): class BoundingBox(BaseModel): - """Bounding box schema.""" + """Bounding box schema for defining a rectangular area within an image. - x0: float = Field(..., example=0.0) - y0: float = Field(..., example=0.0) - x1: float = Field(..., example=100.0) - y1: float = Field(..., example=100.0) + This schema represents the coordinates of the box’s corners, which can be used + to specify an area of interest in image processing tasks. Coordinates are + defined with the origin at the top-left of the image. + """ + + x0: float = Field( + ..., + description=""" + The x-coordinate of the top-left corner of the bounding box. This value marks the horizontal starting + point of the box. + """, + example=0.0, + ) + y0: float = Field( + ..., + description="""" + The y-coordinate of the top-left corner of the bounding box. This value marks the vertical starting + point of the box. + """, + example=0.0, + ) + x1: float = Field( + ..., + description=""" + The x-coordinate of the bottom-right corner of the bounding box. This value marks the horizontal + endpoint of the box. + """, + example=100.0, + ) + y1: float = Field( + ..., + description=""" + The y-coordinate of the bottom-right corner of the bounding box. This value marks the vertical + endpoint of the box. + """, + example=100.0, + ) @field_validator("x0", "y0", "x1", "y1") @classmethod @@ -125,32 +175,112 @@ def load_from_fitz_rect(rect: fitz.Rect) -> "BoundingBox": class Coordinates(BaseModel): - """Coordinates schema.""" + """Coordinates schema for representing geographical data points. - east: float = Field(..., example=1.0) - north: float = Field(..., example=2.0) - projection: str = Field(..., example="LV95") + This schema defines the format for specifying location data using east/north coordinates + along with the projection system used for georeferencing. + """ + + east: float = Field( + ..., + description=""" + Easting coordinate, representing the horizontal position of the point. The value should be in the + units of the specified projection system. + """, + example=1.0, + ) + north: float = Field( + ..., + description=""" + Northing coordinate, representing the vertical position of the point. The value should be in the + units of the specified projection system. + """, + example=2.0, + ) + projection: str = Field( + ..., + description=""" + Projection system used to reference the coordinates. This defines the coordinate reference system, + such as 'LV95' for Swiss coordinate systems. + """, + example="LV95", + ) class ExtractDataRequest(ABC, BaseModel): - """Request schema for the extract_data endpoint. + """Request schema for the `extract_data` endpoint. + + **Coordinate Systems:** + - **PNG coordinates:** Pixels are measured from the top-left corner (0, 0), where x increases rightward + and y downward. + - **PDF coordinates:** Also measured from the top-left corner (0, 0), though any transformations between + PDF and PNG coordinates are managed internally by the `BoundingBox.rescale` method. + + ### Fields + Each field below includes inline examples to aid users in creating requests. See `json_schema_extra` + for a complete example. + + **Attributes:** + - **filename** (`Path`): Path to the file (PNG or PDF). _Example_: `"document.png"` + - **page_number** (`int`): Target page for data extraction. This is a 1-based index. _Example_: `1` + - **bbox** (`BoundingBox`): Bounding box for the extraction area, in PNG coordinates. Origin is the + top-left, with x increasing rightward and y increasing downward. + - Example format: `{"x0": 0.0, "y0": 0.0, "x1": 100.0, "y1": 100.0}` + - **format** (`FormatTypes`): Specifies the expected format for extracted data, e.g., `"coordinates"`. + + ### Validation + Custom validators ensure data integrity: + - **Filename Validator:** Ensures filename is not empty. + - **Page Number Validator:** Confirms page number is positive. + - **Format Validator:** Checks format is valid as per `FormatTypes`. + + + The bounding box should be provided in PNG coordinates. Any necessary coordinate transformations between PNG + and PDF are handled internally using the BoundingBox.rescale method. Each field in the Pydantic model can have an example parameter, which provides an inline example for that specific field. """ - filename: Path = Field(..., example=Path("document.png")) - page_number: int = Field(..., example=1) # 1-based index + filename: Path = Field( + ..., + description=""" + Path to the input document file (PNG or PDF) that contains the data to be extracted. This should be + a valid file path, and the file should be accessible to the API. + """, + example=Path("document.png"), + ) + page_number: int = Field( + ..., + description=""" + Page number within the document where the extraction is to be performed. This is a 1-based + index (e.g., 1 for the first page), applicable for multi-page files like PDFs. + """, + example=1, + ) bbox: BoundingBox = Field( ..., - description="Bounding box in pixels for the PNG image, not for PDF coordinates.", + description=""" + Bounding box defining the area for data extraction within the PNG image. The box is specified in + pixels with the top-left as the origin (0,0), where x increases to the right and y increases + downward. This box should be provided in PNG coordinates, and any transformations to PDF + coordinates are managed internally. + """, example={"x0": 0.0, "y0": 0.0, "x1": 100.0, "y1": 100.0}, ) - format: FormatTypes = Field(..., example=FormatTypes.COORDINATES.value) + format: FormatTypes = Field( + ..., + description=""" + Specifies the desired format for extracted data, allowing for options like `coordinates` or other + defined `FormatTypes` values. This dictates the structure of the output returned by the API. + """, + example=FormatTypes.COORDINATES.value, + ) @field_validator("filename", mode="before") @classmethod def validate_filename(cls, value: str) -> str: + """Ensure the filename is not empty.""" return validate_filename(value) @field_validator("page_number") @@ -187,20 +317,41 @@ class Config: class ExtractDataResponse(ABC, BaseModel): - """Response schema for the extract_data endpoint.""" + """Base response schema for the `extract_data` endpoint, representing the extracted data's bounding box. + + This abstract base class provides a bounding box field for data localization and an abstract property + `response_type` to be implemented by subclasses, indicating the type of extracted content. + """ - bbox: BoundingBox = Field(..., example={"x0": 0.0, "y0": 0.0, "x1": 100.0, "y1": 100.0}) + bbox: BoundingBox = Field( + ..., + description=""" + Bounding box coordinates that define the area within the document where data was extracted. The box + is specified in PNG coordinates, with the origin at the top-left corner (0,0).$ + """, + example={"x0": 0.0, "y0": 0.0, "x1": 100.0, "y1": 100.0}, + ) @property @abstractmethod def response_type(self): - """Abstract property to be implemented by subclasses to define response type.""" + """Abstract property to be implemented by subclasses to define the type of response content.""" class ExtractCoordinatesResponse(ExtractDataResponse): - """Response schema for the extract_data endpoint.""" + """Response schema for the `extract_data` endpoint when returning geographic coordinates. - coordinates: Coordinates = Field(..., example={"east": 1.0, "north": 2.0, "page": 1, "projection": "LV95"}) + This schema includes a `coordinates` field with east/north values and projection information. + """ + + coordinates: Coordinates = Field( + ..., + description=""" + Geographical coordinates extracted from the document, including east, north values, page number, + and projection type. + """, + example={"east": 1.0, "north": 2.0, "page": 1, "projection": "LV95"}, + ) @property def response_type(self): @@ -208,9 +359,18 @@ def response_type(self): class ExtractTextResponse(ExtractDataResponse): - """Response schema for the extract_data endpoint.""" + """Response schema for the `extract_data` endpoint when returning extracted text content. - text: str = Field(..., example="text") + This schema includes a `text` field with the extracted textual content from the specified bounding box. + """ + + text: str = Field( + ..., + description=""" + Text content extracted from the specified bounding box within the document. + """, + example="text", + ) @property def response_type(self): @@ -218,9 +378,20 @@ def response_type(self): class ExtractNumberResponse(ExtractDataResponse): - """Response schema for the extract_data endpoint.""" + """Response schema for the `extract_data` endpoint when returning numerical data. + + This schema includes a `number` field for extracted numeric content, such as measurements or other + quantitative data. + """ - number: float = Field(..., example=1.0) + number: float = Field( + ..., + description=""" + Numeric value extracted from the specified bounding box within the document, representing a + measurement or quantitative data. + """, + example=1.0, + ) @property def response_type(self): From 84887f7e942ea958bee4a90a39cacfadd9342405 Mon Sep 17 00:00:00 2001 From: dcleres Date: Thu, 31 Oct 2024 10:21:00 +0100 Subject: [PATCH 03/12] Updated the route description in the openAPI --- src/app/api/v1/router.py | 49 ++++++++++++++++++++++++++++++++++++++-- src/app/main.py | 27 ++++++++++++++++++++-- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/app/api/v1/router.py b/src/app/api/v1/router.py index 090a44f4..cdaa2971 100644 --- a/src/app/api/v1/router.py +++ b/src/app/api/v1/router.py @@ -38,7 +38,30 @@ class BadRequestResponse(BaseModel): }, ) def post_create_pngs(request: PNGRequest) -> PNGResponse: - """Create PNGs from the given data.""" + """Create PNG images from a PDF stored in the S3 bucket. + + This endpoint generates PNG images from each page of a specified PDF document stored in the AWS S3 bucket. + The PDF file must be accessible in the bucket with a valid filename provided in the request. + + ### Request Body + - **request** (`PNGRequest`): Contains the `filename` of the PDF document in the S3 bucket from which PNGs + should be generated. + + ### Returns + - **PNGResponse**: Response containing a list of keys (filenames) for the generated PNG images stored in the + S3 bucket. + + ### Status Codes + - **200 OK**: PNG images were successfully created and stored in the S3 bucket. + - **400 Bad Request**: The request format or content is invalid. Verify that `filename` is correctly specified. + - **404 Not Found**: The specified PDF file could not be found in the S3 bucket. + - **500 Internal Server Error**: An error occurred on the server while creating PNGs. + + ### Additional Information + - The endpoint connects to AWS S3 to retrieve the specified PDF, converts its pages to PNGs, and stores + the generated images back in S3. Ensure the PDF file exists in the S3 bucket and is accessible before + making a request. + """ return create_pngs(request.filename) @@ -58,7 +81,29 @@ def post_create_pngs(request: PNGRequest) -> PNGResponse: def post_extract_data( extract_data_request: ExtractDataRequest, ) -> ExtractCoordinatesResponse | ExtractTextResponse | ExtractNumberResponse: - """Extract data from the given PNGs.""" + """Extract specified data from a given document based on the bounding box coordinates and format. + + ### Request Body + - **extract_data_request**: Instance of `ExtractDataRequest`, containing file details, page number, bounding + box, and data format. The bounding box in PNG coordinates helps locate the region to extract data from. + + ### Returns + The endpoint responds with one of the following response models based on the extracted data: + - **ExtractCoordinatesResponse**: If geographic coordinates are extracted. + - **ExtractTextResponse**: If text content is extracted. + - **ExtractNumberResponse**: If numerical data is extracted. + + ### Status Codes + - **200 OK**: Successful extraction, returning the specified data type. + - **400 Bad Request**: Input request was invalid, typically due to misformatted or missing parameters. + - **404 Not Found**: Requested data could not be found within the specified bounding box or page. + - **500 Internal Server Error**: An error occurred on the server side during data extraction. + + ### Error Handling + Known `ValueError`s (e.g., invalid input data) result in a `400 Bad Request` response with a relevant error + message. + For other errors, the endpoint returns a `500 Internal Server Error`. + """ try: # Extract the data based on the request response = extract_data(extract_data_request) diff --git a/src/app/main.py b/src/app/main.py index 8b184b59..5da7dde0 100644 --- a/src/app/main.py +++ b/src/app/main.py @@ -76,7 +76,18 @@ async def validation_exception_handler(request: Request, exc: RequestValidationE #################################################################################################### @app.get("/health", tags=["health"]) def get_health(): - """Check the health of the application.""" + """Check the health of the application. + + This endpoint provides a simple health check to verify that the application is up and running. + It can be used for monitoring purposes to ensure the API is responsive. + + ### Returns + - **200 OK**: The application is running and responsive. + - **Response Body**: Returns a plain text message indicating the health status, typically `"Healthy"`. + + ### Usage + Use this endpoint as a basic check in monitoring or load balancer setups to assess application uptime. + """ return "Healthy" @@ -85,7 +96,19 @@ def get_health(): #################################################################################################### @app.get("/version") def get_version(): - """Return the version of the application.""" + """Return the current version of the application. + + This endpoint provides the current application version as specified in the environment variables. + Useful for tracking deployed versions in staging or production environments. + + ### Returns + - **200 OK**: The version information was successfully retrieved. + - **Response Body**: JSON object with the application version, e.g., `{"version": "1.0.0"}`. + + ### Notes + Ensure the `APP_VERSION` environment variable is set; otherwise, the response may contain `null` or an + empty version value. + """ return {"version": os.getenv("APP_VERSION")} From dc56bb68a66e94c582bfe951d1db82ddf91ec1ad Mon Sep 17 00:00:00 2001 From: dcleres Date: Thu, 31 Oct 2024 10:22:05 +0100 Subject: [PATCH 04/12] Fixed typo --- src/app/common/schemas.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/common/schemas.py b/src/app/common/schemas.py index c747630c..ff071c52 100644 --- a/src/app/common/schemas.py +++ b/src/app/common/schemas.py @@ -178,7 +178,7 @@ class Coordinates(BaseModel): """Coordinates schema for representing geographical data points. This schema defines the format for specifying location data using east/north coordinates - along with the projection system used for georeferencing. + along with the projection system used for geo-referencing. """ east: float = Field( @@ -327,7 +327,7 @@ class ExtractDataResponse(ABC, BaseModel): ..., description=""" Bounding box coordinates that define the area within the document where data was extracted. The box - is specified in PNG coordinates, with the origin at the top-left corner (0,0).$ + is specified in PNG coordinates, with the origin at the top-left corner (0,0). """, example={"x0": 0.0, "y0": 0.0, "x1": 100.0, "y1": 100.0}, ) From 139e41ddf8d09a3b2873407c7e7de98fda5c2dd1 Mon Sep 17 00:00:00 2001 From: dcleres Date: Thu, 31 Oct 2024 10:25:44 +0100 Subject: [PATCH 05/12] Fixed typo --- src/app/common/schemas.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/common/schemas.py b/src/app/common/schemas.py index ff071c52..93c19047 100644 --- a/src/app/common/schemas.py +++ b/src/app/common/schemas.py @@ -120,8 +120,8 @@ class BoundingBox(BaseModel): @classmethod def page_number_must_be_positive(cls, v: int) -> int: """Validate that the page number is positive.""" - if v < 0.0: - raise ValueError("Bounding box coordinate must be a positive integer") + if v < 1.0: + raise ValueError("The page number must be a positive number.") return v def rescale( From 9b2931eb4fa8a7c44cfb8176a96309075d0fab69 Mon Sep 17 00:00:00 2001 From: dcleres Date: Thu, 31 Oct 2024 10:49:34 +0100 Subject: [PATCH 06/12] Fixed validation error with the schema --- src/app/api/v1/router.py | 2 +- src/app/common/schemas.py | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/app/api/v1/router.py b/src/app/api/v1/router.py index cdaa2971..c5ce8fe8 100644 --- a/src/app/api/v1/router.py +++ b/src/app/api/v1/router.py @@ -54,7 +54,7 @@ def post_create_pngs(request: PNGRequest) -> PNGResponse: ### Status Codes - **200 OK**: PNG images were successfully created and stored in the S3 bucket. - **400 Bad Request**: The request format or content is invalid. Verify that `filename` is correctly specified. - - **404 Not Found**: The specified PDF file could not be found in the S3 bucket. + - **404 Not Found**: PDF file not found in S3 bucket. - **500 Internal Server Error**: An error occurred on the server while creating PNGs. ### Additional Information diff --git a/src/app/common/schemas.py b/src/app/common/schemas.py index 93c19047..b8219c99 100644 --- a/src/app/common/schemas.py +++ b/src/app/common/schemas.py @@ -17,7 +17,17 @@ def validate_filename(value: str) -> str: - """Ensure the filename is not empty.""" + """Ensure the filename is not empty. + + Args: + value (str): The filename to validate. + + Returns: + str: The validated filename. + + Raises: + ValueError: If the filename is empty + """ if value == "": raise ValueError("Filename must not be empty.") return value @@ -118,10 +128,10 @@ class BoundingBox(BaseModel): @field_validator("x0", "y0", "x1", "y1") @classmethod - def page_number_must_be_positive(cls, v: int) -> int: - """Validate that the page number is positive.""" - if v < 1.0: - raise ValueError("The page number must be a positive number.") + def bbox_corners_must_be_positive(cls, v: int) -> int: + """Validate that the edges of the bounding box are positive.""" + if v < 0.0: + raise ValueError("Bounding box coordinates must be positive") return v def rescale( From e3387ecfad51b4da3031c5545a931a4db04be00c Mon Sep 17 00:00:00 2001 From: dcleres Date: Thu, 31 Oct 2024 10:54:22 +0100 Subject: [PATCH 07/12] Adapted clipping details to router description --- src/app/api/v1/router.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/app/api/v1/router.py b/src/app/api/v1/router.py index c5ce8fe8..5fe10089 100644 --- a/src/app/api/v1/router.py +++ b/src/app/api/v1/router.py @@ -83,6 +83,11 @@ def post_extract_data( ) -> ExtractCoordinatesResponse | ExtractTextResponse | ExtractNumberResponse: """Extract specified data from a given document based on the bounding box coordinates and format. + Behavior of the data extraction from the specified bounding box is the following: extraction on a per-letter + basis, which means that as soon as the specified bounding box overlaps (partially or fully) with a letter + or number, then this character is added to the extracted text. This behavior is consistent with the + clipping behavior of the `PyMuPDF` library. + ### Request Body - **extract_data_request**: Instance of `ExtractDataRequest`, containing file details, page number, bounding box, and data format. The bounding box in PNG coordinates helps locate the region to extract data from. From 89aa0e6595f46f7c04b95fc64fbe6e056454f1c2 Mon Sep 17 00:00:00 2001 From: dcleres Date: Thu, 31 Oct 2024 11:00:43 +0100 Subject: [PATCH 08/12] Fixed test --- tests/test_data_extraction_from_bbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_data_extraction_from_bbox.py b/tests/test_data_extraction_from_bbox.py index 1deef7be..3f391449 100644 --- a/tests/test_data_extraction_from_bbox.py +++ b/tests/test_data_extraction_from_bbox.py @@ -360,7 +360,7 @@ def test_invalid_bbox(test_client: TestClient, upload_test_pdf, upload_test_png) request_json["bbox"] = {"x0": 0, "y0": 0, "x1": 100, "y1": -100.0} response = test_client.post("/api/V1/extract_data", json=request_json) assert response.status_code == 400 - assert response.json() == {"detail": "Bounding box coordinate must be a positive integer"} + assert response.json() == {"detail": "Bounding box coordinates must be positive"} def test_invalid_pdf(test_client: TestClient, upload_test_pdf, upload_test_png): From 21ae6a774ec091388b06d230715e2990b2d66c3f Mon Sep 17 00:00:00 2001 From: David Cleres Date: Thu, 7 Nov 2024 11:27:10 +0100 Subject: [PATCH 09/12] Addressed PR feedback --- src/app/api/v1/router.py | 3 + src/app/common/schemas.py | 115 +++++++++++++------------------------- 2 files changed, 42 insertions(+), 76 deletions(-) diff --git a/src/app/api/v1/router.py b/src/app/api/v1/router.py index 5fe10089..a77a4495 100644 --- a/src/app/api/v1/router.py +++ b/src/app/api/v1/router.py @@ -88,6 +88,9 @@ def post_extract_data( or number, then this character is added to the extracted text. This behavior is consistent with the clipping behavior of the `PyMuPDF` library. + ### Prerequisites + Ensure that the PDF file has been processed by the create_pngs endpoint first. + ### Request Body - **extract_data_request**: Instance of `ExtractDataRequest`, containing file details, page number, bounding box, and data format. The bounding box in PNG coordinates helps locate the region to extract data from. diff --git a/src/app/common/schemas.py b/src/app/common/schemas.py index b8219c99..74366570 100644 --- a/src/app/common/schemas.py +++ b/src/app/common/schemas.py @@ -59,16 +59,9 @@ class PNGResponse(BaseModel): keys: list[str] = Field( ..., - description=""" - List of unique identifiers (keys) for the generated PNG files stored in the S3 bucket. Each key allows - access to a specific file within the bucket. - """, - example=[ - "dataextraction/file1-1.png", - "dataextraction/file1-2.png", - "dataextraction/file2-1.png", - "dataextraction/file3-1.png", - ], + description="""List of unique identifiers (keys) for the generated PNG files stored in the S3 bucket. Each key + allows access to a specific file within the bucket.""", + example=["dataextraction/file1-1.png", "dataextraction/file1-2.png", "dataextraction/file1-3.png"], ) @@ -90,20 +83,18 @@ class BoundingBox(BaseModel): This schema represents the coordinates of the box’s corners, which can be used to specify an area of interest in image processing tasks. Coordinates are - defined with the origin at the top-left of the image. + defined with the origin at the top-left of the image. Coordinates are in pixels. """ x0: float = Field( ..., - description=""" - The x-coordinate of the top-left corner of the bounding box. This value marks the horizontal starting - point of the box. - """, + description="""The x-coordinate of the top-left corner of the bounding box. This value marks the + horizontal starting point of the box.""", example=0.0, ) y0: float = Field( ..., - description="""" + description=""" The y-coordinate of the top-left corner of the bounding box. This value marks the vertical starting point of the box. """, @@ -111,18 +102,14 @@ class BoundingBox(BaseModel): ) x1: float = Field( ..., - description=""" - The x-coordinate of the bottom-right corner of the bounding box. This value marks the horizontal - endpoint of the box. - """, + description="""The x-coordinate of the bottom-right corner of the bounding box. This value marks the + horizontal endpoint of the box.""", example=100.0, ) y1: float = Field( ..., - description=""" - The y-coordinate of the bottom-right corner of the bounding box. This value marks the vertical - endpoint of the box. - """, + description="""The y-coordinate of the bottom-right corner of the bounding box. This value marks the vertical + endpoint of the box.""", example=100.0, ) @@ -188,31 +175,23 @@ class Coordinates(BaseModel): """Coordinates schema for representing geographical data points. This schema defines the format for specifying location data using east/north coordinates - along with the projection system used for geo-referencing. + along with the projection system used. """ east: float = Field( ..., - description=""" - Easting coordinate, representing the horizontal position of the point. The value should be in the - units of the specified projection system. - """, + description="""Easting coordinate. The value should be in the units of the specified projection system.""", example=1.0, ) north: float = Field( ..., - description=""" - Northing coordinate, representing the vertical position of the point. The value should be in the - units of the specified projection system. - """, + description="""Northing coordinate. The value should be in the units of the specified projection system.""", example=2.0, ) projection: str = Field( ..., - description=""" - Projection system used to reference the coordinates. This defines the coordinate reference system, - such as 'LV95' for Swiss coordinate systems. - """, + description="""Projection system used to reference the coordinates. This defines the coordinate reference + system, such as 'LV95' for Swiss coordinate systems.""", example="LV95", ) @@ -220,18 +199,19 @@ class Coordinates(BaseModel): class ExtractDataRequest(ABC, BaseModel): """Request schema for the `extract_data` endpoint. + ** Requirements:** + Before using this schema, ensure that the PDF file has been processed by the create_pngs endpoint first. + **Coordinate Systems:** - **PNG coordinates:** Pixels are measured from the top-left corner (0, 0), where x increases rightward and y downward. - - **PDF coordinates:** Also measured from the top-left corner (0, 0), though any transformations between - PDF and PNG coordinates are managed internally by the `BoundingBox.rescale` method. ### Fields Each field below includes inline examples to aid users in creating requests. See `json_schema_extra` for a complete example. **Attributes:** - - **filename** (`Path`): Path to the file (PNG or PDF). _Example_: `"document.png"` + - **filename** (`Path`): Path to the PDF file. _Example_: `"document.pdf"` - **page_number** (`int`): Target page for data extraction. This is a 1-based index. _Example_: `1` - **bbox** (`BoundingBox`): Bounding box for the extraction area, in PNG coordinates. Origin is the top-left, with x increasing rightward and y increasing downward. @@ -244,9 +224,7 @@ class ExtractDataRequest(ABC, BaseModel): - **Page Number Validator:** Confirms page number is positive. - **Format Validator:** Checks format is valid as per `FormatTypes`. - - The bounding box should be provided in PNG coordinates. Any necessary coordinate transformations between PNG - and PDF are handled internally using the BoundingBox.rescale method. + The bounding box should be provided in PNG coordinates. Each field in the Pydantic model can have an example parameter, which provides an inline example for that specific field. @@ -254,36 +232,29 @@ class ExtractDataRequest(ABC, BaseModel): filename: Path = Field( ..., - description=""" - Path to the input document file (PNG or PDF) that contains the data to be extracted. This should be - a valid file path, and the file should be accessible to the API. - """, + description="""Path to the input PDF document file that contains the data to be extracted. This should be + a valid file path, and the file should be accessible to the API.""", example=Path("document.png"), ) page_number: int = Field( ..., - description=""" - Page number within the document where the extraction is to be performed. This is a 1-based - index (e.g., 1 for the first page), applicable for multi-page files like PDFs. - """, + description="""Page number within the document where the extraction is to be performed. This is a 1-based + index (e.g., 1 for the first page), applicable for multi-page files like PDFs.""", example=1, ) bbox: BoundingBox = Field( ..., - description=""" - Bounding box defining the area for data extraction within the PNG image. The box is specified in - pixels with the top-left as the origin (0,0), where x increases to the right and y increases - downward. This box should be provided in PNG coordinates, and any transformations to PDF - coordinates are managed internally. + description="""Bounding box defining the area for data extraction within the PNG version of the specified + PDF file. The box is specified in pixels with the top-left as the origin (0,0), where x increases to the + right and y increases downward. This box should be provided in PNG coordinates, and any + transformations to PDF coordinates are managed internally. """, example={"x0": 0.0, "y0": 0.0, "x1": 100.0, "y1": 100.0}, ) format: FormatTypes = Field( ..., - description=""" - Specifies the desired format for extracted data, allowing for options like `coordinates` or other - defined `FormatTypes` values. This dictates the structure of the output returned by the API. - """, + description="""Specifies the desired format for extracted data, allowing for options like `coordinates` or + other defined `FormatTypes` values. This dictates the structure of the output returned by the API.""", example=FormatTypes.COORDINATES.value, ) @@ -335,10 +306,8 @@ class ExtractDataResponse(ABC, BaseModel): bbox: BoundingBox = Field( ..., - description=""" - Bounding box coordinates that define the area within the document where data was extracted. The box - is specified in PNG coordinates, with the origin at the top-left corner (0,0). - """, + description="""Bounding box coordinates that define the area within the document where data was extracted. + The box is specified in PNG coordinates, with the origin at the top-left corner (0,0).""", example={"x0": 0.0, "y0": 0.0, "x1": 100.0, "y1": 100.0}, ) @@ -356,11 +325,9 @@ class ExtractCoordinatesResponse(ExtractDataResponse): coordinates: Coordinates = Field( ..., - description=""" - Geographical coordinates extracted from the document, including east, north values, page number, - and projection type. - """, - example={"east": 1.0, "north": 2.0, "page": 1, "projection": "LV95"}, + description="""Geographical coordinates extracted from the document, including east, north values, page number, + and projection type.""", + example={"east": 1.0, "north": 2.0, "projection": "LV95"}, ) @property @@ -376,9 +343,7 @@ class ExtractTextResponse(ExtractDataResponse): text: str = Field( ..., - description=""" - Text content extracted from the specified bounding box within the document. - """, + description="""Text content extracted from the specified bounding box within the document.""", example="text", ) @@ -396,10 +361,8 @@ class ExtractNumberResponse(ExtractDataResponse): number: float = Field( ..., - description=""" - Numeric value extracted from the specified bounding box within the document, representing a - measurement or quantitative data. - """, + description="""Numeric value extracted from the specified bounding box within the document, representing a + measurement or quantitative data.""", example=1.0, ) From 8a1ca930339832e2fad7002e14304cb9c639578d Mon Sep 17 00:00:00 2001 From: Stijn Vermeeren Date: Thu, 7 Nov 2024 13:16:39 +0100 Subject: [PATCH 10/12] LGVISIUM-89: y0 indentation fix --- src/app/common/schemas.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app/common/schemas.py b/src/app/common/schemas.py index 74366570..5dcd6c98 100644 --- a/src/app/common/schemas.py +++ b/src/app/common/schemas.py @@ -94,10 +94,8 @@ class BoundingBox(BaseModel): ) y0: float = Field( ..., - description=""" - The y-coordinate of the top-left corner of the bounding box. This value marks the vertical starting - point of the box. - """, + description="""The y-coordinate of the top-left corner of the bounding box. This value marks the vertical + starting point of the box.""", example=0.0, ) x1: float = Field( From 19efe59a644d1bcd3edee4e0a38bc8da5045055b Mon Sep 17 00:00:00 2001 From: Stijn Vermeeren Date: Thu, 7 Nov 2024 13:18:54 +0100 Subject: [PATCH 11/12] LGVISIUM-89: remove redundant mention of "page number" in API response description --- src/app/common/schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/common/schemas.py b/src/app/common/schemas.py index 5dcd6c98..19bed098 100644 --- a/src/app/common/schemas.py +++ b/src/app/common/schemas.py @@ -323,7 +323,7 @@ class ExtractCoordinatesResponse(ExtractDataResponse): coordinates: Coordinates = Field( ..., - description="""Geographical coordinates extracted from the document, including east, north values, page number, + description="""Geographical coordinates extracted from the document, including east and north values, and projection type.""", example={"east": 1.0, "north": 2.0, "projection": "LV95"}, ) From 530702c317633bbd71ed4a2d292b911d40503ffc Mon Sep 17 00:00:00 2001 From: Stijn Vermeeren Date: Thu, 7 Nov 2024 13:20:28 +0100 Subject: [PATCH 12/12] LGVISIUM-89: change extension in example filename param --- src/app/common/schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/common/schemas.py b/src/app/common/schemas.py index 19bed098..d6c5e830 100644 --- a/src/app/common/schemas.py +++ b/src/app/common/schemas.py @@ -232,7 +232,7 @@ class ExtractDataRequest(ABC, BaseModel): ..., description="""Path to the input PDF document file that contains the data to be extracted. This should be a valid file path, and the file should be accessible to the API.""", - example=Path("document.png"), + example=Path("document.pdf"), ) page_number: int = Field( ...,