texhub/openai

Full-featured OpenAI SDK for any PHP framework with first-class Laravel support: chat, tools/function-calling, vision, assistants (v2), files, images, audio, embeddings, models and usage analytics.

Maintainers

Package info

github.com/TexhubPro/openai

Homepage

Issues

Documentation

pkg:composer/texhub/openai

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

v1.0.0 2026-06-01 12:27 UTC

This package is auto-updated.

Last update: 2026-06-01 12:29:49 UTC


README

🌐 English · Русский

License: MIT PHP Laravel

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

✨ What's covered

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

📦 Installation

composer require texhub/openai

Requirements: PHP ≥ 8.2 with the curl and json extensions.

🚀 Quick start

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.

🧰 Function calling (tools)

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();
    }
}

👁 Vision (images in)

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 mode & streaming

$json = $ai->chat()->json([Message::user('Верни {"city","country"} для Душанбе')]);

$ai->chat()->streamText('Расскажи историю', function (string $delta) {
    echo $delta; // tokens arrive live
});

🤖 Assistants (v2)

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
}

Function tools inside a run

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])],
]);

📁 Files (and file_search)

$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');

🖼 Images

$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');

🔊 Audio

// 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');

🧮 Embeddings & moderation

$vector = $ai->embeddings()->vector('текст для поиска');           // array<float>
$flagged = $ai->moderations()->isFlagged('какой-то текст');        // bool

📊 Usage & analytics

// 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']);

🧯 Error handling

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
}

🧩 Any endpoint (escape hatch)

$ai->http()->post('moderations', ['input' => 'text', 'model' => 'omni-moderation-latest']);
$ai->http()->get('models');

🧩 Laravel

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=60

Facade:

use TexHub\OpenAI\Laravel\OpenAI;

echo OpenAI::chat()->text('Привет из Laravel!');
OpenAI::assistants()->create('gpt-4o', ['name' => 'Bot']);

…or inject \TexHub\OpenAI\OpenAI anywhere.

🧪 Testing

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 test

📚 Architecture

src/
├── 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

License

MIT © TexHub Pro — built by Mahmudi Shodmehr.