|  | 
|  | 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; | 
|  | 13 | + | 
|  | 14 | +use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface; | 
|  | 15 | +use Symfony\AI\Platform\Result\DeferredResult; | 
|  | 16 | +use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface; | 
|  | 17 | +use Symfony\Contracts\Cache\CacheInterface; | 
|  | 18 | +use Symfony\Contracts\Cache\ItemInterface; | 
|  | 19 | + | 
|  | 20 | +/** | 
|  | 21 | + * @author Guillaume Loulier <[email protected]> | 
|  | 22 | + */ | 
|  | 23 | +final class CachedPlatform implements PlatformInterface | 
|  | 24 | +{ | 
|  | 25 | +    public function __construct( | 
|  | 26 | +        private readonly PlatformInterface $platform, | 
|  | 27 | +        private readonly (CacheInterface&TagAwareAdapterInterface)|null $cache = null, | 
|  | 28 | +        private readonly ?string $cacheKey = null, | 
|  | 29 | +    ) { | 
|  | 30 | +    } | 
|  | 31 | + | 
|  | 32 | +    public function invoke(string $model, array|string|object $input, array $options = []): DeferredResult | 
|  | 33 | +    { | 
|  | 34 | +        $invokeCall = fn (string $model, array|string|object $input, array $options = []): DeferredResult => $this->platform->invoke($model, $input, $options); | 
|  | 35 | + | 
|  | 36 | +        if ($this->cache instanceof CacheInterface && (\array_key_exists('prompt_cache_key', $options) && '' !== $options['prompt_cache_key'])) { | 
|  | 37 | +            $cacheKey = \sprintf('%s_%s', $this->cacheKey ?? $options['prompt_cache_key'], md5($model)); | 
|  | 38 | + | 
|  | 39 | +            unset($options['prompt_cache_key']); | 
|  | 40 | + | 
|  | 41 | +            return $this->cache->get($cacheKey, static function (ItemInterface $item) use ($invokeCall, $model, $input, $options, $cacheKey): DeferredResult { | 
|  | 42 | +                $item->tag($model); | 
|  | 43 | + | 
|  | 44 | +                $result = $invokeCall($model, $input, $options); | 
|  | 45 | + | 
|  | 46 | +                $result = new DeferredResult( | 
|  | 47 | +                    $result->getResultConverter(), | 
|  | 48 | +                    $result->getRawResult(), | 
|  | 49 | +                    $options, | 
|  | 50 | +                ); | 
|  | 51 | + | 
|  | 52 | +                $result->getMetadata()->set([ | 
|  | 53 | +                    'cached' => true, | 
|  | 54 | +                    'cache_key' => $cacheKey, | 
|  | 55 | +                    'cached_at' => (new \DateTimeImmutable())->getTimestamp(), | 
|  | 56 | +                ]); | 
|  | 57 | + | 
|  | 58 | +                return $result; | 
|  | 59 | +            }); | 
|  | 60 | +        } | 
|  | 61 | + | 
|  | 62 | +        return $invokeCall($model, $input, $options); | 
|  | 63 | +    } | 
|  | 64 | + | 
|  | 65 | +    public function getModelCatalog(): ModelCatalogInterface | 
|  | 66 | +    { | 
|  | 67 | +        return $this->platform->getModelCatalog(); | 
|  | 68 | +    } | 
|  | 69 | +} | 
0 commit comments