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
27 changes: 27 additions & 0 deletions src/Error/ErrorItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Mindee\Error;

/**
* Explicit details on a problem.
*/
class ErrorItem
{
/**
* @var string|null A JSON Pointer to the location of the body property.
*/
public ?string $pointer;
/**
* @var string Explicit information on the issue.
*/
public string $detail;

/**
* @param array $rawResponse Raw error response from the API.
*/
public function __construct(array $rawResponse)
{
$this->detail = $rawResponse['detail'];
$this->pointer = $rawResponse['pointer'];
}
}
29 changes: 23 additions & 6 deletions src/Error/MindeeV2HttpException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Mindee\Error;

use Mindee\Parsing\V2\ErrorResponse;

/**
* Exceptions relating to HTTP errors for the V2 API.
*/
Expand All @@ -15,15 +17,30 @@ class MindeeV2HttpException extends MindeeException
* @var string|null Details on the exception.
*/
public ?string $detail;
/**
* @var string|null Title of the error.
*/
public ?string $title;
/**
* @var string|null Error code.
* Note: PHP's `RuntimeException` class uses `$code` for the error code.
*/
public ?string $errorCode;
/**
* @var array List of associated errors.
*/
public array $errors;

/**
* @param integer $status HTTP status code, defaults to -1 if not set.
* @param string|null $detail Optional details on the exception.
* @param ErrorResponse $response Server Error response.
*/
public function __construct(int $status, string $detail = null)
public function __construct(ErrorResponse $response)
{
parent::__construct("HTTP Error $status - $detail");
$this->status = $status;
$this->detail = $detail;
parent::__construct("HTTP $response->status - $response->title :: $response->code - $response->detail");
$this->status = $response->status;
$this->detail = $response->detail;
$this->errorCode = $response->code;
$this->title = $response->title;
$this->errors = $response->errors;
}
}
28 changes: 28 additions & 0 deletions src/Error/MindeeV2HttpUnknownError.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Mindee\Error;

use Mindee\Parsing\V2\ErrorResponse;

/**
* Unknown HTTP error for the V2 API.
*/
class MindeeV2HttpUnknownError extends MindeeV2HttpException
{
/**
* @param string|null $response Faulty server response.
*/
public function __construct(?string $response)
{
parent::__construct(
new ErrorResponse(
[
"status" => -1,
"detail" => "Couldn't deserialize server error. Found: $response",
"title" => "Unknown error",
"code" => "000-000"
]
)
);
}
}
29 changes: 21 additions & 8 deletions src/Http/MindeeApiV2.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@

// phpcs:disable
include_once(dirname(__DIR__) . '/version.php');

// phpcs:enable

use Mindee\Error\MindeeV2HttpException;
use Mindee\Error\MindeeV2HttpUnknownError;
use Mindee\Input\InferenceParameters;
use Mindee\Input\InputSource;
use Mindee\Input\LocalInputSource;
use Mindee\Input\URLInputSource;
use Mindee\Parsing\V2\ErrorResponse;
use Mindee\Parsing\V2\InferenceResponse;
use Mindee\Parsing\V2\JobResponse;

Expand Down Expand Up @@ -68,6 +71,7 @@ private function getUserAgent(): string
}
return 'mindee-api-php@v' . VERSION . ' php-v' . PHP_VERSION . ' ' . $os;
}

