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
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
Comment thread
sebO-S marked this conversation as resolved.
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