Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/api-client/src/Transport/Enums/ContentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@
enum ContentType: string
{
case JSON = 'application/json';

case MULTIPART = 'multipart/form-data';
}
9 changes: 6 additions & 3 deletions packages/api-client/src/Transport/Payload.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ private function __construct(
/**
* @param array<string, mixed> $parameters
*/
public static function create(string $resource, array $parameters): self
{
public static function create(
string $resource,
array $parameters,
ContentType $contentType = ContentType::JSON,
): self {
return new self(
contentType: ContentType::JSON,
contentType: $contentType,
method: Method::POST,
resourceUri: ResourceUri::get($resource),
parameters: $parameters,
Expand Down
29 changes: 29 additions & 0 deletions packages/api-client/src/Transport/Response/RawResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Modelflow AI package.
*
* (c) Johannes Wachter <johannes@sulu.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ModelflowAi\ApiClient\Transport\Response;

use ModelflowAi\ApiClient\Responses\MetaInformation;

readonly class RawResponse extends Response
{
/**
* @param resource $resource
*/
public function __construct(
public mixed $resource,
MetaInformation $meta,
) {
parent::__construct($meta);
}
}
40 changes: 34 additions & 6 deletions packages/api-client/src/Transport/SymfonyHttpTransporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

use ModelflowAi\ApiClient\Exceptions\TransportException;
use ModelflowAi\ApiClient\Responses\MetaInformation;
use ModelflowAi\ApiClient\Transport\Enums\ContentType;
use ModelflowAi\ApiClient\Transport\Response\ObjectResponse;
use ModelflowAi\ApiClient\Transport\Response\RawResponse;
use ModelflowAi\ApiClient\Transport\Response\TextResponse;
use Symfony\Component\HttpClient\Exception\ClientException;
use Symfony\Contracts\HttpClient\ChunkInterface;
Expand All @@ -42,15 +44,24 @@ public function __construct(

private function request(Payload $payload): ResponseInterface
{
$options = [
'headers' => [
'Content-Type' => $payload->contentType->value,
],
];

if (ContentType::JSON === $payload->contentType) {
$options['json'] = $payload->parameters;
}

if (ContentType::MULTIPART === $payload->contentType) {
$options['body'] = $payload->parameters;
}

return $this->client->request(
$payload->method->value,
$payload->resourceUri->__toString(),
[
'headers' => [
'Content-Type' => $payload->contentType->value,
],
'json' => $payload->parameters,
],
$options,
);
}

Expand Down Expand Up @@ -103,4 +114,21 @@ public function requestStream(Payload $payload, ?callable $decoder = null): \Ite
}
}
}

public function requestRaw(Payload $payload): RawResponse
{
$response = $this->request($payload);

try {
// @phpstan-ignore-next-line
$metaInformation = MetaInformation::from($response->getHeaders());
} catch (ClientException $exception) {
throw new TransportException($exception->getResponse(), $exception->getCode(), $exception);
}

// @phpstan-ignore-next-line - toStream() exists in concrete implementations but not in ResponseInterface
$resource = $response->toStream();

return new RawResponse($resource, $metaInformation);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use ModelflowAi\ApiClient\Transport\Payload;
use ModelflowAi\ApiClient\Transport\Response\ObjectResponse;
use ModelflowAi\ApiClient\Transport\Response\RawResponse;
use ModelflowAi\ApiClient\Transport\Response\Response;
use ModelflowAi\ApiClient\Transport\Response\TextResponse;

Expand Down Expand Up @@ -71,9 +72,19 @@ public function matchStreamedResponse(Payload $payload): ?StreamedResponse
return null;
}

public function matchRawResponse(Payload $payload): ?RawResponse
{
$response = $this->matchResponse($payload);
if ($response instanceof RawResponse) {
return $response;
}

return null;
}

private function payloadMatches(Payload $payload, PartialPayload $partialPayload): bool
{
if ($payload->contentType->name !== $partialPayload->contentType->name // @phpstan-ignore-line
if ($payload->contentType->name !== $partialPayload->contentType->name
|| $payload->method->name !== $partialPayload->method->name
|| false === $payload->resourceUri->equals($partialPayload->resourceUri)
) {
Expand Down
11 changes: 11 additions & 0 deletions packages/api-client/src/Transport/Testing/MockTransport.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use ModelflowAi\ApiClient\Responses\MetaInformation;
use ModelflowAi\ApiClient\Transport\Payload;
use ModelflowAi\ApiClient\Transport\Response\ObjectResponse;
use ModelflowAi\ApiClient\Transport\Response\RawResponse;
use ModelflowAi\ApiClient\Transport\Response\TextResponse;
use ModelflowAi\ApiClient\Transport\TransportInterface;
use Symfony\Component\HttpClient\Chunk\DataChunk;
Expand Down Expand Up @@ -65,4 +66,14 @@ public function requestStream(Payload $payload, ?callable $decoder = null): \Ite
}
}
}

public function requestRaw(Payload $payload): RawResponse
{
$response = $this->matcher->matchRawResponse($payload);
if (!$response instanceof RawResponse) {
throw new \RuntimeException('No matching response found for payload');
}

return $response;
}
}
3 changes: 3 additions & 0 deletions packages/api-client/src/Transport/TransportInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace ModelflowAi\ApiClient\Transport;

use ModelflowAi\ApiClient\Transport\Response\ObjectResponse;
use ModelflowAi\ApiClient\Transport\Response\RawResponse;
use ModelflowAi\ApiClient\Transport\Response\TextResponse;

interface TransportInterface
Expand All @@ -23,4 +24,6 @@ public function requestText(Payload $payload): TextResponse;
public function requestObject(Payload $payload): ObjectResponse;

public function requestStream(Payload $payload, ?callable $decoder = null): \Iterator;

public function requestRaw(Payload $payload): RawResponse;
}
8 changes: 8 additions & 0 deletions packages/stability-adapter/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.gitattributes export-ignore
.gitignore export-ignore
composer.lock export-ignore
/tests export-ignore
phpunit.xml.dist export-ignore
.php-cs-fixer.dist.php export-ignore
phpstan.neon export-ignore
rector.php export-ignore
10 changes: 10 additions & 0 deletions packages/stability-adapter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/vendor/
/composer.phar
/phpunit.xml
/.phpunit.cache
/tests/var
/docker-compose.override.yml
/.php-cs-fixer.php
/.php-cs-fixer.cache
/var/reports
/var/cobertura-coverage.xml
14 changes: 14 additions & 0 deletions packages/stability-adapter/.php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

