Skip to content

Commit 31bb32a

Browse files
committed
Initial commit
0 parents  commit 31bb32a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+3767
-0
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
OPENAI_BASE_URL=https://api.openai.com

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/vendor/
2+
/references/
3+
/debug/
4+
/.env
5+
composer.lock

LICENSE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
MIT License
2+
3+
Copyright (c) sentosango
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
7+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# PHP client for OpenAI API.
2+
3+
This is a PHP client for the OpenAI API.
4+
5+
## Installation
6+
7+
Install the package via composer:
8+
9+
```bash
10+
composer require php-client/openai
11+
```
12+
13+
## Usage
14+
15+
```php
16+
use PhpClient\OpenAI\OpenAI;
17+
18+
$syncthing = new OpenAI(
19+
baseUrl: 'https://api.openai.com',
20+
token: 'YOUR_API_TOKEN',
21+
);
22+
23+
$response = $syncthing->api->chat()->createChatCompletion(
24+
model: 'gpt-4o',
25+
messages: [
26+
['role' => 'user', 'content' => 'Hello'],
27+
],
28+
);
29+
30+
echo $response->json(key: 'choices.0.message.content');
31+
32+
// or
33+
34+
foreach ($response->json(key: 'choices') as $choice) {
35+
echo $choice['message']['content'];
36+
}
37+
38+
```
39+
40+
## List of available API methods
41+
42+
- Audio
43+
- Create speech|transcription|translation
44+
- Chat
45+
- Create chat completion
46+
- Embeddings
47+
- Create embeddings
48+
- Fine-tuning
49+
- Create|Retrieve|Cancel fine-tuning job
50+
- List fine-tuning jobs|events|checkpoints
51+
- Batch
52+
- Create|Retrieve|Cancel|List batch
53+
- Files
54+
- List files
55+
- Upload|Retrieve|Delete file
56+
- Retrieve file content
57+
- Uploads
58+
- Create|Complete|Cancel upload
59+
- Add upload part
60+
- Images
61+
- Create image
62+
- Create image edit|variation
63+
- Models
64+
- List models
65+
- Retrieve model
66+
- Delete fine-tuned model
67+
- Moderations
68+
- Create moderation
69+
- LegacyCompletions
70+
- Create completion
71+
72+
## Not implemented API methods (in development)
73+
74+
- Assistants
75+
- Administration
76+
- Realtime
77+
- Legacy
78+
79+
## License
80+
81+
This package is released under the [MIT License](LICENSE.md).

composer.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "php-client/openai",
3+
"description": "PHP Client for OpenAI API",
4+
"keywords": ["openai", "api", "client", "saloon", "gpt"],
5+
"type": "library",
6+
"license": "MIT",
7+
"require": {
8+
"php": "^8.3",
9+
"saloonphp/saloon": "^3.10"
10+
},
11+
"require-dev": {
12+
"symfony/var-dumper": "^7.2",
13+
"vlucas/phpdotenv": "^5.6"
14+
},
15+
"autoload": {
16+
"psr-4": {
17+
"PhpClient\\OpenAI\\": "src/"
18+
}
19+
},
20+
"minimum-stability": "stable"
21+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpClient\OpenAI\Helpers;
6+
7+
use InvalidArgumentException;
8+
use Psr\Http\Message\StreamInterface;
9+
use Saloon\Data\MultipartValue;
10+
11+
use function is_int;
12+
use function is_resource;
13+
use function is_string;
14+
15+
final class MultipartValueHelper
16+
{
17+
/**
18+
* @param MultipartValue|string $file MultipartValue representation of file or string path to file
19+
* @return MultipartValue
20+
*/
21+
public static function ensureFile(MultipartValue|string $file): MultipartValue
22+
{
23+
if (is_string(value: $file)) {
24+
if (!file_exists(filename: $file)) {
25+
throw new InvalidArgumentException(message: 'File does not exist');
26+
}
27+
28+
$file = new MultipartValue(
29+
name: basename(path: $file),
30+
value: $file,
31+
);
32+
}
33+
34+
return $file;
35+
}
36+
37+
/**
38+
* @param MultipartValue|StreamInterface|resource|string|int $data
39+
* @return MultipartValue
40+
*/
41+
public static function ensureData(mixed $data): MultipartValue
42+
{
43+
if ($data instanceof MultipartValue) {
44+
return $data;
45+
}
46+
47+
if (
48+
$data instanceof StreamInterface
49+
|| is_resource(value: $data)
50+
|| is_string(value: $data)
51+
|| is_int(value: $data)
52+
) {
53+
return new MultipartValue(name: '', value: $data);
54+
}
55+
56+
throw new InvalidArgumentException(
57+
message: 'Data must be a MultipartValue, StreamInterface, resource, string or integer.',
58+
);
59+
}
60+
}

