Skip to content

Latest commit

Β 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

WaveSpeed

WaveSpeed PHP SDK

PHP SDK for the WaveSpeed inference platform

🌐 Visit wavespeed.ai β€’ πŸ“– Documentation β€’ πŸ’¬ Issues


A port of the official WaveSpeed Python SDK to PHP, with the same API surface and the same retry semantics. Zero runtime dependencies β€” just ext-curl and ext-json.

Requirements

  • PHP 8.1 or newer
  • ext-curl, ext-json

Installation

composer require wavespeedai/wavespeed-php

API Client

Run WaveSpeed AI models with a simple API:

use WaveSpeed\WaveSpeed;

$output = WaveSpeed::run(
    'wavespeed-ai/z-image/turbo',
    ['prompt' => 'Cat'],
);

echo $output['outputs'][0]; // Output URL

Authentication

Set your API key through the environment (get one at wavespeed.ai/accesskey):

export WAVESPEED_API_KEY="your-api-key"

Or pass it directly:

use WaveSpeed\Client;

$client = new Client(apiKey: 'your-api-key');
$output = $client->run('wavespeed-ai/z-image/turbo', ['prompt' => 'Cat']);

Or configure it once during bootstrap, so every client picks it up:

use WaveSpeed\Config;

Config::set(Config::API_KEY, $_ENV['WAVESPEED_API_KEY']);

Options

$output = $client->run(
    'wavespeed-ai/z-image/turbo',
    ['prompt' => 'Cat'],
    timeout: 300.0,          // Max wait for completion; null (default) = no local limit
    pollInterval: 1.0,       // Status check interval (default: 1.0)
    enableSyncMode: false,   // Best-effort sync result attempt (default: false)
    maxRetries: null,        // Task-level retries (default: the client's setting)
);

timeout caps how long run() blocks. Left null it waits as long as the task takes, while each individual HTTP request stays bounded by Config::TIMEOUT (36000s by default). A local timeout never cancels the task β€” see Recovering a Task.

Sync Mode

Pass enableSyncMode: true to ask the API to wait for the result in the initial request. If the server-side wait runs out, the SDK throws SyncModeTimeoutException carrying the task ID and result URL β€” the task keeps processing and can be collected later.

Note: Not all models support sync mode. Check the model documentation for availability.

use WaveSpeed\Exception\SyncModeTimeoutException;

try {
    $output = $client->run(
        'wavespeed-ai/z-image/turbo',
        ['prompt' => 'Cat'],
        enableSyncMode: true,
    );
} catch (SyncModeTimeoutException $e) {
    // Not a failure β€” the task is still running.
    $state = $client->getResult((string) $e->taskId);
}

Handling Failure Without Exceptions

runNoThrow() reports the outcome instead of throwing, which suits queue workers that want to record a task ID and move on:

$result = $client->runNoThrow('wavespeed-ai/z-image/turbo', ['prompt' => 'Cat']);

// ['status' => 'completed'|'failed'|'processing',
//  'outputs' => list|null, 'task_id' => string, 'error' => string|null]
if ($result['outputs'] !== null) {
    echo $result['outputs'][0];
} else {
    error_log("{$result['status']} ({$result['task_id']}): {$result['error']}");
}

status is processing when a sync-mode wait expired: the task is alive server-side, so getResult($result['task_id']) will pick it up.

Recovering a Task

A local timeout does not cancel anything β€” the job keeps running. Fetch its current state by id:

$state = $client->getResult('task-id-from-earlier');

echo $state['data']['status'];   // e.g. "processing" or "completed"
print_r($state['data']['outputs'] ?? []);

Retry Configuration

use WaveSpeed\Client;

$client = new Client(
    apiKey: 'your-api-key',
    maxRetries: 0,             // Replacement task attempts (default: 0)
    maxConnectionRetries: 5,   // Result-query GET retries; POST is never retried
    retryInterval: 1.0,        // Base delay between retries in seconds (default: 1.0)
);

