Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit c6ba1ce

Browse files
committed
refactor: add extension point to payload contract handling
1 parent f910203 commit c6ba1ce

21 files changed

+281
-55
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpLlm\LlmChain\Bridge\OpenAI\DallE;
6+
7+
use PhpLlm\LlmChain\Bridge\OpenAI\DallE;
8+
use PhpLlm\LlmChain\Model\Model;
9+
use PhpLlm\LlmChain\Platform\Contract\Extension;
10+
11+
final class ContractExtension implements Extension
12+
{
13+
public function supports(Model $model): bool
14+
{
15+
return $model instanceof DallE;
16+
}
17+
18+
public function registerTypes(): array
19+
{
20+
return [
21+
'string' => 'handleInput',
22+
];
23+
}
24+
25+
public function handleInput(string $input): array
26+
{
27+
return [
28+
'prompt' => $input,
29+
];
30+
}
31+
}

src/Bridge/OpenAI/DallE/ModelClient.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,17 @@ public function __construct(
2828
Assert::startsWith($apiKey, 'sk-', 'The API key must start with "sk-".');
2929
}
3030

31-
public function supports(Model $model, array|string|object $input): bool
31+
public function supports(Model $model): bool
3232
{
3333
return $model instanceof DallE;
3434
}
3535

36-
public function request(Model $model, object|array|string $input, array $options = []): HttpResponse
36+
public function request(Model $model, array $payload, array $options = []): HttpResponse
3737
{
3838
return $this->httpClient->request('POST', 'https://api.openai.com/v1/images/generations', [
3939
'auth_bearer' => $this->apiKey,
40-
'json' => \array_merge($options, [
40+
'json' => \array_merge($options, $payload, [
4141
'model' => $model->getName(),
42-
'prompt' => $input,
4342
]),
4443
]);
4544
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpLlm\LlmChain\Bridge\OpenAI\Embeddings;
6+
7+
use PhpLlm\LlmChain\Bridge\OpenAI\Embeddings;
8+
use PhpLlm\LlmChain\Model\Model;
9+
use PhpLlm\LlmChain\Platform\Contract\Extension;
10+
11+
final class ContractExtension implements Extension
12+
{
13+
public function supports(Model $model): bool
14+
{
15+
return $model instanceof Embeddings;
16+
}
17+
18+
public function registerTypes(): array
19+
{
20+
return [
21+
'string' => 'handleInput',
22+
];
23+
}
24+
25+
public function handleInput(string $input): array
26+
{
27+
return [
28+
'input' => $input,
29+
];
30+
}
31+
}

src/Bridge/OpenAI/Embeddings/ModelClient.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,17 @@ public function __construct(
2222
Assert::startsWith($apiKey, 'sk-', 'The API key must start with "sk-".');
2323
}
2424

25-
public function supports(Model $model, array|string|object $input): bool
25+
public function supports(Model $model): bool
2626
{
2727
return $model instanceof Embeddings;
2828
}
2929

30-
public function request(Model $model, object|array|string $input, array $options = []): ResponseInterface
30+
public function request(Model $model, array $payload, array $options = []): ResponseInterface
3131
{
3232
return $this->httpClient->request('POST', 'https://api.openai.com/v1/embeddings', [
3333
'auth_bearer' => $this->apiKey,
34-
'json' => array_merge($model->getOptions(), $options, [
34+
'json' => array_merge($options, $payload, [
3535
'model' => $model->getName(),
36-
'input' => $input,
3736
]),
3837
]);
3938
}

src/Bridge/OpenAI/Embeddings/ResponseConverter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
final class ResponseConverter implements PlatformResponseConverter
1616
{
17-
public function supports(Model $model, array|string|object $input): bool
17+
public function supports(Model $model): bool
1818
{
1919
return $model instanceof Embeddings;
2020
}

src/Bridge/OpenAI/GPT/ModelClient.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,26 @@
1818

1919
public function __construct(
2020
HttpClientInterface $httpClient,
21-
#[\SensitiveParameter] private string $apiKey,
21+
#[\SensitiveParameter]
22+
private string $apiKey,
2223
) {
2324
$this->httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
2425
Assert::stringNotEmpty($apiKey, 'The API key must not be empty.');
2526
Assert::startsWith($apiKey, 'sk-', 'The API key must start with "sk-".');
2627
}
2728

28-
public function supports(Model $model, array|string|object $input): bool
29+
public function supports(Model $model): bool
2930
{
3031
return $model instanceof GPT;
3132
}
3233

33-
public function request(Model $model, object|array|string $input, array $options = []): ResponseInterface
34+
public function request(Model $model, array $payload, array $options = []): ResponseInterface
3435
{
3536
return $this->httpClient->request('POST', 'https://api.openai.com/v1/chat/completions', [
3637
'auth_bearer' => $this->apiKey,
3738
'json' => array_merge($options, [
3839
'model' => $model->getName(),
39-
'messages' => $input,
40+
'messages' => $payload,
4041
]),
4142
]);
4243
}

src/Bridge/OpenAI/GPT/ResponseConverter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
final class ResponseConverter implements PlatformResponseConverter
2626
{
27-
public function supports(Model $model, array|string|object $input): bool
27+
public function supports(Model $model): bool
2828
{
2929
return $model instanceof GPT;
3030
}

src/Bridge/OpenAI/PlatformFactory.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44

55
namespace PhpLlm\LlmChain\Bridge\OpenAI;
66

7+
use PhpLlm\LlmChain\Bridge\OpenAI\DallE\ContractExtension as DallEContractExtension;
78
use PhpLlm\LlmChain\Bridge\OpenAI\DallE\ModelClient as DallEModelClient;
9+
use PhpLlm\LlmChain\Bridge\OpenAI\Embeddings\ContractExtension as EmbeddingsContractExtension;
810
use PhpLlm\LlmChain\Bridge\OpenAI\Embeddings\ModelClient as EmbeddingsModelClient;
911
use PhpLlm\LlmChain\Bridge\OpenAI\Embeddings\ResponseConverter as EmbeddingsResponseConverter;
1012
use PhpLlm\LlmChain\Bridge\OpenAI\GPT\ModelClient as GPTModelClient;
1113
use PhpLlm\LlmChain\Bridge\OpenAI\GPT\ResponseConverter as GPTResponseConverter;
14+
use PhpLlm\LlmChain\Bridge\OpenAI\Whisper\ContractExtension as WhisperContractExtension;
1215
use PhpLlm\LlmChain\Bridge\OpenAI\Whisper\ModelClient as WhisperModelClient;
1316
use PhpLlm\LlmChain\Bridge\OpenAI\Whisper\ResponseConverter as WhisperResponseConverter;
1417
use PhpLlm\LlmChain\Platform;
18+
use PhpLlm\LlmChain\Platform\Contract;
1519
use Symfony\Component\HttpClient\EventSourceHttpClient;
1620
use Symfony\Contracts\HttpClient\HttpClientInterface;
1721

@@ -39,6 +43,11 @@ public static function create(
3943
$dallEModelClient,
4044
new WhisperResponseConverter(),
4145
],
46+
Contract::create(
47+
new DallEContractExtension(),
48+
new EmbeddingsContractExtension(),
49+
new WhisperContractExtension(),
50+
),
4251
);
4352
}
4453
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpLlm\LlmChain\Bridge\OpenAI\Whisper;
6+
7+
use PhpLlm\LlmChain\Bridge\OpenAI\Whisper;
8+
use PhpLlm\LlmChain\Model\Message\Content\Audio;
9+
use PhpLlm\LlmChain\Model\Model;
10+
use PhpLlm\LlmChain\Platform\Contract\Extension;
11+
12+
final class ContractExtension implements Extension
13+
{
14+
public function supports(Model $model): bool
15+
{
16+
return $model instanceof Whisper;
17+
}
18+
19+
public function registerTypes(): array
20+
{
21+
return [
22+
Audio::class => 'handleAudioInput',
23+
];
24+
}
25+
26+
public function handleAudioInput(Audio $audio): array
27+
{
28+
return [
29+
'file' => $audio->asResource(),
30+
];
31+
}
32+
}

src/Bridge/OpenAI/Whisper/ModelClient.php

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace PhpLlm\LlmChain\Bridge\OpenAI\Whisper;
66

77
use PhpLlm\LlmChain\Bridge\OpenAI\Whisper;
8-
use PhpLlm\LlmChain\Model\Message\Content\Audio;
98
use PhpLlm\LlmChain\Model\Model;
109
use PhpLlm\LlmChain\Platform\ModelClient as BaseModelClient;
1110
use Symfony\Contracts\HttpClient\HttpClientInterface;
@@ -22,22 +21,17 @@ public function __construct(
2221
Assert::stringNotEmpty($apiKey, 'The API key must not be empty.');
2322
}
2423

25-
public function supports(Model $model, object|array|string $input): bool
24+
public function supports(Model $model): bool
2625
{
27-
return $model instanceof Whisper && $input instanceof Audio;
26+
return $model instanceof Whisper;
2827
}
2928

30-
public function request(Model $model, object|array|string $input, array $options = []): ResponseInterface
29+
public function request(Model $model, array $payload, array $options = []): ResponseInterface
3130
{
32-
assert($input instanceof Audio);
33-
3431
return $this->httpClient->request('POST', 'https://api.openai.com/v1/audio/transcriptions', [
3532
'auth_bearer' => $this->apiKey,
3633
'headers' => ['Content-Type' => 'multipart/form-data'],
37-
'body' => array_merge($options, $model->getOptions(), [
38-
'model' => $model->getName(),
39-
'file' => $input->asResource(),
40-
]),
34+
'body' => array_merge($options, $payload, ['model' => $model->getName()]),
4135
]);
4236
}
4337
}

0 commit comments

Comments
 (0)