Skip to content

Commit dcc4318

Browse files
committed
feature #475 [Platform][Mistral] Add DocumentUrlNormalizer (petski)
This PR was squashed before being merged into the main branch. Discussion ---------- [Platform][Mistral] Add `DocumentUrlNormalizer` | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Docs? | no | Issues | Follows #464 | License | MIT Normalizer for `DocumentUrl` As promised in #464 :) See https://docs.mistral.ai/api/#tag/chat/operation/chat_completion_v1_chat_completions_post for documentation Commits ------- bbaa6e9 [Platform][Mistral] Add `DocumentUrlNormalizer`
2 parents a251c05 + bbaa6e9 commit dcc4318

File tree

5 files changed

+180
-1
lines changed

5 files changed

+180
-1
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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+
use Symfony\AI\Agent\Agent;
13+
use Symfony\AI\Platform\Bridge\Mistral\Mistral;
14+
use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory;
15+
use Symfony\AI\Platform\Message\Content\Document;
16+
use Symfony\AI\Platform\Message\Message;
17+
use Symfony\AI\Platform\Message\MessageBag;
18+
19+
require_once dirname(__DIR__).'/bootstrap.php';
20+
21+
$platform = PlatformFactory::create(env('MISTRAL_API_KEY'), httpClient: http_client());
22+
$model = new Mistral(Mistral::MISTRAL_SMALL);
23+
24+
$agent = new Agent($platform, $model, logger: logger());
25+
$messages = new MessageBag(
26+
Message::ofUser(
27+
Document::fromFile(dirname(__DIR__, 2).'/fixtures/document.pdf'),
28+
'What is this document about?',
29+
),
30+
);
31+
$result = $agent->call($messages);
32+
33+
echo $result->getContent().\PHP_EOL;

examples/mistral/pdf-input-url.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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+
use Symfony\AI\Agent\Agent;
13+
use Symfony\AI\Platform\Bridge\Mistral\Mistral;
14+
use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory;
15+
use Symfony\AI\Platform\Message\Content\DocumentUrl;
16+
use Symfony\AI\Platform\Message\Message;
17+
use Symfony\AI\Platform\Message\MessageBag;
18+
19+
require_once dirname(__DIR__).'/bootstrap.php';
20+
21+
$platform = PlatformFactory::create(env('MISTRAL_API_KEY'), httpClient: http_client());
22+
$model = new Mistral(Mistral::MISTRAL_SMALL);
23+
24+
$agent = new Agent($platform, $model, logger: logger());
25+
$messages = new MessageBag(
26+
Message::ofUser(
27+
new DocumentUrl('https://upload.wikimedia.org/wikipedia/commons/2/20/Re_example.pdf'),
28+
'What is this document about?',
29+
),
30+
);
31+
$result = $agent->call($messages);
32+
33+
echo $result->getContent().\PHP_EOL;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Mistral\Contract;
13+
14+
use Symfony\AI\Platform\Bridge\Mistral\Mistral;
15+
use Symfony\AI\Platform\Contract\Normalizer\ModelContractNormalizer;
16+
use Symfony\AI\Platform\Message\Content\DocumentUrl;
17+
use Symfony\AI\Platform\Model;
18+
19+
class DocumentUrlNormalizer extends ModelContractNormalizer
20+
{
21+
/**
22+
* @param DocumentUrl $data
23+
*
24+
* @return array{type: 'document_url', document_url: string}
25+
*/
26+
public function normalize(mixed $data, ?string $format = null, array $context = []): array
27+
{
28+
return [
29+
'type' => 'document_url',
30+
'document_url' => $data->url,
31+
];
32+
}
33+
34+
protected function supportedDataClass(): string
35+
{
36+
return DocumentUrl::class;
37+
}
38+
39+
protected function supportsModel(Model $model): bool
40+
{
41+
return $model instanceof Mistral;
42+
}
43+
}

src/platform/src/Bridge/Mistral/PlatformFactory.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\AI\Platform\Bridge\Mistral;
1313

1414
use Symfony\AI\Platform\Bridge\Mistral\Contract\DocumentNormalizer;
15+
use Symfony\AI\Platform\Bridge\Mistral\Contract\DocumentUrlNormalizer;
1516
use Symfony\AI\Platform\Bridge\Mistral\Contract\ToolNormalizer;
1617
use Symfony\AI\Platform\Contract;
1718
use Symfony\AI\Platform\Platform;
@@ -36,7 +37,8 @@ public static function create(
3637
[new Embeddings\ResultConverter(), new Llm\ResultConverter()],
3738
$contract ?? Contract::create(
3839
new ToolNormalizer(),
39-
new DocumentNormalizer()
40+
new DocumentNormalizer(),
41+
new DocumentUrlNormalizer(),
4042
),
4143
);
4244
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Tests\Bridge\Mistral\Contract;
13+
14+
use PHPUnit\Framework\Attributes\CoversClass;
15+
use PHPUnit\Framework\Attributes\DataProvider;
16+
use PHPUnit\Framework\Attributes\Medium;
17+
use PHPUnit\Framework\TestCase;
18+
use Symfony\AI\Platform\Bridge\Mistral\Contract\DocumentUrlNormalizer;
19+
use Symfony\AI\Platform\Bridge\Mistral\Mistral;
20+
use Symfony\AI\Platform\Contract;
21+
use Symfony\AI\Platform\Message\Content\DocumentUrl;
22+
23+
#[Medium]
24+
#[CoversClass(DocumentUrlNormalizer::class)]
25+
final class DocumentUrlNormalizerTest extends TestCase
26+
{
27+
public function testSupportsNormalization()
28+
{
29+
$normalizer = new DocumentUrlNormalizer();
30+
31+
$this->assertTrue($normalizer->supportsNormalization(new DocumentUrl('https://example.com/document.pdf'), context: [
32+
Contract::CONTEXT_MODEL => new Mistral(),
33+
]));
34+
$this->assertFalse($normalizer->supportsNormalization('not a document url'));
35+
}
36+
37+
public function testGetSupportedTypes()
38+
{
39+
$normalizer = new DocumentUrlNormalizer();
40+
41+
$expected = [
42+
DocumentUrl::class => true,
43+
];
44+
45+
$this->assertSame($expected, $normalizer->getSupportedTypes(null));
46+
}
47+
48+
#[DataProvider('normalizeDataProvider')]
49+
public function testNormalize(DocumentUrl $file, array $expected)
50+
{
51+
$normalizer = new DocumentUrlNormalizer();
52+
53+
$normalized = $normalizer->normalize($file);
54+
55+
$this->assertEquals($expected, $normalized);
56+
}
57+
58+
public static function normalizeDataProvider(): iterable
59+
{
60+
yield 'document with url' => [
61+
new DocumentUrl('https://example.com/document.pdf'),
62+
[
63+
'type' => 'document_url',
64+
'document_url' => 'https://example.com/document.pdf',
65+
],
66+
];
67+
}
68+
}

0 commit comments

Comments
 (0)