mirror of
https://github.com/symfony/ai.git
synced 2026-03-23 23:42:18 +01:00
Fix Metadata handling on Perplexity streams
This commit is contained in:
@@ -27,5 +27,5 @@ $result = $platform->invoke('sonar', $messages, [
|
||||
echo $result->asText().\PHP_EOL;
|
||||
echo \PHP_EOL;
|
||||
|
||||
print_search_results($result->getMetadata());
|
||||
print_citations($result->getMetadata());
|
||||
print_search_results($result->getMetadata()->get('search_results'));
|
||||
print_citations($result->getMetadata()->get('citations'));
|
||||
|
||||
@@ -9,18 +9,13 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\AI\Platform\Metadata\Metadata;
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
|
||||
function print_search_results(Metadata $metadata): void
|
||||
/**
|
||||
* @param array<int, array<string, string>> $searchResults
|
||||
*/
|
||||
function print_search_results(array $searchResults): void
|
||||
{
|
||||
$searchResults = $metadata->get('search_results');
|
||||
|
||||
if (null === $searchResults) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo 'Search results:'.\PHP_EOL;
|
||||
|
||||
if (0 === count($searchResults)) {
|
||||
@@ -40,14 +35,11 @@ function print_search_results(Metadata $metadata): void
|
||||
}
|
||||
}
|
||||
|
||||
function print_citations(Metadata $metadata): void
|
||||
/**
|
||||
* @param array<int, string> $citations
|
||||
*/
|
||||
function print_citations(array $citations): void
|
||||
{
|
||||
$citations = $metadata->get('citations');
|
||||
|
||||
if (null === $citations) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo 'Citations:'.\PHP_EOL;
|
||||
|
||||
if (0 === count($citations)) {
|
||||
|
||||
@@ -29,5 +29,5 @@ $result = $platform->invoke('sonar', $messages);
|
||||
|
||||
echo $result->asText().\PHP_EOL;
|
||||
|
||||
print_search_results($result->getMetadata());
|
||||
print_citations($result->getMetadata());
|
||||
print_search_results($result->getMetadata()->get('search_results'));
|
||||
print_citations($result->getMetadata()->get('citations'));
|
||||
|
||||
@@ -28,5 +28,5 @@ $result = $platform->invoke('sonar', $messages);
|
||||
|
||||
echo $result->asText().\PHP_EOL;
|
||||
|
||||
print_search_results($result->getMetadata());
|
||||
print_citations($result->getMetadata());
|
||||
print_search_results($result->getMetadata()->get('search_results'));
|
||||
print_citations($result->getMetadata()->get('citations'));
|
||||
|
||||
@@ -30,5 +30,5 @@ foreach ($result->asStream() as $word) {
|
||||
}
|
||||
echo \PHP_EOL;
|
||||
|
||||
print_search_results($result->getMetadata());
|
||||
print_citations($result->getMetadata());
|
||||
print_search_results($result->getResult()->getMetadata()->get('search_results'));
|
||||
print_citations($result->getResult()->getMetadata()->get('citations'));
|
||||
|
||||
@@ -30,5 +30,5 @@ $result = $platform->invoke('sonar', $messages, [
|
||||
echo $result->asText().\PHP_EOL;
|
||||
echo \PHP_EOL;
|
||||
|
||||
print_search_results($result->getMetadata());
|
||||
print_citations($result->getMetadata());
|
||||
print_search_results($result->getMetadata()->get('search_results'));
|
||||
print_citations($result->getMetadata()->get('citations'));
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
namespace Symfony\AI\Platform\Bridge\Perplexity;
|
||||
|
||||
use Symfony\AI\Platform\Exception\RuntimeException;
|
||||
use Symfony\AI\Platform\Metadata\Metadata;
|
||||
use Symfony\AI\Platform\Model;
|
||||
use Symfony\AI\Platform\Result\ChoiceResult;
|
||||
use Symfony\AI\Platform\Result\RawResultInterface;
|
||||
@@ -34,7 +33,7 @@ final class ResultConverter implements ResultConverterInterface
|
||||
public function convert(RawResultInterface $result, array $options = []): ResultInterface
|
||||
{
|
||||
if ($options['stream'] ?? false) {
|
||||
return new StreamResult($this->convertStream($result));
|
||||
return new StreamResult($this->convertStream($result), [new StreamListener()]);
|
||||
}
|
||||
|
||||
$data = $result->getData();
|
||||
@@ -67,26 +66,19 @@ final class ResultConverter implements ResultConverterInterface
|
||||
|
||||
private function convertStream(RawResultInterface $result): \Generator
|
||||
{
|
||||
$searchResults = $citations = [];
|
||||
/** @var Metadata $metadata */
|
||||
$metadata = yield;
|
||||
|
||||
foreach ($result->getDataStream() as $data) {
|
||||
if (isset($data['choices'][0]['delta']['content'])) {
|
||||
yield $data['choices'][0]['delta']['content'];
|
||||
}
|
||||
|
||||
if (isset($data['search_results'])) {
|
||||
$searchResults = $data['search_results'];
|
||||
}
|
||||
|
||||
if (isset($data['citations'])) {
|
||||
$citations = $data['citations'];
|
||||
}
|
||||
}
|
||||
|
||||
$metadata->add('search_results', $searchResults);
|
||||
$metadata->add('citations', $citations);
|
||||
if (isset($data['search_results'])) {
|
||||
yield ['search_results' => $data['search_results']];
|
||||
}
|
||||
|
||||
if (isset($data['citations'])) {
|
||||
yield ['citations' => $data['citations']];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
40
src/platform/src/Bridge/Perplexity/StreamListener.php
Normal file
40
src/platform/src/Bridge/Perplexity/StreamListener.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?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\Bridge\Perplexity;
|
||||
|
||||
use Symfony\AI\Platform\Result\Stream\AbstractStreamListener;
|
||||
use Symfony\AI\Platform\Result\Stream\ChunkEvent;
|
||||
|
||||
/**
|
||||
* @author Christopher Hertel <mail@christopher-hertel.de>
|
||||
*/
|
||||
final class StreamListener extends AbstractStreamListener
|
||||
{
|
||||
public function onChunk(ChunkEvent $event): void
|
||||
{
|
||||
$chunk = $event->getChunk();
|
||||
|
||||
if (!\is_array($chunk)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($chunk['search_results'])) {
|
||||
$event->getMetadata()->add('search_results', $chunk['search_results']);
|
||||
$event->skipChunk();
|
||||
}
|
||||
|
||||
if (isset($chunk['citations'])) {
|
||||
$event->getMetadata()->add('citations', $chunk['citations']);
|
||||
$event->skipChunk();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?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\Bridge\Perplexity\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\AI\Platform\Bridge\Perplexity\StreamListener;
|
||||
use Symfony\AI\Platform\Result\StreamResult;
|
||||
|
||||
final class StreamListenerTest extends TestCase
|
||||
{
|
||||
public function testSearchResultsAreAddedToMetadataAndChunkIsSkipped()
|
||||
{
|
||||
$searchResults = [['url' => 'https://example.com', 'title' => 'Example']];
|
||||
$streamResult = new StreamResult((static function () use ($searchResults): \Generator {
|
||||
yield ['search_results' => $searchResults];
|
||||
yield 'Hello World';
|
||||
})());
|
||||
|
||||
$streamResult->addListener(new StreamListener());
|
||||
|
||||
$chunks = iterator_to_array($streamResult->getContent());
|
||||
|
||||
$this->assertSame(['Hello World'], $chunks);
|
||||
$this->assertTrue($streamResult->getMetadata()->has('search_results'));
|
||||
$this->assertSame($searchResults, $streamResult->getMetadata()->get('search_results'));
|
||||
}
|
||||
|
||||
public function testCitationsAreAddedToMetadataAndChunkIsSkipped()
|
||||
{
|
||||
$citations = ['https://example.com/1', 'https://example.com/2'];
|
||||
$streamResult = new StreamResult((static function () use ($citations): \Generator {
|
||||
yield ['citations' => $citations];
|
||||
yield 'Hello World';
|
||||
})());
|
||||
|
||||
$streamResult->addListener(new StreamListener());
|
||||
|
||||
$chunks = iterator_to_array($streamResult->getContent());
|
||||
|
||||
$this->assertSame(['Hello World'], $chunks);
|
||||
$this->assertTrue($streamResult->getMetadata()->has('citations'));
|
||||
$this->assertSame($citations, $streamResult->getMetadata()->get('citations'));
|
||||
}
|
||||
|
||||
public function testNonArrayChunksAreNotProcessed()
|
||||
{
|
||||
$streamResult = new StreamResult((static function (): \Generator {
|
||||
yield 'Hello ';
|
||||
yield 'World';
|
||||
})());
|
||||
|
||||
$streamResult->addListener(new StreamListener());
|
||||
|
||||
$chunks = iterator_to_array($streamResult->getContent());
|
||||
|
||||
$this->assertSame(['Hello ', 'World'], $chunks);
|
||||
$this->assertFalse($streamResult->getMetadata()->has('search_results'));
|
||||
$this->assertFalse($streamResult->getMetadata()->has('citations'));
|
||||
}
|
||||
|
||||
public function testBothSearchResultsAndCitationsAreProcessed()
|
||||
{
|
||||
$searchResults = [['url' => 'https://example.com']];
|
||||
$citations = ['https://example.com/1'];
|
||||
$streamResult = new StreamResult((static function () use ($searchResults, $citations): \Generator {
|
||||
yield ['search_results' => $searchResults];
|
||||
yield 'Content';
|
||||
yield ['citations' => $citations];
|
||||
})());
|
||||
|
||||
$streamResult->addListener(new StreamListener());
|
||||
|
||||
$chunks = iterator_to_array($streamResult->getContent());
|
||||
|
||||
$this->assertSame(['Content'], $chunks);
|
||||
$this->assertSame($searchResults, $streamResult->getMetadata()->get('search_results'));
|
||||
$this->assertSame($citations, $streamResult->getMetadata()->get('citations'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user