From d5c4cf0dc1fdc376febd3d9ba65eea024e7272e2 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Thu, 23 Jul 2026 17:19:00 +0200 Subject: [PATCH 1/2] :sparkles: add RAG search API --- bin/V2/SearchRagDocumentsCommand.php | 103 ++++++++++++++++++ bin/cli.php | 5 +- src/V2/Client.php | 40 +++++-- src/V2/ClientOptions/BaseSearchParameters.php | 37 +++++++ .../ClientOptions/ModelSearchParameters.php | 41 +++++++ .../RagDocumentSearchParameters.php | 50 +++++++++ src/V2/Http/MindeeApiV2.php | 61 ++++++++--- src/V2/Parsing/Search/BaseSearchResponse.php | 43 ++++++++ src/V2/Parsing/Search/ModelSearchResponse.php | 40 +++++++ src/V2/Parsing/Search/RagDocument.php | 75 +++++++++++++ .../Search/RagDocumentSearchResponse.php | 40 +++++++ src/V2/Parsing/Search/RagDocuments.php | 48 ++++++++ src/V2/Parsing/Search/SearchResponse.php | 44 +------- tests/V2/Cli/MindeeCliCommandV2Test.php | 37 +++++++ .../Parsing/RagDocumentSearchResponseTest.php | 55 ++++++++++ tests/resources | 2 +- 16 files changed, 655 insertions(+), 66 deletions(-) create mode 100644 bin/V2/SearchRagDocumentsCommand.php create mode 100644 src/V2/ClientOptions/BaseSearchParameters.php create mode 100644 src/V2/ClientOptions/ModelSearchParameters.php create mode 100644 src/V2/ClientOptions/RagDocumentSearchParameters.php create mode 100644 src/V2/Parsing/Search/BaseSearchResponse.php create mode 100644 src/V2/Parsing/Search/ModelSearchResponse.php create mode 100644 src/V2/Parsing/Search/RagDocument.php create mode 100644 src/V2/Parsing/Search/RagDocumentSearchResponse.php create mode 100644 src/V2/Parsing/Search/RagDocuments.php create mode 100644 tests/V2/Parsing/RagDocumentSearchResponseTest.php diff --git a/bin/V2/SearchRagDocumentsCommand.php b/bin/V2/SearchRagDocumentsCommand.php new file mode 100644 index 00000000..47d22d44 --- /dev/null +++ b/bin/V2/SearchRagDocumentsCommand.php @@ -0,0 +1,103 @@ +setName('search-rag-docs') + ->setDescription('Search available RAG documents for a given model.') + ->addOption( + 'api-key', + 'k', + InputOption::VALUE_REQUIRED, + 'Mindee V2 API key. Falls back to the MINDEE_V2_API_KEY environment variable.' + ) + ->addOption( + 'model-id', + 'm', + InputOption::VALUE_REQUIRED, + 'Filter by model ID.' + ) + ->addOption( + 'filename', + 'f', + InputOption::VALUE_REQUIRED, + 'Filter by file name partial match (case insensitive).' + ) + ->addOption( + 'raw-json', + 'r', + InputOption::VALUE_NONE, + 'Whether to output the raw JSON response.' + ); + } + + /** + * @param InputInterface $input CLI input. + * @param OutputInterface $output CLI output. + * @return integer Exit code. + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $apiKey = $input->getOption('api-key'); + if (!$apiKey && !getenv('MINDEE_V2_API_KEY')) { + $output->writeln( + 'The Mindee V2 API key is missing. ' + . "Please provide it via the '--api-key' option or the MINDEE_V2_API_KEY environment variable." + ); + return Command::FAILURE; + } + + $modelId = $input->getOption('model-id'); + if (!$modelId) { + $output->writeln('The --model-id option is required.'); + return Command::FAILURE; + } + $filename = $input->getOption('filename'); + $raw = (bool) $input->getOption('raw-json'); + + $client = new Client($apiKey ?: null); + + try { + $response = $client->searchRagDocuments( + new RagDocumentSearchParameters($modelId, $filename ?: null) + ); + } catch (MindeeV2HttpException $e) { + $output->writeln('' . $e->getMessage() . ''); + return Command::FAILURE; + } catch (Exception $e) { + $output->writeln("Something went wrong, '" . $e->getMessage() . "' was raised."); + return Command::FAILURE; + } + + if ($raw) { + $output->writeln($response->getRawHttp()); + } else { + $output->write((string) $response); + } + return Command::SUCCESS; + } +} diff --git a/bin/cli.php b/bin/cli.php index 7ab44b10..fa47ed6f 100755 --- a/bin/cli.php +++ b/bin/cli.php @@ -15,6 +15,7 @@ require __DIR__ . '/V2/OcrCommand.php'; require __DIR__ . '/V2/SplitCommand.php'; require __DIR__ . '/V2/SearchModelsCommand.php'; +require __DIR__ . '/V2/SearchRagDocumentsCommand.php'; use Exception; use Mindee\Cli\V2\ClassificationCommand; @@ -22,6 +23,7 @@ use Mindee\Cli\V2\ExtractionCommand; use Mindee\Cli\V2\OcrCommand; use Mindee\Cli\V2\SearchModelsCommand; +use Mindee\Cli\V2\SearchRagDocumentsCommand; use Mindee\Cli\V2\SplitCommand; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\ArgvInput; @@ -139,8 +141,9 @@ function mindeeRewriteArgvForV1Compat(array $argv, array $knownTopLevelCommands) $cli->add($command); } $cli->add(new SearchModelsCommand()); +$cli->add(new SearchRagDocumentsCommand()); -$knownTopLevelCommands = ['v1', 'search-models', 'list', 'help', 'completion']; +$knownTopLevelCommands = ['v1', 'search-models', 'search-rag-docs', 'list', 'help', 'completion']; foreach ($v2InferenceCommands as $command) { $knownTopLevelCommands[] = $command->getName(); } diff --git a/src/V2/Client.php b/src/V2/Client.php index 9997a827..ae3bf3c6 100644 --- a/src/V2/Client.php +++ b/src/V2/Client.php @@ -10,10 +10,13 @@ use Mindee\Http\CancellationToken; use Mindee\Input\InputSource; use Mindee\V2\ClientOptions\BaseParameters; +use Mindee\V2\ClientOptions\ModelSearchParameters; +use Mindee\V2\ClientOptions\RagDocumentSearchParameters; use Mindee\V2\Http\MindeeApiV2; use Mindee\V2\Parsing\Inference\BaseResponse; use Mindee\V2\Parsing\Job\JobResponse; -use Mindee\V2\Parsing\Search\SearchResponse; +use Mindee\V2\Parsing\Search\ModelSearchResponse; +use Mindee\V2\Parsing\Search\RagDocumentSearchResponse; /** * Mindee Client V2. @@ -165,13 +168,36 @@ public function enqueueAndGetResult( } /** - * Searches for a list of available models for the given API key. - * @param string|null $modelName Optional model name to filter by. - * @param string|null $modelType Optional model type to filter by. - * @return SearchResponse The list of models matching the criteria. + * Searches for a list of available models matching the given criteria. + * + * Pass a {@see ModelSearchParameters} object to use the full search API + * (including pagination). Passing individual `$modelName`/`$modelType` + * strings is deprecated and kept for backward compatibility. + * + * @param ModelSearchParameters|string|null $modelName Search parameters, or a model name filter (deprecated). + * @param string|null $modelType Optional model type to filter by (deprecated string-based path only). + * @return ModelSearchResponse The list of models matching the criteria. + */ + public function searchModels( + ModelSearchParameters|string|null $modelName = null, + ?string $modelType = null + ): ModelSearchResponse { + if ($modelName instanceof ModelSearchParameters) { + return $this->mindeeApi->searchModels($modelName); + } + + return $this->mindeeApi->searchModelsObsolete( + new ModelSearchParameters($modelName, $modelType) + ); + } + + /** + * Searches for a list of RAG documents matching the given criteria. + * @param RagDocumentSearchParameters $params Search parameters. + * @return RagDocumentSearchResponse The list of RAG documents matching the criteria. */ - public function searchModels(?string $modelName = null, ?string $modelType = null): SearchResponse + public function searchRagDocuments(RagDocumentSearchParameters $params): RagDocumentSearchResponse { - return $this->mindeeApi->searchModels($modelName, $modelType); + return $this->mindeeApi->searchRagDocuments($params); } } diff --git a/src/V2/ClientOptions/BaseSearchParameters.php b/src/V2/ClientOptions/BaseSearchParameters.php new file mode 100644 index 00000000..5d222509 --- /dev/null +++ b/src/V2/ClientOptions/BaseSearchParameters.php @@ -0,0 +1,37 @@ + Query parameters. + */ + public function getQueryParams(): array + { + $params = []; + if ($this->page !== null && $this->page > 0) { + $params['page'] = (string) $this->page; + } + if ($this->perPage !== null && $this->perPage > 0) { + $params['per_page'] = (string) $this->perPage; + } + return $params; + } +} diff --git a/src/V2/ClientOptions/ModelSearchParameters.php b/src/V2/ClientOptions/ModelSearchParameters.php new file mode 100644 index 00000000..51452233 --- /dev/null +++ b/src/V2/ClientOptions/ModelSearchParameters.php @@ -0,0 +1,41 @@ + Query parameters. + */ + public function getQueryParams(): array + { + $params = parent::getQueryParams(); + if (!empty($this->name)) { + $params['name'] = $this->name; + } + if (!empty($this->modelType)) { + $params['model_type'] = $this->modelType; + } + return $params; + } +} diff --git a/src/V2/ClientOptions/RagDocumentSearchParameters.php b/src/V2/ClientOptions/RagDocumentSearchParameters.php new file mode 100644 index 00000000..46367fa2 --- /dev/null +++ b/src/V2/ClientOptions/RagDocumentSearchParameters.php @@ -0,0 +1,50 @@ + Query parameters. + * @throws MindeeException Throws if the model ID is not provided. + */ + public function getQueryParams(): array + { + $params = parent::getQueryParams(); + if (!empty($this->modelId)) { + $params['model_id'] = $this->modelId; + } else { + throw new MindeeException( + "ModelId is required in RagDocumentSearchParameters.", + ErrorCode::USER_INPUT_ERROR + ); + } + if (!empty($this->filename)) { + $params['filename'] = $this->filename; + } + return $params; + } +} diff --git a/src/V2/Http/MindeeApiV2.php b/src/V2/Http/MindeeApiV2.php index 6835c1b9..91383c6d 100644 --- a/src/V2/Http/MindeeApiV2.php +++ b/src/V2/Http/MindeeApiV2.php @@ -18,11 +18,15 @@ use Mindee\Input\LocalInputSource; use Mindee\Input\UrlInputSource; use Mindee\V2\ClientOptions\BaseParameters; +use Mindee\V2\ClientOptions\ModelSearchParameters; +use Mindee\V2\ClientOptions\RagDocumentSearchParameters; use Mindee\V2\Error\MindeeV2HttpException; use Mindee\V2\Error\MindeeV2HttpUnknownException; use Mindee\V2\Parsing\Error\ErrorResponse; use Mindee\V2\Parsing\Inference\BaseResponse; use Mindee\V2\Parsing\Job\JobResponse; +use Mindee\V2\Parsing\Search\ModelSearchResponse; +use Mindee\V2\Parsing\Search\RagDocumentSearchResponse; use Mindee\V2\Parsing\Search\SearchResponse; use ReflectionClass; use ReflectionException; @@ -389,20 +393,16 @@ private function checkValidResponse(array $result): void } /** + * Makes a GET call to a search endpoint. + * @param string $path Search endpoint path (e.g. `/v2/search/models`). + * @param array $queryParams Query parameters to append. * @return array> Server response. */ - private function reqGetSearchModels(?string $modelName = null, ?string $modelType = null): array + private function reqGetSearch(string $path, array $queryParams): array { - $url = $this->baseUrl . "/v2/search/models"; - $params = []; - if ($modelName) { - $params['name'] = $modelName; - } - if ($modelType) { - $params['model_type'] = $modelType; - } - if (!empty($params)) { - $url .= '?' . http_build_query($params); + $url = $this->baseUrl . $path; + if (!empty($queryParams)) { + $url .= '?' . http_build_query($queryParams); } $ch = $this->initChannel(); @@ -418,13 +418,42 @@ private function reqGetSearchModels(?string $modelName = null, ?string $modelTyp } /** - * Retrieves a list of models based on criteria. - * @param string|null $modelName Optional model name to filter by. - * @param string|null $modelType Optional model type to filter by. + * Retrieves a list of models matching the given criteria. + * @param ModelSearchParameters $params Search parameters. + * @return ModelSearchResponse The list of models matching the criteria. + */ + public function searchModels(ModelSearchParameters $params): ModelSearchResponse + { + return $this->processResponse( + ModelSearchResponse::class, + $this->reqGetSearch("/v2/search/models", $params->getQueryParams()) + ); + } + + /** + * Retrieves a list of models matching the given criteria (deprecated response type). + * @param ModelSearchParameters $params Search parameters. * @return SearchResponse The list of models matching the criteria. + * @deprecated Use {@see searchModels()} instead. */ - public function searchModels(?string $modelName = null, ?string $modelType = null): SearchResponse + public function searchModelsObsolete(ModelSearchParameters $params): SearchResponse { - return $this->processResponse(SearchResponse::class, $this->reqGetSearchModels($modelName, $modelType)); + return $this->processResponse( + SearchResponse::class, + $this->reqGetSearch("/v2/search/models", $params->getQueryParams()) + ); + } + + /** + * Retrieves a list of RAG documents matching the given criteria. + * @param RagDocumentSearchParameters $params Search parameters. + * @return RagDocumentSearchResponse The list of RAG documents matching the criteria. + */ + public function searchRagDocuments(RagDocumentSearchParameters $params): RagDocumentSearchResponse + { + return $this->processResponse( + RagDocumentSearchResponse::class, + $this->reqGetSearch("/v2/search/rag-documents", $params->getQueryParams()) + ); } } diff --git a/src/V2/Parsing/Search/BaseSearchResponse.php b/src/V2/Parsing/Search/BaseSearchResponse.php new file mode 100644 index 00000000..e1002c65 --- /dev/null +++ b/src/V2/Parsing/Search/BaseSearchResponse.php @@ -0,0 +1,43 @@ +> $rawResponse Raw server response array. + */ + public function __construct(array $rawResponse) + { + parent::__construct($rawResponse); + $this->pagination = new PaginationMetadata($rawResponse['pagination']); + } + + /** + * Renders the shared pagination metadata block. + * + * @return array Lines composing the pagination section. + */ + protected function paginationLines(): array + { + return [ + 'Pagination Metadata', + '###################', + (string) $this->pagination, + '', + ]; + } +} diff --git a/src/V2/Parsing/Search/ModelSearchResponse.php b/src/V2/Parsing/Search/ModelSearchResponse.php new file mode 100644 index 00000000..4f6d0cfa --- /dev/null +++ b/src/V2/Parsing/Search/ModelSearchResponse.php @@ -0,0 +1,40 @@ +> $rawResponse Raw server response array. + */ + public function __construct(array $rawResponse) + { + parent::__construct($rawResponse); + $this->models = new SearchModels($rawResponse['models']); + } + + /** + * @return string String representation. + */ + public function __toString(): string + { + return implode("\n", array_merge( + [ + 'Models', + '######', + (string) $this->models, + ], + $this->paginationLines() + )); + } +} diff --git a/src/V2/Parsing/Search/RagDocument.php b/src/V2/Parsing/Search/RagDocument.php new file mode 100644 index 00000000..ddb2668b --- /dev/null +++ b/src/V2/Parsing/Search/RagDocument.php @@ -0,0 +1,75 @@ +> $rawResponse Raw server response array. + */ + public function __construct(array $rawResponse) + { + $this->id = $rawResponse['id']; + $this->modelId = $rawResponse['model_id']; + $this->filename = $rawResponse['filename']; + $this->createdAt = new DateTimeImmutable($rawResponse['created_at']); + $this->totalMatches = $rawResponse['total_matches']; + $this->lastMatchAt = $this->parseDate($rawResponse['last_match_at'] ?? null); + $this->status = $rawResponse['status']; + } + + /** + * Parse a date string into a DateTimeImmutable object. + * + * @param string|null $dateString Date string to parse. + * @return DateTimeImmutable|null Parsed date or null if empty/invalid. + */ + private function parseDate(?string $dateString): ?DateTimeImmutable + { + if (empty($dateString)) { + return null; + } + try { + return new DateTimeImmutable($dateString); + } catch (Exception) { + return null; + } + } +} diff --git a/src/V2/Parsing/Search/RagDocumentSearchResponse.php b/src/V2/Parsing/Search/RagDocumentSearchResponse.php new file mode 100644 index 00000000..01a1a5ae --- /dev/null +++ b/src/V2/Parsing/Search/RagDocumentSearchResponse.php @@ -0,0 +1,40 @@ +> $rawResponse Raw server response array. + */ + public function __construct(array $rawResponse) + { + parent::__construct($rawResponse); + $this->ragDocuments = new RagDocuments($rawResponse['rag_documents']); + } + + /** + * @return string String representation. + */ + public function __toString(): string + { + return implode("\n", array_merge( + [ + 'RAG Documents', + '############', + (string) $this->ragDocuments, + ], + $this->paginationLines() + )); + } +} diff --git a/src/V2/Parsing/Search/RagDocuments.php b/src/V2/Parsing/Search/RagDocuments.php new file mode 100644 index 00000000..0231dc53 --- /dev/null +++ b/src/V2/Parsing/Search/RagDocuments.php @@ -0,0 +1,48 @@ + + */ +class RagDocuments extends ArrayObject implements Stringable +{ + /** + * @param array>> $prediction Raw prediction. + */ + public function __construct(array $prediction) + { + $documents = array_map(static fn($entry) => new RagDocument($entry), $prediction); + + parent::__construct($documents); + } + + /** + * Default string representation. + */ + public function __toString(): string + { + if ($this->count() === 0) { + return "\n"; + } + + $lines = []; + foreach ($this as $document) { + $lines[] = "* :ID: " . $document->id; + $lines[] = " :Model ID: " . $document->modelId; + $lines[] = " :Filename: " . $document->filename; + $lines[] = " :Created At: " . $document->createdAt->format(DATE_ATOM); + $lines[] = " :Total Matches: " . $document->totalMatches; + $lines[] = " :Last Match At: " . ($document->lastMatchAt?->format(DATE_ATOM) ?? ''); + $lines[] = " :Status: " . $document->status; + } + + return implode("\n", $lines) . "\n"; + } +} diff --git a/src/V2/Parsing/Search/SearchResponse.php b/src/V2/Parsing/Search/SearchResponse.php index c58d6d32..64d261b3 100644 --- a/src/V2/Parsing/Search/SearchResponse.php +++ b/src/V2/Parsing/Search/SearchResponse.php @@ -4,47 +4,9 @@ namespace Mindee\V2\Parsing\Search; -use Mindee\V2\Parsing\Inference\BaseResponse; -use Stringable; - /** * Models search response. + * + * @deprecated Use {@see ModelSearchResponse} instead. */ -class SearchResponse extends BaseResponse implements Stringable -{ - /** - * @var SearchModels Parsed search payload. - */ - public SearchModels $models; - - /** - * @var PaginationMetadata Pagination metadata for the search results. - */ - public PaginationMetadata $pagination; - - /** - * @param array> $rawResponse Raw server response array. - */ - public function __construct(array $rawResponse) - { - parent::__construct($rawResponse); - $this->models = new SearchModels($rawResponse['models']); - $this->pagination = new PaginationMetadata($rawResponse['pagination']); - } - - /** - * @return string String representation. - */ - public function __toString(): string - { - return implode("\n", [ - 'Models', - '######', - (string) $this->models, - 'Pagination Metadata', - '###################', - (string) $this->pagination, - '', - ]); - } -} +class SearchResponse extends ModelSearchResponse {} diff --git a/tests/V2/Cli/MindeeCliCommandV2Test.php b/tests/V2/Cli/MindeeCliCommandV2Test.php index 422b04b1..200a30da 100644 --- a/tests/V2/Cli/MindeeCliCommandV2Test.php +++ b/tests/V2/Cli/MindeeCliCommandV2Test.php @@ -49,6 +49,7 @@ public function testListShouldShowAllV2Commands(): void self::assertStringContainsString('ocr', $stdout); self::assertStringContainsString('split', $stdout); self::assertStringContainsString('search-models', $stdout); + self::assertStringContainsString('search-rag-docs', $stdout); self::assertStringContainsString('v1', $stdout); } @@ -195,6 +196,42 @@ public function testSearchModelsMissingApiKeyMustFail(): void ); } + public function testSearchRagDocsHelpExposesExpectedOptions(): void + { + $cmdOutput = MindeeCliV2TestingUtilities::executeTest(['search-rag-docs', '--help']); + self::assertSame(0, $cmdOutput['code']); + $stdout = implode("\n", $cmdOutput['output']); + self::assertStringContainsString('--api-key', $stdout); + self::assertStringContainsString('--model-id', $stdout); + self::assertStringContainsString('--filename', $stdout); + self::assertStringContainsString('--raw-json', $stdout); + } + + public function testSearchRagDocsMissingApiKeyMustFail(): void + { + $cmdOutput = MindeeCliV2TestingUtilities::executeTest( + ['search-rag-docs', '--model-id', 'some-model-id'], + ['MINDEE_V2_API_KEY' => false] + ); + self::assertSame(1, $cmdOutput['code']); + self::assertStringContainsString( + 'API key is missing', + implode("\n", $cmdOutput['output']) + ); + } + + public function testSearchRagDocsMissingModelIdMustFail(): void + { + $cmdOutput = MindeeCliV2TestingUtilities::executeTest( + ['search-rag-docs', '-k', 'dummy-key'] + ); + self::assertSame(1, $cmdOutput['code']); + self::assertStringContainsString( + '--model-id', + implode("\n", $cmdOutput['output']) + ); + } + public function testV1BackwardCompatibilityDispatch(): void { $cmdOutput = MindeeCliV2TestingUtilities::executeTest( diff --git a/tests/V2/Parsing/RagDocumentSearchResponseTest.php b/tests/V2/Parsing/RagDocumentSearchResponseTest.php new file mode 100644 index 00000000..166915aa --- /dev/null +++ b/tests/V2/Parsing/RagDocumentSearchResponseTest.php @@ -0,0 +1,55 @@ +ragDocuments); + foreach ($response->ragDocuments as $document) { + self::assertInstanceOf(RagDocument::class, $document); + self::assertNotEmpty($document->id); + self::assertNotEmpty($document->modelId); + self::assertNotEmpty($document->filename); + } + + $firstItem = $response->ragDocuments[0]; + self::assertEquals("cc831599-c545-48b7-aa27-6d7ccd5b8d32", $firstItem->id); + self::assertEquals("12345678-1234-1234-1234-123456789abc", $firstItem->modelId); + self::assertEquals("invoice_01.pdf", $firstItem->filename); + self::assertEquals(0, $firstItem->totalMatches); + self::assertNull($firstItem->lastMatchAt); + self::assertEquals("Processing", $firstItem->status); + + $thirdItem = $response->ragDocuments[2]; + self::assertEquals("a6bcae7d-0439-476b-8a63-5a39ec05dc21", $thirdItem->id); + self::assertEquals("invoice_03.pdf", $thirdItem->filename); + self::assertEquals(5, $thirdItem->totalMatches); + self::assertNotNull($thirdItem->lastMatchAt); + self::assertEquals("Active", $thirdItem->status); + + self::assertEquals(50, $response->pagination->perPage); + self::assertEquals(1, $response->pagination->page); + self::assertEquals(3, $response->pagination->totalItems); + self::assertEquals(1, $response->pagination->totalPages); + } +} diff --git a/tests/resources b/tests/resources index e41ab97c..fa7b7666 160000 --- a/tests/resources +++ b/tests/resources @@ -1 +1 @@ -Subproject commit e41ab97c2833f15ea5c4edf221c2d197d212f632 +Subproject commit fa7b76669c0e53fc46ca9f87b0151bac3ed40083 From a54cc75a569e7908cbdec7e406005bab84e814e5 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Thu, 23 Jul 2026 18:10:56 +0200 Subject: [PATCH 2/2] apply suggested changes --- bin/V2/SearchModelsCommand.php | 5 +- src/Parsing/DateHelper.php | 51 +++++++++++++++++++ src/V2/Client.php | 22 ++------ src/V2/Http/MindeeApiV2.php | 15 ------ src/V2/Parsing/Job/Job.php | 24 ++------- src/V2/Parsing/Job/JobWebhook.php | 22 +------- src/V2/Parsing/Search/BaseSearchResponse.php | 26 ++++++---- src/V2/Parsing/Search/ModelSearchResponse.php | 17 +++---- src/V2/Parsing/Search/RagDocument.php | 22 +------- .../Search/RagDocumentSearchResponse.php | 17 +++---- 10 files changed, 97 insertions(+), 124 deletions(-) create mode 100644 src/Parsing/DateHelper.php diff --git a/bin/V2/SearchModelsCommand.php b/bin/V2/SearchModelsCommand.php index c4ff273e..3777b5a6 100644 --- a/bin/V2/SearchModelsCommand.php +++ b/bin/V2/SearchModelsCommand.php @@ -6,6 +6,7 @@ use Exception; use Mindee\V2\Client; +use Mindee\V2\ClientOptions\ModelSearchParameters; use Mindee\V2\Error\MindeeV2HttpException; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -83,7 +84,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $client = new Client($apiKey ?: null); try { - $response = $client->searchModels($name ?: null, $modelType ?: null); + $response = $client->searchModels( + new ModelSearchParameters($name ?: null, $modelType ?: null) + ); } catch (MindeeV2HttpException $e) { $output->writeln('' . $e->getMessage() . ''); return Command::FAILURE; diff --git a/src/Parsing/DateHelper.php b/src/Parsing/DateHelper.php new file mode 100644 index 00000000..c6f6c448 --- /dev/null +++ b/src/Parsing/DateHelper.php @@ -0,0 +1,51 @@ +mindeeApi->searchModels($modelName); - } - - return $this->mindeeApi->searchModelsObsolete( - new ModelSearchParameters($modelName, $modelType) - ); + public function searchModels(?ModelSearchParameters $params = null): ModelSearchResponse + { + return $this->mindeeApi->searchModels($params ?? new ModelSearchParameters()); } /** diff --git a/src/V2/Http/MindeeApiV2.php b/src/V2/Http/MindeeApiV2.php index 91383c6d..5af23128 100644 --- a/src/V2/Http/MindeeApiV2.php +++ b/src/V2/Http/MindeeApiV2.php @@ -27,7 +27,6 @@ use Mindee\V2\Parsing\Job\JobResponse; use Mindee\V2\Parsing\Search\ModelSearchResponse; use Mindee\V2\Parsing\Search\RagDocumentSearchResponse; -use Mindee\V2\Parsing\Search\SearchResponse; use ReflectionClass; use ReflectionException; use ReflectionProperty; @@ -430,20 +429,6 @@ public function searchModels(ModelSearchParameters $params): ModelSearchResponse ); } - /** - * Retrieves a list of models matching the given criteria (deprecated response type). - * @param ModelSearchParameters $params Search parameters. - * @return SearchResponse The list of models matching the criteria. - * @deprecated Use {@see searchModels()} instead. - */ - public function searchModelsObsolete(ModelSearchParameters $params): SearchResponse - { - return $this->processResponse( - SearchResponse::class, - $this->reqGetSearch("/v2/search/models", $params->getQueryParams()) - ); - } - /** * Retrieves a list of RAG documents matching the given criteria. * @param RagDocumentSearchParameters $params Search parameters. diff --git a/src/V2/Parsing/Job/Job.php b/src/V2/Parsing/Job/Job.php index 982853c4..3e2d923d 100644 --- a/src/V2/Parsing/Job/Job.php +++ b/src/V2/Parsing/Job/Job.php @@ -5,7 +5,7 @@ namespace Mindee\V2\Parsing\Job; use DateTime; -use Exception; +use Mindee\Parsing\DateHelper; use Mindee\V2\Parsing\Error\ErrorResponse; use function array_key_exists; @@ -86,9 +86,9 @@ public function __construct(array $rawResponse) $this->error = new ErrorResponse($rawResponse['error']); } - $this->createdAt = $this->parseDate($rawResponse['created_at']); + $this->createdAt = DateHelper::parseDate($rawResponse['created_at']); $this->completedAt = isset($rawResponse['completed_at']) - ? $this->parseDate($rawResponse['completed_at']) + ? DateHelper::parseDate($rawResponse['completed_at']) : null; $this->modelId = $rawResponse['model_id']; @@ -103,22 +103,4 @@ public function __construct(array $rawResponse) } } } - - /** - * Parse a date string into a DateTime object. - * - * @param string|null $dateString Date string to parse. - */ - private function parseDate(?string $dateString): ?DateTime - { - if (empty($dateString)) { - return null; - } - - try { - return new DateTime($dateString); - } catch (Exception) { - return null; - } - } } diff --git a/src/V2/Parsing/Job/JobWebhook.php b/src/V2/Parsing/Job/JobWebhook.php index e12d5ccf..8c9f2f94 100644 --- a/src/V2/Parsing/Job/JobWebhook.php +++ b/src/V2/Parsing/Job/JobWebhook.php @@ -5,7 +5,7 @@ namespace Mindee\V2\Parsing\Job; use DateTime; -use Exception; +use Mindee\Parsing\DateHelper; use Mindee\V2\Parsing\Error\ErrorResponse; /** @@ -40,29 +40,11 @@ public function __construct(array $rawResponse) { $this->id = $rawResponse['id']; $this->createdAt = isset($rawResponse['created_at']) - ? $this->parseDate($rawResponse['created_at']) + ? DateHelper::parseDate($rawResponse['created_at']) : null; $this->status = $rawResponse['status']; $this->error = isset($rawResponse['error']) ? new ErrorResponse($rawResponse['error']) : null; } - - /** - * Parse a date string into a DateTime object. - * - * @param string|null $dateString Date string to parse. - */ - private function parseDate(?string $dateString): ?DateTime - { - if (empty($dateString)) { - return null; - } - - try { - return new DateTime($dateString); - } catch (Exception) { - return null; - } - } } diff --git a/src/V2/Parsing/Search/BaseSearchResponse.php b/src/V2/Parsing/Search/BaseSearchResponse.php index e1002c65..143a07b2 100644 --- a/src/V2/Parsing/Search/BaseSearchResponse.php +++ b/src/V2/Parsing/Search/BaseSearchResponse.php @@ -27,17 +27,25 @@ public function __construct(array $rawResponse) } /** - * Renders the shared pagination metadata block. + * Lines composing the response-specific body (header + items). * - * @return array Lines composing the pagination section. + * @return array Body lines. */ - protected function paginationLines(): array + abstract protected function bodyLines(): array; + + /** + * @return string String representation. + */ + public function __toString(): string { - return [ - 'Pagination Metadata', - '###################', - (string) $this->pagination, - '', - ]; + return implode("\n", array_merge( + $this->bodyLines(), + [ + 'Pagination Metadata', + '###################', + (string) $this->pagination, + '', + ] + )); } } diff --git a/src/V2/Parsing/Search/ModelSearchResponse.php b/src/V2/Parsing/Search/ModelSearchResponse.php index 4f6d0cfa..4b573f81 100644 --- a/src/V2/Parsing/Search/ModelSearchResponse.php +++ b/src/V2/Parsing/Search/ModelSearchResponse.php @@ -24,17 +24,14 @@ public function __construct(array $rawResponse) } /** - * @return string String representation. + * @return array Body lines. */ - public function __toString(): string + protected function bodyLines(): array { - return implode("\n", array_merge( - [ - 'Models', - '######', - (string) $this->models, - ], - $this->paginationLines() - )); + return [ + 'Models', + '######', + (string) $this->models, + ]; } } diff --git a/src/V2/Parsing/Search/RagDocument.php b/src/V2/Parsing/Search/RagDocument.php index ddb2668b..cfb26a45 100644 --- a/src/V2/Parsing/Search/RagDocument.php +++ b/src/V2/Parsing/Search/RagDocument.php @@ -5,7 +5,7 @@ namespace Mindee\V2\Parsing\Search; use DateTimeImmutable; -use Exception; +use Mindee\Parsing\DateHelper; /** * Individual RAG document information. @@ -51,25 +51,7 @@ public function __construct(array $rawResponse) $this->filename = $rawResponse['filename']; $this->createdAt = new DateTimeImmutable($rawResponse['created_at']); $this->totalMatches = $rawResponse['total_matches']; - $this->lastMatchAt = $this->parseDate($rawResponse['last_match_at'] ?? null); + $this->lastMatchAt = DateHelper::parseDateImmutable($rawResponse['last_match_at'] ?? null); $this->status = $rawResponse['status']; } - - /** - * Parse a date string into a DateTimeImmutable object. - * - * @param string|null $dateString Date string to parse. - * @return DateTimeImmutable|null Parsed date or null if empty/invalid. - */ - private function parseDate(?string $dateString): ?DateTimeImmutable - { - if (empty($dateString)) { - return null; - } - try { - return new DateTimeImmutable($dateString); - } catch (Exception) { - return null; - } - } } diff --git a/src/V2/Parsing/Search/RagDocumentSearchResponse.php b/src/V2/Parsing/Search/RagDocumentSearchResponse.php index 01a1a5ae..4157fdef 100644 --- a/src/V2/Parsing/Search/RagDocumentSearchResponse.php +++ b/src/V2/Parsing/Search/RagDocumentSearchResponse.php @@ -24,17 +24,14 @@ public function __construct(array $rawResponse) } /** - * @return string String representation. + * @return array Body lines. */ - public function __toString(): string + protected function bodyLines(): array { - return implode("\n", array_merge( - [ - 'RAG Documents', - '############', - (string) $this->ragDocuments, - ], - $this->paginationLines() - )); + return [ + 'RAG Documents', + '############', + (string) $this->ragDocuments, + ]; } }