diff --git a/examples/mistral/pdf-input-binary.php b/examples/mistral/pdf-input-binary.php new file mode 100644 index 000000000..a8b05c26f --- /dev/null +++ b/examples/mistral/pdf-input-binary.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\AI\Agent\Agent; +use Symfony\AI\Platform\Bridge\Mistral\Mistral; +use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory; +use Symfony\AI\Platform\Message\Content\Document; +use Symfony\AI\Platform\Message\Message; +use Symfony\AI\Platform\Message\MessageBag; + +require_once dirname(__DIR__).'/bootstrap.php'; + +$platform = PlatformFactory::create(env('MISTRAL_API_KEY'), httpClient: http_client()); +$model = new Mistral(Mistral::MISTRAL_SMALL); + +$agent = new Agent($platform, $model, logger: logger()); +$messages = new MessageBag( + Message::ofUser( + Document::fromFile(dirname(__DIR__, 2).'/fixtures/document.pdf'), + 'What is this document about?', + ), +); +$result = $agent->call($messages); + +echo $result->getContent().\PHP_EOL; diff --git a/examples/mistral/pdf-input-url.php b/examples/mistral/pdf-input-url.php new file mode 100644 index 000000000..1d69e27f5 --- /dev/null +++ b/examples/mistral/pdf-input-url.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\AI\Agent\Agent; +use Symfony\AI\Platform\Bridge\Mistral\Mistral; +use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory; +use Symfony\AI\Platform\Message\Content\DocumentUrl; +use Symfony\AI\Platform\Message\Message; +use Symfony\AI\Platform\Message\MessageBag; + +require_once dirname(__DIR__).'/bootstrap.php'; + +$platform = PlatformFactory::create(env('MISTRAL_API_KEY'), httpClient: http_client()); +$model = new Mistral(Mistral::MISTRAL_SMALL); + +$agent = new Agent($platform, $model, logger: logger()); +$messages = new MessageBag( + Message::ofUser( + new DocumentUrl('https://upload.wikimedia.org/wikipedia/commons/2/20/Re_example.pdf'), + 'What is this document about?', + ), +); +$result = $agent->call($messages); + +echo $result->getContent().\PHP_EOL; diff --git a/src/platform/src/Bridge/Mistral/Contract/DocumentUrlNormalizer.php b/src/platform/src/Bridge/Mistral/Contract/DocumentUrlNormalizer.php new file mode 100644 index 000000000..343e714d1 --- /dev/null +++ b/src/platform/src/Bridge/Mistral/Contract/DocumentUrlNormalizer.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\AI\Platform\Bridge\Mistral\Contract; + +use Symfony\AI\Platform\Bridge\Mistral\Mistral; +use Symfony\AI\Platform\Contract\Normalizer\ModelContractNormalizer; +use Symfony\AI\Platform\Message\Content\DocumentUrl; +use Symfony\AI\Platform\Model; + +class DocumentUrlNormalizer extends ModelContractNormalizer +{ + /** + * @param DocumentUrl $data + * + * @return array{type: 'document_url', document_url: string} + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + return [ + 'type' => 'document_url', + 'document_url' => $data->url, + ]; + } + + protected function supportedDataClass(): string + { + return DocumentUrl::class; + } + + protected function supportsModel(Model $model): bool + { + return $model instanceof Mistral; + } +} diff --git a/src/platform/src/Bridge/Mistral/PlatformFactory.php b/src/platform/src/Bridge/Mistral/PlatformFactory.php index c3825ae9c..e38f9bd1a 100644 --- a/src/platform/src/Bridge/Mistral/PlatformFactory.php +++ b/src/platform/src/Bridge/Mistral/PlatformFactory.php @@ -12,6 +12,7 @@ namespace Symfony\AI\Platform\Bridge\Mistral; use Symfony\AI\Platform\Bridge\Mistral\Contract\DocumentNormalizer; +use Symfony\AI\Platform\Bridge\Mistral\Contract\DocumentUrlNormalizer; use Symfony\AI\Platform\Bridge\Mistral\Contract\ToolNormalizer; use Symfony\AI\Platform\Contract; use Symfony\AI\Platform\Platform; @@ -36,7 +37,8 @@ public static function create( [new Embeddings\ResultConverter(), new Llm\ResultConverter()], $contract ?? Contract::create( new ToolNormalizer(), - new DocumentNormalizer() + new DocumentNormalizer(), + new DocumentUrlNormalizer(), ), ); } diff --git a/src/platform/tests/Bridge/Mistral/Contract/DocumentUrlNormalizerTest.php b/src/platform/tests/Bridge/Mistral/Contract/DocumentUrlNormalizerTest.php new file mode 100644 index 000000000..e5ecb3daf --- /dev/null +++ b/src/platform/tests/Bridge/Mistral/Contract/DocumentUrlNormalizerTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\AI\Platform\Tests\Bridge\Mistral\Contract; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\TestCase; +use Symfony\AI\Platform\Bridge\Mistral\Contract\DocumentUrlNormalizer; +use Symfony\AI\Platform\Bridge\Mistral\Mistral; +use Symfony\AI\Platform\Contract; +use Symfony\AI\Platform\Message\Content\DocumentUrl; + +#[Medium] +#[CoversClass(DocumentUrlNormalizer::class)] +final class DocumentUrlNormalizerTest extends TestCase +{ + public function testSupportsNormalization() + { + $normalizer = new DocumentUrlNormalizer(); + + $this->assertTrue($normalizer->supportsNormalization(new DocumentUrl('https://example.com/document.pdf'), context: [ + Contract::CONTEXT_MODEL => new Mistral(), + ])); + $this->assertFalse($normalizer->supportsNormalization('not a document url')); + } + + public function testGetSupportedTypes() + { + $normalizer = new DocumentUrlNormalizer(); + + $expected = [ + DocumentUrl::class => true, + ]; + + $this->assertSame($expected, $normalizer->getSupportedTypes(null)); + } + + #[DataProvider('normalizeDataProvider')] + public function testNormalize(DocumentUrl $file, array $expected) + { + $normalizer = new DocumentUrlNormalizer(); + + $normalized = $normalizer->normalize($file); + + $this->assertEquals($expected, $normalized); + } + + public static function normalizeDataProvider(): iterable + { + yield 'document with url' => [ + new DocumentUrl('https://example.com/document.pdf'), + [ + 'type' => 'document_url', + 'document_url' => 'https://example.com/document.pdf', + ], + ]; + } +}