Implement creator studio and upload updates

This commit is contained in:
2026-04-04 10:12:02 +02:00
parent 1da7d3bf88
commit 0b216b7ecd
15107 changed files with 31206 additions and 626514 deletions

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace App\Data\Images;
final readonly class CropBoxData
{
public function __construct(
public int $x,
public int $y,
public int $width,
public int $height,
) {
}
public function clampToImage(int $imageWidth, int $imageHeight): self
{
$width = max(1, min($this->width, max(1, $imageWidth)));
$height = max(1, min($this->height, max(1, $imageHeight)));
$x = max(0, min($this->x, max(0, $imageWidth - $width)));
$y = max(0, min($this->y, max(0, $imageHeight - $height)));
return new self($x, $y, $width, $height);
}
public function centerX(): float
{
return $this->x + ($this->width / 2);
}
public function centerY(): float
{
return $this->y + ($this->height / 2);
}
/**
* @return array{x: int, y: int, width: int, height: int}
*/
public function toArray(): array
{
return [
'x' => $this->x,
'y' => $this->y,
'width' => $this->width,
'height' => $this->height,
];
}
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Data\Images;
final readonly class SquareThumbnailResultData
{
/**
* @param array<string, mixed> $meta
*/
public function __construct(
public string $destinationPath,
public CropBoxData $cropBox,
public string $cropMode,
public int $sourceWidth,
public int $sourceHeight,
public int $targetWidth,
public int $targetHeight,
public int $outputWidth,
public int $outputHeight,
public ?string $detectionReason = null,
public array $meta = [],
) {
}
/**
* @return array<string, mixed>
*/
public function toArray(): array
{
return [
'destination_path' => $this->destinationPath,
'crop_mode' => $this->cropMode,
'source_width' => $this->sourceWidth,
'source_height' => $this->sourceHeight,
'target_width' => $this->targetWidth,
'target_height' => $this->targetHeight,
'output_width' => $this->outputWidth,
'output_height' => $this->outputHeight,
'detection_reason' => $this->detectionReason,
'crop_box' => $this->cropBox->toArray(),
'meta' => $this->meta,
];
}
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace App\Data\Images;
final readonly class SubjectDetectionResultData
{
/**
* @param array<string, mixed> $meta
*/
public function __construct(
public CropBoxData $cropBox,
public string $strategy,
public ?string $reason = null,
public float $confidence = 0.0,
public array $meta = [],
) {
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace App\Data\Moderation;
use App\Enums\ModerationStatus;
use App\Enums\ModerationSeverity;
class ModerationResultData
{
public function __construct(
public readonly int $score,
public readonly ModerationSeverity $severity,
public readonly ModerationStatus $status,
public readonly array $reasons,
public readonly array $matchedLinks,
public readonly array $matchedDomains,
public readonly array $matchedKeywords,
public readonly string $contentHash,
public readonly string $scannerVersion,
public readonly array $ruleHits = [],
public readonly ?string $contentHashNormalized = null,
public readonly ?string $groupKey = null,
public readonly ?int $userRiskScore = null,
public readonly bool $autoHideRecommended = false,
public readonly ?string $contentTargetType = null,
public readonly ?int $contentTargetId = null,
public readonly ?string $campaignKey = null,
public readonly ?int $clusterScore = null,
public readonly ?string $clusterReason = null,
public readonly ?string $policyName = null,
public readonly ?int $priorityScore = null,
public readonly ?string $reviewBucket = null,
public readonly ?string $escalationStatus = null,
public readonly ?string $aiProvider = null,
public readonly ?string $aiLabel = null,
public readonly ?string $aiSuggestedAction = null,
public readonly ?int $aiConfidence = null,
public readonly ?string $aiExplanation = null,
public readonly array $aiRawResponse = [],
public readonly array $scoreBreakdown = [],
) {}
public function isClean(): bool
{
return $this->severity === ModerationSeverity::Low && $this->score === 0;
}
public function isSuspicious(): bool
{
return $this->score >= app('config')->get('content_moderation.severity_thresholds.medium', 30);
}
public function toArray(): array
{
return [
'score' => $this->score,
'severity' => $this->severity->value,
'status' => $this->status->value,
'reasons' => $this->reasons,
'matched_links' => $this->matchedLinks,
'matched_domains' => $this->matchedDomains,
'matched_keywords' => $this->matchedKeywords,
'content_hash' => $this->contentHash,
'scanner_version' => $this->scannerVersion,
'rule_hits' => $this->ruleHits,
'content_hash_normalized' => $this->contentHashNormalized,
'group_key' => $this->groupKey,
'user_risk_score' => $this->userRiskScore,
'auto_hide_recommended' => $this->autoHideRecommended,
'content_target_type' => $this->contentTargetType,
'content_target_id' => $this->contentTargetId,
'campaign_key' => $this->campaignKey,
'cluster_score' => $this->clusterScore,
'cluster_reason' => $this->clusterReason,
'policy_name' => $this->policyName,
'priority_score' => $this->priorityScore,
'review_bucket' => $this->reviewBucket,
'escalation_status' => $this->escalationStatus,
'ai_provider' => $this->aiProvider,
'ai_label' => $this->aiLabel,
'ai_suggested_action' => $this->aiSuggestedAction,
'ai_confidence' => $this->aiConfidence,
'ai_explanation' => $this->aiExplanation,
'ai_raw_response' => $this->aiRawResponse,
'score_breakdown' => $this->scoreBreakdown,
];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Data\Moderation;
class ModerationSuggestionData
{
/**
* @param array<string, mixed> $rawResponse
* @param array<int, string> $campaignTags
*/
public function __construct(
public readonly string $provider,
public readonly ?string $suggestedLabel = null,
public readonly ?string $suggestedAction = null,
public readonly ?int $confidence = null,
public readonly ?string $explanation = null,
public readonly array $campaignTags = [],
public readonly array $rawResponse = [],
) {
}
public function isEmpty(): bool
{
return $this->suggestedLabel === null
&& $this->suggestedAction === null
&& $this->confidence === null
&& $this->explanation === null;
}
}