Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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/DataObject.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 DataObject
Comment thread
gehrisandro marked this conversation as resolved.
Outdated
{
/**
* Return the data as array.
Comment thread
gehrisandro marked this conversation as resolved.
Outdated
*
* @return array<array-key, mixed>
*/
public function toArray(): array;
}
30 changes: 30 additions & 0 deletions src/DataObjects/Moderation/Moderation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace OpenAI\DataObjects\Moderation;
Comment thread
gehrisandro marked this conversation as resolved.
Outdated

use OpenAI\Contracts\DataObject;

final class Moderation implements DataObject
Comment thread
gehrisandro marked this conversation as resolved.
Outdated
{
/**
* @param array<array-key, ModerationResult> $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 (ModerationResult $result): array => $result->toArray(), $this->results),
];
}
}
28 changes: 28 additions & 0 deletions src/DataObjects/Moderation/ModerationCategory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace OpenAI\DataObjects\Moderation;
Comment thread
gehrisandro marked this conversation as resolved.
Outdated

use OpenAI\Contracts\DataObject;
use OpenAI\Enums\Moderation\Category;

final class ModerationCategory implements DataObject
Comment thread
gehrisandro marked this conversation as resolved.
Outdated
{
public function __construct(
public readonly Category $category,
public readonly bool $violated,
public readonly float $score,
) {
}

/**
* @return array<string, string|float|bool>
*/
public function toArray(): array
{
return [
'category' => $this->category->value,
'violated' => $this->violated,
'score' => $this->score,
];
}
}
28 changes: 28 additions & 0 deletions src/DataObjects/Moderation/ModerationResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace OpenAI\DataObjects\Moderation;

use OpenAI\Contracts\DataObject;

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

/**
* @return array<string, mixed>
*/
public function toArray(): array
{
return [
'categories' => array_map(fn (ModerationCategory $category): array => $category->toArray(), $this->categories),
'flagged' => $this->flagged,
];
}
}
14 changes: 14 additions & 0 deletions src/Enums/Moderation/Category.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

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';
}
40 changes: 40 additions & 0 deletions src/Factories/DataObjects/Moderation/ModerationCategoryFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace OpenAI\Factories\DataObjects\Moderation;

use OpenAI\DataObjects\Moderation\ModerationCategory;
use OpenAI\Enums\Moderation\Category;

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

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

/**
* @param array<string, bool|float|string> $attributes
*/
public function make(array $attributes): ModerationCategory
{
return new ModerationCategory(
category: Category::from((string) $attributes['category']),
violated: (bool) $attributes['violated'],
score: (float) $attributes['score'],
);
}
}
30 changes: 30 additions & 0 deletions src/Factories/DataObjects/Moderation/ModerationFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace OpenAI\Factories\DataObjects\Moderation;

use OpenAI\DataObjects\Moderation\Moderation;

final class ModerationFactory
{
/**
* @param array<string, array<array-key, array<string, array<string, bool|float>>>|string> $attributes
*/
public static function new(array $attributes): Moderation
{
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): Moderation
{
return new Moderation(
id: strval($attributes['id']),
model: strval($attributes['model']),
results: ModerationResultFactory::collection($attributes['results']), /** @phpstan-ignore-line */
);
}
}
45 changes: 45 additions & 0 deletions src/Factories/DataObjects/Moderation/ModerationResultFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace OpenAI\Factories\DataObjects\Moderation;

use OpenAI\DataObjects\Moderation\ModerationResult;
use OpenAI\Enums\Moderation\Category;

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

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

/**
* @param array<string, array<string, bool|float>> $attributes
*/
public function make(array $attributes): ModerationResult
{
$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 ModerationResult(
categories: ModerationCategoryFactory::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\DataObjects\Moderation\Moderation;
use OpenAI\Factories\DataObjects\Moderation\ModerationFactory;
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): Moderation
{
$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 ModerationFactory::new($result);
}
}
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
27 changes: 27 additions & 0 deletions tests/DataObjects/Moderation/Moderation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

use OpenAI\DataObjects\Moderation\Moderation;
use OpenAI\DataObjects\Moderation\ModerationResult;
use OpenAI\Factories\DataObjects\Moderation\ModerationFactory;

test('build new moderation', function () {
$moderation = ModerationFactory::new(moderationResource());

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

test('create array from moderation', function () {
$moderation = ModerationFactory::new(moderationResource());

expect($moderation->toArray())
->toBeArray()
->id->toBe('modr-5MWoLO')
->model->toBe('text-moderation-001')
->results->toBeArray()->toHaveCount(1)
->results->each->toBeArray();
});
31 changes: 31 additions & 0 deletions tests/DataObjects/Moderation/ModerationCategory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

use OpenAI\Enums\Moderation\Category;
use OpenAI\Factories\DataObjects\Moderation\ModerationCategoryFactory;

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

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

test('create array from moderation category', function () {
$raw = [
'category' => Category::Hate->value,
'violated' => true,
'score' => 0.1234,
];

$category = ModerationCategoryFactory::new($raw);

expect($category->toArray())
->toBeArray()
->toBe($raw);
});
22 changes: 22 additions & 0 deletions tests/DataObjects/Moderation/ModerationResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

use OpenAI\DataObjects\Moderation\ModerationCategory;
use OpenAI\Factories\DataObjects\Moderation\ModerationResultFactory;

test('build new moderation result', function () {
$result = ModerationResultFactory::new(moderationResource()['results'][0]);

expect($result)
->flagged->toBeTrue()
->categories->toHaveCount(7)
->each->toBeInstanceOf(ModerationCategory::class);
});

test('create array from moderation result', function () {
$result = ModerationResultFactory::new(moderationResource()['results'][0]);

expect($result->toArray())
->flagged->toBeTrue()
->categories->toHaveCount(7)
->each->toBeArray();
});
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\DataObjects\Moderation\Moderation;
use OpenAI\DataObjects\Moderation\ModerationCategory;
use OpenAI\DataObjects\Moderation\ModerationResult;
use OpenAI\Enums\Moderation\Category;

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(Moderation::class)
->id->toBe('modr-5MWoLO')
->model->toBe('text-moderation-001')
->results->toBeArray()->toHaveCount(1)
->results->each->toBeInstanceOf(ModerationResult::class);

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

expect($result->results[0]->categories[0])
->category->toBe(Category::Hate)
->violated->toBe(false)
->score->toBe(0.22714105248451233);
});