A submission POST is never retried automatically. It is not idempotent: if it fails without a response, the task may already exist, and replaying it would risk paying for the same job twice. Result-query GETs are idempotent and are retried freely. Setting maxRetries above 0 opts into submitting a replacement task after a confirmed transient failure.

Diagnostics

Retries are silent by default β€” a library should not write to your output uninvited. Opt in with a logger:

use WaveSpeed\Client;
use WaveSpeed\Support\CallableLogger;
use WaveSpeed\Support\StderrLogger;

$client = new Client(logger: new StderrLogger());

// Or bridge to PSR-3 / any framework logger:
$client = new Client(
    logger: new CallableLogger(fn (string $m) => $psrLogger->warning($m)),
);

Upload Files

Upload images, videos, or audio files. Large files stream straight from disk, so memory use stays flat:

use WaveSpeed\WaveSpeed;

$url = WaveSpeed::upload('/path/to/image.png');
echo $url;

// A stream works too β€” including one you did not open from disk.
$url = WaveSpeed::upload($stream);

Errors

Every exception implements WaveSpeed\Exception\WaveSpeedException, so one catch covers the SDK without swallowing unrelated errors:

Exception Meaning Retried by the SDK
ConfigurationException No API key, or an unusable argument β€”
FileNotFoundException Upload path missing or unreadable β€”
SubmissionException The submit POST failed Never (not idempotent)
PredictionFailedException Task reached failed / cancelled / timeout Never (a verdict, not a hiccup)
SyncModeTimeoutException Sync wait expired; task still running Never β€” poll instead
TimeoutException Local wait budget ran out Yes, at the task level
ConnectionException No response obtained Yes, for idempotent requests
ApiException Any other API-level failure Yes for 429/5xx

Custom HTTP Transport

Client talks to the API only through the HttpClient interface, so you can substitute your own stack (a proxy-aware handler, a shared connection pool, a test double):

use WaveSpeed\Client;
use WaveSpeed\Http\CurlHttpClient;

$client = new Client(
    http: new CurlHttpClient([CURLOPT_PROXY => 'http://proxy.internal:3128']),
);

Examples

Runnable scripts live in examples/:

WAVESPEED_API_KEY=your-key php examples/run.php "a lighthouse at dusk"
WAVESPEED_API_KEY=your-key php examples/upload.php /path/to/image.png
WAVESPEED_API_KEY=your-key php examples/sync_mode.php
WAVESPEED_API_KEY=your-key php examples/run_no_throw.php
WAVESPEED_API_KEY=your-key php examples/configuration.php

Local Development

composer install

# Run all tests
composer test

# Run one file, or one test
vendor/bin/phpunit tests/ClientTest.php
vendor/bin/phpunit --filter testRunReturnsOutputs

# Static analysis (level 8)
composer stan

# Tests that hit the real API (excluded by default, costs credits)
WAVESPEED_API_KEY=your-key vendor/bin/phpunit --group integration

The default suite never touches the network: MockHttpClient scripts the responses and FakeClock makes polling and backoff instant.

Environment Variables

Variable Description
WAVESPEED_API_KEY WaveSpeed API key
WAVESPEED_CLIENT_NAME Channel-attribution name sent as the X-Client-Name header (overrides the clientName argument; defaults to wavespeed-php)

Mapping From the Python SDK

Python PHP
wavespeed.run(...) WaveSpeed::run(...)
wavespeed.run_no_throw(...) WaveSpeed::runNoThrow(...)
wavespeed.get_result(id) WaveSpeed::getResult($id)
wavespeed.upload(file) WaveSpeed::upload($file)
wavespeed.Client(api_key=...) new WaveSpeed\Client(apiKey: ...)
wavespeed.config.api.timeout = 60 Config::set(Config::TIMEOUT, 60.0)
with wavespeed.config.patch(...) Config::patch([...], fn () => ...)
RuntimeError / ValueError Typed exceptions (see the table above)

License

MIT


WaveSpeed AI β€” AI image & video generation platform. Try it in the browser: Image generator Β· Video generator

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages