PHPackages                             xp-forge/openai - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. xp-forge/openai

ActiveLibrary[API Development](/categories/api)

xp-forge/openai
===============

OpenAI APIs for XP Framework

v0.12.0(2mo ago)0341↓50%[2 issues](https://github.com/xp-forge/openai/issues)BSD-3-ClausePHPPHP &gt;=7.4.0CI passing

Since Oct 19Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/xp-forge/openai)[ Packagist](https://packagist.org/packages/xp-forge/openai)[ Docs](http://xp-framework.net/)[ RSS](/packages/xp-forge-openai/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (7)Versions (15)Used By (0)

OpenAI APIs for XP
==================

[](#openai-apis-for-xp)

[![Build status on GitHub](https://github.com/xp-forge/openai/workflows/Tests/badge.svg)](https://github.com/xp-forge/openai/actions)[![XP Framework Module](https://raw.githubusercontent.com/xp-framework/web/master/static/xp-framework-badge.png)](https://github.com/xp-framework/core)[![BSD Licence](https://raw.githubusercontent.com/xp-framework/web/master/static/licence-bsd.png)](https://github.com/xp-framework/core/blob/master/LICENCE.md)[![Requires PHP 7.4+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-7_4plus.svg)](http://php.net/)[![Supports PHP 8.0+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-8_0plus.svg)](http://php.net/)[![Latest Stable Version](https://camo.githubusercontent.com/2fc51d3312e5544ad2720cef9a951a808307bf390b71ff81b3e1960b190b0ea7/68747470733a2f2f706f7365722e707567782e6f72672f78702d666f7267652f6f70656e61692f76657273696f6e2e737667)](https://packagist.org/packages/xp-forge/openai)

This library implements OpenAI APIs with a low-level abstraction approach, supporting their REST and realtime APIs, request and response streaming, function calling and TikToken encoding.

Quick start
-----------

[](#quick-start)

Using the REST API, see

```
use com\openai\rest\OpenAIEndpoint;
use util\cmd\Console;

$ai= new OpenAIEndpoint('https://'.getenv('OPENAI_API_KEY').'@api.openai.com/v1');

Console::writeLine($ai->api('/responses')->invoke([
  'model' => 'gpt-5.2',
  'input' => $prompt,
]));
```

Streaming
---------

[](#streaming)

The REST API can use server-sent events to stream responses, see

```
use com\openai\rest\OpenAIEndpoint;
use util\cmd\Console;

$ai= new OpenAIEndpoint('https://'.getenv('OPENAI_API_KEY').'@api.openai.com/v1');

$events= $ai->api('/responses')->stream([
  'model' => 'gpt-5.2',
  'input' => $prompt,
]);
foreach ($events as $type => $value) {
  Console::write(' ', $value);
}
Console::writeLine();
```

To access the result object, check for the *response.completed* event type and use its value. It contains the outuputs as well as model, filter results and usage information.

TikToken
--------

[](#tiktoken)

Encodes text to tokens. Download the vocabularies [cl100k\_base](https://openaipublic.blob.core.windows.net/encodings/cl100k_base.tiktoken) (used for GPT-3.5 and GPT-4.0) and [o200k\_base](https://openaipublic.blob.core.windows.net/encodings/o200k_base.tiktoken) (used for Omni and O1) first!

```
use com\openai\{Encoding, TikTokenFilesIn};

$source= new TikTokenFilesIn('.');

// By name => [9906, 4435, 0]
$tokens= Encoding::named('cl100k_base')->load($source)->encode('Hello World!');

// By model => [13225, 5922, 0]
$tokens= Encoding::for('omni')->load($source)->encode('Hello World!');
```

Instead of *encode()*, you can use *count()* to count the number of tokens.

Embeddings
----------

[](#embeddings)

To create an embedding for a given text, use

```
use com\openai\rest\OpenAIEndpoint;
use util\cmd\Console;

$ai= new OpenAIEndpoint('https://'.getenv('OPENAI_API_KEY').'@api.openai.com/v1');

Console::writeLine($ai->api('/embeddings')->invoke([
  'input' => $text,
  'model' => 'text-embedding-3-small'],
));
```

Text to speech
--------------

[](#text-to-speech)

To stream generate audio, use the API's *transmit()* method, which sends the given payload and returns the response. See

```
use com\openai\rest\OpenAIEndpoint;
use util\cmd\Console;

$ai= new OpenAIEndpoint('https://'.getenv('OPENAI_API_KEY').'@api.openai.com/v1');
$payload= [
  'input' => $input,
  'voice' => 'alloy',  // or: echo, fable, onyx, nova, shimmer
  'model' => 'tts-1',
];

$stream= $ai->api('/audio/speech')->transmit($payload)->stream();
while ($stream->available()) {
  Console::write($stream->read());
}
```

Speech to text
--------------

[](#speech-to-text)

To convert audio into text, upload files via the API's *open()* method, which returns an *Upload* instance. See

```
use com\openai\rest\OpenAIEndpoint;
use io\File;
use util\cmd\Console;

$ai= new OpenAIEndpoint('https://'.getenv('OPENAI_API_KEY').'@api.openai.com/v1');
$file= new File($argv[1]);

$response= $ai->api('/audio/transcriptions')
  ->open(['model' => 'whisper-1'])
  ->transfer('file', $file->in(), $file->filename)
  ->finish()
;
Console::writeLine($response->value());
```

You can also stream uploads from *InputStream*s as follows:

```
// ...setup code from above...

$upload= $ai->api('/audio/transcriptions')->open(['model' => 'whisper-1']);

$stream= $upload->stream('file', 'audio.mp3');
while ($in->available()) {
  $stream->write($in->read());
}
$response= $upload->finish();

Console::writeLine($response->value());
```

Tracing the calls
-----------------

[](#tracing-the-calls)

REST API calls can be traced with the [logging library](https://github.com/xp-framework/logging):

```
use com\openai\rest\OpenAIEndpoint;
use util\log\Logging;

$ai= new OpenAIEndpoint('https://'.getenv('OPENAI_API_KEY').'@api.openai.com/v1');
$ai->setTrace(Logging::all()->toConsole());

// ...perform API calls...
```

Tool calls
----------

[](#tool-calls)

There are two types of tools: Built-ins like *file\_search* and *code\_interpreter* (available [in the assistants API](https://platform.openai.com/docs/assistants/tools)) as well as custom functions, see

### Defining functions

[](#defining-functions)

Custom functions map to instance methods in a class:

```
use com\openai\tools\Param;
use webservices\rest\Endpoint;

class Weather {
  private $endpoint;

  public function __construct(string $base= 'https://wttr.in/') {
    $this->endpoint= new Endpoint($base);
  }

  public function in(#[Param] string $city): string {
    return $this->endpoint->resource('/{0}?0mT', [$city])->get()->content();
  }
}
```

The *Param* annnotation may define a description and a [JSON schema type](https://json-schema.org/understanding-json-schema/reference):

- `#[Param('The name of the city')] $name`
- `#[Param(type: ['type' => 'string', 'enum' => ['C', 'F']])] $unit`

### Passing custom functions

[](#passing-custom-functions)

Custom functions are registered in a `Functions` instance and passed via *tools* inside the payload.

```
use com\openai\rest\OpenAIEndpoint;
use com\openai\tools\{Tools, Functions};

$functions= (new Functions())->register('weather', new Weather());

$ai= new OpenAIEndpoint('https://'.getenv('OPENAI_API_KEY').'@api.openai.com/v1');
$payload= [
  'model' => 'gpt-5.2',
  'tools' => new Tools($functions),
  'input' => [['type' => 'message', 'role' => 'user', 'content' => $content]],
];
```

### Invoking custom functions

[](#invoking-custom-functions)

If tool calls are requested by the LLM, invoke them and return to next completion cycle. See

```
use util\cmd\Console;

// ...setup code from above...

$calls= $functions->calls()->catching(fn($t) => $t->printStackTrace());
next: $result= $ai->api('/responses')->invoke($payload));

// If function calls are requested, invoke them and return to next response cycle
$invokations= false;
foreach ($result['output'] as $output) {
  if ('function_call' !== $output['type']) continue;

  $invokations= true;
  $return= $calls->call($call['name'], $call['arguments']);

  $payload['input'][]= $call;
  $payload['input'][]= [
    'type'    => 'function_call_output',
    'call_id' => $call['call_id'],
    'output'  => $return,
  ];
}
if ($invokations) goto next;

// Print out final result
Console::writeLine($result);
```

### Passing context

[](#passing-context)

Functions can be passed a context as follows by annotating parameters with the *Context* annotation:

```
use com\mongodb\{Collection, Document, ObjectId};
use com\openai\tools\{Context, Param};

// Declaration
class Memory {

  public function __construct(private Collection $facts) { }

  public function store(#[Context] Document $user, #[Param] string $fact): ObjectId {
    return $this->facts->insert(new Document(['owner' => $user->id(), 'fact' => $fact]))->id();
  }
}

// ...shortened for brevity...

$context= ['user' => $user];
$return= $calls->call($call['name'], $call['arguments'], $context);
```

Azure OpenAI
------------

[](#azure-openai)

These endpoints differ slightly in how they are invoked, which is handled by the *AzureAI* implementation. See

```
use com\openai\rest\AzureAIEndpoint;
use util\cmd\Console;

// Using V1 API
$ai= new AzureAIEndpoint('https://'.getenv('AZUREAI_API_KEY').'@example.openai.azure.com/openai/v1');

// Using API version
$ai= new AzureAIEndpoint(
  'https://'.getenv('AZUREAI_API_KEY').'@example.openai.azure.com/openai/deployments/gpt-5.2',
  '2025-04-01-preview'
);

Console::writeLine($ai->api('/responses')->invoke([
  'model' => 'gpt-5.2',
  'input' => $prompt,
]));
```

Distributing requests
---------------------

[](#distributing-requests)

The *Distributed* endpoint allows to distribute requests over multiple endpoints. The *ByRemainingRequests* class uses the `x-ratelimit-remaining-requests` header to determine the target. See

```
use com\openai\rest\{AzureAIEndpoint, Distributed, ByRemainingRequests};
use util\cmd\Console;

$endpoints= [
  new AzureAIEndpoint('https://...@r1.openai.azure.com/openai/v1'),
  new AzureAIEndpoint('https://...@r2.openai.azure.com/openai/v1'),
];

$ai= new Distributed($endpoints, new ByRemainingRequests());

Console::writeLine($ai->api('/responses')->invoke([
  'model' => 'gpt-5.2',
  'input' => $prompt,
]));
foreach ($endpoints as $i => $endpoint) {
  Console::writeLine('Endpoint #', $i, ': ', $endpoint->rateLimit());
}
```

For more complex load balancing, have a look at [this blog article using Azure API management](https://techcommunity.microsoft.com/t5/apps-on-azure-blog/openai-at-scale-maximizing-api-management-through-effective/ba-p/4240317)

Realtime API
------------

[](#realtime-api)

The realtime API allows streaming audio and/or text to and from language models, see

```
use com\openai\realtime\RealtimeApi;
use util\cmd\Console;

$api= new RealtimeApi('wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview');
$session= $api->connect([
  'Authorization' => 'Bearer '.getenv('OPENAI_API_KEY'),
  'OpenAI-Beta'   => 'realtime=v1',
];
Console::writeLine($session);

// Send prompt
$api->transmit([
  'type' => 'conversation.item.create',
  'item' => [
    'type'    => 'message',
    'role'    => 'user',
    'content' => [['type' => 'input_text', 'text' => $message]],
  ]
]);

// Receive response(s)
$api->send(['type' => 'response.create', 'response' => ['modalities' => ['text']]]);
do {
  $event= $api->receive();
  Console::writeLine($event);
} while ('response.done' !== $event['type'] && 'error' !== $event['type']);

$api->close();
```

For Azure AI, the setup code is slightly different:

```
use com\openai\realtime\RealtimeApi;
use util\cmd\Console;

$api= new RealtimeApi('wss://example.openai.azure.com/openai/realtime', [
  'api-version' => '2024-10-01-preview',
  'deployment'  => 'gpt-4o-realtime-preview',
]);
$session= $api->connect(['api-key' => getenv('AZUREAI_API_KEY')]);
```

Completions API
---------------

[](#completions-api)

To use the legacy (but industry standard) chat completions API, see :

```
use com\openai\rest\OpenAIEndpoint;
use util\cmd\Console;

$ai= new OpenAIEndpoint('https://'.getenv('OPENAI_API_KEY').'@api.openai.com/v1');

$flow= $ai->api('/chat/completions')->flow([
  'model'    => 'gpt-5.2',
  'messages' => [['role' => 'user', 'content' => $prompt]],
]);
foreach ($flow->deltas() as $type => $delta) {
  Console::writeLine(' ', $delta);
}
Console::writeLine();
```

The result object is computed from the streamed deltas and can be retrieved by accessing *$flow-&gt;result()*.

See also
--------

[](#see-also)

-
-
-
-
-  - GPT Function calling in a nutshell

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance83

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity37

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~40 days

Recently: every ~78 days

Total

13

Last Release

87d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/07d18d882c8b4aaf3466432f64018214f2771eda333202175431ee7233795376?d=identicon)[thekid](/maintainers/thekid)

---

Top Contributors

[![thekid](https://avatars.githubusercontent.com/u/696742?v=4)](https://github.com/thekid "thekid (175 commits)")

---

Tags

azure-aiazureaiembeddingsfunction-callingload-balancingopenaiopenai-apiopenai-api-clientopenai-realtimeopenai-streamingphp7php8responses-apirest-apitiktokentiktoken-phpxp-frameworkmodulexp

### Embed Badge

![Health badge](/badges/xp-forge-openai/health.svg)

```
[![Health](https://phpackages.com/badges/xp-forge-openai/health.svg)](https://phpackages.com/packages/xp-forge-openai)
```

###  Alternatives

[xp-framework/compiler

XP Compiler

2026.0k9](/packages/xp-framework-compiler)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
