Add asFile() method to BinaryResult and DeferredResult

This commit is contained in:
Christopher Hertel
2026-03-17 00:45:18 +01:00
parent d9fb5ef744
commit 8d2461158c
7 changed files with 90 additions and 2 deletions

View File

@@ -820,7 +820,16 @@ Binary Results
);
$result = $platform->invoke('gpt-4o-mini', 'generate PDF document');
$binary = $result->asBinary(); // Returns Binary object with content and MIME type
$binary = $result->asBinary(); // Returns the binary data as string
You can also save binary results directly to a file using
:method:`Symfony\\AI\\Platform\\Result\\DeferredResult::asFile`::
$result = $platform->invoke('gemini-2.5-flash-image', $messages);
$result->asFile('/path/to/output.png'); // Saves the binary content to a file
The method throws a :class:`Symfony\\AI\\Platform\\Exception\\RuntimeException` if the
target directory does not exist or is not writable.
Raw Results
~~~~~~~~~~~

View File

@@ -26,6 +26,6 @@ $messages = new MessageBag(
);
$result = $platform->invoke('gemini-2.5-flash-image', $messages);
file_put_contents(__DIR__.'/result.png', $result->asBinary());
$result->asFile(__DIR__.'/result.png');
echo 'Result image saved to result.png'.\PHP_EOL;

View File

@@ -4,6 +4,7 @@ CHANGELOG
0.7
---
* Add `asFile()` method to `BinaryResult` and `DeferredResult` for saving binary content to a file
* Add reranking support via `RerankingResult`, `RerankingEntry`, and `Capability::RERANKING`
* Add `description` and `example` properties to `#[With]` attribute

View File

@@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\AI\Platform\Exception;
/**
* @author Christopher Hertel <mail@christopher-hertel.de>
*/
class IOException extends RuntimeException implements ExceptionInterface
{
}

View File

@@ -11,6 +11,7 @@
namespace Symfony\AI\Platform\Result;
use Symfony\AI\Platform\Exception\IOException;
use Symfony\AI\Platform\Exception\RuntimeException;
/**
@@ -50,6 +51,23 @@ final class BinaryResult extends BaseResult
return base64_encode($this->data);
}
public function asFile(string $path): void
{
$directory = \dirname($path);
if (!is_dir($directory)) {
throw new IOException(\sprintf('The directory "%s" does not exist.', $directory));
}
if (!is_writable($directory)) {
throw new IOException(\sprintf('The directory "%s" is not writable.', $directory));
}
if (false === file_put_contents($path, $this->data)) {
throw new IOException(\sprintf('Failed to write file to "%s".', $path));
}
}
public function toDataUri(?string $mimeType = null): string
{
if (null === ($mimeType ?? $this->mimeType)) {

View File

@@ -109,6 +109,18 @@ final class DeferredResult
return $this->as(BinaryResult::class)->getContent();
}
/**
* @throws ExceptionInterface
*/
public function asFile(string $path): void
{
$result = $this->as(BinaryResult::class);
\assert($result instanceof BinaryResult);
$result->asFile($path);
}
/**
* @throws ExceptionInterface
*/

View File

@@ -12,6 +12,7 @@
namespace Symfony\AI\Platform\Tests\Result;
use PHPUnit\Framework\TestCase;
use Symfony\AI\Platform\Exception\IOException;
use Symfony\AI\Platform\Result\BinaryResult;
final class BinaryResultTest extends TestCase
@@ -67,4 +68,32 @@ final class BinaryResultTest extends TestCase
$this->assertSame($expected, $actual);
}
public function testAsFile()
{
$data = 'binary file content';
$result = new BinaryResult($data, 'image/png');
$path = sys_get_temp_dir().'/symfony_ai_test_'.uniqid().'.png';
try {
$result->asFile($path);
$this->assertFileExists($path);
$this->assertSame($data, file_get_contents($path));
} finally {
if (file_exists($path)) {
unlink($path);
}
}
}
public function testAsFileThrowsExceptionWhenDirectoryDoesNotExist()
{
$result = new BinaryResult('binary data');
$this->expectException(IOException::class);
$this->expectExceptionMessage('The directory "/non/existent/directory" does not exist.');
$result->asFile('/non/existent/directory/file.png');
}
}