/**
* @var string|null API key.
*/
Expand Down Expand Up @@ -164,23 +168,19 @@ public function reqPostInferenceEnqueue(InputSource $inputDoc, InferenceParamete
* @return JobResponse|InferenceResponse The processed response object.
* @throws MindeeException Throws if HTTP status indicates an error or deserialization fails.
* @throws MindeeV2HttpException Throws if the HTTP status indicates an error.
* @throws MindeeV2HttpUnknownError Throws if the server sends an unexpected reply.
*/
private function processResponse(array $result, string $responseType)
private function processResponse(array $result, string $responseType): InferenceResponse|JobResponse
{
$statusCode = $result['code'] ?? -1;

if ($statusCode > 399 || $statusCode < 200) {
$responseData = json_decode($result['data'], true);

if ($responseData && isset($responseData['status'])) {
throw new MindeeV2HttpException(
$responseData['status'],
$responseData['detail'] ?? 'Unknown error.'
);
throw new MindeeV2HttpException(new ErrorResponse($responseData));
}

$detail = $responseData && $responseData['detail'] ? $responseData['detail'] : 'Unknown Error';
throw new MindeeException($result['code'] ?? -1, $detail);
throw new MindeeV2HttpUnknownError(json_encode($result, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
}

try {
Expand Down Expand Up @@ -321,6 +321,19 @@ private function documentEnqueuePost(
if (isset($params->rag)) {
$postFields['rag'] = $params->rag ? 'true' : 'false';
}
if (isset($params->webhooksIds) && count($params->webhooksIds) > 0) {
if (PHP_VERSION_ID < 80200 && count($params->webhooksIds) > 1) {
# NOTE: see https://bugs.php.net/bug.php?id=51634
error_log("PHP version is too low to support webbook array destructuring.
\nOnly the first webhook ID will be sent to the server.");
$postFields['webhook_ids'] = $params->webhooksIds[0];
} else {
$postFields['webhook_ids'] = $params->webhooksIds;
}
}
if (isset($params->alias)) {
$postFields['alias'] = $params->alias;
}

$url = $this->baseUrl . '/inferences/enqueue';
curl_setopt($ch, CURLOPT_URL, $url);
Expand Down
4 changes: 2 additions & 2 deletions src/Input/LocalInputSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ public function fixPDF(): void
*/
public function compress(
int $quality = 85,
int $maxWidth = null,
int $maxHeight = null,
?int $maxWidth = null,
?int $maxHeight = null,
bool $forceSourceTextCompression = false,
bool $disableSourceText = true
): void {
Expand Down
2 changes: 1 addition & 1 deletion src/Input/LocalResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public function isValidHMACSignature(string $secretKey, string $signature): bool
* @return mixed An instance of responseClass populated with the file content.
* @throws MindeeException If the provided class cannot be instantiated.
*/
public function deserializeResponse(string $responseClass)
public function deserializeResponse(string $responseClass): mixed
{
try {
$data = $this->toArray();
Expand Down
29 changes: 27 additions & 2 deletions src/Parsing/V2/ErrorResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,52 @@

namespace Mindee\Parsing\V2;

use Mindee\Error\ErrorItem;

/**
* Error response class.
*/
class ErrorResponse
{
/**
* @var integer HTTP Status code.
* @var integer The HTTP status code returned by the server.
*/
public int $status;

/**
* @var string The detail on the error.
* @var string A human-readable explanation specific to the occurrence of the problem.
*/
public string $detail;

/**
* @var string|null A short, human-readable summary of the problem.
*/
public ?string $title;
/**
* @var string|null A machine-readable code specific to the occurrence of the problem.
* Note: PHP's `RuntimeException` class uses `$code` for the error code.
*/
public ?string $code;
/**
* @var array|mixed|null A list of explicit error details.
*/
public ?array $errors;

/**
* @param array $serverResponse Raw server response array.
*/
public function __construct(array $serverResponse)
{
$this->status = $serverResponse['status'];
$this->detail = $serverResponse['detail'];
$this->title = $serverResponse['title'] ?? null;
$this->code = $serverResponse['code'] ?? null;
if (isset($serverResponse['errors']) && is_array($serverResponse['errors'])) {
$this->errors = array_map(static function ($error) {
return new ErrorItem($error);
}, $serverResponse['errors']);
} else {
$this->errors = [];
}
}
}
8 changes: 8 additions & 0 deletions src/Parsing/V2/InferenceResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ class InferenceResult
*/
public ?RawText $rawText;

/**
* @var RagMetadata|null RAG metadata.
*/
public ?RagMetadata $rag;

/**
* @param array $serverResponse Raw server response array.
*/
Expand All @@ -28,6 +33,9 @@ public function __construct(array $serverResponse)
$this->rawText = isset($serverResponse['raw_text'])
? new RawText($serverResponse['raw_text'])
: null;
$this->rag = isset(
$serverResponse['rag']
) ? new RagMetadata($serverResponse['rag']) : null;
}

/**
Expand Down
22 changes: 22 additions & 0 deletions src/Parsing/V2/RagMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Mindee\Parsing\V2;

/**
* Metadata about the RAG operation.
*/
class RagMetadata
{
/**
* @var string|null ID of the matched document, if present.
*/
public ?string $retrievedDocumentId;

/**
* @param array $rawResponse Raw response from the server.
*/
public function __construct(array $rawResponse)
{
$this->retrievedDocumentId = $rawResponse['retrieved_document_id'] ?? null;
}
}
13 changes: 7 additions & 6 deletions tests/ClientV2Test.php → tests/V2/ClientV2Test.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

namespace V2;

use Mindee\ClientV2;
use Mindee\Http\MindeeApiV2;
use Mindee\Input\InferenceParameters;
Expand All @@ -11,7 +13,6 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;


class ClientV2Test extends TestCase
{
private static function makeClientWithMockedApi(MindeeApiV2 $mockedApi): ClientV2
Expand All @@ -27,7 +28,7 @@ private static function makeClientWithMockedApi(MindeeApiV2 $mockedApi): ClientV
public function testEnqueuePostAsync(): void
{
$predictable = $this->createMock(MindeeApiV2::class);
$syntheticResponse = file_get_contents(__DIR__ . '/resources/v2/job/ok_processing.json');
$syntheticResponse = file_get_contents(\TestingUtilities::getV2DataDir() . '/job/ok_processing.json');
$predictable->expects($this->once())
->method('reqPostInferenceEnqueue')
->with(
Expand All @@ -38,7 +39,7 @@ public function testEnqueuePostAsync(): void

$mindeeClient = self::makeClientWithMockedApi($predictable);

$input = new PathInput(__DIR__ . '/resources/file_types/pdf/blank_1.pdf');
$input = new PathInput(\TestingUtilities::getFileTypesDir() . '/pdf/blank_1.pdf');
$params = new InferenceParameters('dummy-model-id');

$response = $mindeeClient->enqueueInference($input, $params);
Expand All @@ -52,7 +53,7 @@ public function testDocumentGetJobAsync(): void
/** @var MindeeApiV2&MockObject $predictable */
$predictable = $this->createMock(MindeeApiV2::class);

$syntheticResponse = file_get_contents(__DIR__ . '/resources/v2/job/ok_processing.json');
$syntheticResponse = file_get_contents(\TestingUtilities::getV2DataDir() . '/job/ok_processing.json');
$processing = new JobResponse(json_decode($syntheticResponse, true));

$predictable->expects($this->once())
Expand All @@ -73,7 +74,7 @@ public function testDocumentGetInferenceAsync(): void
/** @var MindeeApiV2&MockObject $predictable */
$predictable = $this->createMock(MindeeApiV2::class);

$jsonFile = __DIR__ . '/resources/v2/products/financial_document/complete.json';
$jsonFile = \TestingUtilities::getV2DataDir() . '/products/financial_document/complete.json';
$this->assertFileExists($jsonFile, 'Test resource file must exist');

$json = json_decode(file_get_contents($jsonFile), true);
Expand Down Expand Up @@ -108,7 +109,7 @@ public function testDocumentGetInferenceAsync(): void

public function testInferenceLoadsLocally(): void
{
$jsonFile = __DIR__ . '/resources/v2/products/financial_document/complete.json';
$jsonFile = \TestingUtilities::getV2DataDir() . '/products/financial_document/complete.json';
$this->assertFileExists($jsonFile, 'Test resource file must exist');

$localResponse = new LocalResponse($jsonFile);
Expand Down
Loading