Usamos cookies. Las cookies y el almacenamiento del navegador mantienen tu sesión iniciada y recuerdan tus preferencias. Con tu permiso, también medimos cómo se usa el sitio. Puedes en cualquier momento. Consulta nuestra política de cookies.

PHP

Guías de SDK

PHP

Usa openai-php/client con api14: crea el cliente con la factory, configura la URI base y prueba chat, streaming, herramientas, embeddings, voz y reintentos.

Usa openai-php/client con api14. Crea el cliente con la factory, establece la URI base de api14 y usa ids de modelo con el formato provider/model.

Instalación

composer require openai-php/client guzzlehttp/guzzle
export API14_API_KEY="sk-api14-..."

Configuración

<?php
require __DIR__ . '/vendor/autoload.php';

$client = OpenAI::factory()
    ->withApiKey(getenv('API14_API_KEY'))
    ->withBaseUri(getenv('API14_BASE_URL') ?: 'https://api14.com/api/v1')
    ->withHttpClient(new \GuzzleHttp\Client(['timeout' => 120, 'connect_timeout' => 5]))
    ->make();

Mantén la clave en el entorno (o en el .env de tu framework), nunca en el código fuente. El timeout de Guzzle está en segundos y cubre toda la petición; auméntalo para llamadas largas de razonamiento o streaming.

Chat

$result = $client->chat()->create([
    'model' => 'openai/gpt-5-mini',
    'messages' => [
        ['role' => 'user', 'content' => 'Explain vector databases in two sentences.'],
    ],
]);

echo $result->choices[0]->message->content;

Streaming

$stream = $client->chat()->createStreamed([
    'model' => 'anthropic/claude-sonnet-4.5',
    'messages' => [['role' => 'user', 'content' => 'Write a haiku about APIs.']],
]);

foreach ($stream as $response) {
    echo $response->choices[0]->delta->content;
}

Consulta Streaming.

Llamadas a herramientas

$tools = [[
    'type' => 'function',
    'function' => [
        'name' => 'get_weather',
        'description' => 'Current weather for a city',
        'parameters' => [
            'type' => 'object',
            'properties' => ['city' => ['type' => 'string']],
            'required' => ['city'],
        ],
    ],
]];
$messages = [['role' => 'user', 'content' => "What's the weather in Istanbul?"]];

while (true) {
    $response = $client->chat()->create(['model' => 'openai/gpt-5-mini', 'messages' => $messages, 'tools' => $tools]);
    $message = $response->choices[0]->message;
    if (empty($message->toolCalls)) {
        echo $message->content;
        break;
    }
    $messages[] = $message->toArray();
    foreach ($message->toolCalls as $call) {
        $args = json_decode($call->function->arguments, true);
        $messages[] = [
            'role' => 'tool',
            'tool_call_id' => $call->id,
            'content' => json_encode(getWeather($args['city'])), // tu función
        ];
    }
}

Consulta Llamadas a herramientas.

Salida estructurada

$result = $client->chat()->create([
    'model' => 'openai/gpt-5-mini',
    'messages' => [['role' => 'user', 'content' => 'Extract: Ada Lovelace, born 1815 in London.']],
    'response_format' => [
        'type' => 'json_schema',
        'json_schema' => [
            'name' => 'person',
            'strict' => true,
            'schema' => [
                'type' => 'object',
                'properties' => [
                    'name' => ['type' => 'string'],
                    'born' => ['type' => 'integer'],
                    'city' => ['type' => 'string'],
                ],
                'required' => ['name', 'born', 'city'],
                'additionalProperties' => false,
            ],
        ],
    ],
]);

$person = json_decode($result->choices[0]->message->content, true, flags: JSON_THROW_ON_ERROR);

Consulta Salidas estructuradas.

Entrada de imagen

$image = base64_encode(file_get_contents('photo.png'));

$result = $client->chat()->create([
    'model' => 'google/gemini-2.5-flash',
    'messages' => [[
        'role' => 'user',
        'content' => [
            ['type' => 'text', 'text' => 'What is in this picture?'],
            ['type' => 'image_url', 'image_url' => ['url' => "data:image/png;base64,{$image}"]],
        ],
    ]],
]);

Consulta Visión y archivos.

Embeddings

$result = $client->embeddings()->create([
    'model' => 'openai/text-embedding-3-small',
    'input' => ['The quick brown fox', 'Lorem ipsum'],
]);

echo count($result->embeddings[0]->embedding);

Voz

$audio = $client->audio()->speech([
    'model' => 'openai/gpt-4o-mini-tts',
    'input' => 'Hello from api14!',
    'voice' => 'alloy',
]);

file_put_contents('speech.mp3', $audio);

Errores

Los errores de la pasarela usan el formato de OpenAI, así que el cliente lanza OpenAI\Exceptions\ErrorException con el estado y el código legible por máquina:

use OpenAI\Exceptions\ErrorException;

try {
    $client->chat()->create([
        'model' => 'openai/gpt-5-mini',
        'messages' => [['role' => 'user', 'content' => 'Hi']],
    ]);
} catch (ErrorException $e) {
    match ($e->getStatusCode()) {
        402 => error_log('Balance too low, add funds: ' . $e->getErrorCode()), // insufficient_balance
        429 => error_log('Rate limited, retry in 60s: ' . $e->getErrorCode()),  // rate_limited
        default => throw $e,
    };
}

La pasarela envía Retry-After: 60 con rate_limited. Consulta Límites de tasa y Errores.

Reintentos con retroceso

openai-php/client no reintenta por sí mismo. Envuelve las llamadas en un pequeño bucle que reintente rate_limited y los 5xx, y se rinda con todo lo demás:

use OpenAI\Exceptions\ErrorException;
use OpenAI\Exceptions\TransporterException;

function withRetry(callable $fn, int $attempts = 5): mixed
{
    for ($i = 0; ; $i++) {
        try {
            return $fn();
        } catch (ErrorException $e) {
            $retryable = $e->getErrorCode() === 'rate_limited' || $e->getStatusCode() >= 500;
            if (!$retryable || $i + 1 >= $attempts) throw $e;
        } catch (TransporterException $e) { // error de red o tiempo de espera agotado
            if ($i + 1 >= $attempts) throw $e;
        }
        usleep((min(60, 2 ** $i) * 1000 + random_int(0, 1000)) * 1000); // retroceso + jitter
    }
}

$result = withRetry(fn () => $client->chat()->create([
    'model' => 'openai/gpt-5-mini',
    'messages' => [['role' => 'user', 'content' => 'Hi']],
]));

daily_limit_reached e insufficient_balance no se reintentan, porque esperar unos segundos no los resuelve.

Todas las capacidades

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api14.com/api/v1",
  apiKey: process.env.API14_API_KEY,
});

const result = await client.chat.completions.create({
  "model": "openai/gpt-5-mini",
  "messages": [
    {
      "role": "user",
      "content": "Explain vector databases in two sentences."
    }
  ]
});
console.log(result.choices[0].message.content);