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

declare(strict_types=1);

namespace OpenAI\Contracts;

/**
* @internal
*/
interface Response
{
/**
* Returns the response on the array format, the original format.
*
* @return array<array-key, mixed>
*/
public function toArray(): array;
}
16 changes: 16 additions & 0 deletions src/Enums/Moderation/Category.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace OpenAI\Enums\Moderation;

enum Category: string
{
case Hate = 'hate';
case HateThreatening = 'hate/threatening';
case SelfHarm = 'self-harm';
case Sexual = 'sexual';
case SexualMinors = 'sexual/minors';
case Violence = 'violence';
case ViolenceGraphic = 'violence/graphic';
}
32 changes: 32 additions & 0 deletions src/Factories/Responses/Moderations/CreateResponseFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace OpenAI\Factories\Responses\Moderations;

use OpenAI\Responses\Moderations\CreateResponse;

final class CreateResponseFactory
{
/**
* @param array<string, array<array-key, array<string, array<string, bool|float>>>|string> $attributes
*/
public static function new(array $attributes): CreateResponse
{
return (new self)->make(
attributes: $attributes,
);
}

/**
* @param array<string, array<array-key, array<string, array<string, bool|float>>>|string> $attributes
*/
public function make(array $attributes): CreateResponse
{
return new CreateResponse(
id: strval($attributes['id']),
model: strval($attributes['model']),
results: CreateResponseModerationResultFactory::collection($attributes['results']), /** @phpstan-ignore-line */
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace OpenAI\Factories\Responses\Moderations;

use OpenAI\Enums\Moderation\Category;
use OpenAI\Responses\Moderations\CreateResponseModerationCategory;

final class CreateResponseModerationCategoryFactory
{
/**
* @param array<array-key, array<string, bool|float|string>> $results
* @return CreateResponseModerationCategory[]
*/
public static function collection(array $results): array
{
return array_map(fn ($result): CreateResponseModerationCategory => static::new($result), $results);
}

/**
* @param array<string, bool|float|string> $attributes
*/
public static function new(array $attributes): CreateResponseModerationCategory
{
return (new self)->make(
attributes: $attributes,
);
}

/**
* @param array<string, bool|float|string> $attributes
*/
public function make(array $attributes): CreateResponseModerationCategory
{
return new CreateResponseModerationCategory(
category: Category::from((string) $attributes['category']),
violated: (bool) $attributes['violated'],
score: (float) $attributes['score'],
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace OpenAI\Factories\Responses\Moderations;

use OpenAI\Enums\Moderation\Category;
use OpenAI\Responses\Moderations\CreateResponseModerationResult;

final class CreateResponseModerationResultFactory
{
/**
* @param array<array-key, array<string, array<string, bool|float>>> $results
* @return CreateResponseModerationResult[]
*/
public static function collection(array $results): array
{
return array_map(fn ($result): CreateResponseModerationResult => static::new($result), $results);
}

/**
* @param array<string, array<string, bool|float>> $attributes
*/
public static function new(array $attributes): CreateResponseModerationResult
{
return (new self)->make(
attributes: $attributes,
);
}

/**
* @param array<string, array<string, bool|float>> $attributes
*/
public function make(array $attributes): CreateResponseModerationResult
{
$categories = array_map(fn (Category $category): array => [
'category' => $category->value,
'violated' => $attributes['categories'][$category->value],
'score' => $attributes['category_scores'][$category->value],
], Category::cases());

return new CreateResponseModerationResult(
categories: CreateResponseModerationCategoryFactory::collection($categories),
flagged: (bool) ($attributes['flagged']),
);
}
}
9 changes: 5 additions & 4 deletions src/Resources/Moderations.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace OpenAI\Resources;

use OpenAI\Factories\Responses\Moderations\CreateResponseFactory;
use OpenAI\Responses\Moderations\CreateResponse;
use OpenAI\ValueObjects\Transporter\Payload;

final class Moderations
Expand All @@ -16,15 +18,14 @@ final class Moderations
* @see https://beta.openai.com/docs/api-reference/moderations/create
*
* @param array<string, mixed> $parameters
* @return array<string, mixed>
*/
public function create(array $parameters): array
public function create(array $parameters): CreateResponse
{
$payload = Payload::create('moderations', $parameters);

/** @var array<string, mixed> $result */
/** @var array<string, array<array-key, array<string, array<string, bool|float>>>|string> $result */
$result = $this->transporter->requestObject($payload);

return $result;
return CreateResponseFactory::new($result);
}
}
32 changes: 32 additions & 0 deletions src/Responses/Moderations/CreateResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace OpenAI\Responses\Moderations;

use OpenAI\Contracts\Response;

final class CreateResponse implements Response
{
/**
* @param array<array-key, CreateResponseModerationResult> $results
*/
public function __construct(
public readonly string $id,
public readonly string $model,
public readonly array $results,
) {
}

/**
* @return array<string, mixed>
*/
public function toArray(): array
{
return [
'id' => $this->id,
'model' => $this->model,
'results' => array_map(fn (CreateResponseModerationResult $result): array => $result->toArray(), $this->results),
];
}
}
17 changes: 17 additions & 0 deletions src/Responses/Moderations/CreateResponseModerationCategory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace OpenAI\Responses\Moderations;

use OpenAI\Enums\Moderation\Category;

final class CreateResponseModerationCategory
{
public function __construct(
public readonly Category $category,
public readonly bool $violated,
public readonly float $score,
) {
}
}
36 changes: 36 additions & 0 deletions src/Responses/Moderations/CreateResponseModerationResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace OpenAI\Responses\Moderations;

final class CreateResponseModerationResult
{
/**
* @param array<array-key, CreateResponseModerationCategory> $categories
*/
public function __construct(
public readonly array $categories,
public readonly bool $flagged,
) {
}

/**
* @return array<string, mixed>
*/
public function toArray(): array
{
$categories = [];
$category_scores = [];
foreach ($this->categories as $category) {
$categories[$category->category->value] = $category->violated;
$category_scores[$category->category->value] = $category->score;
}

return [
'categories' => $categories,
'category_scores' => $category_scores,
'flagged' => $this->flagged,
];
}
}
1 change: 1 addition & 0 deletions src/ValueObjects/Transporter/Payload.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Request as Psr7Request;
use OpenAI\Contracts\Request;
use OpenAI\Enums\Transporter\ContentType;
use OpenAI\Enums\Transporter\Method;
use OpenAI\ValueObjects\ResourceUri;
Expand Down
13 changes: 7 additions & 6 deletions tests/Fixtures/Completion.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ function completion(): array
'object' => 'text_completion',
'created' => 1664136088,
'model' => 'davinci',
'choices' => [[
'text' => "el, she elaborates more on the Corruptor's role, suggesting K",
'index' => 0,
'logprobs' => null,
'finish_reason' => 'length',
],
'choices' => [
[
'text' => "el, she elaborates more on the Corruptor's role, suggesting K",
'index' => 0,
'logprobs' => null,
'finish_reason' => 'length',
],
],
'usage' => [
'prompt_tokens' => 1,
Expand Down
22 changes: 21 additions & 1 deletion tests/Resources/Moderations.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<?php

use OpenAI\Enums\Moderation\Category;
use OpenAI\Responses\Moderations\CreateResponse;
use OpenAI\Responses\Moderations\CreateResponseModerationCategory;
use OpenAI\Responses\Moderations\CreateResponseModerationResult;

test('create', function () {
$client = mockClient('POST', 'moderations', [
'model' => 'text-moderation-latest',
Expand All @@ -11,5 +16,20 @@
'input' => 'I want to kill them.',
]);

expect($result)->toBeArray()->toBe(moderationResource());
expect($result)
->toBeInstanceOf(CreateResponse::class)
->id->toBe('modr-5MWoLO')
->model->toBe('text-moderation-001')
->results->toBeArray()->toHaveCount(1)
->results->each->toBeInstanceOf(CreateResponseModerationResult::class);

expect($result->results[0])
->flagged->toBeTrue()
->categories->toHaveCount(7)
->each->toBeInstanceOf(CreateResponseModerationCategory::class);

expect($result->results[0]->categories[0])
->category->toBe(Category::Hate)
->violated->toBe(false)
->score->toBe(0.22714105248451233);
});
24 changes: 24 additions & 0 deletions tests/Responses/Moderations/CreateResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

use OpenAI\Factories\Responses\Moderations\CreateResponseFactory;
use OpenAI\Responses\Moderations\CreateResponse;
use OpenAI\Responses\Moderations\CreateResponseModerationResult;

test('build new create moderation response', function () {
$moderation = CreateResponseFactory::new(moderationResource());

expect($moderation)
->toBeInstanceOf(CreateResponse::class)
->id->toBe('modr-5MWoLO')
->model->toBe('text-moderation-001')
->results->toBeArray()->toHaveCount(1)
->results->each->toBeInstanceOf(CreateResponseModerationResult::class);
});

test('returns the original api response', function () {
$moderation = CreateResponseFactory::new(moderationResource());

expect($moderation->toArray())
->toBeArray()
->toBe(moderationResource());
});
17 changes: 17 additions & 0 deletions tests/Responses/Moderations/CreateResponseModerationCategory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

use OpenAI\Enums\Moderation\Category;
use OpenAI\Factories\Responses\Moderations\CreateResponseModerationCategoryFactory;

test('build new create response moderation category', function () {
$category = CreateResponseModerationCategoryFactory::new([
'category' => Category::Hate->value,
'violated' => true,
'score' => 0.1234,
]);

expect($category)
->category->toBe(Category::Hate)
->violated->toBe(true)
->score->toBe(0.1234);
});
Loading