Skip to content

Commit 3a1af5d

Browse files
committed
ref
1 parent 92dbd99 commit 3a1af5d

File tree

7 files changed

+253
-90
lines changed

7 files changed

+253
-90
lines changed

src/platform/src/Bridge/Venice/ModelCatalog.php

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,55 +12,90 @@
1212
namespace Symfony\AI\Platform\Bridge\Venice;
1313

1414
use Symfony\AI\Platform\Capability;
15-
use Symfony\AI\Platform\Model;
16-
use Symfony\AI\Platform\ModelCatalog\AbstractModelCatalog;
15+
use Symfony\AI\Platform\Exception\InvalidArgumentException;
16+
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
17+
use Symfony\Contracts\HttpClient\HttpClientInterface;
1718

1819
/**
1920
* @author Guillaume Loulier <personal@guillaumeloulier.fr>
2021
*/
21-
final class ModelCatalog extends AbstractModelCatalog
22+
final class ModelCatalog implements ModelCatalogInterface
2223
{
23-
/**
24-
* @param array<string, array{class: class-string<Model>, capabilities: list<Capability>}> $additionalModels
25-
*/
26-
public function __construct(array $additionalModels = [])
24+
public function __construct(
25+
private readonly HttpClientInterface $httpClient,
26+
) {
27+
}
28+
29+
public function getModel(string $modelName): Venice
2730
{
28-
$defaultModels = [
29-
'venice-uncensored' => [
31+
$models = $this->getModels();
32+
33+
if (!\array_key_exists($modelName, $models)) {
34+
throw new InvalidArgumentException(\sprintf('The model "%s" cannot be retrieved from the API.', $modelName));
35+
}
36+
37+
if ([] === $models[$modelName]['capabilities']) {
38+
throw new InvalidArgumentException(\sprintf('The model "%s" is not supported, please check the Venice API.', $modelName));
39+
}
40+
41+
return new Venice($modelName, $models[$modelName]['capabilities']);
42+
}
43+
44+
public function getModels(): array
45+
{
46+
$results = $this->httpClient->request('GET', 'models', [
47+
'query' => [
48+
'type' => 'all',
49+
],
50+
]);
51+
52+
$models = $results->toArray();
53+
54+
if ([] === $models['data']) {
55+
return [];
56+
}
57+
58+
$payload = static fn (array $model): array => match ($model['type']) {
59+
'asr' => [
3060
'class' => Venice::class,
3161
'capabilities' => [
32-
Capability::INPUT_MESSAGES,
62+
Capability::SPEECH_RECOGNITION,
63+
Capability::INPUT_TEXT,
3364
],
3465
],
35-
'tts-kokoro' => [
66+
'embedding' => [
3667
'class' => Venice::class,
3768
'capabilities' => [
38-
Capability::TEXT_TO_SPEECH,
69+
Capability::EMBEDDINGS,
70+
Capability::INPUT_TEXT,
3971
],
4072
],
41-
'nvidia/parakeet-tdt-0.6b-v3' => [
73+
'text' => [
4274
'class' => Venice::class,
4375
'capabilities' => [
44-
Capability::SPEECH_TO_TEXT,
76+
Capability::INPUT_TEXT,
77+
Capability::INPUT_MESSAGES,
4578
],
4679
],
47-
'openai/whisper-large-v3' => [
80+
'tts' => [
4881
'class' => Venice::class,
4982
'capabilities' => [
50-
Capability::SPEECH_TO_TEXT,
83+
Capability::TEXT_TO_SPEECH,
84+
Capability::INPUT_TEXT,
5185
],
5286
],
53-
'text-embedding-bge-m3' => [
87+
'video' => [
5488
'class' => Venice::class,
5589
'capabilities' => [
56-
Capability::EMBEDDINGS,
90+
Capability::IMAGE_TO_VIDEO,
91+
Capability::INPUT_IMAGE,
5792
],
5893
],
59-
];
94+
};
6095

61-
$this->models = [
62-
...$defaultModels,
63-
...$additionalModels,
64-
];
96+
return array_combine(
97+
array_map(static fn (array $model): string => $model['id'], $models['data']),
98+
array_map(static fn (array $model): array => $payload($model), $models['data']),
99+
);
65100
}
66101
}

src/platform/src/Bridge/Venice/PlatformFactory.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,24 @@
2727
final class PlatformFactory
2828
{
2929
public static function create(
30-
#[\SensitiveParameter] string $apiKey,
30+
#[\SensitiveParameter] ?string $apiKey = null,
3131
string $endpoint = 'https://api.venice.ai/api/v1/',
3232
?HttpClientInterface $httpClient = null,
33-
ModelCatalogInterface $modelCatalog = new ModelCatalog(),
3433
?Contract $contract = null,
3534
?EventDispatcherInterface $eventDispatcher = null,
3635
): PlatformInterface {
3736
$httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
3837

39-
$httpClient = ScopingHttpClient::forBaseUri($httpClient, $endpoint, [
40-
'auth_bearer' => $apiKey,
41-
]);
38+
if (null !== $apiKey) {
39+
$httpClient = ScopingHttpClient::forBaseUri($httpClient, $endpoint, [
40+
'auth_bearer' => $apiKey,
41+
]);
42+
}
4243

4344
return new Platform(
4445
[new VeniceClient($httpClient)],
4546
[new ResultConverter()],
46-
$modelCatalog ?? new VeniceApiModelCatalog($httpClient),
47+
new ModelCatalog($httpClient),
4748
$contract ?? VeniceContract::create(),
4849
$eventDispatcher,
4950
);

src/platform/src/Bridge/Venice/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
Ollama Platform
1+
Venice Platform
22
===============
33

4-
Ollama platform bridge for Symfony AI.
4+
Venice platform bridge for Symfony AI.
55

66
Resources
77
---------
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Platform\Bridge\Venice\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\AI\Platform\Bridge\Venice\ModelCatalog;
16+
use Symfony\AI\Platform\Capability;
17+
use Symfony\AI\Platform\Exception\InvalidArgumentException;
18+
use Symfony\Component\HttpClient\MockHttpClient;
19+
use Symfony\Component\HttpClient\Response\JsonMockResponse;
20+
21+
final class ModelCatalogTest extends TestCase
22+
{
23+
public function testModelCatalogCannotReturnModelFromApiWhenUndefined()
24+
{
25+
$httpClient = new MockHttpClient([
26+
new JsonMockResponse(['data' => []]),
27+
]);
28+
29+
$modelCatalog = new ModelCatalog($httpClient);
30+
31+
$this->expectException(InvalidArgumentException::class);
32+
$this->expectExceptionMessage('The model "foo" cannot be retrieved from the API.');
33+
$this->expectExceptionCode(0);
34+
$modelCatalog->getModel('foo');
35+
}
36+
37+
public function testModelCatalogCannotReturnUnsupportedModelFromApi()
38+
{
39+
$httpClient = new MockHttpClient([
40+
new JsonMockResponse([
41+
'data' => [
42+
[
43+
'createdAt' => (new \DateTimeImmutable())->getTimestamp(),
44+
'id' => 'llama-3.2-3b',
45+
'model_spec' => [
46+
'capabilities' => [
47+
'optimizedForCode' => true,
48+
'quantization' => 'fp16',
49+
'supportsFunctionCalling' => true,
50+
'supportsReasoning' => false,
51+
'supportsVision' => false,
52+
'supportsWebSearch' => true,
53+
],
54+
],
55+
'object' => 'model',
56+
'owned_by' => 'venice.ai',
57+
'type' => 'text',
58+
],
59+
[
60+
'createdAt' => (new \DateTimeImmutable())->getTimestamp(),
61+
'id' => 'foo',
62+
'model_spec' => [
63+
'capabilities' => [
64+
'optimizedForCode' => false,
65+
'quantization' => 'fp16',
66+
'supportsFunctionCalling' => false,
67+
'supportsReasoning' => false,
68+
'supportsVision' => false,
69+
'supportsWebSearch' => false,
70+
],
71+
],
72+
'object' => 'model',
73+
'owned_by' => 'venice.ai',
74+
'type' => 'text',
75+
],
76+
],
77+
'object' => 'list',
78+
'type' => 'all',
79+
]),
80+
]);
81+
82+
$modelCatalog = new ModelCatalog($httpClient);
83+
84+
$this->expectException(InvalidArgumentException::class);
85+
$this->expectExceptionMessage('The model "foo" is not supported, please check the Venice API.');
86+
$this->expectExceptionCode(0);
87+
$modelCatalog->getModel('foo');
88+
}
89+
90+
public function testModelCatalogCanReturnAsrModelFromApi()
91+
{
92+
$httpClient = new MockHttpClient([
93+
new JsonMockResponse([
94+
'data' => [
95+
[
96+
'createdAt' => (new \DateTimeImmutable())->getTimestamp(),
97+
'id' => 'nvidia/parakeet-tdt-0.6b-v3',
98+
'model_spec' => [
99+
'pricing' => [
100+
'per_audio_second' => [
101+
'usd' => 0.0001,
102+
'diem' => 0.0001
103+
],
104+
],
105+
],
106+
'name' => 'Parakeet ASR',
107+
'modelSource' => 'https://huggingface.co/nvidia/parakeet-tdt-0.6b-v3',
108+
'offline' => false,
109+
'privacy' => 'private',
110+
'object' => 'model',
111+
'owned_by' => 'venice.ai',
112+
'type' => 'asr',
113+
],
114+
],
115+
'object' => 'list',
116+
'type' => 'all',
117+
]),
118+
]);
119+
120+
$modelCatalog = new ModelCatalog($httpClient);
121+
122+
$model = $modelCatalog->getModel('nvidia/parakeet-tdt-0.6b-v3');
123+
124+
$this->assertSame('nvidia/parakeet-tdt-0.6b-v3', $model->getName());
125+
$this->assertSame([
126+
Capability::SPEECH_RECOGNITION,
127+
Capability::INPUT_TEXT,
128+
], $model->getCapabilities());
129+
130+
$this->assertSame(1, $httpClient->getRequestsCount());
131+
}
132+
133+
public function testModelCatalogCanReturnEmbeddingModelFromApi()
134+
{
135+
$httpClient = new MockHttpClient([
136+
new JsonMockResponse([
137+
'data' => [
138+
[
139+
'createdAt' => (new \DateTimeImmutable())->getTimestamp(),
140+
'id' => 'text-embedding-bge-m3',
141+
'model_spec' => [
142+
'pricing' => [
143+
'input' => [
144+
'usd' => 0.15,
145+
'diem' => 0.15
146+
],
147+
'output' => [
148+
'usd' => 0.6,
149+
'diem' => 0.6
150+
],
151+
],
152+
],
153+
'name' => 'BGE-3',
154+
'modelSource' => 'https://huggingface.co/BAAI/bge-m3',
155+
'offline' => false,
156+
'privacy' => 'private',
157+
'object' => 'model',
158+
'owned_by' => 'venice.ai',
159+
'type' => 'embedding',
160+
],
161+
],
162+
'object' => 'list',
163+
'type' => 'all',
164+
]),
165+
]);
166+
167+
$modelCatalog = new ModelCatalog($httpClient);
168+
169+
$model = $modelCatalog->getModel('text-embedding-bge-m3');
170+
171+
$this->assertSame('text-embedding-bge-m3', $model->getName());
172+
$this->assertSame([
173+
Capability::EMBEDDINGS,
174+
Capability::INPUT_TEXT,
175+
], $model->getCapabilities());
176+
177+
$this->assertSame(1, $httpClient->getRequestsCount());
178+
}
179+
180+
public function testModelCatalogCanReturnImageModelFromApi()
181+
{
182+
183+
}
184+
}

src/platform/src/Bridge/Venice/Tests/VeniceModelCatalogTest.php

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/platform/src/Bridge/Venice/VeniceApiModelCatalog.php

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)