🌐 English · Русский
A complete, framework-agnostic OpenAI SDK for PHP — chat, function-calling/tools, vision, assistants (v2), files, images, audio, embeddings, moderations, models and usage analytics — with first-class Laravel support.
Designed to make working with OpenAI проще простого: a one-liner for a quick prompt, full power when you need it.
Reference: https://platform.openai.com/docs/api-reference
| Area | Methods |
|---|---|
| Chat | text(), ask(), create(), vision(), json(), stream(), streamText() |
| Tools / functions | Tool::function(), code_interpreter, file_search, tool calls in responses |
| Responses API | responses()->create() / stream() (modern unified endpoint) |
| Assistants (v2) | create / retrieve / update / list / delete |
| Threads & runs | messages, runs, run steps, tool outputs, poll-until-done |
| Files | upload (disk or memory), list, retrieve, download, delete |
| Images | generate, edit, variation (DALL·E / gpt-image-1) |
| Audio | transcribe, translate, text-to-speech |
| Embeddings | create(), vector() |
| Moderations | create(), isFlagged() |
| Models | list, ids, retrieve, delete |
| Usage | token & cost analytics (admin key) |
| Escape hatch | ->http() to call any endpoint |
composer require texhub/openaiRequirements: PHP ≥ 8.2 with the curl and json extensions.
use TexHub\OpenAI\OpenAI;
$ai = OpenAI::make('sk-...'); // or with org/project: OpenAI::make('sk-...', 'org-...', 'proj-...')
// Simplest possible — just text in, text out:
echo $ai->chat()->text('Объясни квантовую запутанность одним предложением.');
// With a system prompt and options:
$response = $ai->chat()->ask(
'Напиши слоган для кофейни',
system: 'Ты креативный копирайтер.',
options: ['model' => 'gpt-4o', 'temperature' => 0.9],
);
echo $response->content();
echo $response->totalTokens();Pick the model per-call via options: ['model' => '...'], or set a default in config.
use TexHub\OpenAI\Builders\Tool;
use TexHub\OpenAI\Builders\Message;
$response = $ai->chat()->create([
'messages' => [Message::user('Какая погода в Душанбе?')],
'tools' => [
Tool::function('get_weather', 'Получить погоду по городу', Tool::objectSchema(
properties: ['city' => ['type' => 'string']],
required: ['city'],
)),
],
]);
if ($response->hasToolCalls()) {
foreach ($response->toolCalls() as $call) {
$args = json_decode($call['function']['arguments'], true);
$result = myWeatherLookup($args['city']);
// send the result back:
$final = $ai->chat()->create([
'messages' => [
Message::user('Какая погода в Душанбе?'),
$response->message(),
Message::toolResult($call['id'], json_encode($result)),
],
'tools' => [/* same tools */],
]);
echo $final->content();
}
}use TexHub\OpenAI\Builders\Message;
// Remote URL:
$ai->chat()->vision('Что на картинке?', ['https://example.com/photo.jpg']);
// Local file as a data URL:
$ai->chat()->vision('Опиши фото', [Message::imageDataUrl('/path/to/photo.jpg')]);$json = $ai->chat()->json([Message::user('Верни {"city","country"} для Душанбе')]);
$ai->chat()->streamText('Расскажи историю', function (string $delta) {
echo $delta; // tokens arrive live
});use TexHub\OpenAI\Builders\Tool;
// 1) Create a reusable assistant
$assistant = $ai->assistants()->create('gpt-4o', [
'name' => 'Data Analyst',
'instructions' => 'Ты аналитик. Отвечай кратко, считай через code interpreter.',
'tools' => [Tool::codeInterpreter()],
]);
// 2) Create a thread, add a message, run, and wait for completion
$thread = $ai->threads()->create();
$ai->threads()->addMessage($thread->id(), 'Посчитай факториал 10');
$run = $ai->threads()->runAndPoll($thread->id(), $assistant->id());
// 3) Read the assistant's reply
foreach ($ai->threads()->messages($thread->id())->data() as $message) {
// newest first
}When a run returns status: requires_action, submit your tool outputs:
$ai->threads()->submitToolOutputs($threadId, $runId, [
['tool_call_id' => 'call_1', 'output' => json_encode(['result' => 42])],
]);$file = $ai->files()->upload('/path/to/manual.pdf', purpose: 'assistants');
$ai->files()->list(['purpose' => 'assistants']);
$content = $ai->files()->download($file->id());
$ai->files()->delete($file->id());
// In-memory upload:
$ai->files()->uploadContents($csvString, 'data.csv');$image = $ai->images()->generate('Кот-космонавт, акварель', 'gpt-image-1', [
'size' => '1024x1024',
'n' => 1,
]);
$image->firstUrl(); // when response_format=url
$image->base64(); // when response_format=b64_json
$ai->images()->edit('/path/in.png', 'Добавь радугу', maskPath: '/path/mask.png');
$ai->images()->variation('/path/in.png');// Speech → text
$ai->audio()->transcribe('/path/voice.mp3', options: ['language' => 'ru'])->get('text');
// Text → speech (returns mp3 bytes, or write to file)
$ai->audio()->speechToFile('Привет, мир!', '/path/out.mp3', voice: 'alloy');$vector = $ai->embeddings()->vector('текст для поиска'); // array<float>
$flagged = $ai->moderations()->isFlagged('какой-то текст'); // bool// Per-request token usage is on every response:
$ai->chat()->ask('hi')->usage(); // ['prompt_tokens'=>..,'completion_tokens'=>..,'total_tokens'=>..]
// Org-wide analytics (requires an ADMIN api key, sk-admin-...):
$ai->usage()->completionsSince(strtotime('-7 days'));
$ai->usage()->costs(['start_time' => strtotime('-30 days'), 'bucket_width' => '1d']);use TexHub\OpenAI\Exceptions\ApiException;
use TexHub\OpenAI\Exceptions\TransportException;
try {
$ai->chat()->text('hi');
} catch (ApiException $e) {
$e->httpStatus; // 401, 429, 500, ...
$e->errorType; // invalid_request_error, rate_limit_exceeded, ...
$e->errorCode; // e.g. invalid_api_key
$e->isRateLimit(); $e->isRetryable();
} catch (TransportException $e) {
// network failure
}$ai->http()->post('moderations', ['input' => 'text', 'model' => 'omni-moderation-latest']);
$ai->http()->get('models');Auto-discovered. Publish config:
php artisan vendor:publish --tag=openai-config.env:
OPENAI_API_KEY=sk-...
OPENAI_DEFAULT_MODEL=gpt-4o-mini
# optional:
OPENAI_ORGANIZATION=
OPENAI_PROJECT=
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_TIMEOUT=60Facade:
use TexHub\OpenAI\Laravel\OpenAI;
echo OpenAI::chat()->text('Привет из Laravel!');
OpenAI::assistants()->create('gpt-4o', ['name' => 'Bot']);…or inject \TexHub\OpenAI\OpenAI anywhere.
Inject the fake transport to test without network calls:
use TexHub\OpenAI\OpenAI;
use TexHub\OpenAI\Config;
use TexHub\OpenAI\Tests\Support\FakeTransport;
$t = (new FakeTransport())->push([
'choices' => [['message' => ['content' => 'Hi!'], 'finish_reason' => 'stop']],
]);
$ai = new OpenAI(new Config('sk-test'), $t);
$ai->chat()->text('hello'); // "Hi!"
// assert on $t->lastJson(), $t->lastHeaders(), $t->lastRequest()Run the suite:
composer install
composer testsrc/
├── OpenAI.php # entry — chat()/assistants()/threads()/files()/images()/audio()/…
├── Config.php # immutable configuration
├── Http/ # Transport, CurlTransport (JSON/multipart/SSE), HttpClient, FileParam
├── Builders/ # Message (incl. vision), Tool (functions, code_interpreter, file_search)
├── Resources/ # Chat, Responses, Models, Embeddings, Files, Images, Audio,
│ # Moderations, Assistants, Threads, Usage
├── Responses/ # Response (ArrayAccess), ChatResponse, ImageResponse, ListResponse
├── Exceptions/ # ApiException, TransportException, ConfigurationException
└── Laravel/ # ServiceProvider + Facade
MIT © TexHub Pro — built by Mahmudi Shodmehr.