diff --git a/src/Responses/FineTuning/ListJobsResponse.php b/src/Responses/FineTuning/ListJobsResponse.php index e7396d0f..9b402412 100644 --- a/src/Responses/FineTuning/ListJobsResponse.php +++ b/src/Responses/FineTuning/ListJobsResponse.php @@ -12,12 +12,12 @@ use OpenAI\Testing\Responses\Concerns\Fakeable; /** - * @implements ResponseContract, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}>, has_more: bool}> + * @implements ResponseContract, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}>, has_more: bool}> */ final class ListJobsResponse implements ResponseContract, ResponseHasMetaInformationContract { /** - * @use ArrayAccessible, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}>, has_more: bool}> + * @use ArrayAccessible, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}>, has_more: bool}> */ use ArrayAccessible; @@ -37,7 +37,7 @@ private function __construct( /** * Acts as static factory, and returns a new Response instance. * - * @param array{object: string, data: array, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}>, has_more: bool} $attributes + * @param array{object: string, data: array, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}>, has_more: bool} $attributes */ public static function from(array $attributes, MetaInformation $meta): self { diff --git a/src/Responses/FineTuning/RetrieveJobResponse.php b/src/Responses/FineTuning/RetrieveJobResponse.php index 641148c3..6d6974f3 100644 --- a/src/Responses/FineTuning/RetrieveJobResponse.php +++ b/src/Responses/FineTuning/RetrieveJobResponse.php @@ -12,12 +12,12 @@ use OpenAI\Testing\Responses\Concerns\Fakeable; /** - * @implements ResponseContract, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}> + * @implements ResponseContract, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}> */ final class RetrieveJobResponse implements ResponseContract, ResponseHasMetaInformationContract { /** - * @use ArrayAccessible, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}> + * @use ArrayAccessible, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code: string, param: ?string, message: string}}> */ use ArrayAccessible; @@ -34,7 +34,7 @@ private function __construct( public readonly int $createdAt, public readonly ?int $finishedAt, public readonly ?string $fineTunedModel, - public readonly RetrieveJobResponseHyperparameters $hyperparameters, + public readonly ?RetrieveJobResponseHyperparameters $hyperparameters, public readonly string $organizationId, public readonly array $resultFiles, public readonly string $status, @@ -48,7 +48,7 @@ private function __construct( /** * Acts as static factory, and returns a new Response instance. * - * @param array{id: string, object: string, model: string, created_at: int, finished_at: ?int, fine_tuned_model: ?string, hyperparameters: array{n_epochs: int|string, batch_size: int|string|null, learning_rate_multiplier: float|string|null}, organization_id: string, result_files: array, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code?: string, param?: ?string, message?: string}} $attributes + * @param array{id: string, object: string, model: string, created_at: int, finished_at: ?int, fine_tuned_model: ?string, hyperparameters?: array{n_epochs: int|string, batch_size: int|string|null, learning_rate_multiplier: float|string|null}, organization_id: string, result_files: array, status: string, validation_file: ?string, training_file: string, trained_tokens: ?int, error: ?array{code?: string, param?: ?string, message?: string}} $attributes */ public static function from(array $attributes, MetaInformation $meta): self { @@ -59,7 +59,9 @@ public static function from(array $attributes, MetaInformation $meta): self $attributes['created_at'], $attributes['finished_at'], $attributes['fine_tuned_model'], - RetrieveJobResponseHyperparameters::from($attributes['hyperparameters']), + isset($attributes['hyperparameters']) + ? RetrieveJobResponseHyperparameters::from($attributes['hyperparameters']) + : null, $attributes['organization_id'], $attributes['result_files'], $attributes['status'], @@ -81,14 +83,13 @@ public static function from(array $attributes, MetaInformation $meta): self */ public function toArray(): array { - return [ + $result = [ 'id' => $this->id, 'object' => $this->object, 'model' => $this->model, 'created_at' => $this->createdAt, 'finished_at' => $this->finishedAt, 'fine_tuned_model' => $this->fineTunedModel, - 'hyperparameters' => $this->hyperparameters->toArray(), 'organization_id' => $this->organizationId, 'result_files' => $this->resultFiles, 'status' => $this->status, @@ -97,5 +98,11 @@ public function toArray(): array 'trained_tokens' => $this->trainedTokens, 'error' => $this->error?->toArray(), ]; + + if ($this->hyperparameters) { + $result['hyperparameters'] = $this->hyperparameters->toArray(); + } + + return $result; } } diff --git a/tests/Fixtures/FineTuning.php b/tests/Fixtures/FineTuning.php index 735c5f57..825e988c 100644 --- a/tests/Fixtures/FineTuning.php +++ b/tests/Fixtures/FineTuning.php @@ -12,11 +12,6 @@ function fineTuningJobCreateResource(): array 'created_at' => 1614807352, 'finished_at' => null, 'fine_tuned_model' => null, - 'hyperparameters' => [ - 'n_epochs' => 9, - 'batch_size' => 'auto', - 'learning_rate_multiplier' => 'auto', - ], 'organization_id' => 'org-jwe45798ASN82s', 'result_files' => [], 'status' => 'created', @@ -24,6 +19,11 @@ function fineTuningJobCreateResource(): array 'training_file' => 'file-abc123', 'trained_tokens' => null, 'error' => null, + 'hyperparameters' => [ + 'n_epochs' => 9, + 'batch_size' => 'auto', + 'learning_rate_multiplier' => 'auto', + ], ]; } @@ -39,11 +39,6 @@ function fineTuningJobRetrieveResource(): array 'created_at' => 1614807352, 'finished_at' => 1692819450, 'fine_tuned_model' => 'ft:gpt-3.5-turbo-0613:jwe-dev::7qnxQ0sQ', - 'hyperparameters' => [ - 'n_epochs' => 9, - 'batch_size' => 1, - 'learning_rate_multiplier' => 2.2, - ], 'organization_id' => 'org-jwe45798ASN82s', 'result_files' => [ 'file-1bl05WrhsKDDEdg8XSP617QF', @@ -53,6 +48,11 @@ function fineTuningJobRetrieveResource(): array 'training_file' => 'file-abc123', 'trained_tokens' => 5049, 'error' => null, + 'hyperparameters' => [ + 'n_epochs' => 9, + 'batch_size' => 1, + 'learning_rate_multiplier' => 2.2, + ], ]; } @@ -68,11 +68,6 @@ function fineTuningFailedJobRetrieveResource(): array 'created_at' => 1614807352, 'finished_at' => null, 'fine_tuned_model' => null, - 'hyperparameters' => [ - 'n_epochs' => 9, - 'batch_size' => 'auto', - 'learning_rate_multiplier' => 'auto', - ], 'organization_id' => 'org-jwe45798ASN82s', 'result_files' => [], 'status' => 'failed', @@ -84,6 +79,11 @@ function fineTuningFailedJobRetrieveResource(): array 'param' => 'training_file', 'message' => 'Training file has 3 example(s), but must have at least 10 examples', ], + 'hyperparameters' => [ + 'n_epochs' => 9, + 'batch_size' => 'auto', + 'learning_rate_multiplier' => 'auto', + ], ]; } diff --git a/tests/Responses/FineTuning/RetrieveJobResponse.php b/tests/Responses/FineTuning/RetrieveJobResponse.php index c85b5115..a458acd5 100644 --- a/tests/Responses/FineTuning/RetrieveJobResponse.php +++ b/tests/Responses/FineTuning/RetrieveJobResponse.php @@ -47,6 +47,26 @@ ->meta()->toBeInstanceOf(MetaInformation::class); }); +test('from retrieve response with missing hyperparameters', function () { + $payload = fineTuningJobRetrieveResource(); + unset($payload['hyperparameters']); + $result = RetrieveJobResponse::from($payload, meta()); + + expect($result) + ->toBeInstanceOf(RetrieveJobResponse::class) + ->hyperparameters->toBeNull(); +}); + +test('from retrieve response with null hyperparameters', function () { + $payload = fineTuningJobRetrieveResource(); + $payload['hyperparameters'] = null; + $result = RetrieveJobResponse::from($payload, meta()); + + expect($result) + ->toBeInstanceOf(RetrieveJobResponse::class) + ->hyperparameters->toBeNull(); +}); + test('as array accessible', function () { $result = RetrieveJobResponse::from(fineTuningJobCreateResource(), meta());