src/OpenAI.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpClient\OpenAI;
6+
7+
use PhpClient\OpenAI\Resources\Api;
8+
use Saloon\Http\Connector;
9+
use Saloon\Traits\Plugins\HasTimeout;
10+
11+
use function array_filter;
12+
13+
/**
14+
* PHP Client for OpenAI API.
15+
*
16+
* @see https://platform.openai.com/docs/api-reference/introduction
17+
* @version Relevant for 2025-02-13, OpenAI API v1
18+
*/
19+
final class OpenAI extends Connector
20+
{
21+
use HasTimeout;
22+
23+
public readonly Api $api;
24+
public readonly float $requestTimeout;
25+
26+
/**
27+
* @param string $baseUrl The base URL of the OpenAI server
28+
*/
29+
public function __construct(
30+
private readonly string $baseUrl,
31+
private readonly null|string $token = null,
32+
private readonly null|string $organization = null,
33+
private readonly null|string $project = null,
34+
) {
35+
$this->api = new Api(connector: $this);
36+
$this->requestTimeout = 300.0;
37+
}
38+
39+
public function resolveBaseUrl(): string
40+
{
41+
return $this->baseUrl;
42+
}
43+
44+
protected function defaultHeaders(): array
45+
{
46+
return array_filter(
47+
array: [
48+
'Accept' => 'application/json',
49+
'Authorization' => $this->token ? "Bearer $this->token" : null,
50+
'Content-Type' => 'application/json',
51+
'OpenAI-Organization' => $this->organization,
52+
'OpenAI-Project' => $this->project,
53+
],
54+
);
55+
}
56+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpClient\OpenAI\Requests\Audio;
6+
7+
use Saloon\Contracts\Body\HasBody;
8+
use Saloon\Enums\Method;
9+
use Saloon\Http\Request;
10+
use Saloon\Traits\Body\HasJsonBody;
11+
12+
use function array_filter;
13+
14+
/**
15+
* Generates audio from the input text.
16+
*
17+
* @see https://platform.openai.com/docs/api-reference/audio/createSpeech
18+
* @version Relevant for 2025-02-13, OpenAI API v1
19+
*/
20+
final class CreateSpeechRequest extends Request implements HasBody
21+
{
22+
use HasJsonBody;
23+
24+
protected Method $method = Method::POST;
25+
26+
/**
27+
* @param string $model One of the available TTS models: `tts-1` or `tts-1-hd`.
28+
*
29+
* @param string $input The text to generate audio for. The maximum length is 4096 characters.
30+
*
31+
* @param string $voice The voice to use when generating the audio. Supported voices are `alloy`, `ash`,
32+
* `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`.
33+
*
34+
* @param string|null $responseFormat The format to audio in. Supported formats are `mp3`, `opus`, `aac`,
35+
* `flac`, `wav`, and `pcm`.
36+
*
37+
* @param float|null $speed The speed of the generated audio. Select a value from `0.25` to `4.0`.
38+
* `1.0` is the default.
39+
*/
40+
public function __construct(
41+
public readonly string $model,
42+
public readonly string $input,
43+
public readonly string $voice,
44+
public readonly null|string $responseFormat = null,
45+
public readonly null|float $speed = null,
46+
) {}
47+
48+
public function resolveEndpoint(): string
49+
{
50+
return '/v1/audio/speech';
51+
}
52+
53+
protected function defaultBody(): array
54+
{
55+
return array_filter(
56+
array: [
57+
'model' => $this->model,
58+
'input' => $this->input,
59+
'voice' => $this->voice,
60+
'response_format' => $this->responseFormat,
61+
'speed' => $this->speed,
62+
],
63+
callback: static fn(mixed $value): bool => $value !== null,
64+
);
65+
}
66+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpClient\OpenAI\Requests\Audio;
6+
7+
use PhpClient\OpenAI\Helpers\MultipartValueHelper;
8+
use Saloon\Contracts\Body\HasBody;
9+
use Saloon\Data\MultipartValue;
10+
use Saloon\Enums\Method;
11+
use Saloon\Http\Request;
12+
use Saloon\Traits\Body\HasMultipartBody;
13+
14+
use function array_filter;
15+
16+
/**
17+
* Transcribes audio into the input language.
18+
*
19+
* @see https://platform.openai.com/docs/api-reference/audio/createTranscription
20+
* @version Relevant for 2025-02-13, OpenAI API v1
21+
*/
22+
final class CreateTranscriptionRequest extends Request implements HasBody
23+
{
24+
use HasMultipartBody;
25+
26+
protected Method $method = Method::POST;
27+
28+
/**
29+
* @param MultipartValue|string $file The audio file (object or path) to transcribe, in one of these formats:
30+
* `flac`, `mp3`, `mp4`, `mpeg`, `mpga`, `m4a`, `ogg`, `wav`, or `webm`.
31+
*
32+
* @param string $model ID of the model to use. Only `whisper-1` is currently available.
33+
*
34+
* @param string|null $language The language of the input audio. Supplying the input language in ISO-639-1
35+
* (e.g. en) format will improve accuracy and latency.
36+
*
37+
* @param string|null $prompt An optional text to guide the model's style or continue a previous audio segment.
38+
* The prompt should match the audio language.
39+
*
40+
* @param string|null $responseFormat The format of the output, in one of these options:
41+
* `json`, `text`, `srt`, `verbose_json`, or `vtt`.
42+
*
43+
* @param float|null $temperature The sampling temperature, between 0 and 1. Higher values like 0.8 will make
44+
* the output more random, while lower values like 0.2 will make it more focused and deterministic.
45+
* If set to 0, the model will use log probability to automatically increase the temperature until certain
46+
* thresholds are hit.
47+
*
48+
* @param array|null $timestampGranularities The timestamp granularities to populate for this transcription.
49+
* `$responseFormat` must be set `verbose_json` to use timestamp granularities. Either or both of these options
50+
* are supported: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating
51+
* word timestamps incurs additional latency.
52+
*/
53+
public function __construct(
54+
public readonly MultipartValue|string $file,
55+
public readonly string $model,
56+
public readonly null|string $language = null,
57+
public readonly null|string $prompt = null,
58+
public readonly null|string $responseFormat = null,
59+
public readonly null|float $temperature = null,
60+
public readonly null|array $timestampGranularities = null,
61+
) {}
62+
63+
public function resolveEndpoint(): string
64+
{
65+
return '/v1/audio/transcriptions';
66+
}
67+
68+
protected function defaultBody(): array
69+
{
70+
return array_filter(
71+
array: [
72+
'file' => MultipartValueHelper::ensureFile(file: $this->file),
73+
'model' => $this->model,
74+
'language' => $this->language,
75+
'prompt' => $this->prompt,
76+
'response_format' => $this->responseFormat,
77+
'temperature' => $this->temperature,
78+
'timestamp_granularity' => $this->timestampGranularities,
79+
],
80+
callback: static fn(mixed $value): bool => $value !== null,
81+
);
82+
}
83+
}

0 commit comments

Comments
 (0)