$phpCsConfig = require(dirname(__DIR__, 2) . '/.php-cs-fixer.dist.php');

$finder = (new PhpCsFixer\Finder())
->in(__DIR__)
->ignoreVCSIgnored(true);

$phpCsConfig->setFinder($finder);

return $phpCsConfig->setFinder($finder);

94 changes: 94 additions & 0 deletions packages/stability-adapter/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"name": "modelflow-ai/stability-adapter",
"description": "Integrates the StabilityAI ecosystem into modelflow-ai.",
"type": "library",
"license": "MIT",
"keywords": [
"ai",
"stability",
"stable-diffusion",
"image-generation"
],
"autoload": {
"psr-4": {
"ModelflowAi\\StabilityAdapter\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"ModelflowAi\\StabilityAdapter\\Tests\\": "tests/"
}
},
"authors": [
{
"name": "Johannes Wachter",
"email": "johannes@sulu.io"
}
],
"require": {
"php": "^8.2",
"modelflow-ai/stability": "^0.4",
"modelflow-ai/image": "^0.4"
},
"require-dev": {
"php-cs-fixer/shim": "^3.15",
"phpstan/extension-installer": "^1.2",
"phpstan/phpstan": "^1.10, <1.10.55",
"phpstan/phpstan-phpunit": "^1.3@stable",
"phpunit/phpunit": "^10.3",
"rector/rector": "^0.18.1",
"phpspec/prophecy": "^1.0@dev",
"jangregor/phpstan-prophecy": "^1.0",
"phpspec/prophecy-phpunit": "^2.1@stable",
"symfony/dotenv": "^7.1",
"symfony/console": "^7.1",
"asapo/remove-vendor-plugin": "^0.1"
},
"suggest": {
"modelflow-ai/image": "To use the image generation."
},
"scripts": {
"test-with-coverage": "@test --coverage-php var/reports/coverage.cov --coverage-cobertura=var/cobertura-coverage.xml --coverage-html var/reports/html --log-junit var/reports/junit.xml",
"test": [
"Composer\\Config::disableProcessTimeout",
"vendor/bin/phpunit"
],
"phpstan": "@php vendor/bin/phpstan analyze",
"lint-rector": "@php vendor/bin/rector process --dry-run",
"lint-php-cs": "@php vendor/bin/php-cs-fixer fix --verbose --diff --dry-run",
"lint": [
"@phpstan",
"@lint-php-cs",
"@lint-rector",
"@lint-composer"
],
"lint-composer": "@composer validate --strict",
"rector": "@php vendor/bin/rector process",
"php-cs-fix": "@php vendor/bin/php-cs-fixer fix",
"fix": [
"@rector",
"@php-cs-fix"
]
},
"repositories": [
{
"type": "path",
"url": "./../*",
"options": {
"symlink": false
}
}
],
"minimum-stability": "dev",
"config": {
"allow-plugins": {
"phpstan/extension-installer": true,
"asapo/remove-vendor-plugin": true
}
},
"extra": {
"remove-folders": [
"modelflow-ai/*/vendor"
]
}
}
Loading
Loading