120 lines
3.1 KiB
PHP
Executable File
120 lines
3.1 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Modules\ChatGPT\Services;
|
|
|
|
use Illuminate\Http\Client\PendingRequest;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Modules\ChatGPT\Exceptions\OpenAiFileException;
|
|
|
|
class OpenAiFileService
|
|
{
|
|
private const BASE_URL = 'https://api.openai.com/v1';
|
|
|
|
public function __construct(private readonly string $apiKey) {}
|
|
|
|
/**
|
|
* List all OpenAI API files visible to the configured API key.
|
|
*
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
public function listFiles(): array
|
|
{
|
|
$files = [];
|
|
$after = null;
|
|
|
|
do {
|
|
$query = ['limit' => 100];
|
|
|
|
if (is_string($after) && $after !== '') {
|
|
$query['after'] = $after;
|
|
}
|
|
|
|
$response = $this->client()
|
|
->get(self::BASE_URL . '/files', $query);
|
|
|
|
if ($response->failed()) {
|
|
throw new OpenAiFileException('OpenAI file list request failed: ' . $response->body());
|
|
}
|
|
|
|
$payload = $response->json();
|
|
$batch = $payload['data'] ?? [];
|
|
|
|
foreach ($batch as $file) {
|
|
if (is_array($file)) {
|
|
$files[] = $file;
|
|
}
|
|
}
|
|
|
|
$hasMore = (bool) ($payload['has_more'] ?? false);
|
|
$after = $payload['last_id'] ?? null;
|
|
} while ($hasMore && is_string($after) && $after !== '');
|
|
|
|
return $files;
|
|
}
|
|
|
|
/**
|
|
* Delete one OpenAI API file by ID.
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function deleteFile(string $fileId): array
|
|
{
|
|
$response = $this->client()
|
|
->delete(self::BASE_URL . '/files/' . rawurlencode($fileId));
|
|
|
|
if ($response->failed()) {
|
|
throw new OpenAiFileException("OpenAI file delete request failed for {$fileId}: " . $response->body());
|
|
}
|
|
|
|
return $response->json() ?? [];
|
|
}
|
|
|
|
/**
|
|
* Delete every OpenAI API file visible to the configured API key.
|
|
*
|
|
* @return array{listed:int, deleted:int, failed:int, failures:array<int, array{file_id:string, error:string}>}
|
|
*/
|
|
public function deleteAllFiles(): array
|
|
{
|
|
$files = $this->listFiles();
|
|
$deleted = 0;
|
|
$failures = [];
|
|
|
|
foreach ($files as $file) {
|
|
$fileId = (string) ($file['id'] ?? '');
|
|
|
|
if ($fileId === '') {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$this->deleteFile($fileId);
|
|
$deleted++;
|
|
} catch (OpenAiFileException $exception) {
|
|
$failures[] = [
|
|
'file_id' => $fileId,
|
|
'error' => $exception->getMessage(),
|
|
];
|
|
}
|
|
}
|
|
|
|
return [
|
|
'listed' => count($files),
|
|
'deleted' => $deleted,
|
|
'failed' => count($failures),
|
|
'failures' => $failures,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Build the authenticated OpenAI HTTP client.
|
|
*/
|
|
private function client(): PendingRequest
|
|
{
|
|
return Http::withToken($this->apiKey)
|
|
->acceptJson()
|
|
->timeout(60)
|
|
->retry(2, 500);
|
|
}
|
|
}
|