Files
fotospiel-app/app/Services/AiEditing/Safety/AiAbuseEscalationService.php
Codex Agent 1d2242fb4d
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run
tests / ui (push) Waiting to run
feat(ai): finalize AI magic edits epic rollout and operations
2026-02-06 22:41:51 +01:00

65 lines
2.3 KiB
PHP

<?php
namespace App\Services\AiEditing\Safety;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class AiAbuseEscalationService
{
public const REASON_CODE = 'abuse_escalation_threshold_reached';
/**
* @return array{type:string,count:int,threshold:int,escalated:bool,reason_code:?string}
*/
public function recordPromptBlock(int $tenantId, int $eventId, string $scope): array
{
return $this->record('prompt_block', $tenantId, $eventId, $scope);
}
/**
* @return array{type:string,count:int,threshold:int,escalated:bool,reason_code:?string}
*/
public function recordOutputBlock(int $tenantId, int $eventId, string $scope): array
{
return $this->record('output_block', $tenantId, $eventId, $scope);
}
/**
* @return array{type:string,count:int,threshold:int,escalated:bool,reason_code:?string}
*/
private function record(string $type, int $tenantId, int $eventId, string $scope): array
{
$threshold = max(1, (int) config('ai-editing.abuse.escalation_threshold_per_hour', 25));
$cooldownMinutes = max(1, (int) config('ai-editing.abuse.escalation_cooldown_minutes', 30));
$bucket = now()->format('YmdH');
$counterKey = sprintf('ai-editing:abuse:%s:tenant:%d:event:%d:hour:%s', $type, $tenantId, $eventId, $bucket);
Cache::add($counterKey, 0, now()->addHours(2));
$count = (int) Cache::increment($counterKey);
$escalated = $count >= $threshold;
if ($escalated) {
$cooldownKey = sprintf('ai-editing:abuse:%s:tenant:%d:event:%d:cooldown', $type, $tenantId, $eventId);
if (Cache::add($cooldownKey, 1, now()->addMinutes($cooldownMinutes))) {
Log::warning('AI abuse escalation threshold reached', [
'tenant_id' => $tenantId,
'event_id' => $eventId,
'type' => $type,
'count' => $count,
'threshold' => $threshold,
'scope_hash' => hash('sha256', $scope),
]);
}
}
return [
'type' => $type,
'count' => $count,
'threshold' => $threshold,
'escalated' => $escalated,
'reason_code' => $escalated ? self::REASON_CODE : null,
];
}
}