Skip to content

Commit

Permalink
load endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
sergix44 committed Aug 2, 2023
1 parent d2b34ee commit f217edc
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 60 deletions.
96 changes: 48 additions & 48 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,79 +2,79 @@

namespace SergiX44\Gradio;

use GuzzleHttp\Client as Guzzle;
use InvalidArgumentException;
use SergiX44\Gradio\Client\Endpoint;
use SergiX44\Gradio\Client\RemoteClient;
use SergiX44\Gradio\DTO\Config;
use SergiX44\Hydrator\Hydrator;
use SergiX44\Hydrator\HydratorInterface;
use WebSocket\Client as WebSocket;

class Client
class Client extends RemoteClient
{

private const HTTP_PREDICT = 'run/predict';

private const WS_PREDICT = 'queue/join';

private const HTTP_CONFIG = 'config';
protected Config $config;
private string $sessionHash;
private array $endpoints = [];

private Config $config;

private Guzzle $httpClient;

private WebSocket $wsClient;

private HydratorInterface $hydrator;

public function __construct(string $src)
public function __construct(string $src, ?Config $config = null)
{
if (
! str_starts_with($src, 'http://') &&
! str_starts_with($src, 'https://') &&
! str_starts_with($src, 'ws://') &&
! str_starts_with($src, 'wss://')
) {
throw new InvalidArgumentException('The src must not contain the protocol');
}

$src = str_ends_with($src, '/') ? $src : "{$src}/";
parent::__construct($src);
$this->config = $config ?? $this->get(self::HTTP_CONFIG, dto: Config::class);
$this->loadEndpoints($this->config->dependencies);
$this->sessionHash = substr(md5(microtime()), 0, 11);
$this->hydrator = new Hydrator();
}

$this->httpClient = new Guzzle([
'base_uri' => str_replace('ws', 'http', $src),
'headers' => [
'User-Agent' => 'gradio_client_php/1.0',
],
]);
$this->wsClient = new WebSocket(str_replace('http', 'ws', $src));
protected function loadEndpoints(array $dependencies): void
{
foreach ($dependencies as $index => $dep) {
$endpoint = new Endpoint(
$this,
$index,
$dep['api_name'] ?? null,
$dep['queue'] !== false,
);

$this->endpoints[$index] = $endpoint;
if ($endpoint->apiName !== null) {
$this->endpoints[$endpoint->apiName] = $endpoint;
}
}
}

$this->config = $this->loadConfig();
public function getConfig(): Config
{
return $this->config;
}

public function predict(string $apiName = null, int $fnIndex = null, mixed ...$arguments)
public function predict(array $arguments, string $apiName = null, int $fnIndex = null): mixed
{
if ($apiName === null && $fnIndex === null) {
throw new InvalidArgumentException('You must provide an apiName or fnIndex');
}

$fn = $fnIndex ?? $this->config->fnIndexFromApiName($apiName);

}
$endpoint = $this->endpoints[$apiName ?? $fnIndex] ?? null;

private function submit(int $dnIndex, mixed ...$arguments)
{
if ($endpoint === null) {
throw new InvalidArgumentException('Endpoint not found');
}

return $this->submit($endpoint, $arguments);
}

private function loadConfig()
private function submit(Endpoint $endpoint, array $arguments)
{
$response = $this->httpClient->get('config');

return $this->hydrator->hydrateWithJson(Config::class, $response->getBody()->getContents());
$payload = $this->preparePayload($arguments);

if ($endpoint->useWebsockets) {
$ws = $this->ws(self::WS_PREDICT);
$ws->send(json_encode($payload));
$response = json_decode($ws->receive(), true);
$ws->close();
} else {
$response = $this->post(self::HTTP_PREDICT, $payload);
}
}

public function getConfig(): Config
{
return $this->config;
}
}
18 changes: 18 additions & 0 deletions src/Client/Endpoint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace SergiX44\Gradio\Client;

use SergiX44\Gradio\Client;

readonly class Endpoint
{

public function __construct(
public Client $client,
public int $index,
public ?string $apiName,
public bool $useWebsockets
) {
}

}
74 changes: 74 additions & 0 deletions src/Client/RemoteClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

namespace SergiX44\Gradio\Client;

use GuzzleHttp\Client as Guzzle;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use SergiX44\Hydrator\Hydrator;
use SergiX44\Hydrator\HydratorInterface;
use WebSocket\Client as WebSocket;

abstract class RemoteClient
{
private string $src;

protected Guzzle $httpClient;

protected HydratorInterface $hydrator;

public function __construct(string $src)
{
if (
!str_starts_with($src, 'http://') &&
!str_starts_with($src, 'https://') &&
!str_starts_with($src, 'ws://') &&
!str_starts_with($src, 'wss://')
) {
throw new InvalidArgumentException('The src must not contain the protocol');
}

$this->src = str_ends_with($src, '/') ? $src : "{$src}/";

$this->hydrator = new Hydrator();

$this->httpClient = new Guzzle([
'base_uri' => str_replace('ws', 'http', $this->src),
'headers' => [
'User-Agent' => 'gradio_client_php/1.0',
],
]);
}


protected function get(string $uri, array $params = [], ?string $dto = null)
{
$response = $this->httpClient->get($uri, ['query' => $params]);

return $this->parseResponse($response, $dto);
}

protected function post(string $uri, array $params = [], ?string $dto = null)
{
$response = $this->httpClient->post($uri, ['json' => $params]);

return $this->parseResponse($response, $dto);
}

protected function ws(string $uri, array $options = []): WebSocket
{
return new WebSocket(str_replace('http', 'ws', $this->src).$uri, $options);
}

private function parseResponse(ResponseInterface $response, string $mapTo = null): mixed
{
$body = $response->getBody()->getContents();

if ($mapTo !== null) {
return $this->hydrator->hydrateWithJson($mapTo, $body);
}

return json_decode($body, flags: JSON_THROW_ON_ERROR);
}

}
11 changes: 0 additions & 11 deletions src/DTO/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,4 @@ class Config
public array $dependencies = [];

public ?string $root = null;

public function fnIndexFromApiName(string $apiName): ?int
{
foreach ($this->dependencies as $index => $dep) {
if ($dep->api_name === $apiName) {
return $index;
}
}

return null;
}
}
2 changes: 1 addition & 1 deletion tests/ExampleTest.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

it('can test', function () {
$c = new \SergiX44\Gradio\Client('https://sanchit-gandhi-whisper-jax.hf.space/');
$c = new \SergiX44\Gradio\Client('https://huggingface-projects-qr-code-ai-art-generator--85d7ps6wv.hf.space');

expect($c)->toBeInstanceOf(\SergiX44\Gradio\Client::class);
expect($c->getConfig())->toBeInstanceOf(\SergiX44\Gradio\DTO\Config::class);
Expand Down

0 comments on commit f217edc

Please sign in to comment.