From 699db9caebce485616de07ab3b948d74f30ce896 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Sat, 7 Sep 2024 00:03:42 +0400 Subject: [PATCH 1/3] Add file cache service --- ai.xml | 2 +- composer.json | 4 +- composer.lock | 222 ++++++++++++------ src/Bootstrap.php | 11 +- .../Attribute/ConfigAttribute.php | 2 +- .../Container => Config}/Attribute/Env.php | 2 +- .../Attribute/InputArgument.php | 2 +- .../Attribute/InputOption.php | 2 +- .../Container => Config}/Attribute/PhpIni.php | 2 +- .../Container => Config}/Attribute/XPath.php | 2 +- .../Attribute/XPathEmbedList.php | 2 +- src/Config/Bibliographer.php | 16 ++ src/Config/Source.php | 8 +- src/Config/Source/Directory.php | 2 +- src/Config/Source/File.php | 2 +- src/Module/Finder/Finder.php | 2 + src/Module/Finder/Internal/FinderImpl.php | 53 +++-- src/Service/Cache.php | 85 +++++++ src/Service/Container.php | 3 +- src/Service/Internal/Cache/PsrCache.php | 65 +++++ .../Container/ContainerImpl.php | 4 +- .../Container/Injection/ConfigLoader.php | 18 +- .../{ => Internal}/Logger/LogLevel.php | 2 +- .../{ => Internal}/Logger/LoggerImpl.php | 2 +- 24 files changed, 389 insertions(+), 126 deletions(-) rename src/{Service/Container => Config}/Attribute/ConfigAttribute.php (61%) rename src/{Service/Container => Config}/Attribute/Env.php (82%) rename src/{Service/Container => Config}/Attribute/InputArgument.php (81%) rename src/{Service/Container => Config}/Attribute/InputOption.php (80%) rename src/{Service/Container => Config}/Attribute/PhpIni.php (82%) rename src/{Service/Container => Config}/Attribute/XPath.php (82%) rename src/{Service/Container => Config}/Attribute/XPathEmbedList.php (86%) create mode 100644 src/Config/Bibliographer.php create mode 100644 src/Service/Cache.php create mode 100644 src/Service/Internal/Cache/PsrCache.php rename src/Service/{ => Internal}/Container/ContainerImpl.php (96%) rename src/Service/{ => Internal}/Container/Injection/ConfigLoader.php (91%) rename src/Service/{ => Internal}/Logger/LogLevel.php (95%) rename src/Service/{ => Internal}/Logger/LoggerImpl.php (97%) diff --git a/ai.xml b/ai.xml index d6dd8f4..8af8a82 100644 --- a/ai.xml +++ b/ai.xml @@ -1,7 +1,7 @@ diff --git a/composer.json b/composer.json index d2fae66..e1372ae 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,9 @@ "psr/container": "^2.0", "psr/log": "^3.0.1", "psr/simple-cache": "^3.0", - "symfony/finder": "^7.1" + "symfony/finder": "^7.1", + "yiisoft/cache-file": "^3.1", + "yiisoft/injector": "^1.2" }, "require-dev": { "buggregator/trap": "^1.10", diff --git a/composer.lock b/composer.lock index 0280983..5e29b2d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ab27c82146678b34bdac308d089416b4", + "content-hash": "cea9ec9ab97e59531e5940e1c2423840", "packages": [ { "name": "brick/math", @@ -547,6 +547,156 @@ } ], "time": "2024-08-13T14:28:19+00:00" + }, + { + "name": "yiisoft/cache-file", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/cache-file.git", + "reference": "226ff0731adabc884c149f711190a7ac8b14800d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/cache-file/zipball/226ff0731adabc884c149f711190a7ac8b14800d", + "reference": "226ff0731adabc884c149f711190a7ac8b14800d", + "shasum": "" + }, + "require": { + "php": "^8.0", + "psr/simple-cache": "^2.0|^3.0" + }, + "provide": { + "psr/simple-cache-implementation": "1.0.0" + }, + "require-dev": { + "maglnet/composer-require-checker": "^4.4", + "php-mock/php-mock-phpunit": "^2.6", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.18.3", + "roave/infection-static-analysis-plugin": "^1.16", + "spatie/phpunit-watcher": "^1.23", + "vimeo/psalm": "^4.30|^5.6", + "yiisoft/aliases": "^3.0", + "yiisoft/di": "^1.2" + }, + "type": "library", + "extra": { + "config-plugin-options": { + "source-directory": "config" + }, + "config-plugin": { + "di": "di.php", + "params": "params.php" + } + }, + "autoload": { + "psr-4": { + "Yiisoft\\Cache\\File\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Yii Caching Library - File Handler", + "homepage": "https://www.yiiframework.com/", + "keywords": [ + "cache", + "file", + "framework", + "psr-16", + "yii" + ], + "support": { + "chat": "https://t.me/yii3en", + "forum": "https://www.yiiframework.com/forum/", + "irc": "irc://irc.freenode.net/yii", + "issues": "https://github.com/yiisoft/cache-file/issues?state=open", + "source": "https://github.com/yiisoft/cache-file", + "wiki": "https://www.yiiframework.com/wiki/" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + } + ], + "time": "2023-10-09T14:49:20+00:00" + }, + { + "name": "yiisoft/injector", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/injector.git", + "reference": "0dc0127a7542341bdaabda7b85204e992938b83e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/injector/zipball/0dc0127a7542341bdaabda7b85204e992938b83e", + "reference": "0dc0127a7542341bdaabda7b85204e992938b83e", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "require-dev": { + "maglnet/composer-require-checker": "^3.8|^4.2", + "phpbench/phpbench": "^1.1", + "phpunit/phpunit": "^9.5", + "psr/container": "^1.0|^2.0", + "rector/rector": "^0.18.12", + "roave/infection-static-analysis-plugin": "^1.16", + "spatie/phpunit-watcher": "^1.23", + "vimeo/psalm": "^4.30|^5.7", + "yiisoft/test-support": "^1.2" + }, + "suggest": { + "psr/container": "For automatic resolving of dependencies" + }, + "type": "library", + "autoload": { + "psr-4": { + "Yiisoft\\Injector\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR-11 compatible injector. Executes a callable and makes an instances by injecting dependencies from a given DI container.", + "homepage": "https://www.yiiframework.com/", + "keywords": [ + "PSR-11", + "dependency injection", + "di", + "injector", + "reflection" + ], + "support": { + "chat": "https://t.me/yii3en", + "forum": "https://www.yiiframework.com/forum/", + "irc": "irc://irc.freenode.net/yii", + "issues": "https://github.com/yiisoft/injector/issues?state=open", + "source": "https://github.com/yiisoft/injector", + "wiki": "https://www.yiiframework.com/wiki/" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + } + ], + "time": "2023-12-20T09:39:03+00:00" } ], "packages-dev": [ @@ -6062,76 +6212,6 @@ "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, "time": "2022-06-03T18:03:27+00:00" - }, - { - "name": "yiisoft/injector", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/yiisoft/injector.git", - "reference": "0dc0127a7542341bdaabda7b85204e992938b83e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/yiisoft/injector/zipball/0dc0127a7542341bdaabda7b85204e992938b83e", - "reference": "0dc0127a7542341bdaabda7b85204e992938b83e", - "shasum": "" - }, - "require": { - "php": "^7.4|^8.0" - }, - "require-dev": { - "maglnet/composer-require-checker": "^3.8|^4.2", - "phpbench/phpbench": "^1.1", - "phpunit/phpunit": "^9.5", - "psr/container": "^1.0|^2.0", - "rector/rector": "^0.18.12", - "roave/infection-static-analysis-plugin": "^1.16", - "spatie/phpunit-watcher": "^1.23", - "vimeo/psalm": "^4.30|^5.7", - "yiisoft/test-support": "^1.2" - }, - "suggest": { - "psr/container": "For automatic resolving of dependencies" - }, - "type": "library", - "autoload": { - "psr-4": { - "Yiisoft\\Injector\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "PSR-11 compatible injector. Executes a callable and makes an instances by injecting dependencies from a given DI container.", - "homepage": "https://www.yiiframework.com/", - "keywords": [ - "PSR-11", - "dependency injection", - "di", - "injector", - "reflection" - ], - "support": { - "chat": "https://t.me/yii3en", - "forum": "https://www.yiiframework.com/forum/", - "irc": "irc://irc.freenode.net/yii", - "issues": "https://github.com/yiisoft/injector/issues?state=open", - "source": "https://github.com/yiisoft/injector", - "wiki": "https://www.yiiframework.com/wiki/" - }, - "funding": [ - { - "url": "https://github.com/yiisoft", - "type": "github" - }, - { - "url": "https://opencollective.com/yiisoft", - "type": "open_collective" - } - ], - "time": "2023-12-20T09:39:03+00:00" } ], "aliases": [], diff --git a/src/Bootstrap.php b/src/Bootstrap.php index bf95f19..a584caf 100644 --- a/src/Bootstrap.php +++ b/src/Bootstrap.php @@ -6,15 +6,19 @@ use LLM\Assistant\Module\Finder\Finder; use LLM\Assistant\Module\Finder\Internal\FinderImpl; +use LLM\Assistant\Service\Cache; use LLM\Assistant\Service\Container; -use LLM\Assistant\Service\Container\ContainerImpl; -use LLM\Assistant\Service\Container\Injection\ConfigLoader; +use LLM\Assistant\Service\Internal\Cache\PsrCache; +use LLM\Assistant\Service\Internal\Container\ContainerImpl; +use LLM\Assistant\Service\Internal\Container\Injection\ConfigLoader; +use LLM\Assistant\Service\Internal\Logger\LoggerImpl; use LLM\Assistant\Service\Logger; -use LLM\Assistant\Service\Logger\LoggerImpl; +use Psr\SimpleCache\CacheInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\StyleInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Yiisoft\Cache\File\FileCache; /** * Build the container based on the configuration. @@ -45,6 +49,7 @@ public function finish(): Container unset($this->container); $c->bind(Finder::class, FinderImpl::class); + $c->bind(Cache::class, PsrCache::class); return $c; } diff --git a/src/Service/Container/Attribute/ConfigAttribute.php b/src/Config/Attribute/ConfigAttribute.php similarity index 61% rename from src/Service/Container/Attribute/ConfigAttribute.php rename to src/Config/Attribute/ConfigAttribute.php index 39cf4f0..d47ac27 100644 --- a/src/Service/Container/Attribute/ConfigAttribute.php +++ b/src/Config/Attribute/ConfigAttribute.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Container\Attribute; +namespace LLM\Assistant\Config\Attribute; /** * @internal diff --git a/src/Service/Container/Attribute/Env.php b/src/Config/Attribute/Env.php similarity index 82% rename from src/Service/Container/Attribute/Env.php rename to src/Config/Attribute/Env.php index 910e68e..19b482e 100644 --- a/src/Service/Container/Attribute/Env.php +++ b/src/Config/Attribute/Env.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Container\Attribute; +namespace LLM\Assistant\Config\Attribute; /** * @internal diff --git a/src/Service/Container/Attribute/InputArgument.php b/src/Config/Attribute/InputArgument.php similarity index 81% rename from src/Service/Container/Attribute/InputArgument.php rename to src/Config/Attribute/InputArgument.php index c392b2e..15d8534 100644 --- a/src/Service/Container/Attribute/InputArgument.php +++ b/src/Config/Attribute/InputArgument.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Container\Attribute; +namespace LLM\Assistant\Config\Attribute; /** * @internal diff --git a/src/Service/Container/Attribute/InputOption.php b/src/Config/Attribute/InputOption.php similarity index 80% rename from src/Service/Container/Attribute/InputOption.php rename to src/Config/Attribute/InputOption.php index 8dd10d0..ced14cc 100644 --- a/src/Service/Container/Attribute/InputOption.php +++ b/src/Config/Attribute/InputOption.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Container\Attribute; +namespace LLM\Assistant\Config\Attribute; /** * @internal diff --git a/src/Service/Container/Attribute/PhpIni.php b/src/Config/Attribute/PhpIni.php similarity index 82% rename from src/Service/Container/Attribute/PhpIni.php rename to src/Config/Attribute/PhpIni.php index 8011b0d..1d62fbf 100644 --- a/src/Service/Container/Attribute/PhpIni.php +++ b/src/Config/Attribute/PhpIni.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Container\Attribute; +namespace LLM\Assistant\Config\Attribute; /** * @internal diff --git a/src/Service/Container/Attribute/XPath.php b/src/Config/Attribute/XPath.php similarity index 82% rename from src/Service/Container/Attribute/XPath.php rename to src/Config/Attribute/XPath.php index 18b6037..3e42fd9 100644 --- a/src/Service/Container/Attribute/XPath.php +++ b/src/Config/Attribute/XPath.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Container\Attribute; +namespace LLM\Assistant\Config\Attribute; /** * @internal diff --git a/src/Service/Container/Attribute/XPathEmbedList.php b/src/Config/Attribute/XPathEmbedList.php similarity index 86% rename from src/Service/Container/Attribute/XPathEmbedList.php rename to src/Config/Attribute/XPathEmbedList.php index 240e9f2..8d0212d 100644 --- a/src/Service/Container/Attribute/XPathEmbedList.php +++ b/src/Config/Attribute/XPathEmbedList.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Container\Attribute; +namespace LLM\Assistant\Config\Attribute; /** * @internal diff --git a/src/Config/Bibliographer.php b/src/Config/Bibliographer.php new file mode 100644 index 0000000..8f01582 --- /dev/null +++ b/src/Config/Bibliographer.php @@ -0,0 +1,16 @@ + */ diff --git a/src/Module/Finder/Internal/FinderImpl.php b/src/Module/Finder/Internal/FinderImpl.php index e797cc5..1508fb2 100644 --- a/src/Module/Finder/Internal/FinderImpl.php +++ b/src/Module/Finder/Internal/FinderImpl.php @@ -10,46 +10,51 @@ final class FinderImpl implements Finder { public function __construct( - Source $config, - private \Symfony\Component\Finder\Finder $finder, - ) { - $finder->ignoreUnreadableDirs(); - $finder->in(\array_map($this->directoryToPattern(...), $config->includeDir)); - $finder->exclude(\array_map($this->directoryToPattern(...), $config->excludeDir)); - $finder->path(\array_map(static fn(Source\File $file): string => $file->path, $config->includeFile)); - $finder->notPath(\array_map(static fn(Source\File $file): string => $file->path, $config->excludeFile)); - - // $config->path === null ?: $finder->path($config->path); + private readonly Source $config, + private ?\DateTimeInterface $after = null, + ) {} - // todo cached last scan - // $this->finder->date() + public function getIterator(): \Traversable + { + return $this->finder()->getIterator(); } - public function getIterator(): \Traversable + public function after(\DateTimeInterface $date): static { - return $this->finder->getIterator(); + return new self($this->config, $date); } public function files(): \Traversable { - foreach ($this->getIterator() as $name => $file) { - if ($file->isFile()) { - yield $name => $file; - } - } + return $this->finder()->files(); } public function directories(): \Traversable { - foreach ($this->getIterator() as $name => $file) { - if ($file->isDir()) { - yield $name => $file; - } - } + return $this->finder()->directories(); } private function directoryToPattern(Source\Directory $dir): string { return $dir->path; } + + private function finder(): \Symfony\Component\Finder\Finder + { + // todo make better flexible finder + $finder = new \Symfony\Component\Finder\Finder(); + $finder->ignoreUnreadableDirs(); + $finder->in(\array_map($this->directoryToPattern(...), $this->config->includeDir)); + $finder->exclude(\array_map($this->directoryToPattern(...), $this->config->excludeDir)); + $finder->path(\array_map(static fn(Source\File $file): string => $file->path, $this->config->includeFile)); + $finder->notPath(\array_map(static fn(Source\File $file): string => $file->path, $this->config->excludeFile)); + $finder->exclude(\array_map($this->directoryToPattern(...), $this->config->excludeDir)); + // $finder->exclude($this->config->cacheDir); + + if ($this->after !== null) { + $finder->date('> ' . $this->after->format('Y-m-d H:i:s')); + } + + return $finder; + } } diff --git a/src/Service/Cache.php b/src/Service/Cache.php new file mode 100644 index 0000000..94bca9e --- /dev/null +++ b/src/Service/Cache.php @@ -0,0 +1,85 @@ + $id - * @param class-string|null|array|\Closure(ContainerImpl): T $binding + * @param class-string|null|array|\Closure(Container): T $binding */ public function bind(string $id, \Closure|array|string|null $binding = null): void; } diff --git a/src/Service/Internal/Cache/PsrCache.php b/src/Service/Internal/Cache/PsrCache.php new file mode 100644 index 0000000..a8816ff --- /dev/null +++ b/src/Service/Internal/Cache/PsrCache.php @@ -0,0 +1,65 @@ +cache = new FileCache( + $config->cacheDir, + ); + } + + public function has(string $key): bool + { + return $this->cache->has($key); + } + + public function get(string $key, mixed $default = null): mixed + { + return $this->cache->get($key, $default); + } + + public function getOrSet( + string $key, + \Closure $callable, + \DateInterval|int|null $ttl = null, + ): mixed { + $value = $this->cache->get($key, null); + + // Simple implementation + if ($value === null) { + $value = $callable(); + $this->cache->set($key, $value, $ttl); + } + + return $value; + } + + public function set(string $key, mixed $value, \DateInterval|int|null $ttl = null): bool + { + return $this->cache->set($key, $value, $ttl); + } + + public function delete(string $key): bool + { + return $this->cache->delete($key); + } + + public function clear(): bool + { + return $this->cache->clear(); + } +} diff --git a/src/Service/Container/ContainerImpl.php b/src/Service/Internal/Container/ContainerImpl.php similarity index 96% rename from src/Service/Container/ContainerImpl.php rename to src/Service/Internal/Container/ContainerImpl.php index 16240b6..fa4cb4d 100644 --- a/src/Service/Container/ContainerImpl.php +++ b/src/Service/Internal/Container/ContainerImpl.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Container; +namespace LLM\Assistant\Service\Internal\Container; use LLM\Assistant\Service\Container as AppContainerInterface; -use LLM\Assistant\Service\Container\Injection\ConfigLoader; use LLM\Assistant\Service\Destroyable; use LLM\Assistant\Service\Factoriable; +use LLM\Assistant\Service\Internal\Container\Injection\ConfigLoader; use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; use Yiisoft\Injector\Injector; diff --git a/src/Service/Container/Injection/ConfigLoader.php b/src/Service/Internal/Container/Injection/ConfigLoader.php similarity index 91% rename from src/Service/Container/Injection/ConfigLoader.php rename to src/Service/Internal/Container/Injection/ConfigLoader.php index f8a9348..86dc01b 100644 --- a/src/Service/Container/Injection/ConfigLoader.php +++ b/src/Service/Internal/Container/Injection/ConfigLoader.php @@ -2,15 +2,15 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Container\Injection; - -use LLM\Assistant\Service\Container\Attribute\ConfigAttribute; -use LLM\Assistant\Service\Container\Attribute\Env; -use LLM\Assistant\Service\Container\Attribute\InputArgument; -use LLM\Assistant\Service\Container\Attribute\InputOption; -use LLM\Assistant\Service\Container\Attribute\PhpIni; -use LLM\Assistant\Service\Container\Attribute\XPath; -use LLM\Assistant\Service\Container\Attribute\XPathEmbedList; +namespace LLM\Assistant\Service\Internal\Container\Injection; + +use LLM\Assistant\Config\Attribute\ConfigAttribute; +use LLM\Assistant\Config\Attribute\Env; +use LLM\Assistant\Config\Attribute\InputArgument; +use LLM\Assistant\Config\Attribute\InputOption; +use LLM\Assistant\Config\Attribute\PhpIni; +use LLM\Assistant\Config\Attribute\XPath; +use LLM\Assistant\Config\Attribute\XPathEmbedList; use LLM\Assistant\Service\Logger; /** diff --git a/src/Service/Logger/LogLevel.php b/src/Service/Internal/Logger/LogLevel.php similarity index 95% rename from src/Service/Logger/LogLevel.php rename to src/Service/Internal/Logger/LogLevel.php index 72333c0..264f2a2 100644 --- a/src/Service/Logger/LogLevel.php +++ b/src/Service/Internal/Logger/LogLevel.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Logger; +namespace LLM\Assistant\Service\Internal\Logger; /** * @internal diff --git a/src/Service/Logger/LoggerImpl.php b/src/Service/Internal/Logger/LoggerImpl.php similarity index 97% rename from src/Service/Logger/LoggerImpl.php rename to src/Service/Internal/Logger/LoggerImpl.php index abe5ce4..65990aa 100644 --- a/src/Service/Logger/LoggerImpl.php +++ b/src/Service/Internal/Logger/LoggerImpl.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace LLM\Assistant\Service\Logger; +namespace LLM\Assistant\Service\Internal\Logger; use Psr\Log\LoggerTrait; use Symfony\Component\Console\Output\OutputInterface; From c5663c4ef90a74dc96a70be21c69357a54aed6db Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Sat, 7 Sep 2024 01:32:08 +0400 Subject: [PATCH 2/3] Add prompt finder --- src/Bootstrap.php | 11 +- src/Command/Run.php | 13 ++- src/Module/Finder/Dto/File.php | 17 +++ src/Module/Finder/Dto/Prompt.php | 19 ++++ .../{Finder.php => FilesystemFinder.php} | 7 +- ...inderImpl.php => FilesystemFinderImpl.php} | 21 ++-- src/Module/Finder/Internal/PromptCache.php | 10 ++ .../Finder/Internal/PromptFinderImpl.php | 101 ++++++++++++++++++ src/Module/Finder/PromptFinder.php | 15 +++ 9 files changed, 197 insertions(+), 17 deletions(-) create mode 100644 src/Module/Finder/Dto/File.php create mode 100644 src/Module/Finder/Dto/Prompt.php rename src/Module/Finder/{Finder.php => FilesystemFinder.php} (78%) rename src/Module/Finder/Internal/{FinderImpl.php => FilesystemFinderImpl.php} (73%) create mode 100644 src/Module/Finder/Internal/PromptCache.php create mode 100644 src/Module/Finder/Internal/PromptFinderImpl.php create mode 100644 src/Module/Finder/PromptFinder.php diff --git a/src/Bootstrap.php b/src/Bootstrap.php index a584caf..a977502 100644 --- a/src/Bootstrap.php +++ b/src/Bootstrap.php @@ -4,8 +4,10 @@ namespace LLM\Assistant; -use LLM\Assistant\Module\Finder\Finder; -use LLM\Assistant\Module\Finder\Internal\FinderImpl; +use LLM\Assistant\Module\Finder\FilesystemFinder; +use LLM\Assistant\Module\Finder\Internal\FilesystemFinderImpl; +use LLM\Assistant\Module\Finder\Internal\PromptFinderImpl; +use LLM\Assistant\Module\Finder\PromptFinder; use LLM\Assistant\Service\Cache; use LLM\Assistant\Service\Container; use LLM\Assistant\Service\Internal\Cache\PsrCache; @@ -13,12 +15,10 @@ use LLM\Assistant\Service\Internal\Container\Injection\ConfigLoader; use LLM\Assistant\Service\Internal\Logger\LoggerImpl; use LLM\Assistant\Service\Logger; -use Psr\SimpleCache\CacheInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\StyleInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use Yiisoft\Cache\File\FileCache; /** * Build the container based on the configuration. @@ -48,7 +48,8 @@ public function finish(): Container $c = $this->container; unset($this->container); - $c->bind(Finder::class, FinderImpl::class); + $c->bind(FilesystemFinder::class, FilesystemFinderImpl::class); + $c->bind(PromptFinder::class, PromptFinderImpl::class); $c->bind(Cache::class, PsrCache::class); return $c; diff --git a/src/Command/Run.php b/src/Command/Run.php index 4aef567..6fd587f 100644 --- a/src/Command/Run.php +++ b/src/Command/Run.php @@ -4,7 +4,7 @@ namespace LLM\Assistant\Command; -use LLM\Assistant\Module\Finder\Finder; +use LLM\Assistant\Module\Finder\PromptFinder; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -32,11 +32,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->logger->alert('Assistant is running'); - $finder = $this->container->get(Finder::class); + $finder = $this->container->get(PromptFinder::class); - foreach ($finder->files() as $name => $file) { - $this->logger->info($name); - } + #AI test + tr($finder->getNext()); + + // foreach ($finder->files() as $name => $file) { + // $this->logger->info($name); + // } return Command::SUCCESS; } diff --git a/src/Module/Finder/Dto/File.php b/src/Module/Finder/Dto/File.php new file mode 100644 index 0000000..c65305b --- /dev/null +++ b/src/Module/Finder/Dto/File.php @@ -0,0 +1,17 @@ + $prompts + */ + public function __construct( + public readonly \SplFileInfo $file, + public readonly string $content, + public readonly array $prompts, + ) {} +} diff --git a/src/Module/Finder/Dto/Prompt.php b/src/Module/Finder/Dto/Prompt.php new file mode 100644 index 0000000..19d11fb --- /dev/null +++ b/src/Module/Finder/Dto/Prompt.php @@ -0,0 +1,19 @@ + $start + * @param positive-int $length + * @param non-empty-string $prompt + */ + public function __construct( + public readonly int $start, + public readonly int $length, + public readonly string $prompt, + ) {} +} diff --git a/src/Module/Finder/Finder.php b/src/Module/Finder/FilesystemFinder.php similarity index 78% rename from src/Module/Finder/Finder.php rename to src/Module/Finder/FilesystemFinder.php index bf650d8..d3c24d9 100644 --- a/src/Module/Finder/Finder.php +++ b/src/Module/Finder/FilesystemFinder.php @@ -9,7 +9,7 @@ * * @extends \IteratorAggregate */ -interface Finder extends \IteratorAggregate +interface FilesystemFinder extends \IteratorAggregate { /** * @return \Traversable @@ -18,6 +18,11 @@ public function getIterator(): \Traversable; public function after(\DateTimeInterface $date): static; + /** + * Sort by modify time, oldest first + */ + public function oldest(): static; + /** * @return \Traversable */ diff --git a/src/Module/Finder/Internal/FinderImpl.php b/src/Module/Finder/Internal/FilesystemFinderImpl.php similarity index 73% rename from src/Module/Finder/Internal/FinderImpl.php rename to src/Module/Finder/Internal/FilesystemFinderImpl.php index 1508fb2..d58f05d 100644 --- a/src/Module/Finder/Internal/FinderImpl.php +++ b/src/Module/Finder/Internal/FilesystemFinderImpl.php @@ -5,13 +5,17 @@ namespace LLM\Assistant\Module\Finder\Internal; use LLM\Assistant\Config\Source; -use LLM\Assistant\Module\Finder\Finder; +use LLM\Assistant\Module\Finder\FilesystemFinder; -final class FinderImpl implements Finder +final class FilesystemFinderImpl implements FilesystemFinder { + /** + * @param bool|null $sort If true, sort by newest first + */ public function __construct( private readonly Source $config, private ?\DateTimeInterface $after = null, + private ?bool $sort = null, ) {} public function getIterator(): \Traversable @@ -21,7 +25,12 @@ public function getIterator(): \Traversable public function after(\DateTimeInterface $date): static { - return new self($this->config, $date); + return new self($this->config, $date, $this->sort); + } + + public function oldest(): static + { + return new self($this->config, $this->after, false); } public function files(): \Traversable @@ -51,9 +60,9 @@ private function finder(): \Symfony\Component\Finder\Finder $finder->exclude(\array_map($this->directoryToPattern(...), $this->config->excludeDir)); // $finder->exclude($this->config->cacheDir); - if ($this->after !== null) { - $finder->date('> ' . $this->after->format('Y-m-d H:i:s')); - } + $this->after === null or $finder->date('>= ' . $this->after->format('Y-m-d H:i:s')); + // todo direction + $this->sort === null or $finder->sortByModifiedTime(); return $finder; } diff --git a/src/Module/Finder/Internal/PromptCache.php b/src/Module/Finder/Internal/PromptCache.php new file mode 100644 index 0000000..5866396 --- /dev/null +++ b/src/Module/Finder/Internal/PromptCache.php @@ -0,0 +1,10 @@ +getOrUpdateCache(); + + // Get last modified files + $files = $cache->lastScan === null + ? $this->files->oldest()->files() + : $this->files->after($cache->lastScan)->oldest()->files(); + + foreach ($files as $file) { + $result = $this->scanFile($file); + if ($result !== null) { + // Update modified time in cache DTO to be saved later + $mtime = $file->getMTime(); + $mtime === false or $cache->lastScan = new \DateTimeImmutable('@' . $mtime); + + $this->lastCache = $cache; + return $result; + } + } + + return null; + } + + private function getOrUpdateCache(): PromptCache + { + try { + if ($this->lastCache !== null) { + $this->cache->set(self::CACHE_KEY, $this->lastCache); + return $this->lastCache; + } + + return $this->cache->get(self::CACHE_KEY) ?? new PromptCache(); + } catch (\Throwable) { + return new PromptCache(); + } + } + + private function scanFile(\SplFileInfo $file): ?File + { + $content = \file_get_contents($file->getPathname()); + $this->logger->debug( + \sprintf( + 'Scanning MT: %s Path: %s', + (new \DateTimeImmutable('@' . (int) $file->getMTime()))->format('Y-m-d H:i:s'), + $file->getPathname(), + ), + ); + + // Find all inline prompts started with "#AI" from a new line + $matches = []; + $result = \preg_match_all( + '/^[ \\t]*#AI[ \\t]+(.+)$/m', + $content, + $matches, + \PREG_OFFSET_CAPTURE, + ); + + if ($result === 0) { + return null; + } + + $prompts = []; + /** + * @var array{ + * list}>, + * list + * } $matches + */ + foreach ($matches[0] as $key => $match) { + $prompts[] = new Prompt($match[1], \strlen($match[0]), $matches[1][$key][0]); + } + + return new File($file, $content, $prompts); + } +} diff --git a/src/Module/Finder/PromptFinder.php b/src/Module/Finder/PromptFinder.php new file mode 100644 index 0000000..356d7b8 --- /dev/null +++ b/src/Module/Finder/PromptFinder.php @@ -0,0 +1,15 @@ + Date: Sat, 7 Sep 2024 01:46:04 +0400 Subject: [PATCH 3/3] Update psalm baseline --- psalm-baseline.xml | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index a2737b3..1f18068 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,11 +1,31 @@ - + + + + + + cache->get(self::CACHE_KEY) ?? new PromptCache()]]> + cache->get(self::CACHE_KEY) ?? new PromptCache()]]> + + + + + + + + + + + + + + - + class()]]> @@ -13,9 +33,4 @@ - - - - -