Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion .github/workflows/_test-code-samples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:

- name: Tests code samples
run: |
./tests/test_code_samples.sh ${{ secrets.MINDEE_ACCOUNT_SE_TESTS }} ${{ secrets.MINDEE_ENDPOINT_SE_TESTS }} ${{ secrets.MINDEE_API_KEY_SE_TESTS }} ${{ secrets.MINDEE_V2_SE_TESTS_API_KEY }} ${{ secrets.MINDEE_V2_SE_TESTS_FINDOC_MODEL_ID }}
./tests/test_code_samples.sh ${{ secrets.MINDEE_ACCOUNT_SE_TESTS }} ${{ secrets.MINDEE_ENDPOINT_SE_TESTS }} ${{ secrets.MINDEE_API_KEY_SE_TESTS }} ${{ secrets.MINDEE_V2_SE_TESTS_API_KEY }} ${{ secrets.MINDEE_V2_SE_TESTS_FINDOC_MODEL_ID }} ${{ secrets.MINDEE_V2_SE_TESTS_SPLIT_MODEL_ID }}

- name: Notify Slack Action on Failure
uses: ravsamhq/notify-slack-action@2.3.0
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/_test-integrations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ jobs:
MINDEE_V2_API_KEY: ${{ secrets.MINDEE_V2_SE_TESTS_API_KEY }}
MINDEE_V2_FINDOC_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_FINDOC_MODEL_ID }}
MINDEE_V2_SE_TESTS_BLANK_PDF_URL: ${{ secrets.MINDEE_V2_SE_TESTS_BLANK_PDF_URL }}
MINDEE_V2_SE_TESTS_SPLIT_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_SPLIT_MODEL_ID }}
run: |
pytest --cov mindee -m integration

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from mindee import ClientV2, InferenceParameters, PathInput
from mindee import ClientV2, InferenceParameters, InferenceResponse, PathInput

