1818use Symfony \AI \Platform \ModelCatalog \ModelCatalogInterface ;
1919use Symfony \AI \Platform \Result \DeferredResult ;
2020use Symfony \AI \Platform \Result \RawResultInterface ;
21+ use Symfony \AI \Platform \Speech \SpeechListenerInterface ;
2122
2223/**
2324 * @author Christopher Hertel <[email protected] > @@ -34,20 +35,28 @@ final class Platform implements PlatformInterface
3435 */
3536 private readonly array $ resultConverters ;
3637
38+ /**
39+ * @var SpeechListenerInterface[]
40+ */
41+ private readonly iterable $ speechListeners ;
42+
3743 /**
3844 * @param iterable<ModelClientInterface> $modelClients
3945 * @param iterable<ResultConverterInterface> $resultConverters
46+ * @param iterable<SpeechListenerInterface> $speechListeners
4047 */
4148 public function __construct (
4249 iterable $ modelClients ,
4350 iterable $ resultConverters ,
51+ iterable $ speechListeners ,
4452 private readonly ModelCatalogInterface $ modelCatalog ,
4553 private ?Contract $ contract = null ,
4654 private readonly ?EventDispatcherInterface $ eventDispatcher = null ,
4755 ) {
4856 $ this ->contract = $ contract ?? Contract::create ();
4957 $ this ->modelClients = $ modelClients instanceof \Traversable ? iterator_to_array ($ modelClients ) : $ modelClients ;
5058 $ this ->resultConverters = $ resultConverters instanceof \Traversable ? iterator_to_array ($ resultConverters ) : $ resultConverters ;
59+ $ this ->speechListeners = $ speechListeners instanceof \Traversable ? iterator_to_array ($ speechListeners ) : $ speechListeners ;
5160 }
5261
5362 public function invoke (string $ model , array |string |object $ input , array $ options = []): DeferredResult
@@ -65,8 +74,9 @@ public function invoke(string $model, array|string|object $input, array $options
6574 }
6675
6776 $ result = $ this ->convertResult ($ model , $ this ->doInvoke ($ model , $ payload , $ options ), $ options );
77+ $ finalResult = $ this ->addSpeech ($ result , $ payload , $ options );
6878
69- $ event = new ResultEvent ($ model , $ result , $ options );
79+ $ event = new ResultEvent ($ model , $ finalResult , $ options );
7080 $ this ->eventDispatcher ?->dispatch($ event );
7181
7282 return $ event ->getDeferredResult ();
@@ -105,4 +115,21 @@ private function convertResult(Model $model, RawResultInterface $result, array $
105115
106116 throw new RuntimeException (\sprintf ('No ResultConverter registered for model "%s" with given input. ' , $ model ::class));
107117 }
118+
119+ private function addSpeech (DeferredResult $ result , array |string $ payload , array $ options ): DeferredResult
120+ {
121+ if ([] === $ this ->speechListeners ) {
122+ return $ result ;
123+ }
124+
125+ foreach ($ this ->speechListeners as $ speechListener ) {
126+ if ($ speechListener ->supportListening ($ payload , $ options )) {
127+ $ result ->setSpeech ($ speechListener ->listen ($ payload , $ options ));
128+
129+ return $ result ;
130+ }
131+ }
132+
133+ throw new RuntimeException ('No SpeechListener registered. ' );
134+ }
108135}
0 commit comments