input_path = "/path/to/the/file.ext"
api_key = "MY_API_KEY"
Expand Down Expand Up @@ -29,8 +29,10 @@ params = InferenceParameters(
input_source = PathInput(input_path)

# Send for processing
response = mindee_client.enqueue_and_get_inference(
input_source, params
response = mindee_client.enqueue_and_get_result(
InferenceResponse,
input_source,
params,
)

# Print a brief summary of the parsed data
Expand Down
27 changes: 27 additions & 0 deletions docs/extras/code_samples/v2_split.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from mindee import ClientV2, SplitParameters, SplitResponse, PathInput

input_path = "/path/to/the/file.ext"
api_key = "MY_API_KEY"
model_id = "MY_SPLIT_MODEL_ID"

# Init a new client
mindee_client = ClientV2(api_key)

# Set inference parameters
params = SplitParameters(
# ID of the model, required.
model_id=model_id,
)

# Load a file from disk
input_source = PathInput(input_path)

# Send for processing
response = mindee_client.enqueue_and_get_result(
SplitResponse,
input_source,
params,
)

# Print a brief summary of the parsed data
print(response.inference)
32 changes: 18 additions & 14 deletions mindee/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from mindee import product
from mindee.client import Client
from mindee.client_v2 import ClientV2
from mindee.input import LocalResponse, PageOptions, PollingOptions
from mindee.input.inference_parameters import (
InferenceParameters,
DataSchemaField,
DataSchema,
DataSchemaField,
DataSchemaReplace,
InferenceParameters,
)
from mindee.input import LocalResponse, PageOptions, PollingOptions
from mindee.input.sources import (
Base64Input,
BytesInput,
Expand All @@ -22,29 +22,33 @@
from mindee.parsing.common.predict_response import PredictResponse
from mindee.parsing.common.workflow_response import WorkflowResponse
from mindee.parsing.v2 import InferenceResponse, JobResponse
from mindee.v2.product.split.split_parameters import SplitParameters
from mindee.v2.product.split.split_response import SplitResponse

__all__ = [
"ApiResponse",
"AsyncPredictResponse",
"Base64Input",
"BytesInput",
"Client",
"ClientV2",
"DataSchema",
"DataSchemaField",
"DataSchemaReplace",
"InferenceParameters",
"FeedbackResponse",
"FileInput",
"PathInput",
"BytesInput",
"Base64Input",
"UrlInputSource",
"InferenceParameters",
"InferenceResponse",
"Job",
"JobResponse",
"LocalResponse",
"PageOptions",
"PathInput",
"PollingOptions",
"ApiResponse",
"AsyncPredictResponse",
"FeedbackResponse",
"PredictResponse",
"SplitParameters",
"SplitResponse",
"UrlInputSource",
"WorkflowResponse",
"JobResponse",
"Job",
"InferenceResponse",
"product",
]
2 changes: 1 addition & 1 deletion mindee/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ def enqueue_and_parse( # pylint: disable=too-many-locals
if poll_results.job.status == "failed":
raise MindeeError("Parsing failed for job {poll_results.job.id}")
logger.debug(
"Polling server for parsing result with job id: %s", queue_result.job.id
"Polling server for product result with job id: %s", queue_result.job.id
)
retry_counter += 1
sleep(delay_sec)
Expand Down
89 changes: 73 additions & 16 deletions mindee/client_v2.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import warnings
from time import sleep
from typing import Optional, Union
from typing import Optional, Union, Type, TypeVar

from mindee.client_mixin import ClientMixin
from mindee.error.mindee_error import MindeeError
from mindee.error.mindee_http_error_v2 import handle_error_v2
from mindee.input import UrlInputSource
from mindee.input import UrlInputSource, BaseParameters
from mindee.input.inference_parameters import InferenceParameters
from mindee.input.polling_options import PollingOptions
from mindee.input.sources.local_input_source import LocalInputSource
Expand All @@ -15,9 +16,12 @@
is_valid_post_response,
)
from mindee.parsing.v2.common_response import CommonStatus
from mindee.v2.parsing.inference.base_response import BaseResponse
from mindee.parsing.v2.inference_response import InferenceResponse
from mindee.parsing.v2.job_response import JobResponse

TypeBaseResponse = TypeVar("TypeBaseResponse", bound=BaseResponse)


class ClientV2(ClientMixin):
"""
Expand All @@ -41,20 +45,34 @@ def __init__(self, api_key: Optional[str] = None) -> None:
def enqueue_inference(
self,
input_source: Union[LocalInputSource, UrlInputSource],
params: InferenceParameters,
params: BaseParameters,
disable_redundant_warnings: bool = False,
) -> JobResponse:
"""[Deprecated] Use `enqueue` instead."""
if not disable_redundant_warnings:
warnings.warn(
"enqueue_inference is deprecated; use enqueue instead",
DeprecationWarning,
stacklevel=2,
)
return self.enqueue(input_source, params)

def enqueue(
self,
input_source: Union[LocalInputSource, UrlInputSource],
params: BaseParameters,
) -> JobResponse:
"""
Enqueues a document to a given model.

:param input_source: The document/source file to use. Can be local or remote.

:param params: Parameters to set when sending a file.

:return: A valid inference response.
"""
logger.debug("Enqueuing inference using model: %s", params.model_id)

response = self.mindee_api.req_post_inference_enqueue(
input_source=input_source, params=params
input_source=input_source, params=params, slug=params.get_enqueue_slug()
)
dict_response = response.json()

Expand All @@ -79,34 +97,49 @@ def get_job(self, job_id: str) -> JobResponse:
dict_response = response.json()
return JobResponse(dict_response)

def get_inference(self, inference_id: str) -> InferenceResponse:
def get_inference(
self,
inference_id: str,
) -> BaseResponse:
"""[Deprecated] Use `get_result` instead."""
return self.get_result(InferenceResponse, inference_id)

def get_result(
self,
response_type: Type[TypeBaseResponse],
inference_id: str,
) -> TypeBaseResponse:
"""
Get the result of an inference that was previously enqueued.

The inference will only be available after it has finished processing.

:param inference_id: UUID of the inference to retrieve.
:param response_type: Class of the product to instantiate.
:return: An inference response.
"""
logger.debug("Fetching inference: %s", inference_id)

response = self.mindee_api.req_get_inference(inference_id)
response = self.mindee_api.req_get_inference(
inference_id, response_type.get_result_slug()
)
if not is_valid_get_response(response):
handle_error_v2(response.json())
dict_response = response.json()
return InferenceResponse(dict_response)
return response_type(dict_response)

def enqueue_and_get_inference(
def enqueue_and_get_result(
self,
response_type: Type[TypeBaseResponse],
input_source: Union[LocalInputSource, UrlInputSource],
params: InferenceParameters,
) -> InferenceResponse:
params: BaseParameters,
) -> TypeBaseResponse:
"""
Enqueues to an asynchronous endpoint and automatically polls for a response.

:param input_source: The document/source file to use. Can be local or remote.

:param params: Parameters to set when sending a file.
:param response_type: The product class to use for the response object.

:return: A valid inference response.
"""
Expand All @@ -117,14 +150,15 @@ def enqueue_and_get_inference(
params.polling_options.delay_sec,
params.polling_options.max_retries,
)
enqueue_response = self.enqueue_inference(input_source, params)
enqueue_response = self.enqueue_inference(input_source, params, True)
logger.debug(
"Successfully enqueued inference with job id: %s", enqueue_response.job.id
"Successfully enqueued document with job id: %s", enqueue_response.job.id
)
sleep(params.polling_options.initial_delay_sec)
try_counter = 0
while try_counter < params.polling_options.max_retries:
job_response = self.get_job(enqueue_response.job.id)
assert isinstance(job_response, JobResponse)
if job_response.job.status == CommonStatus.FAILED.value:
if job_response.job.error:
detail = job_response.job.error.detail
Expand All @@ -134,8 +168,31 @@ def enqueue_and_get_inference(
f"Parsing failed for job {job_response.job.id}: {detail}"
)
if job_response.job.status == CommonStatus.PROCESSED.value:
return self.get_inference(job_response.job.id)
result = self.get_result(
response_type or InferenceResponse, job_response.job.id
)
assert isinstance(result, response_type), (
f'Invalid response type "{type(result)}"'
)
return result
try_counter += 1
sleep(params.polling_options.delay_sec)

raise MindeeError(f"Couldn't retrieve document after {try_counter + 1} tries.")

def enqueue_and_get_inference(
self,
input_source: Union[LocalInputSource, UrlInputSource],
params: InferenceParameters,
) -> InferenceResponse:
"""[Deprecated] Use `enqueue_and_get_result` instead."""
warnings.warn(
"enqueue_and_get_inference is deprecated; use enqueue_and_get_result instead",
DeprecationWarning,
stacklevel=2,
)
response = self.enqueue_and_get_result(InferenceResponse, input_source, params)
assert isinstance(response, InferenceResponse), (
f'Invalid response type "{type(response)}"'
)
return response
4 changes: 2 additions & 2 deletions mindee/error/mindee_http_error_v2.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import json
from typing import Optional
from typing import List, Optional

from mindee.parsing.common.string_dict import StringDict
from mindee.parsing.v2 import ErrorItem, ErrorResponse
Expand All @@ -18,7 +18,7 @@ def __init__(self, response: ErrorResponse) -> None:
self.title = response.title
self.code = response.code
self.detail = response.detail
self.errors: list[ErrorItem] = response.errors
self.errors: List[ErrorItem] = response.errors
super().__init__(
f"HTTP {self.status} - {self.title} :: {self.code} - {self.detail}"
)
Expand Down
20 changes: 13 additions & 7 deletions mindee/input/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from mindee.input.local_response import LocalResponse
from mindee.input.base_parameters import BaseParameters
from mindee.input.inference_parameters import InferenceParameters
from mindee.v2.product.split.split_parameters import SplitParameters
from mindee.input.page_options import PageOptions
from mindee.input.polling_options import PollingOptions
from mindee.input.sources.base_64_input import Base64Input
Expand All @@ -11,15 +14,18 @@
from mindee.input.workflow_options import WorkflowOptions

__all__ = [
"Base64Input",
"BaseParameters",
"BytesInput",
"FileInput",
"InputType",
"InferenceParameters",
"LocalInputSource",
"UrlInputSource",
"LocalResponse",
"PageOptions",
"PathInput",
"FileInput",
"Base64Input",
"BytesInput",
"WorkflowOptions",
"PollingOptions",
"PageOptions",
"LocalResponse",
"UrlInputSource",
"SplitParameters",
"WorkflowOptions",
]
Loading